diff --git a/9pfs-local-Fix-possible-memory-leak-in-local_link.patch b/9pfs-local-Fix-possible-memory-leak-in-local_link.patch deleted file mode 100644 index 56b7acb14b023fe3d9f94e22ece7c995a73c3fa6..0000000000000000000000000000000000000000 --- a/9pfs-local-Fix-possible-memory-leak-in-local_link.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 841b8d099c462cd4282c4ced8c2a6512899fd8d9 Mon Sep 17 00:00:00 2001 -From: Jiajun Chen -Date: Mon, 20 Jan 2020 15:11:39 +0100 -Subject: [PATCH] 9pfs: local: Fix possible memory leak in local_link() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There is a possible memory leak while local_link return -1 without free -odirpath and oname. - -Reported-by: Euler Robot -Signed-off-by: Jaijun Chen -Signed-off-by: Xiang Zheng -Reviewed-by: Christian Schoenebeck -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Greg Kurz -(cherry picked from commit 841b8d099c462cd4282c4ced8c2a6512899fd8d9) ---- - hw/9pfs/9p-local.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c -index ca64139..d0592c3 100644 ---- a/hw/9pfs/9p-local.c -+++ b/hw/9pfs/9p-local.c -@@ -947,7 +947,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, - if (ctx->export_flags & V9FS_SM_MAPPED_FILE && - local_is_mapped_file_metadata(ctx, name)) { - errno = EINVAL; -- return -1; -+ goto out; - } - - odirfd = local_opendir_nofollow(ctx, odirpath); --- -1.8.3.1 - diff --git a/9pfs-prevent-opening-special-files-CVE-2023-2861.patch b/9pfs-prevent-opening-special-files-CVE-2023-2861.patch new file mode 100644 index 0000000000000000000000000000000000000000..f19e039e8c56f05a20cd7f1287a8bf843d67b332 --- /dev/null +++ b/9pfs-prevent-opening-special-files-CVE-2023-2861.patch @@ -0,0 +1,172 @@ +From beed3295acf786cec520a8a0aec5efcd2ca12b23 Mon Sep 17 00:00:00 2001 +From: liuxiangdong +Date: Fri, 14 Jul 2023 05:11:57 +0800 +Subject: [PATCH] 9pfs: prevent opening special files (CVE-2023-2861) The 9p + protocol does not specifically define how server shall behave when client + tries to open a special file, however from security POV it does make sense + for 9p server to prohibit opening any special file on host side in general. A + sane Linux 9p client for instance would never attempt to open a special file + on host side, it would always handle those exclusively on its guest side. A + malicious client however could potentially escape from the exported 9p tree + by creating and opening a device file on host side. + +With QEMU this could only be exploited in the following unsafe setups: + + - Running QEMU binary as root AND 9p 'local' fs driver AND 'passthrough' + security model. + +or + + - Using 9p 'proxy' fs driver (which is running its helper daemon as + root). + +These setups were already discouraged for safety reasons before, +however for obvious reasons we are now tightening behaviour on this. + +Fixes: CVE-2023-2861 +Reported-by: Yanwu Shen +Reported-by: Jietao Xiao +Reported-by: Jinku Li +Reported-by: Wenbo Shen +Signed-off-by: Christian Schoenebeck +Reviewed-by: Greg Kurz +Reviewed-by: Michael Tokarev +Message-Id: +--- + fsdev/virtfs-proxy-helper.c | 27 +++++++++++++++++++++++-- + hw/9pfs/9p-util.h | 40 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 2 deletions(-) + +diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c +index 15c0e79b06..f9e4669a5b 100644 +--- a/fsdev/virtfs-proxy-helper.c ++++ b/fsdev/virtfs-proxy-helper.c +@@ -26,6 +26,7 @@ + #include "qemu/xattr.h" + #include "9p-iov-marshal.h" + #include "hw/9pfs/9p-proxy.h" ++#include "hw/9pfs/9p-util.h" + #include "fsdev/9p-iov-marshal.h" + + #define PROGNAME "virtfs-proxy-helper" +@@ -338,6 +339,28 @@ static void resetugid(int suid, int sgid) + } + } + ++/* ++ * Open regular file or directory. Attempts to open any special file are ++ * rejected. ++ * ++ * returns file descriptor or -1 on error ++ */ ++static int open_regular(const char *pathname, int flags, mode_t mode) ++{ ++ int fd; ++ ++ fd = open(pathname, flags, mode); ++ if (fd < 0) { ++ return fd; ++ } ++ ++ if (close_if_special_file(fd) < 0) { ++ return -1; ++ } ++ ++ return fd; ++} ++ + /* + * send response in two parts + * 1) ProxyHeader +@@ -682,7 +705,7 @@ static int do_create(struct iovec *iovec) + if (ret < 0) { + goto unmarshal_err_out; + } +- ret = open(path.data, flags, mode); ++ ret = open_regular(path.data, flags, mode); + if (ret < 0) { + ret = -errno; + } +@@ -707,7 +730,7 @@ static int do_open(struct iovec *iovec) + if (ret < 0) { + goto err_out; + } +- ret = open(path.data, flags); ++ ret = open_regular(path.data, flags, 0); + if (ret < 0) { + ret = -errno; + } +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 546f46dc7d..23000e917f 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -13,12 +13,16 @@ + #ifndef QEMU_9P_UTIL_H + #define QEMU_9P_UTIL_H + ++#include "qemu/error-report.h" ++ + #ifdef O_PATH + #define O_PATH_9P_UTIL O_PATH + #else + #define O_PATH_9P_UTIL 0 + #endif + ++#define qemu_fstat fstat ++ + static inline void close_preserve_errno(int fd) + { + int serrno = errno; +@@ -26,6 +30,38 @@ static inline void close_preserve_errno(int fd) + errno = serrno; + } + ++/** ++ * close_if_special_file() - Close @fd if neither regular file nor directory. ++ * ++ * @fd: file descriptor of open file ++ * Return: 0 on regular file or directory, -1 otherwise ++ * ++ * CVE-2023-2861: Prohibit opening any special file directly on host ++ * (especially device files), as a compromised client could potentially gain ++ * access outside exported tree under certain, unsafe setups. We expect ++ * client to handle I/O on special files exclusively on guest side. ++ */ ++static inline int close_if_special_file(int fd) ++{ ++ struct stat stbuf; ++ ++ if (qemu_fstat(fd, &stbuf) < 0) { ++ close_preserve_errno(fd); ++ return -1; ++ } ++ if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) { ++ error_report_once( ++ "9p: broken or compromised client detected; attempt to open " ++ "special file (i.e. neither regular file, nor directory)" ++ ); ++ close(fd); ++ errno = ENXIO; ++ return -1; ++ } ++ ++ return 0; ++} ++ + static inline int openat_dir(int dirfd, const char *name) + { + return openat(dirfd, name, +@@ -56,6 +92,10 @@ again: + return -1; + } + ++ if (close_if_special_file(fd) < 0) { ++ return -1; ++ } ++ + serrno = errno; + /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't + * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat() +-- +2.41.0.windows.1 + diff --git a/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch b/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch deleted file mode 100644 index 3012512988402756527c95341aa921a362c9e43e..0000000000000000000000000000000000000000 --- a/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch +++ /dev/null @@ -1,64 +0,0 @@ -From e3a7ec839fa4f823666d726989c375dcf73348a4 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 15 Apr 2020 16:14:50 +0800 -Subject: [PATCH] ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > - 256 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Host kernel within [4.18, 5.3] report an erroneous KVM_MAX_VCPUS=512 -for ARM. The actual capability to instantiate more than 256 vcpus -was fixed in 5.4 with the upgrade of the KVM_IRQ_LINE ABI to support -vcpu id encoded on 12 bits instead of 8 and a redistributor consuming -a single KVM IO device instead of 2. - -So let's check this capability when attempting to use more than 256 -vcpus within any ARM kvm accelerated machine. - -Signed-off-by: Eric Auger -Reviewed-by: Richard Henderson -Reviewed-by: Andrew Jones -Acked-by: Marc Zyngier -Message-id: 20191003154640.22451-4-eric.auger@redhat.com -Signed-off-by: Peter Maydell -(cherry-picked from commit fff9f5558d0e0813d4f80bfe1602acf225eca4fd) -[yu: Use the legacy smp_cpus instead of ms->smp.cpus, as we don't have - ¦struct CpuTopology in MachineState at that time. See commit - ¦edeeec911702 for details.] -Signed-off-by: Zenghui Yu ---- - target/arm/kvm.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index 50e86f8b..cc7a46df 100644 ---- a/target/arm/kvm.c -+++ b/target/arm/kvm.c -@@ -173,6 +173,8 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - - int kvm_arch_init(MachineState *ms, KVMState *s) - { -+ int ret = 0; -+ unsigned int smp_cpus = ms->smp.cpus; - /* For ARM interrupt delivery is always asynchronous, - * whether we are using an in-kernel VGIC or not. - */ -@@ -186,7 +188,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - - cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); - -- return 0; -+ if (smp_cpus > 256 && -+ !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) { -+ error_report("Using more than 256 vcpus requires a host kernel " -+ "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2"); -+ ret = -EINVAL; -+ } -+ -+ return ret; - } - - unsigned long kvm_arch_vcpu_id(CPUState *cpu) --- -2.23.0 diff --git a/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch b/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch deleted file mode 100644 index 4681e9f33f6877f199768b7a06a65df5356e6a7f..0000000000000000000000000000000000000000 --- a/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 4646a24045cf53f2cc5e0ef1974da88ef50ef676 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 27 May 2020 11:54:31 +0800 -Subject: [PATCH] ARM64: record vtimer tick when cpu is stopped - -The vtimer kick still increases even if the vcpu is stopped when VM has -save/restore or suspend/resume operation. This will cause guest watchdog -soft-lockup if the VM has lots of memory in use. - -Signed-off-by: Hao Hong -Signed-off-by: Haibin Wang -Signed-off-by: Ying Fang ---- - cpus.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ - target/arm/cpu.h | 2 ++ - target/arm/machine.c | 1 + - 3 files changed, 61 insertions(+) - -diff --git a/cpus.c b/cpus.c -index 927a00aa..b9aa51f8 100644 ---- a/cpus.c -+++ b/cpus.c -@@ -1066,6 +1066,28 @@ void cpu_synchronize_all_pre_loadvm(void) - } - } - -+#ifdef __aarch64__ -+static void get_vcpu_timer_tick(CPUState *cs) -+{ -+ CPUARMState *env = &ARM_CPU(cs)->env; -+ int err; -+ struct kvm_one_reg reg; -+ uint64_t timer_tick; -+ -+ reg.id = KVM_REG_ARM_TIMER_CNT; -+ reg.addr = (uintptr_t) &timer_tick; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); -+ if (err < 0) { -+ error_report("get vcpu tick failed, ret = %d", err); -+ env->vtimer = 0; -+ return; -+ } -+ env->vtimer = timer_tick; -+ return; -+} -+#endif -+ - static int do_vm_stop(RunState state, bool send_stop) - { - int ret = 0; -@@ -1073,6 +1095,11 @@ static int do_vm_stop(RunState state, bool send_stop) - if (runstate_is_running()) { - cpu_disable_ticks(); - pause_all_vcpus(); -+#ifdef __aarch64__ -+ if (first_cpu) { -+ get_vcpu_timer_tick(first_cpu); -+ } -+#endif - runstate_set(state); - vm_state_notify(0, state); - if (send_stop) { -@@ -1918,11 +1945,42 @@ void cpu_resume(CPUState *cpu) - qemu_cpu_kick(cpu); - } - -+#ifdef __aarch64__ -+static void set_vcpu_timer_tick(CPUState *cs) -+{ -+ CPUARMState *env = &ARM_CPU(cs)->env; -+ -+ if (env->vtimer == 0) { -+ return; -+ } -+ -+ int err; -+ struct kvm_one_reg reg; -+ uint64_t timer_tick = env->vtimer; -+ env->vtimer = 0; -+ -+ reg.id = KVM_REG_ARM_TIMER_CNT; -+ reg.addr = (uintptr_t) &timer_tick; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); -+ if (err < 0) { -+ error_report("Set vcpu tick failed, ret = %d", err); -+ return; -+ } -+ return; -+} -+#endif -+ - void resume_all_vcpus(void) - { - CPUState *cpu; - - qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); -+#ifdef __aarch64__ -+ if (first_cpu) { -+ set_vcpu_timer_tick(first_cpu); -+ } -+#endif - CPU_FOREACH(cpu) { - cpu_resume(cpu); - } -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 86eb79cd..aec6a214 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -262,6 +262,8 @@ typedef struct CPUARMState { - uint64_t sp_el[4]; /* AArch64 banked stack pointers */ - - -+ uint64_t vtimer; /* Timer tick when vcpu stop */ -+ - /* System control coprocessor (cp15) */ - struct { - uint32_t c0_cpuid; -diff --git a/target/arm/machine.c b/target/arm/machine.c -index ee3c59a6..ec28b839 100644 ---- a/target/arm/machine.c -+++ b/target/arm/machine.c -@@ -814,6 +814,7 @@ const VMStateDescription vmstate_arm_cpu = { - VMSTATE_UINT32(env.exception.syndrome, ARMCPU), - VMSTATE_UINT32(env.exception.fsr, ARMCPU), - VMSTATE_UINT64(env.exception.vaddress, ARMCPU), -+ VMSTATE_UINT64(env.vtimer, ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), - { --- -2.23.0 - diff --git a/AVX512-support-for-xbzrle_encode_buffer.patch b/AVX512-support-for-xbzrle_encode_buffer.patch new file mode 100644 index 0000000000000000000000000000000000000000..63484267376bcc25149765f2908a58970d3432f5 --- /dev/null +++ b/AVX512-support-for-xbzrle_encode_buffer.patch @@ -0,0 +1,310 @@ +From 4d572573175449f48fc12c9f9524fc09f219cdbd Mon Sep 17 00:00:00 2001 +From: ling xu +Date: Wed, 16 Nov 2022 23:29:22 +0800 +Subject: [PATCH] AVX512 support for xbzrle_encode_buffer + +mainline inclusion +from mainline-v8.0.0-rc0 +commit 04ffce137b6d85ab4e7687e54e4dffcef0a9ab99 +category: feature +feature: AVX512 support for xbzrle_encode_buffer +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Z50P + +Intel-SIG: commit 04ffce137b6d ("AVX512 support for xbzrle_encode_buffer") + +------------------------------------- + +AVX512 support for xbzrle_encode_buffer + +This commit is the same with [PATCH v6 1/2], and provides avx512 support for xbzrle_encode_buffer +function to accelerate xbzrle encoding speed. Runtime check of avx512 +support and benchmark for this feature are added. Compared with C +version of xbzrle_encode_buffer function, avx512 version can achieve +50%-70% performance improvement on benchmarking. In addition, if dirty +data is randomly located in 4K page, the avx512 version can achieve +almost 140% performance gain. + +Signed-off-by: ling xu +Co-authored-by: Zhou Zhao +Co-authored-by: Jun Jin +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Aichun Shi +--- + meson.build | 17 +++++ + meson_options.txt | 2 + + migration/ram.c | 34 +++++++++- + migration/xbzrle.c | 124 ++++++++++++++++++++++++++++++++++ + migration/xbzrle.h | 4 ++ + scripts/meson-buildoptions.sh | 3 + + 6 files changed, 181 insertions(+), 3 deletions(-) + +diff --git a/meson.build b/meson.build +index 9f77254861..45bc69bf0c 100644 +--- a/meson.build ++++ b/meson.build +@@ -1816,6 +1816,22 @@ config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' + return -1; + }''')) + ++config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \ ++ .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512BW') \ ++ .require(cc.links(''' ++ #pragma GCC push_options ++ #pragma GCC target("avx512bw") ++ #include ++ #include ++ static int bar(void *a) { ++ ++ __m512i *x = a; ++ __m512i res= _mm512_abs_epi8(*x); ++ return res[1]; ++ } ++ int main(int argc, char *argv[]) { return bar(argv[0]); } ++ '''), error_message: 'AVX512BW not available').allowed()) ++ + ignored = ['CONFIG_QEMU_INTERP_PREFIX', # actually per-target + 'HAVE_GDB_BIN'] + arrays = ['CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] +@@ -3318,6 +3334,7 @@ summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_US + summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')} + summary_info += {'memory allocator': get_option('malloc')} + summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} ++summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')} + summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} + summary_info += {'gprof enabled': config_host.has_key('CONFIG_GPROF')} + summary_info += {'gcov': get_option('b_coverage')} +diff --git a/meson_options.txt b/meson_options.txt +index e9cbe48cb9..ec9c3c0a05 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -70,6 +70,8 @@ option('avx2', type: 'feature', value: 'auto', + description: 'AVX2 optimizations') + option('avx512f', type: 'feature', value: 'disabled', + description: 'AVX512F optimizations') ++option('avx512bw', type: 'feature', value: 'auto', ++ description: 'AVX512BW optimizations') + + option('attr', type : 'feature', value : 'auto', + description: 'attr/xattr support') +diff --git a/migration/ram.c b/migration/ram.c +index c3484ee1a9..a4383954b4 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -91,6 +91,34 @@ static inline bool is_zero_range(uint8_t *p, uint64_t size) + return buffer_is_zero(p, size); + } + ++int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int, ++ uint8_t *, int) = xbzrle_encode_buffer; ++#if defined(CONFIG_AVX512BW_OPT) ++#include "qemu/cpuid.h" ++static void __attribute__((constructor)) init_cpu_flag(void) ++{ ++ unsigned max = __get_cpuid_max(0, NULL); ++ int a, b, c, d; ++ if (max >= 1) { ++ __cpuid(1, a, b, c, d); ++ /* We must check that AVX is not just available, but usable. */ ++ if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { ++ int bv; ++ __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); ++ __cpuid_count(7, 0, a, b, c, d); ++ /* 0xe6: ++ * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 ++ * and ZMM16-ZMM31 state are enabled by OS) ++ * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) ++ */ ++ if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { ++ xbzrle_encode_buffer_func = xbzrle_encode_buffer_avx512; ++ } ++ } ++ } ++} ++#endif ++ + XBZRLECacheStats xbzrle_counters; + + /* struct contains XBZRLE cache and a static page +@@ -1031,9 +1059,9 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, + memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE); + + /* XBZRLE encoding (if there is no overflow) */ +- encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf, +- TARGET_PAGE_SIZE, XBZRLE.encoded_buf, +- TARGET_PAGE_SIZE); ++ encoded_len = xbzrle_encode_buffer_func(prev_cached_page, XBZRLE.current_buf, ++ TARGET_PAGE_SIZE, XBZRLE.encoded_buf, ++ TARGET_PAGE_SIZE); + + /* + * Update the cache contents, so that it corresponds to the data +diff --git a/migration/xbzrle.c b/migration/xbzrle.c +index 1ba482ded9..05366e86c0 100644 +--- a/migration/xbzrle.c ++++ b/migration/xbzrle.c +@@ -174,3 +174,127 @@ int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen) + + return d; + } ++ ++#if defined(CONFIG_AVX512BW_OPT) ++#pragma GCC push_options ++#pragma GCC target("avx512bw") ++#include ++int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, ++ uint8_t *dst, int dlen) ++{ ++ uint32_t zrun_len = 0, nzrun_len = 0; ++ int d = 0, i = 0, num = 0; ++ uint8_t *nzrun_start = NULL; ++ /* add 1 to include residual part in main loop */ ++ uint32_t count512s = (slen >> 6) + 1; ++ /* countResidual is tail of data, i.e., countResidual = slen % 64 */ ++ uint32_t count_residual = slen & 0b111111; ++ bool never_same = true; ++ uint64_t mask_residual = 1; ++ mask_residual <<= count_residual; ++ mask_residual -= 1; ++ __m512i r = _mm512_set1_epi32(0); ++ ++ while (count512s) { ++ if (d + 2 > dlen) { ++ return -1; ++ } ++ ++ int bytes_to_check = 64; ++ uint64_t mask = 0xffffffffffffffff; ++ if (count512s == 1) { ++ bytes_to_check = count_residual; ++ mask = mask_residual; ++ } ++ __m512i old_data = _mm512_mask_loadu_epi8(r, ++ mask, old_buf + i); ++ __m512i new_data = _mm512_mask_loadu_epi8(r, ++ mask, new_buf + i); ++ uint64_t comp = _mm512_cmpeq_epi8_mask(old_data, new_data); ++ count512s--; ++ ++ bool is_same = (comp & 0x1); ++ while (bytes_to_check) { ++ if (is_same) { ++ if (nzrun_len) { ++ d += uleb128_encode_small(dst + d, nzrun_len); ++ if (d + nzrun_len > dlen) { ++ return -1; ++ } ++ nzrun_start = new_buf + i - nzrun_len; ++ memcpy(dst + d, nzrun_start, nzrun_len); ++ d += nzrun_len; ++ nzrun_len = 0; ++ } ++ /* 64 data at a time for speed */ ++ if (count512s && (comp == 0xffffffffffffffff)) { ++ i += 64; ++ zrun_len += 64; ++ break; ++ } ++ never_same = false; ++ num = __builtin_ctzll(~comp); ++ num = (num < bytes_to_check) ? num : bytes_to_check; ++ zrun_len += num; ++ bytes_to_check -= num; ++ comp >>= num; ++ i += num; ++ if (bytes_to_check) { ++ /* still has different data after same data */ ++ d += uleb128_encode_small(dst + d, zrun_len); ++ zrun_len = 0; ++ } else { ++ break; ++ } ++ } ++ if (never_same || zrun_len) { ++ /* ++ * never_same only acts if ++ * data begins with diff in first count512s ++ */ ++ d += uleb128_encode_small(dst + d, zrun_len); ++ zrun_len = 0; ++ never_same = false; ++ } ++ /* has diff, 64 data at a time for speed */ ++ if ((bytes_to_check == 64) && (comp == 0x0)) { ++ i += 64; ++ nzrun_len += 64; ++ break; ++ } ++ num = __builtin_ctzll(comp); ++ num = (num < bytes_to_check) ? num : bytes_to_check; ++ nzrun_len += num; ++ bytes_to_check -= num; ++ comp >>= num; ++ i += num; ++ if (bytes_to_check) { ++ /* mask like 111000 */ ++ d += uleb128_encode_small(dst + d, nzrun_len); ++ /* overflow */ ++ if (d + nzrun_len > dlen) { ++ return -1; ++ } ++ nzrun_start = new_buf + i - nzrun_len; ++ memcpy(dst + d, nzrun_start, nzrun_len); ++ d += nzrun_len; ++ nzrun_len = 0; ++ is_same = true; ++ } ++ } ++ } ++ ++ if (nzrun_len != 0) { ++ d += uleb128_encode_small(dst + d, nzrun_len); ++ /* overflow */ ++ if (d + nzrun_len > dlen) { ++ return -1; ++ } ++ nzrun_start = new_buf + i - nzrun_len; ++ memcpy(dst + d, nzrun_start, nzrun_len); ++ d += nzrun_len; ++ } ++ return d; ++} ++#pragma GCC pop_options ++#endif +diff --git a/migration/xbzrle.h b/migration/xbzrle.h +index a0db507b9c..6feb49160a 100644 +--- a/migration/xbzrle.h ++++ b/migration/xbzrle.h +@@ -18,4 +18,8 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen); + + int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen); ++#if defined(CONFIG_AVX512BW_OPT) ++int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, ++ uint8_t *dst, int dlen); ++#endif + #endif +diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh +index b994bf16f0..8c00cce411 100644 +--- a/scripts/meson-buildoptions.sh ++++ b/scripts/meson-buildoptions.sh +@@ -26,6 +26,7 @@ meson_options_help() { + printf "%s\n" ' attr attr/xattr support' + printf "%s\n" ' auth-pam PAM access control' + printf "%s\n" ' avx2 AVX2 optimizations' ++ printf "%s\n" ' avx512bw AVX512BW optimizations' + printf "%s\n" ' avx512f AVX512F optimizations' + printf "%s\n" ' bpf eBPF support' + printf "%s\n" ' brlapi brlapi character device driver' +@@ -111,6 +112,8 @@ _meson_option_parse() { + --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; + --enable-avx2) printf "%s" -Davx2=enabled ;; + --disable-avx2) printf "%s" -Davx2=disabled ;; ++ --enable-avx512bw) printf "%s" -Davx512bw=enabled ;; ++ --disable-avx512bw) printf "%s" -Davx512bw=disabled ;; + --enable-avx512f) printf "%s" -Davx512f=enabled ;; + --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-bpf) printf "%s" -Dbpf=enabled ;; +-- +2.27.0 + diff --git a/Add-PowerManager-support.patch b/Add-PowerManager-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ed7b2bea9e83e33ee3b4dc3851c8ca7a567fe4f --- /dev/null +++ b/Add-PowerManager-support.patch @@ -0,0 +1,758 @@ +From 1fc8fa6cd621c17988b043c1b3abe9ccb189a1d7 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 06:34:32 -0500 +Subject: [PATCH] Add PowerManager support. + +Add Loongarch ACPI power management device simulation. + +Signed-off-by: lixianglai +--- + hw/acpi/Kconfig | 8 + + hw/acpi/larch_7a.c | 616 +++++++++++++++++++++++++++++++++++++++++ + hw/acpi/meson.build | 1 + + include/hw/acpi/ls7a.h | 79 ++++++ + 4 files changed, 704 insertions(+) + create mode 100644 hw/acpi/larch_7a.c + create mode 100644 include/hw/acpi/ls7a.h + +diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig +index 622b0b50b7..245c5554df 100644 +--- a/hw/acpi/Kconfig ++++ b/hw/acpi/Kconfig +@@ -15,6 +15,14 @@ config ACPI_X86_ICH + bool + select ACPI_X86 + ++config ACPI_LOONGARCH ++ bool ++ select ACPI ++ select ACPI_CPU_HOTPLUG ++ select ACPI_MEMORY_HOTPLUG ++ select ACPI_PIIX4 ++ select ACPI_PCIHP ++ + config ACPI_CPU_HOTPLUG + bool + +diff --git a/hw/acpi/larch_7a.c b/hw/acpi/larch_7a.c +new file mode 100644 +index 0000000000..59b43170ff +--- /dev/null ++++ b/hw/acpi/larch_7a.c +@@ -0,0 +1,616 @@ ++/* ++ * Loongarch acpi emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++#include "qemu/osdep.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/runstate.h" ++#include "sysemu/reset.h" ++#include "hw/hw.h" ++#include "hw/irq.h" ++#include "hw/acpi/acpi.h" ++#include "hw/acpi/ls7a.h" ++#include "hw/nvram/fw_cfg.h" ++#include "qemu/config-file.h" ++#include "qapi/opts-visitor.h" ++#include "qapi/qapi-events-run-state.h" ++#include "qapi/error.h" ++#include "hw/loongarch/ls7a.h" ++#include "hw/mem/pc-dimm.h" ++#include "hw/mem/nvdimm.h" ++#include "migration/vmstate.h" ++ ++static void ls7a_pm_update_sci_fn(ACPIREGS *regs) ++{ ++ LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs); ++ acpi_update_sci(&pm->acpi_regs, pm->irq); ++} ++ ++static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); ++} ++ ++static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, ++ unsigned width) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); ++ acpi_update_sci(&pm->acpi_regs, pm->irq); ++} ++ ++static const MemoryRegionOps ls7a_gpe_ops = { ++ .read = ls7a_gpe_readb, ++ .write = ls7a_gpe_writeb, ++ .valid.min_access_size = 1, ++ .valid.max_access_size = 8, ++ .impl.min_access_size = 1, ++ .impl.max_access_size = 1, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++#define VMSTATE_GPE_ARRAY(_field, _state) \ ++{ \ ++ .name = (stringify(_field)), .version_id = 0, .num = ACPI_GPE0_LEN, \ ++ .info = &vmstate_info_uint8, .size = sizeof(uint8_t), \ ++ .flags = VMS_ARRAY | VMS_POINTER, \ ++ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ ++} ++ ++static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width) ++{ ++ return 0; ++} ++ ++static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val, ++ unsigned width) ++{ ++ if (val & 1) { ++ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); ++ } ++} ++ ++static const MemoryRegionOps ls7a_reset_ops = { ++ .read = ls7a_reset_readw, ++ .write = ls7a_reset_writew, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static bool vmstate_test_use_memhp(void *opaque) ++{ ++ LS7APCIPMRegs *s = opaque; ++ return s->acpi_memory_hotplug.is_enabled; ++} ++ ++static const VMStateDescription vmstate_memhp_state = { ++ .name = "ls7a_pm/memhp", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .minimum_version_id_old = 1, ++ .needed = vmstate_test_use_memhp, ++ .fields = (VMStateField[]){ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ++ LS7APCIPMRegs), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static const VMStateDescription vmstate_cpuhp_state = { ++ .name = "ls7a_pm/cpuhp", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .minimum_version_id_old = 1, ++ .fields = ++ (VMStateField[]){ VMSTATE_CPU_HOTPLUG(cpuhp_state, LS7APCIPMRegs), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++const VMStateDescription vmstate_ls7a_pm = { ++ .name = "ls7a_pm", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = ++ (VMStateField[]){ ++ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs), ++ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs), ++ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs), ++ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs), ++ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs), ++ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs), ++ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs), ++ VMSTATE_END_OF_LIST() }, ++ .subsections = (const VMStateDescription *[]){ &vmstate_memhp_state, ++ &vmstate_cpuhp_state, NULL } ++}; ++ ++static inline int64_t acpi_pm_tmr_get_clock(void) ++{ ++ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, ++ NANOSECONDS_PER_SECOND); ++} ++ ++static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) ++{ ++ uint32_t d = acpi_pm_tmr_get_clock(); ++ return d & 0xffffff; ++} ++ ++static void acpi_pm_tmr_timer(void *opaque) ++{ ++ ACPIREGS *ar = opaque; ++ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); ++ ar->tmr.update_sci(ar); ++} ++ ++static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) ++{ ++ return acpi_pm_tmr_get(opaque); ++} ++ ++static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned width) ++{ ++ /* nothing */ ++} ++ ++static const MemoryRegionOps acpi_pm_tmr_ops = { ++ .read = acpi_pm_tmr_read, ++ .write = acpi_pm_tmr_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, ++ MemoryRegion *parent, uint64_t offset) ++{ ++ ar->tmr.update_sci = update_sci; ++ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); ++ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), ++ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); ++ memory_region_add_subregion(parent, offset, &ar->tmr.io); ++} ++ ++static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) ++{ ++ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); ++ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { ++ /* if TMRSTS is reset, then compute the new overflow time */ ++ acpi_pm_tmr_calc_overflow_time(ar); ++ } ++ ar->pm1.evt.sts &= ~val; ++} ++ ++static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) ++{ ++ ACPIREGS *ar = opaque; ++ switch (addr) { ++ case 0: ++ return acpi_pm1_evt_get_sts(ar); ++ case 4: ++ return ar->pm1.evt.en; ++ default: ++ return 0; ++ } ++} ++ ++static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) ++{ ++ ar->pm1.evt.en = val; ++ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, ++ val & ACPI_BITMASK_RT_CLOCK_ENABLE); ++ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, ++ val & ACPI_BITMASK_TIMER_ENABLE); ++} ++ ++static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned width) ++{ ++ ACPIREGS *ar = opaque; ++ switch (addr) { ++ case 0: ++ acpi_pm1_evt_write_sts(ar, val); ++ ar->pm1.evt.update_sci(ar); ++ break; ++ case 4: ++ acpi_pm1_evt_write_en(ar, val); ++ ar->pm1.evt.update_sci(ar); ++ break; ++ default: ++ break; ++ } ++} ++ ++static const MemoryRegionOps acpi_pm_evt_ops = { ++ .read = acpi_pm_evt_read, ++ .write = acpi_pm_evt_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, ++ MemoryRegion *parent, uint64_t offset) ++{ ++ ar->pm1.evt.update_sci = update_sci; ++ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), ++ &acpi_pm_evt_ops, ar, "acpi-evt", 8); ++ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io); ++} ++ ++static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) ++{ ++ ACPIREGS *ar = opaque; ++ return ar->pm1.cnt.cnt; ++} ++ ++/* ACPI PM1aCNT */ ++static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) ++{ ++ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); ++ if (val & ACPI_BITMASK_SLEEP_ENABLE) { ++ /* change suspend type */ ++ uint16_t sus_typ = (val >> 10) & 7; ++ switch (sus_typ) { ++ /* s3,s4 not support */ ++ case 5: ++ case 6: ++ warn_report("acpi s3,s4 state not support"); ++ break; ++ /* s5: soft off */ ++ case 7: ++ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned width) ++{ ++ acpi_pm1_cnt_write(opaque, val); ++} ++ ++static const MemoryRegionOps acpi_pm_cnt_ops = { ++ .read = acpi_pm_cnt_read, ++ .write = acpi_pm_cnt_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static void acpi_notify_wakeup(Notifier *notifier, void *data) ++{ ++ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); ++ WakeupReason *reason = data; ++ ++ switch (*reason) { ++ case QEMU_WAKEUP_REASON_RTC: ++ ar->pm1.evt.sts |= ++ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); ++ break; ++ case QEMU_WAKEUP_REASON_PMTIMER: ++ ar->pm1.evt.sts |= ++ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); ++ break; ++ case QEMU_WAKEUP_REASON_OTHER: ++ /* ++ * ACPI_BITMASK_WAKE_STATUS should be set on resume. ++ * Pretend that resume was caused by power button ++ */ ++ ar->pm1.evt.sts |= ++ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, ++ bool disable_s3, bool disable_s4, uint8_t s4_val, ++ uint64_t offset) ++{ ++ FWCfgState *fw_cfg; ++ ++ ar->pm1.cnt.s4_val = s4_val; ++ ar->wakeup.notify = acpi_notify_wakeup; ++ qemu_register_wakeup_notifier(&ar->wakeup); ++ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), ++ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4); ++ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io); ++ ++ fw_cfg = fw_cfg_find(); ++ if (fw_cfg) { ++ uint8_t suspend[6] = { 128, 0, 0, 129, 128, 128 }; ++ suspend[3] = 1 | ((!disable_s3) << 7); ++ suspend[4] = s4_val | ((!disable_s4) << 7); ++ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); ++ } ++} ++ ++static void ls7a_pm_reset(void *opaque) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ ++ acpi_pm1_evt_reset(&pm->acpi_regs); ++ acpi_pm1_cnt_reset(&pm->acpi_regs); ++ acpi_pm_tmr_reset(&pm->acpi_regs); ++ acpi_gpe_reset(&pm->acpi_regs); ++ ++ acpi_update_sci(&pm->acpi_regs, pm->irq); ++} ++ ++static void pm_powerdown_req(Notifier *n, void *opaque) ++{ ++ LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier); ++ ++ acpi_pm1_evt_power_down(&pm->acpi_regs); ++} ++ ++void ls7a_pm_init(LS7APCIPMRegs *pm, qemu_irq *pic) ++{ ++ unsigned long base, gpe_len, acpi_aci_irq; ++ ++ /* ++ * ls7a board acpi hardware info, including ++ * acpi system io base address ++ * acpi gpe length ++ * acpi sci irq number ++ */ ++ base = ACPI_IO_BASE; ++ gpe_len = ACPI_GPE0_LEN; ++ acpi_aci_irq = ACPI_SCI_IRQ; ++ ++ pm->irq = pic[acpi_aci_irq - 64]; ++ memory_region_init(&pm->iomem, NULL, "ls7a_pm", ACPI_IO_SIZE); ++ memory_region_add_subregion(get_system_memory(), base, &pm->iomem); ++ ++ cpu_hotplug_hw_init(get_system_memory(), NULL, &pm->cpuhp_state, ++ CPU_HOTPLUG_BASE); ++ ++ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, ++ LS7A_PM_TMR_BLK); ++ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, ++ LS7A_PM_EVT_BLK); ++ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, false, false, 2, ++ LS7A_PM_CNT_BLK); ++ ++ acpi_gpe_init(&pm->acpi_regs, gpe_len); ++ memory_region_init_io(&pm->iomem_gpe, NULL, &ls7a_gpe_ops, pm, "acpi-gpe0", ++ gpe_len); ++ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe); ++ ++ memory_region_init_io(&pm->iomem_reset, NULL, &ls7a_reset_ops, pm, ++ "acpi-reset", 4); ++ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG, ++ &pm->iomem_reset); ++ ++ qemu_register_reset(ls7a_pm_reset, pm); ++ ++ pm->powerdown_notifier.notify = pm_powerdown_req; ++ qemu_register_powerdown_notifier(&pm->powerdown_notifier); ++ ++ if (pm->acpi_memory_hotplug.is_enabled) { ++ acpi_memory_hotplug_init(get_system_memory(), NULL, ++ &pm->acpi_memory_hotplug, ++ MEMORY_HOTPLUG_BASE); ++ } ++} ++ ++static void ls7a_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint64_t value = ACPI_IO_BASE + LS7A_GPE0_STS_REG; ++ ++ visit_type_uint64(v, name, &value, errp); ++} ++ ++static bool ls7a_pm_get_memory_hotplug_support(Object *obj, Error **errp) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(obj); ++ ++ return ls7a->pm.acpi_memory_hotplug.is_enabled; ++} ++ ++static void ls7a_pm_set_memory_hotplug_support(Object *obj, bool value, ++ Error **errp) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(obj); ++ ++ ls7a->pm.acpi_memory_hotplug.is_enabled = value; ++} ++ ++static void ls7a_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ uint8_t value = pm->disable_s3; ++ ++ visit_type_uint8(v, name, &value, errp); ++} ++ ++static void ls7a_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ Error *local_err = NULL; ++ uint8_t value; ++ ++ visit_type_uint8(v, name, &value, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ pm->disable_s3 = value; ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void ls7a_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ uint8_t value = pm->disable_s4; ++ ++ visit_type_uint8(v, name, &value, errp); ++} ++ ++static void ls7a_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ Error *local_err = NULL; ++ uint8_t value; ++ ++ visit_type_uint8(v, name, &value, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ pm->disable_s4 = value; ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void ls7a_pm_get_s4_val(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ uint8_t value = pm->s4_val; ++ ++ visit_type_uint8(v, name, &value, errp); ++} ++ ++static void ls7a_pm_set_s4_val(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LS7APCIPMRegs *pm = opaque; ++ Error *local_err = NULL; ++ uint8_t value; ++ ++ visit_type_uint8(v, name, &value, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ pm->s4_val = value; ++out: ++ error_propagate(errp, local_err); ++} ++ ++void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp) ++{ ++ static const uint32_t gpe0_len = ACPI_GPE0_LEN; ++ pm->acpi_memory_hotplug.is_enabled = true; ++ pm->disable_s3 = 0; ++ pm->disable_s4 = 0; ++ pm->s4_val = 2; ++ ++ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, ++ &pm->pm_io_base, OBJ_PROP_FLAG_READ); ++ object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", ++ ls7a_pm_get_gpe0_blk, NULL, NULL, pm); ++ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, &gpe0_len, ++ OBJ_PROP_FLAG_READ); ++ object_property_add_bool(obj, "memory-hotplug-support", ++ ls7a_pm_get_memory_hotplug_support, ++ ls7a_pm_set_memory_hotplug_support); ++ object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", ++ ls7a_pm_get_disable_s3, ls7a_pm_set_disable_s3, NULL, ++ pm); ++ object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", ++ ls7a_pm_get_disable_s4, ls7a_pm_set_disable_s4, NULL, ++ pm); ++ object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", ls7a_pm_get_s4_val, ++ ls7a_pm_set_s4_val, NULL, pm); ++} ++ ++void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); ++ ++ if (ls7a->pm.acpi_memory_hotplug.is_enabled && ++ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { ++ nvdimm_acpi_plug_cb(hotplug_dev, dev); ++ } else { ++ acpi_memory_plug_cb(hotplug_dev, &ls7a->pm.acpi_memory_hotplug, ++ dev, errp); ++ } ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_plug_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, errp); ++ } else { ++ error_setg(errp, ++ "acpi: device plug request for not supported device" ++ " type: %s", ++ object_get_typename(OBJECT(dev))); ++ } ++} ++ ++void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); ++ ++ if (ls7a->pm.acpi_memory_hotplug.is_enabled && ++ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ acpi_memory_unplug_request_cb( ++ hotplug_dev, &ls7a->pm.acpi_memory_hotplug, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_request_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, ++ errp); ++ } else { ++ error_setg(errp, ++ "acpi: device unplug request for not supported device" ++ " type: %s", ++ object_get_typename(OBJECT(dev))); ++ } ++} ++ ++void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); ++ ++ if (ls7a->pm.acpi_memory_hotplug.is_enabled && ++ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ acpi_memory_unplug_cb(&ls7a->pm.acpi_memory_hotplug, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_cb(&ls7a->pm.cpuhp_state, dev, errp); ++ } else { ++ error_setg(errp, ++ "acpi: device unplug for not supported device" ++ " type: %s", ++ object_get_typename(OBJECT(dev))); ++ } ++} ++ ++void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); ++ ++ acpi_memory_ospm_status(&ls7a->pm.acpi_memory_hotplug, list); ++ acpi_cpu_ospm_status(&ls7a->pm.cpuhp_state, list); ++} ++ ++void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); ++ ++ acpi_send_gpe_event(&ls7a->pm.acpi_regs, ls7a->pm.irq, ev); ++} +diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build +index 448ea6afb4..4718d143fc 100644 +--- a/hw/acpi/meson.build ++++ b/hw/acpi/meson.build +@@ -6,6 +6,7 @@ acpi_ss.add(files( + 'core.c', + 'utils.c', + )) ++acpi_ss.add(when: 'CONFIG_ACPI_LOONGARCH', if_true: files('larch_7a.c')) + acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_true: files('cpu.c', 'cpu_hotplug.c')) + acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false: files('acpi-cpu-hotplug-stub.c')) + acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true: files('memory_hotplug.c')) +diff --git a/include/hw/acpi/ls7a.h b/include/hw/acpi/ls7a.h +new file mode 100644 +index 0000000000..295baa4b5a +--- /dev/null ++++ b/include/hw/acpi/ls7a.h +@@ -0,0 +1,79 @@ ++/* ++ * QEMU GMCH/LS7A PCI PM Emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_ACPI_LS7A_H ++#define HW_ACPI_LS7A_H ++ ++#include "hw/acpi/acpi.h" ++#include "hw/acpi/cpu_hotplug.h" ++#include "hw/acpi/cpu.h" ++#include "hw/acpi/memory_hotplug.h" ++#include "hw/acpi/acpi_dev_interface.h" ++#include "hw/acpi/tco.h" ++ ++#define CPU_HOTPLUG_BASE 0x1e000000 ++#define MEMORY_HOTPLUG_BASE 0x1e00000c ++ ++typedef struct LS7APCIPMRegs { ++ /* ++ * In ls7a spec says that pm1_cnt register is 32bit width and ++ * that the upper 16bits are reserved and unused. ++ * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. ++ */ ++ ACPIREGS acpi_regs; ++ ++ MemoryRegion iomem; ++ MemoryRegion iomem_gpe; ++ MemoryRegion iomem_smi; ++ MemoryRegion iomem_reset; ++ ++ qemu_irq irq; /* SCI */ ++ ++ uint32_t pm_io_base; ++ Notifier powerdown_notifier; ++ ++ bool cpu_hotplug_legacy; ++ AcpiCpuHotplug gpe_cpu; ++ CPUHotplugState cpuhp_state; ++ ++ MemHotplugState acpi_memory_hotplug; ++ ++ uint8_t disable_s3; ++ uint8_t disable_s4; ++ uint8_t s4_val; ++} LS7APCIPMRegs; ++ ++void ls7a_pm_init(LS7APCIPMRegs *ls7a, qemu_irq *sci_irq); ++ ++void ls7a_pm_iospace_update(LS7APCIPMRegs *pm, uint32_t pm_io_base); ++extern const VMStateDescription vmstate_ls7a_pm; ++ ++void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp); ++ ++void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp); ++void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp); ++void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp); ++ ++void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); ++ ++void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev); ++#endif /* HW_ACPI_LS7A_H */ +-- +2.27.0 + diff --git a/Add-RTC-support.patch b/Add-RTC-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..06e50c07e157702de6b96097257813f5191fe2af --- /dev/null +++ b/Add-RTC-support.patch @@ -0,0 +1,402 @@ +From 1b831c95e652d185c20efe74457927f5d7e35153 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 06:35:16 -0500 +Subject: [PATCH] Add RTC support. + +Add Loongarch real-time clock device simulation. + +Signed-off-by: lixianglai +--- + hw/meson.build | 1 + + hw/timer/Kconfig | 2 + + hw/timer/ls7a_rtc.c | 343 +++++++++++++++++++++++++++++++++++++++++++ + hw/timer/meson.build | 1 + + 4 files changed, 347 insertions(+) + create mode 100644 hw/timer/ls7a_rtc.c + +diff --git a/hw/meson.build b/hw/meson.build +index f39c1f7e70..a9a078ec33 100644 +--- a/hw/meson.build ++++ b/hw/meson.build +@@ -17,6 +17,7 @@ subdir('intc') + subdir('ipack') + subdir('ipmi') + subdir('isa') ++subdir('loongarch') + subdir('mem') + subdir('misc') + subdir('net') +diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig +index 010be7ed1f..b395c72d7d 100644 +--- a/hw/timer/Kconfig ++++ b/hw/timer/Kconfig +@@ -60,3 +60,5 @@ config STELLARIS_GPTM + + config AVR_TIMER16 + bool ++config LS7A_RTC ++ bool +diff --git a/hw/timer/ls7a_rtc.c b/hw/timer/ls7a_rtc.c +new file mode 100644 +index 0000000000..56c2695654 +--- /dev/null ++++ b/hw/timer/ls7a_rtc.c +@@ -0,0 +1,343 @@ ++/* ++ * Loongarch rtc emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "hw/irq.h" ++#include "include/hw/register.h" ++#include "qemu/timer.h" ++#include "sysemu/sysemu.h" ++#include "qemu/cutils.h" ++#include "qemu/log.h" ++#include "qemu-common.h" ++#include "migration/vmstate.h" ++ ++#ifdef DEBUG_LS7A_RTC ++#define DPRINTF \ ++ (fmt, ...) do \ ++ { \ ++ printf("ls7a_rtc: " fmt, ##__VA_ARGS__); \ ++ } \ ++ while (0) ++#else ++#define DPRINTF \ ++ (fmt, ...) do \ ++ { \ ++ } \ ++ while (0) ++#endif ++ ++#define SYS_TOYTRIM 0x20 ++#define SYS_TOYWRITE0 0x24 ++#define SYS_TOYWRITE1 0x28 ++#define SYS_TOYREAD0 0x2C ++#define SYS_TOYREAD1 0x30 ++#define SYS_TOYMATCH0 0x34 ++#define SYS_TOYMATCH1 0x38 ++#define SYS_TOYMATCH2 0x3C ++#define SYS_RTCCTRL 0x40 ++#define SYS_RTCTRIM 0x60 ++#define SYS_RTCWRTIE0 0x64 ++#define SYS_RTCREAD0 0x68 ++#define SYS_RTCMATCH0 0x6C ++#define SYS_RTCMATCH1 0x70 ++#define SYS_RTCMATCH2 0x74 ++ ++/** ++ ** shift bits and filed mask ++ **/ ++#define TOY_MON_MASK 0x3f ++#define TOY_DAY_MASK 0x1f ++#define TOY_HOUR_MASK 0x1f ++#define TOY_MIN_MASK 0x3f ++#define TOY_SEC_MASK 0x3f ++#define TOY_MSEC_MASK 0xf ++ ++#define TOY_MON_SHIFT 26 ++#define TOY_DAY_SHIFT 21 ++#define TOY_HOUR_SHIFT 16 ++#define TOY_MIN_SHIFT 10 ++#define TOY_SEC_SHIFT 4 ++#define TOY_MSEC_SHIFT 0 ++ ++#define TOY_MATCH_YEAR_MASK 0x3f ++#define TOY_MATCH_MON_MASK 0xf ++#define TOY_MATCH_DAY_MASK 0x1f ++#define TOY_MATCH_HOUR_MASK 0x1f ++#define TOY_MATCH_MIN_MASK 0x3f ++#define TOY_MATCH_SEC_MASK 0x3f ++ ++#define TOY_MATCH_YEAR_SHIFT 26 ++#define TOY_MATCH_MON_SHIFT 22 ++#define TOY_MATCH_DAY_SHIFT 17 ++#define TOY_MATCH_HOUR_SHIFT 12 ++#define TOY_MATCH_MIN_SHIFT 6 ++#define TOY_MATCH_SEC_SHIFT 0 ++ ++#define TOY_ENABLE_BIT (1U << 11) ++ ++#define TYPE_LS7A_RTC "ls7a_rtc" ++#define LS7A_RTC(obj) OBJECT_CHECK(LS7A_RTCState, (obj), TYPE_LS7A_RTC) ++ ++typedef struct LS7A_RTCState { ++ SysBusDevice parent_obj; ++ ++ MemoryRegion iomem; ++ QEMUTimer *timer; ++ /* ++ * Needed to preserve the tick_count across migration, even if the ++ * absolute value of the rtc_clock is different on the source and ++ * destination. ++ */ ++ int64_t offset; ++ int64_t data; ++ int64_t save_alarm_offset; ++ int tidx; ++ uint32_t toymatch[3]; ++ uint32_t toytrim; ++ uint32_t cntrctl; ++ uint32_t rtctrim; ++ uint32_t rtccount; ++ uint32_t rtcmatch[3]; ++ qemu_irq toy_irq; ++} LS7A_RTCState; ++ ++enum { ++ TOYEN = 1UL << 11, ++ RTCEN = 1UL << 13, ++}; ++ ++static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ LS7A_RTCState *s = (LS7A_RTCState *)opaque; ++ struct tm tm; ++ unsigned int val = 0; ++ ++ switch (addr) { ++ case SYS_TOYREAD0: ++ qemu_get_timedate(&tm, s->offset); ++ val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT) | ++ (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT) | ++ (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT) | ++ (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT) | ++ (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0; ++ break; ++ case SYS_TOYREAD1: ++ qemu_get_timedate(&tm, s->offset); ++ val = tm.tm_year; ++ break; ++ case SYS_TOYMATCH0: ++ val = s->toymatch[0]; ++ break; ++ case SYS_TOYMATCH1: ++ val = s->toymatch[1]; ++ break; ++ case SYS_TOYMATCH2: ++ val = s->toymatch[2]; ++ break; ++ case SYS_RTCCTRL: ++ val = s->cntrctl; ++ break; ++ case SYS_RTCREAD0: ++ val = s->rtccount; ++ break; ++ case SYS_RTCMATCH0: ++ val = s->rtcmatch[0]; ++ break; ++ case SYS_RTCMATCH1: ++ val = s->rtcmatch[1]; ++ break; ++ case SYS_RTCMATCH2: ++ val = s->rtcmatch[2]; ++ break; ++ default: ++ break; ++ } ++ return val; ++} ++ ++static void ls7a_rtc_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ LS7A_RTCState *s = (LS7A_RTCState *)opaque; ++ struct tm tm; ++ int64_t alarm_offset, year_diff, expire_time; ++ ++ switch (addr) { ++ case SYS_TOYWRITE0: ++ qemu_get_timedate(&tm, s->offset); ++ tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK; ++ tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK; ++ tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK; ++ tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK); ++ tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1; ++ s->offset = qemu_timedate_diff(&tm); ++ break; ++ case SYS_TOYWRITE1: ++ qemu_get_timedate(&tm, s->offset); ++ tm.tm_year = val; ++ s->offset = qemu_timedate_diff(&tm); ++ break; ++ case SYS_TOYMATCH0: ++ s->toymatch[0] = val; ++ qemu_get_timedate(&tm, s->offset); ++ tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; ++ tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; ++ tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); ++ tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); ++ tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; ++ year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); ++ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); ++ tm.tm_year = tm.tm_year + year_diff; ++ alarm_offset = qemu_timedate_diff(&tm) - s->offset; ++ if ((alarm_offset < 0) && (alarm_offset > -5)) { ++ alarm_offset = 0; ++ } ++ expire_time = qemu_clock_get_ms(rtc_clock); ++ expire_time += ((alarm_offset * 1000) + 100); ++ timer_mod(s->timer, expire_time); ++ break; ++ case SYS_TOYMATCH1: ++ s->toymatch[1] = val; ++ break; ++ case SYS_TOYMATCH2: ++ s->toymatch[2] = val; ++ break; ++ case SYS_RTCCTRL: ++ s->cntrctl = val; ++ break; ++ case SYS_RTCWRTIE0: ++ s->rtccount = val; ++ break; ++ case SYS_RTCMATCH0: ++ s->rtcmatch[0] = val; ++ break; ++ case SYS_RTCMATCH1: ++ val = s->rtcmatch[1]; ++ break; ++ case SYS_RTCMATCH2: ++ val = s->rtcmatch[2]; ++ break; ++ default: ++ break; ++ } ++} ++ ++static const MemoryRegionOps ls7a_rtc_ops = { ++ .read = ls7a_rtc_read, ++ .write = ls7a_rtc_write, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++ .valid = { ++ .min_access_size = 4, ++ .max_access_size = 4, ++ }, ++ ++}; ++ ++static void toy_timer(void *opaque) ++{ ++ LS7A_RTCState *s = (LS7A_RTCState *)opaque; ++ ++ if (s->cntrctl & TOY_ENABLE_BIT) { ++ qemu_irq_pulse(s->toy_irq); ++ } ++} ++ ++static void ls7a_rtc_realize(DeviceState *dev, Error **errp) ++{ ++ SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ++ LS7A_RTCState *d = LS7A_RTC(sbd); ++ memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, (void *)d, ++ "ls7a_rtc", 0x100); ++ ++ sysbus_init_irq(sbd, &d->toy_irq); ++ ++ sysbus_init_mmio(sbd, &d->iomem); ++ d->timer = timer_new_ms(rtc_clock, toy_timer, d); ++ timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100); ++ d->offset = 0; ++} ++ ++static int ls7a_rtc_pre_save(void *opaque) ++{ ++ LS7A_RTCState *s = (LS7A_RTCState *)opaque; ++ struct tm tm; ++ int64_t year_diff, value; ++ ++ value = s->toymatch[0]; ++ qemu_get_timedate(&tm, s->offset); ++ tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; ++ tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; ++ tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); ++ tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); ++ tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; ++ year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); ++ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); ++ tm.tm_year = tm.tm_year + year_diff; ++ s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset; ++ ++ return 0; ++} ++ ++static int ls7a_rtc_post_load(void *opaque, int version_id) ++{ ++ LS7A_RTCState *s = (LS7A_RTCState *)opaque; ++ int64_t expire_time; ++ ++ expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000); ++ timer_mod(s->timer, expire_time); ++ ++ return 0; ++} ++ ++static const VMStateDescription vmstate_ls7a_rtc = { ++ .name = "ls7a_rtc", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = ls7a_rtc_pre_save, ++ .post_load = ls7a_rtc_post_load, ++ .fields = ++ (VMStateField[]){ VMSTATE_INT64(offset, LS7A_RTCState), ++ VMSTATE_INT64(save_alarm_offset, LS7A_RTCState), ++ VMSTATE_UINT32(toymatch[0], LS7A_RTCState), ++ VMSTATE_UINT32(cntrctl, LS7A_RTCState), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static void ls7a_rtc_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ dc->vmsd = &vmstate_ls7a_rtc; ++ dc->realize = ls7a_rtc_realize; ++ dc->desc = "ls7a rtc"; ++} ++ ++static const TypeInfo ls7a_rtc_info = { ++ .name = TYPE_LS7A_RTC, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(LS7A_RTCState), ++ .class_init = ls7a_rtc_class_init, ++}; ++ ++static void ls7a_rtc_register_types(void) ++{ ++ type_register_static(&ls7a_rtc_info); ++} ++ ++type_init(ls7a_rtc_register_types) +diff --git a/hw/timer/meson.build b/hw/timer/meson.build +index 03092e2ceb..e841a2f6ee 100644 +--- a/hw/timer/meson.build ++++ b/hw/timer/meson.build +@@ -16,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c')) + softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c')) + softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c')) + softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c')) ++softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) + softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c')) + softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c')) + softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c')) +-- +2.27.0 + diff --git a/Add-bios.patch b/Add-bios.patch new file mode 100644 index 0000000000000000000000000000000000000000..00647298f0b946ca4cf8134c0e2554eafb787f13 --- /dev/null +++ b/Add-bios.patch @@ -0,0 +1,28 @@ +From 6921fc74a9a58445e453eeb3c2ee74cead690ee4 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:22:18 -0500 +Subject: [PATCH] Add bios. + +Add loongarch bios. + +Signed-off-by: lixianglai +--- + pc-bios/meson.build | 2 ++ + 1 files changed, 2 insertions(+) + +diff --git a/pc-bios/meson.build b/pc-bios/meson.build +index 05e9065ad6..f2a1d111a1 100644 +--- a/pc-bios/meson.build ++++ b/pc-bios/meson.build +@@ -86,6 +86,8 @@ blobs = files( + 'opensbi-riscv32-generic-fw_dynamic.elf', + 'opensbi-riscv64-generic-fw_dynamic.elf', + 'npcm7xx_bootrom.bin', ++ 'loongarch_bios.bin', ++ 'loongarch_vars.bin', + ) + + if get_option('install_blobs') +-- +2.27.0 + diff --git a/Add-command-line.patch b/Add-command-line.patch new file mode 100644 index 0000000000000000000000000000000000000000..ee9af2d36e49764d799f1f62afc2323f54f52220 --- /dev/null +++ b/Add-command-line.patch @@ -0,0 +1,104 @@ +From a88f2d12afb6a6b5b3d97983cea95d6088f0bf04 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:21:17 -0500 +Subject: [PATCH] Add command line. + +Add loongarch command support. + +Signed-off-by: lixianglai +--- + include/sysemu/arch_init.h | 1 + + qapi/machine-target.json | 6 ++++-- + qapi/machine.json | 2 +- + qapi/misc-target.json | 1 + + qemu-options.hx | 2 +- + softmmu/qdev-monitor.c | 2 +- + 6 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h +index 1cf27baa7c..0907b92cd1 100644 +--- a/include/sysemu/arch_init.h ++++ b/include/sysemu/arch_init.h +@@ -25,6 +25,7 @@ enum { + QEMU_ARCH_AVR = (1 << 21), + QEMU_ARCH_HEXAGON = (1 << 22), + QEMU_ARCH_SW64 = (1 << 23), ++ QEMU_ARCH_LOONGARCH64 = (1 << 24), + }; + + extern const uint32_t arch_type; +diff --git a/qapi/machine-target.json b/qapi/machine-target.json +index f5ec4bc172..682dc86b42 100644 +--- a/qapi/machine-target.json ++++ b/qapi/machine-target.json +@@ -324,7 +324,8 @@ + 'TARGET_ARM', + 'TARGET_I386', + 'TARGET_S390X', +- 'TARGET_MIPS' ] } } ++ 'TARGET_MIPS', ++ 'TARGET_LOONGARCH64' ] } } + + ## + # @query-cpu-definitions: +@@ -340,4 +341,5 @@ + 'TARGET_ARM', + 'TARGET_I386', + 'TARGET_S390X', +- 'TARGET_MIPS' ] } } ++ 'TARGET_MIPS', ++ 'TARGET_LOONGARCH64' ] } } +diff --git a/qapi/machine.json b/qapi/machine.json +index 03cfb268a4..31b0350b99 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -34,7 +34,7 @@ + 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', + 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', + 'sh4eb', 'sparc', 'sparc64', 'tricore', +- 'x86_64', 'xtensa', 'xtensaeb' ] } ++ 'x86_64', 'xtensa', 'xtensaeb', 'loongarch64' ] } + + ## + # @CpuS390State: +diff --git a/qapi/misc-target.json b/qapi/misc-target.json +index 4bc45d2474..63cebef573 100644 +--- a/qapi/misc-target.json ++++ b/qapi/misc-target.json +@@ -33,6 +33,7 @@ + 'TARGET_PPC64', + 'TARGET_S390X', + 'TARGET_SH4', ++ 'TARGET_LOONGARCH64', + 'TARGET_SPARC' ] } } + + ## +diff --git a/qemu-options.hx b/qemu-options.hx +index 047d28a357..e62bb6bebd 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -2533,7 +2533,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, + " specify SMBIOS type 17 fields\n" + "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" + " specify SMBIOS type 41 fields\n", +- QEMU_ARCH_I386 | QEMU_ARCH_ARM) ++ QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64) + SRST + ``-smbios file=binary`` + Load SMBIOS entry from binary file. +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 142352b24e..4ca4e92ce2 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -62,7 +62,7 @@ typedef struct QDevAlias + QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ + QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ + QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ +- QEMU_ARCH_SW64) ++ QEMU_ARCH_SW64 | QEMU_ARCH_LOONGARCH64) + #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) + #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) + +-- +2.27.0 + diff --git a/Add-compile-script.patch b/Add-compile-script.patch new file mode 100644 index 0000000000000000000000000000000000000000..f897aa74f3114675447d57328f40c06949bf2a95 --- /dev/null +++ b/Add-compile-script.patch @@ -0,0 +1,255 @@ +From 6668690dee884342e29103b5df1ab751bb236bba Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:22:58 -0500 +Subject: [PATCH] Add compile script. + +Modify the compile script for loongarch. + +Signed-off-by: lixianglai +--- + .../devices/loongarch64-softmmu/default.mak | 158 ++++++++++++++++++ + configs/targets/loongarch64-softmmu.mak | 3 + + configure | 5 + + meson.build | 7 +- + 4 files changed, 172 insertions(+), 1 deletion(-) + create mode 100644 configs/devices/loongarch64-softmmu/default.mak + create mode 100644 configs/targets/loongarch64-softmmu.mak + +diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak +new file mode 100644 +index 0000000000..c4cc246833 +--- /dev/null ++++ b/configs/devices/loongarch64-softmmu/default.mak +@@ -0,0 +1,158 @@ ++# Default configuration for loongarch-softmmu ++ ++CONFIG_PCI=y ++CONFIG_ACPI_PCI=y ++# For now, CONFIG_IDE_CORE requires ISA, so we enable it here ++CONFIG_ISA_BUS=y ++CONFIG_VIRTIO_PCI=y ++ ++CONFIG_VGA_PCI=y ++CONFIG_ACPI_SMBUS=y ++CONFIG_VHOST_USER_SCSI=y ++CONFIG_VHOST_USER_BLK=y ++CONFIG_VIRTIO=y ++CONFIG_VIRTIO_BALLOON=y ++CONFIG_VIRTIO_BLK=y ++CONFIG_VIRTIO_CRYPTO=y ++CONFIG_VIRTIO_GPU=y ++CONFIG_VIRTIO_INPUT=y ++CONFIG_VIRTIO_NET=y ++CONFIG_VIRTIO_RNG=y ++CONFIG_SCSI=y ++CONFIG_VIRTIO_SCSI=y ++CONFIG_VIRTIO_SERIAL=y ++ ++CONFIG_USB_UHCI=y ++CONFIG_USB_OHCI=y ++CONFIG_USB_OHCI_PCI=y ++CONFIG_USB_XHCI=y ++CONFIG_USB_XHCI_NEC=y ++CONFIG_NE2000_PCI=y ++CONFIG_EEPRO100_PCI=y ++CONFIG_PCNET_PCI=y ++CONFIG_PCNET_COMMON=y ++CONFIG_AC97=y ++CONFIG_HDA=y ++CONFIG_ES1370=y ++CONFIG_SCSI=y ++CONFIG_LSI_SCSI_PCI=y ++CONFIG_VMW_PVSCSI_SCSI_PCI=y ++CONFIG_MEGASAS_SCSI_PCI=y ++CONFIG_MPTSAS_SCSI_PCI=y ++CONFIG_RTL8139_PCI=y ++CONFIG_E1000_PCI=y ++CONFIG_IDE_CORE=y ++CONFIG_IDE_QDEV=y ++CONFIG_IDE_PCI=y ++CONFIG_AHCI=y ++CONFIG_AHCI_ICH9=y ++CONFIG_ESP=y ++CONFIG_ESP_PCI=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_ISA=y ++CONFIG_SERIAL_PCI=y ++CONFIG_CAN_BUS=y ++CONFIG_CAN_SJA1000=y ++CONFIG_CAN_PCI=y ++CONFIG_USB_UHCI=y ++CONFIG_USB_OHCI=y ++CONFIG_USB_XHCI=y ++CONFIG_USB_XHCI_NEC=y ++CONFIG_NE2000_PCI=y ++CONFIG_EEPRO100_PCI=y ++CONFIG_PCNET_PCI=y ++CONFIG_PCNET_COMMON=y ++CONFIG_AC97=y ++CONFIG_HDA=y ++CONFIG_ES1370=y ++CONFIG_SCSI=y ++CONFIG_LSI_SCSI_PCI=y ++CONFIG_VMW_PVSCSI_SCSI_PCI=y ++CONFIG_MEGASAS_SCSI_PCI=y ++CONFIG_MPTSAS_SCSI_PCI=y ++CONFIG_RTL8139_PCI=y ++CONFIG_E1000_PCI=y ++CONFIG_IDE_CORE=y ++CONFIG_IDE_QDEV=y ++CONFIG_IDE_PCI=y ++CONFIG_AHCI=y ++CONFIG_ESP=y ++CONFIG_ESP_PCI=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_ISA=y ++CONFIG_SERIAL_PCI=y ++CONFIG_CAN_BUS=y ++CONFIG_CAN_SJA1000=y ++CONFIG_CAN_PCI=y ++ ++CONFIG_SPICE=y ++CONFIG_QXL=y ++CONFIG_ESP=y ++CONFIG_SCSI=y ++CONFIG_VGA_ISA=y ++CONFIG_VGA_ISA_MM=y ++CONFIG_VGA_CIRRUS=y ++CONFIG_VMWARE_VGA=y ++CONFIG_VIRTIO_VGA=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_ISA=y ++CONFIG_PARALLEL=y ++CONFIG_I8254=y ++CONFIG_PCSPK=y ++CONFIG_PCKBD=y ++CONFIG_FDC=y ++CONFIG_ACPI=y ++CONFIG_ACPI_MEMORY_HOTPLUG=y ++CONFIG_ACPI_NVDIMM=y ++CONFIG_ACPI_CPU_HOTPLUG=y ++CONFIG_APM=y ++CONFIG_I8257=y ++CONFIG_PIIX4=y ++CONFIG_IDE_ISA=y ++CONFIG_IDE_PIIX=y ++CONFIG_MIPSNET=y ++CONFIG_PFLASH_CFI01=y ++CONFIG_I8259=y ++CONFIG_MC146818RTC=y ++CONFIG_ISA_TESTDEV=y ++CONFIG_EMPTY_SLOT=y ++CONFIG_I2C=y ++CONFIG_DIMM=y ++CONFIG_MEM_DEVICE=y ++ ++# Arch Specified CONFIG defines ++CONFIG_IDE_VIA=y ++CONFIG_VT82C686=y ++CONFIG_RC4030=y ++CONFIG_DP8393X=y ++CONFIG_DS1225Y=y ++CONFIG_FITLOADER=y ++CONFIG_SMBIOS=y ++ ++CONFIG_PCIE_PORT=y ++CONFIG_I82801B11=y ++CONFIG_XIO3130=y ++CONFIG_PCI_EXPRESS=y ++CONFIG_MSI_NONBROKEN=y ++CONFIG_IOH3420=y ++CONFIG_SD=y ++CONFIG_SDHCI=y ++CONFIG_VIRTFS=y ++CONFIG_VIRTIO_9P=y ++CONFIG_USB_EHCI=y ++CONFIG_USB_EHCI_PCI=y ++CONFIG_USB_EHCI_SYSBUS=y ++CONFIG_USB_STORAGE_BOT=y ++CONFIG_TPM_EMULATOR=y ++CONFIG_TPM_TIS=y ++CONFIG_PLATFORM_BUS=y ++CONFIG_TPM_TIS_SYSBUS=y ++CONFIG_ACPI_LOONGARCH=y ++CONFIG_LS7A_RTC=y ++ ++#vfio config ++CONFIG_VFIO=y ++CONFIG_VFIO_PCI=y ++CONFIG_VFIO_PLATFORM=y ++CONFIG_VFIO_XGMAC=y ++CONFIG_VFIO_AMD_XGBE=y +diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak +new file mode 100644 +index 0000000000..c42dfbbd9c +--- /dev/null ++++ b/configs/targets/loongarch64-softmmu.mak +@@ -0,0 +1,3 @@ ++TARGET_ARCH=loongarch64 ++TARGET_SUPPORTS_MTTCG=y ++TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml +diff --git a/configure b/configure +index 2576d1c693..a84dc891cc 100755 +--- a/configure ++++ b/configure +@@ -579,6 +579,8 @@ elif check_define __arm__ ; then + cpu="arm" + elif check_define __aarch64__ ; then + cpu="aarch64" ++elif check_define __loongarch__ ; then ++ cpu="loongarch64" + else + cpu=$(uname -m) + fi +@@ -604,6 +606,9 @@ case "$cpu" in + aarch64) + cpu="aarch64" + ;; ++ loongarch64) ++ cpu="loongarch64" ++ ;; + mips*) + cpu="mips" + ;; +diff --git a/meson.build b/meson.build +index d0bbceffe1..d80426b3e8 100644 +--- a/meson.build ++++ b/meson.build +@@ -56,7 +56,7 @@ python = import('python').find_installation() + + supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] + supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', +- 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'sw64'] ++ 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'sw64', 'loongarch64'] + + cpu = host_machine.cpu_family() + +@@ -83,6 +83,8 @@ elif cpu in ['mips', 'mips64'] + kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] + elif cpu == 'sw64' + kvm_targets = ['sw64-softmmu'] ++elif cpu == 'loongarch64' ++ kvm_targets = ['loongarch64-softmmu'] + else + kvm_targets = [] + endif +@@ -367,6 +369,8 @@ if not get_option('tcg').disabled() + tcg_arch = 'ppc' + elif config_host['ARCH'] in ['sw64'] + tcg_arch = 'sw64' ++ elif config_host['ARCH'] == 'loongarch64' ++ tcg_arch = 'loongarch64' + endif + add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, + language: ['c', 'cpp', 'objc']) +@@ -1822,6 +1826,7 @@ disassemblers = { + 'sh4' : ['CONFIG_SH4_DIS'], + 'sparc' : ['CONFIG_SPARC_DIS'], + 'xtensa' : ['CONFIG_XTENSA_DIS'], ++ 'loongarch64' : ['CONFIG_LOONGARCH_DIS'], + 'sw64' : ['CONFIG_SW64_DIS'], + } + if link_language == 'cpp' +-- +2.27.0 + diff --git a/Add-disas-gdb.patch b/Add-disas-gdb.patch new file mode 100644 index 0000000000000000000000000000000000000000..3ccf9076a564145033a61d031a7dd9db2c51b55b --- /dev/null +++ b/Add-disas-gdb.patch @@ -0,0 +1,2882 @@ +From e66da47c4fc44bf2e861fbe58a84e08b11fd3f3b Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:17:12 -0500 +Subject: [PATCH] Add disas gdb. + +Add disas gdb xml. + +Signed-off-by: lixianglai +--- + disas/loongarch.c | 2736 ++++++++++++++++++++++++++++++++++ + disas/meson.build | 1 + + gdb-xml/loongarch-base64.xml | 45 + + gdb-xml/loongarch-fpu.xml | 50 + + 4 files changed, 2832 insertions(+) + create mode 100644 disas/loongarch.c + create mode 100644 gdb-xml/loongarch-base64.xml + create mode 100644 gdb-xml/loongarch-fpu.xml + +diff --git a/disas/loongarch.c b/disas/loongarch.c +new file mode 100644 +index 0000000000..b3f38e99ab +--- /dev/null ++++ b/disas/loongarch.c +@@ -0,0 +1,2736 @@ ++/* ++ * QEMU Loongarch Disassembler ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++#include "qemu/osdep.h" ++#include "disas/dis-asm.h" ++ ++#define INSNLEN 4 ++ ++/* types */ ++typedef uint16_t la_opcode; ++ ++/* enums */ ++typedef enum { ++ la_op_illegal = 0, ++ la_op_gr2scr = 1, ++ la_op_scr2gr = 2, ++ la_op_clo_w = 3, ++ la_op_clz_w = 4, ++ la_op_cto_w = 5, ++ la_op_ctz_w = 6, ++ la_op_clo_d = 7, ++ la_op_clz_d = 8, ++ la_op_cto_d = 9, ++ la_op_ctz_d = 10, ++ la_op_revb_2h = 11, ++ la_op_revb_4h = 12, ++ la_op_revb_2w = 13, ++ la_op_revb_d = 14, ++ la_op_revh_2w = 15, ++ la_op_revh_d = 16, ++ la_op_bitrev_4b = 17, ++ la_op_bitrev_8b = 18, ++ la_op_bitrev_w = 19, ++ la_op_bitrev_d = 20, ++ la_op_ext_w_h = 21, ++ la_op_ext_w_b = 22, ++ la_op_rdtime_d = 23, ++ la_op_cpucfg = 24, ++ la_op_asrtle_d = 25, ++ la_op_asrtgt_d = 26, ++ la_op_alsl_w = 27, ++ la_op_alsl_wu = 28, ++ la_op_bytepick_w = 29, ++ la_op_bytepick_d = 30, ++ la_op_add_w = 31, ++ la_op_add_d = 32, ++ la_op_sub_w = 33, ++ la_op_sub_d = 34, ++ la_op_slt = 35, ++ la_op_sltu = 36, ++ la_op_maskeqz = 37, ++ la_op_masknez = 38, ++ la_op_nor = 39, ++ la_op_and = 40, ++ la_op_or = 41, ++ la_op_xor = 42, ++ la_op_orn = 43, ++ la_op_andn = 44, ++ la_op_sll_w = 45, ++ la_op_srl_w = 46, ++ la_op_sra_w = 47, ++ la_op_sll_d = 48, ++ la_op_srl_d = 49, ++ la_op_sra_d = 50, ++ la_op_rotr_w = 51, ++ la_op_rotr_d = 52, ++ la_op_mul_w = 53, ++ la_op_mulh_w = 54, ++ la_op_mulh_wu = 55, ++ la_op_mul_d = 56, ++ la_op_mulh_d = 57, ++ la_op_mulh_du = 58, ++ la_op_mulw_d_w = 59, ++ la_op_mulw_d_wu = 60, ++ la_op_div_w = 61, ++ la_op_mod_w = 62, ++ la_op_div_wu = 63, ++ la_op_mod_wu = 64, ++ la_op_div_d = 65, ++ la_op_mod_d = 66, ++ la_op_div_du = 67, ++ la_op_mod_du = 68, ++ la_op_crc_w_b_w = 69, ++ la_op_crc_w_h_w = 70, ++ la_op_crc_w_w_w = 71, ++ la_op_crc_w_d_w = 72, ++ la_op_crcc_w_b_w = 73, ++ la_op_crcc_w_h_w = 74, ++ la_op_crcc_w_w_w = 75, ++ la_op_crcc_w_d_w = 76, ++ la_op_break = 77, ++ la_op_dbcl = 78, ++ la_op_syscall = 79, ++ la_op_alsl_d = 80, ++ la_op_slli_w = 81, ++ la_op_slli_d = 82, ++ la_op_srli_w = 83, ++ la_op_srli_d = 84, ++ la_op_srai_w = 85, ++ la_op_srai_d = 86, ++ la_op_rotri_w = 87, ++ la_op_rotri_d = 88, ++ la_op_bstrins_w = 89, ++ la_op_bstrpick_w = 90, ++ la_op_bstrins_d = 91, ++ la_op_bstrpick_d = 92, ++ la_op_fadd_s = 93, ++ la_op_fadd_d = 94, ++ la_op_fsub_s = 95, ++ la_op_fsub_d = 96, ++ la_op_fmul_s = 97, ++ la_op_fmul_d = 98, ++ la_op_fdiv_s = 99, ++ la_op_fdiv_d = 100, ++ la_op_fmax_s = 101, ++ la_op_fmax_d = 102, ++ la_op_fmin_s = 103, ++ la_op_fmin_d = 104, ++ la_op_fmaxa_s = 105, ++ la_op_fmaxa_d = 106, ++ la_op_fmina_s = 107, ++ la_op_fmina_d = 108, ++ la_op_fscaleb_s = 109, ++ la_op_fscaleb_d = 110, ++ la_op_fcopysign_s = 111, ++ la_op_fcopysign_d = 112, ++ la_op_fabs_s = 113, ++ la_op_fabs_d = 114, ++ la_op_fneg_s = 115, ++ la_op_fneg_d = 116, ++ la_op_flogb_s = 117, ++ la_op_flogb_d = 118, ++ la_op_fclass_s = 119, ++ la_op_fclass_d = 120, ++ la_op_fsqrt_s = 121, ++ la_op_fsqrt_d = 122, ++ la_op_frecip_s = 123, ++ la_op_frecip_d = 124, ++ la_op_frsqrt_s = 125, ++ la_op_frsqrt_d = 126, ++ la_op_fmov_s = 127, ++ la_op_fmov_d = 128, ++ la_op_movgr2fr_w = 129, ++ la_op_movgr2fr_d = 130, ++ la_op_movgr2frh_w = 131, ++ la_op_movfr2gr_s = 132, ++ la_op_movfr2gr_d = 133, ++ la_op_movfrh2gr_s = 134, ++ la_op_movgr2fcsr = 135, ++ la_op_movfcsr2gr = 136, ++ la_op_movfr2cf = 137, ++ la_op_movcf2fr = 138, ++ la_op_movgr2cf = 139, ++ la_op_movcf2gr = 140, ++ la_op_fcvt_s_d = 141, ++ la_op_fcvt_d_s = 142, ++ ++ la_op_ftintrm_w_s = 143, ++ la_op_ftintrm_w_d = 144, ++ la_op_ftintrm_l_s = 145, ++ la_op_ftintrm_l_d = 146, ++ la_op_ftintrp_w_s = 147, ++ la_op_ftintrp_w_d = 148, ++ la_op_ftintrp_l_s = 149, ++ la_op_ftintrp_l_d = 150, ++ la_op_ftintrz_w_s = 151, ++ la_op_ftintrz_w_d = 152, ++ la_op_ftintrz_l_s = 153, ++ la_op_ftintrz_l_d = 154, ++ la_op_ftintrne_w_s = 155, ++ la_op_ftintrne_w_d = 156, ++ la_op_ftintrne_l_s = 157, ++ la_op_ftintrne_l_d = 158, ++ la_op_ftint_w_s = 159, ++ la_op_ftint_w_d = 160, ++ la_op_ftint_l_s = 161, ++ la_op_ftint_l_d = 162, ++ la_op_ffint_s_w = 163, ++ la_op_ffint_s_l = 164, ++ la_op_ffint_d_w = 165, ++ la_op_ffint_d_l = 166, ++ la_op_frint_s = 167, ++ la_op_frint_d = 168, ++ ++ la_op_slti = 169, ++ la_op_sltui = 170, ++ la_op_addi_w = 171, ++ la_op_addi_d = 172, ++ la_op_lu52i_d = 173, ++ la_op_addi = 174, ++ la_op_ori = 175, ++ la_op_xori = 176, ++ ++ la_op_csrxchg = 177, ++ la_op_cacop = 178, ++ la_op_lddir = 179, ++ la_op_ldpte = 180, ++ la_op_iocsrrd_b = 181, ++ la_op_iocsrrd_h = 182, ++ la_op_iocsrrd_w = 183, ++ la_op_iocsrrd_d = 184, ++ la_op_iocsrwr_b = 185, ++ la_op_iocsrwr_h = 186, ++ la_op_iocsrwr_w = 187, ++ la_op_iocsrwr_d = 188, ++ la_op_tlbclr = 189, ++ la_op_tlbflush = 190, ++ la_op_tlbsrch = 191, ++ la_op_tlbrd = 192, ++ la_op_tlbwr = 193, ++ la_op_tlbfill = 194, ++ la_op_ertn = 195, ++ la_op_idle = 196, ++ la_op_invtlb = 197, ++ ++ la_op_fmadd_s = 198, ++ la_op_fmadd_d = 199, ++ la_op_fmsub_s = 200, ++ la_op_fmsub_d = 201, ++ la_op_fnmadd_s = 202, ++ la_op_fnmadd_d = 203, ++ la_op_fnmsub_s = 204, ++ la_op_fnmsub_d = 205, ++ la_op_fcmp_cond_s = 206, ++ la_op_fcmp_cond_d = 207, ++ la_op_fsel = 208, ++ la_op_addu16i_d = 209, ++ la_op_lu12i_w = 210, ++ la_op_lu32i_d = 211, ++ la_op_pcaddi = 212, ++ la_op_pcalau12i = 213, ++ la_op_pcaddu12i = 214, ++ la_op_pcaddu18i = 215, ++ ++ la_op_ll_w = 216, ++ la_op_sc_w = 217, ++ la_op_ll_d = 218, ++ la_op_sc_d = 219, ++ la_op_ldptr_w = 220, ++ la_op_stptr_w = 221, ++ la_op_ldptr_d = 222, ++ la_op_stptr_d = 223, ++ la_op_ld_b = 224, ++ la_op_ld_h = 225, ++ la_op_ld_w = 226, ++ la_op_ld_d = 227, ++ la_op_st_b = 228, ++ la_op_st_h = 229, ++ la_op_st_w = 230, ++ la_op_st_d = 231, ++ la_op_ld_bu = 232, ++ la_op_ld_hu = 233, ++ la_op_ld_wu = 234, ++ la_op_preld = 235, ++ la_op_fld_s = 236, ++ la_op_fst_s = 237, ++ la_op_fld_d = 238, ++ la_op_fst_d = 239, ++ la_op_ldl_w = 240, ++ la_op_ldr_w = 241, ++ la_op_ldl_d = 242, ++ la_op_ldr_d = 243, ++ la_op_stl_d = 244, ++ la_op_str_d = 245, ++ la_op_ldx_b = 246, ++ la_op_ldx_h = 247, ++ la_op_ldx_w = 248, ++ la_op_ldx_d = 249, ++ la_op_stx_b = 250, ++ la_op_stx_h = 251, ++ la_op_stx_w = 252, ++ la_op_stx_d = 253, ++ la_op_ldx_bu = 254, ++ la_op_ldx_hu = 255, ++ la_op_ldx_wu = 256, ++ la_op_fldx_s = 257, ++ la_op_fldx_d = 258, ++ la_op_fstx_s = 259, ++ la_op_fstx_d = 260, ++ ++ la_op_amswap_w = 261, ++ la_op_amswap_d = 262, ++ la_op_amadd_w = 263, ++ la_op_amadd_d = 264, ++ la_op_amand_w = 265, ++ la_op_amand_d = 266, ++ la_op_amor_w = 267, ++ la_op_amor_d = 268, ++ la_op_amxor_w = 269, ++ la_op_amxor_d = 270, ++ la_op_ammax_w = 271, ++ la_op_ammax_d = 272, ++ la_op_ammin_w = 273, ++ la_op_ammin_d = 274, ++ la_op_ammax_wu = 275, ++ la_op_ammax_du = 276, ++ la_op_ammin_wu = 277, ++ la_op_ammin_du = 278, ++ la_op_amswap_db_w = 279, ++ la_op_amswap_db_d = 280, ++ la_op_amadd_db_w = 281, ++ la_op_amadd_db_d = 282, ++ la_op_amand_db_w = 283, ++ la_op_amand_db_d = 284, ++ la_op_amor_db_w = 285, ++ la_op_amor_db_d = 286, ++ la_op_amxor_db_w = 287, ++ la_op_amxor_db_d = 288, ++ la_op_ammax_db_w = 289, ++ la_op_ammax_db_d = 290, ++ la_op_ammin_db_w = 291, ++ la_op_ammin_db_d = 292, ++ la_op_ammax_db_wu = 293, ++ la_op_ammax_db_du = 294, ++ la_op_ammin_db_wu = 295, ++ la_op_ammin_db_du = 296, ++ la_op_dbar = 297, ++ la_op_ibar = 298, ++ la_op_fldgt_s = 299, ++ la_op_fldgt_d = 300, ++ la_op_fldle_s = 301, ++ la_op_fldle_d = 302, ++ la_op_fstgt_s = 303, ++ la_op_fstgt_d = 304, ++ ls_op_fstle_s = 305, ++ la_op_fstle_d = 306, ++ la_op_ldgt_b = 307, ++ la_op_ldgt_h = 308, ++ la_op_ldgt_w = 309, ++ la_op_ldgt_d = 310, ++ la_op_ldle_b = 311, ++ la_op_ldle_h = 312, ++ la_op_ldle_w = 313, ++ la_op_ldle_d = 314, ++ la_op_stgt_b = 315, ++ la_op_stgt_h = 316, ++ la_op_stgt_w = 317, ++ la_op_stgt_d = 318, ++ la_op_stle_b = 319, ++ la_op_stle_h = 320, ++ la_op_stle_w = 321, ++ la_op_stle_d = 322, ++ la_op_beqz = 323, ++ la_op_bnez = 324, ++ la_op_bceqz = 325, ++ la_op_bcnez = 326, ++ la_op_jirl = 327, ++ la_op_b = 328, ++ la_op_bl = 329, ++ la_op_beq = 330, ++ la_op_bne = 331, ++ la_op_blt = 332, ++ la_op_bge = 333, ++ la_op_bltu = 334, ++ la_op_bgeu = 335, ++ ++ /* vz insn */ ++ la_op_hvcl = 336, ++ ++} la_op; ++ ++typedef enum { ++ la_codec_illegal, ++ la_codec_empty, ++ la_codec_2r, ++ la_codec_2r_u5, ++ la_codec_2r_u6, ++ la_codec_2r_2bw, ++ la_codec_2r_2bd, ++ la_codec_3r, ++ la_codec_3r_rd0, ++ la_codec_3r_sa2, ++ la_codec_3r_sa3, ++ la_codec_4r, ++ la_codec_r_im20, ++ la_codec_2r_im16, ++ la_codec_2r_im14, ++ la_codec_2r_im12, ++ la_codec_im5_r_im12, ++ la_codec_2r_im8, ++ la_codec_r_sd, ++ la_codec_r_sj, ++ la_codec_r_cd, ++ la_codec_r_cj, ++ la_codec_r_seq, ++ la_codec_code, ++ la_codec_whint, ++ la_codec_invtlb, ++ la_codec_r_ofs21, ++ la_codec_cj_ofs21, ++ la_codec_ofs26, ++ la_codec_cond, ++ la_codec_sel, ++ ++} la_codec; ++ ++#define la_fmt_illegal "nte" ++#define la_fmt_empty "nt" ++#define la_fmt_sd_rj "ntA,1" ++#define la_fmt_rd_sj "nt0,B" ++#define la_fmt_rd_rj "nt0,1" ++#define la_fmt_rj_rk "nt1,2" ++#define la_fmt_rj_seq "nt1,x" ++#define la_fmt_rd_si20 "nt0,i(x)" ++#define la_fmt_rd_rj_ui5 "nt0,1,C" ++#define la_fmt_rd_rj_ui6 "nt0,1.C" ++#define la_fmt_rd_rj_level "nt0,1,x" ++#define la_fmt_rd_rj_msbw_lsbw "nt0,1,C,D" ++#define la_fmt_rd_rj_msbd_lsbd "nt0,1,C,D" ++#define la_fmt_rd_rj_si12 "nt0,1,i(x)" ++#define la_fmt_hint_rj_si12 "ntE,1,i(x)" ++#define la_fmt_rd_rj_csr "nt0,1,x" ++#define la_fmt_rd_rj_si14 "nt0,1,i(x)" ++#define la_fmt_rd_rj_si16 "nt0,1,i(x)" ++#define la_fmt_rd_rj_rk "nt0,1,2" ++#define la_fmt_fd_rj_rk "nt3,1,2" ++#define la_fmt_rd_rj_rk_sa2 "nt0,1,2,D" ++#define la_fmt_rd_rj_rk_sa3 "nt0,1,2,D" ++#define la_fmt_fd_rj "nt3,1" ++#define la_fmt_rd_fj "nt0,4" ++#define la_fmt_fd_fj "nt3,4" ++#define la_fmt_fd_fj_si12 "nt3,4,i(x)" ++#define la_fmt_fcsrd_rj "ntF,1" ++#define la_fmt_rd_fcsrs "nt0,G" ++#define la_fmt_cd_fj "ntH,4" ++#define la_fmt_fd_cj "nt3,I" ++#define la_fmt_fd_fj_fk "nt3,4,5" ++#define la_fmt_code "ntJ" ++#define la_fmt_whint "ntx" ++#define la_fmt_invtlb "ntx,1,2" /* op,rj,rk */ ++#define la_fmt_offs26 "nto(X)p" ++#define la_fmt_rj_offs21 "nt1,o(X)p" ++#define la_fmt_cj_offs21 "ntQ,o(X)p" ++#define la_fmt_rd_rj_offs16 "nt0,1,o(X)" ++#define la_fmt_rj_rd_offs16 "nt1,0,o(X)p" ++#define la_fmt_s_cd_fj_fk "K.stH,4,5" ++#define la_fmt_d_cd_fj_fk "K.dtH,4,5" ++#define la_fmt_fd_fj_fk_fa "nt3,4,5,6" ++#define la_fmt_fd_fj_fk_ca "nt3,4,5,L" ++#define la_fmt_cop_rj_si12 "ntM,1,i(x)" ++ ++/* structures */ ++ ++typedef struct { ++ uint32_t pc; ++ uint32_t insn; ++ int32_t imm; ++ int32_t imm2; ++ uint16_t op; ++ uint16_t code; ++ uint8_t codec; ++ uint8_t r1; ++ uint8_t r2; ++ uint8_t r3; ++ uint8_t r4; ++ uint8_t bit; ++} la_decode; ++ ++typedef struct { ++ const char *const name; ++ const la_codec codec; ++ const char *const format; ++} la_opcode_data; ++ ++/* reg names */ ++const char *const loongarch_r_normal_name[32] = { ++ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", ++ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", ++ "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", ++ "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31", ++}; ++ ++const char *const loongarch_f_normal_name[32] = { ++ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", ++ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", ++ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", ++ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", ++}; ++ ++const char *const loongarch_cr_normal_name[4] = { ++ "$scr0", ++ "$scr1", ++ "$scr2", ++ "$scr3", ++}; ++ ++const char *const loongarch_c_normal_name[8] = { ++ "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", ++}; ++ ++/* instruction data */ ++const la_opcode_data opcode_la[] = { ++ { "illegal", la_codec_illegal, la_fmt_illegal }, ++ { "gr2scr", la_codec_r_sd, la_fmt_sd_rj }, ++ { "scr2gr", la_codec_r_sj, la_fmt_rd_sj }, ++ { "clo.w", la_codec_2r, la_fmt_rd_rj }, ++ { "clz.w", la_codec_2r, la_fmt_rd_rj }, ++ { "cto.w", la_codec_2r, la_fmt_rd_rj }, ++ { "ctz.w", la_codec_2r, la_fmt_rd_rj }, ++ { "clo.d", la_codec_2r, la_fmt_rd_rj }, ++ { "clz.d", la_codec_2r, la_fmt_rd_rj }, ++ { "cto.d", la_codec_2r, la_fmt_rd_rj }, ++ { "ctz_d", la_codec_2r, la_fmt_rd_rj }, ++ { "revb.2h", la_codec_2r, la_fmt_rd_rj }, ++ { "revb.4h", la_codec_2r, la_fmt_rd_rj }, ++ { "revb.2w", la_codec_2r, la_fmt_rd_rj }, ++ { "revb.d", la_codec_2r, la_fmt_rd_rj }, ++ { "revh.2w", la_codec_2r, la_fmt_rd_rj }, ++ { "revh.d", la_codec_2r, la_fmt_rd_rj }, ++ { "bitrev.4b", la_codec_2r, la_fmt_rd_rj }, ++ { "bitrev.8b", la_codec_2r, la_fmt_rd_rj }, ++ { "bitrev.w", la_codec_2r, la_fmt_rd_rj }, ++ { "bitrev.d", la_codec_2r, la_fmt_rd_rj }, ++ { "ext.w.h", la_codec_2r, la_fmt_rd_rj }, ++ { "ext.w.b", la_codec_2r, la_fmt_rd_rj }, ++ { "rdtime.d", la_codec_2r, la_fmt_rd_rj }, ++ { "cpucfg", la_codec_2r, la_fmt_rd_rj }, ++ { "asrtle.d", la_codec_3r_rd0, la_fmt_rj_rk }, ++ { "asrtgt.d", la_codec_3r_rd0, la_fmt_rj_rk }, ++ { "alsl.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, ++ { "alsl.wu", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, ++ { "bytepick.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, ++ { "bytepick.d", la_codec_3r_sa3, la_fmt_rd_rj_rk_sa3 }, ++ { "add.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "add.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sub.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sub.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "slt", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sltu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "maskeqz", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "masknez", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "nor", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "and", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "or", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "xor", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "orn", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "andn", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sll.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "srl.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sra.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sll.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "srl.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "sra.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "rotr.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "rotr.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mul.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulh.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulh.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mul.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulh.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulh.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulw.d.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mulw.d.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "div.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mod.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "div.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mod.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "div.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mod.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "div.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "mod.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crcc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crcc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crcc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "crcc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "break", la_codec_code, la_fmt_code }, ++ { "dbcl", la_codec_code, la_fmt_code }, ++ { "syscall", la_codec_code, la_fmt_code }, ++ { "alsl.d", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, ++ { "slli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, ++ { "slli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, ++ { "srli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, ++ { "srli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, ++ { "srai.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, ++ { "srai.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, ++ { "rotri.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, ++ { "rotri.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, ++ { "bstrins.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, ++ { "bstrpick.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, ++ { "bstrins.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, ++ { "bstrpick.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, ++ { "fadd.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fadd.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fsub.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fsub.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmul.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmul.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fdiv.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fdiv.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmax.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmax.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmin.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmin.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmaxa.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmaxa.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmina.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fmina.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fscaleb.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fscaleb.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fcopysign.s", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fcopysign.d", la_codec_3r, la_fmt_fd_fj_fk }, ++ { "fabs.s", la_codec_2r, la_fmt_fd_fj }, ++ { "fabs.d", la_codec_2r, la_fmt_fd_fj }, ++ { "fneg.s", la_codec_2r, la_fmt_fd_fj }, ++ { "fneg.d", la_codec_2r, la_fmt_fd_fj }, ++ { "flogb.s", la_codec_2r, la_fmt_fd_fj }, ++ { "flogb.d", la_codec_2r, la_fmt_fd_fj }, ++ { "fclass.s", la_codec_2r, la_fmt_fd_fj }, ++ { "fclass.d", la_codec_2r, la_fmt_fd_fj }, ++ { "fsqrt.s", la_codec_2r, la_fmt_fd_fj }, ++ { "fsqrt.d", la_codec_2r, la_fmt_fd_fj }, ++ { "frecip.s", la_codec_2r, la_fmt_fd_fj }, ++ { "frecip.d", la_codec_2r, la_fmt_fd_fj }, ++ { "frsqrt.s", la_codec_2r, la_fmt_fd_fj }, ++ { "frsqrt.d", la_codec_2r, la_fmt_fd_fj }, ++ { "fmov.s", la_codec_2r, la_fmt_fd_fj }, ++ { "fmov.d", la_codec_2r, la_fmt_fd_fj }, ++ { "movgr2fr.w", la_codec_2r, la_fmt_fd_rj }, ++ { "movgr2fr.d", la_codec_2r, la_fmt_fd_rj }, ++ { "movgr2frh.w", la_codec_2r, la_fmt_fd_rj }, ++ { "movfr2gr.s", la_codec_2r, la_fmt_rd_fj }, ++ { "movfr2gr.d", la_codec_2r, la_fmt_rd_fj }, ++ { "movfrh2gr.s", la_codec_2r, la_fmt_rd_fj }, ++ { "movgr2fcsr", la_codec_2r, la_fmt_fcsrd_rj }, ++ { "movfcsr2gr", la_codec_2r, la_fmt_rd_fcsrs }, ++ { "movfr2cf", la_codec_r_cd, la_fmt_cd_fj }, ++ { "movcf2fr", la_codec_r_cj, la_fmt_fd_cj }, ++ { "movgr2cf", la_codec_r_cd, la_fmt_cd_fj }, ++ { "movcf2gr", la_codec_r_cj, la_fmt_fd_cj }, ++ { "fcvt.s.d", la_codec_2r, la_fmt_fd_fj }, ++ { "fcvt.d.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrm.w.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrm.w.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrm.l.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrm.l.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrp.w.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrp.w.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrp.l.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrp.l.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrz.w.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrz.w.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrz.l.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrz.l.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrne.w.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrne.w.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrne.l.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftintrne.l.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftint.w.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftint.w.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ftint.l.s", la_codec_2r, la_fmt_fd_fj }, ++ { "ftint.l.d", la_codec_2r, la_fmt_fd_fj }, ++ { "ffint.s.w", la_codec_2r, la_fmt_fd_fj }, ++ { "ffint.s.l", la_codec_2r, la_fmt_fd_fj }, ++ { "ffint.d.w", la_codec_2r, la_fmt_fd_fj }, ++ { "ffint.d.l", la_codec_2r, la_fmt_fd_fj }, ++ { "frint.s", la_codec_2r, la_fmt_fd_fj }, ++ { "frint.d", la_codec_2r, la_fmt_fd_fj }, ++ { "slti", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "sltui", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "addi.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "addi.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "lu52i.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "addi", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "xori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "csrxchg", la_codec_2r_im14, la_fmt_rd_rj_csr }, ++ { "cacop", la_codec_im5_r_im12, la_fmt_cop_rj_si12 }, ++ { "lddir", la_codec_2r_im8, la_fmt_rd_rj_level }, ++ { "ldpte", la_codec_r_seq, la_fmt_rj_seq }, ++ { "iocsrrd.b", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrrd.h", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrrd.w", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrrd.d", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrwr.b", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrwr.h", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrwr.w", la_codec_2r, la_fmt_rd_rj }, ++ { "iocsrwr.d", la_codec_2r, la_fmt_rd_rj }, ++ { "tlbclr", la_codec_empty, la_fmt_empty }, ++ { "tlbflush", la_codec_empty, la_fmt_empty }, ++ { "tlbsrch", la_codec_empty, la_fmt_empty }, ++ { "tlbrd", la_codec_empty, la_fmt_empty }, ++ { "tlbwr", la_codec_empty, la_fmt_empty }, ++ { "tlbfill", la_codec_empty, la_fmt_empty }, ++ { "ertn", la_codec_empty, la_fmt_empty }, ++ { "idle", la_codec_whint, la_fmt_whint }, ++ { "invtlb", la_codec_invtlb, la_fmt_invtlb }, ++ { "fmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fnmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fnmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fnmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fnmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, ++ { "fcmp.cond.s", la_codec_cond, la_fmt_s_cd_fj_fk }, ++ { "fcmp.cond.d", la_codec_cond, la_fmt_d_cd_fj_fk }, ++ { "fsel", la_codec_sel, la_fmt_fd_fj_fk_ca }, ++ { "addu16i.d", la_codec_2r_im16, la_fmt_rd_rj_si16 }, ++ { "lu12i.w", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "lu32i.d", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "pcaddi", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "pcalau12i", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "pcaddu12i", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "pcaddu18i", la_codec_r_im20, la_fmt_rd_si20 }, ++ { "ll.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "sc.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "ll.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "sc.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "ldptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "stptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "ldptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "stptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, ++ { "ld.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "st.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "st.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "st.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "st.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.bu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.hu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ld.wu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "preld", la_codec_2r_im12, la_fmt_hint_rj_si12 }, ++ { "fld.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, ++ { "fst.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, ++ { "fld.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, ++ { "fst.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, ++ { "ldl.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ldr.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ldl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ldr.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "stl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "str.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, ++ { "ldx.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stx.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stx.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stx.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stx.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.bu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.hu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldx.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "fldx.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fldx.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstx.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstx.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "amswap.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amswap.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amadd.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amadd.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amand.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amand.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amor.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amor.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amxor.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amxor.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amswap.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amswap.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amadd.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amadd.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amand.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amand.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amxor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "amxor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.db.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.db.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammax.db.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ammin.db.du", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "dbar", la_codec_whint, la_fmt_whint }, ++ { "ibar", la_codec_whint, la_fmt_whint }, ++ { "fldgt.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fldgt.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fldle.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fldle.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstgt.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstgt.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstle.s", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "fstle.d", la_codec_3r, la_fmt_fd_rj_rk }, ++ { "ldgt.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldgt.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldgt.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldgt.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldle.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldle.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldle.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "ldle.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stgt.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stgt.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stgt.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stgt.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stle.b", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stle.h", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stle.w", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "stle.d", la_codec_3r, la_fmt_rd_rj_rk }, ++ { "beqz", la_codec_r_ofs21, la_fmt_rj_offs21 }, ++ { "bnez", la_codec_r_ofs21, la_fmt_rj_offs21 }, ++ { "bceqz", la_codec_cj_ofs21, la_fmt_cj_offs21 }, ++ { "bcnez", la_codec_cj_ofs21, la_fmt_cj_offs21 }, ++ { "jirl", la_codec_2r_im16, la_fmt_rd_rj_offs16 }, ++ { "b", la_codec_ofs26, la_fmt_offs26 }, ++ { "bl", la_codec_ofs26, la_fmt_offs26 }, ++ { "beq", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ { "bne", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ { "blt", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ { "bge", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ { "bltu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ { "bgeu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, ++ ++ /* vz insn */ ++ { "hvcl", la_codec_code, la_fmt_code }, ++ ++}; ++ ++/* decode opcode */ ++static void decode_insn_opcode(la_decode *dec) ++{ ++ uint32_t insn = dec->insn; ++ uint16_t op = la_op_illegal; ++ switch ((insn >> 26) & 0x3f) { ++ case 0x0: ++ switch ((insn >> 22) & 0xf) { ++ case 0x0: ++ switch ((insn >> 18) & 0xf) { ++ case 0x0: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x2: ++ switch ((insn >> 2) & 0x7) { ++ case 0x0: ++ op = la_op_gr2scr; ++ break; ++ } ++ break; ++ case 0x3: ++ switch ((insn >> 7) & 0x7) { ++ case 0x0: ++ op = la_op_scr2gr; ++ break; ++ } ++ break; ++ case 0x4: ++ op = la_op_clo_w; ++ break; ++ case 0x5: ++ op = la_op_clz_w; ++ break; ++ case 0x6: ++ op = la_op_cto_w; ++ break; ++ case 0x7: ++ op = la_op_ctz_w; ++ break; ++ case 0x8: ++ op = la_op_clo_d; ++ break; ++ case 0x9: ++ op = la_op_clz_d; ++ break; ++ case 0xa: ++ op = la_op_cto_d; ++ break; ++ case 0xb: ++ op = la_op_ctz_d; ++ break; ++ case 0xc: ++ op = la_op_revb_2h; ++ break; ++ case 0xd: ++ op = la_op_revb_4h; ++ break; ++ case 0xe: ++ op = la_op_revb_2w; ++ break; ++ case 0xf: ++ op = la_op_revb_d; ++ break; ++ case 0x10: ++ op = la_op_revh_2w; ++ break; ++ case 0x11: ++ op = la_op_revh_d; ++ break; ++ case 0x12: ++ op = la_op_bitrev_4b; ++ break; ++ case 0x13: ++ op = la_op_bitrev_8b; ++ break; ++ case 0x14: ++ op = la_op_bitrev_w; ++ break; ++ case 0x15: ++ op = la_op_bitrev_d; ++ break; ++ case 0x16: ++ op = la_op_ext_w_h; ++ break; ++ case 0x17: ++ op = la_op_ext_w_b; ++ break; ++ case 0x1a: ++ op = la_op_rdtime_d; ++ break; ++ case 0x1b: ++ op = la_op_cpucfg; ++ break; ++ } ++ break; ++ case 0x2: ++ switch (insn & 0x0000001f) { ++ case 0x00000000: ++ op = la_op_asrtle_d; ++ break; ++ } ++ break; ++ case 0x3: ++ switch (insn & 0x0000001f) { ++ case 0x00000000: ++ op = la_op_asrtgt_d; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x1: ++ switch ((insn >> 17) & 0x1) { ++ case 0x0: ++ op = la_op_alsl_w; ++ break; ++ case 0x1: ++ op = la_op_alsl_wu; ++ break; ++ } ++ break; ++ case 0x2: ++ switch ((insn >> 17) & 0x1) { ++ case 0x0: ++ op = la_op_bytepick_w; ++ break; ++ } ++ break; ++ case 0x3: ++ op = la_op_bytepick_d; ++ break; ++ case 0x4: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_add_w; ++ break; ++ case 0x1: ++ op = la_op_add_d; ++ break; ++ case 0x2: ++ op = la_op_sub_w; ++ break; ++ case 0x3: ++ op = la_op_sub_d; ++ break; ++ case 0x4: ++ op = la_op_slt; ++ break; ++ case 0x5: ++ op = la_op_sltu; ++ break; ++ case 0x6: ++ op = la_op_maskeqz; ++ break; ++ case 0x7: ++ op = la_op_masknez; ++ break; ++ } ++ break; ++ case 0x5: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_nor; ++ break; ++ case 0x1: ++ op = la_op_and; ++ break; ++ case 0x2: ++ op = la_op_or; ++ break; ++ case 0x3: ++ op = la_op_xor; ++ break; ++ case 0x4: ++ op = la_op_orn; ++ break; ++ case 0x5: ++ op = la_op_andn; ++ break; ++ case 0x6: ++ op = la_op_sll_w; ++ break; ++ case 0x7: ++ op = la_op_srl_w; ++ break; ++ } ++ break; ++ case 0x6: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_sra_w; ++ break; ++ case 0x1: ++ op = la_op_sll_d; ++ break; ++ case 0x2: ++ op = la_op_srl_d; ++ break; ++ case 0x3: ++ op = la_op_sra_d; ++ break; ++ case 0x6: ++ op = la_op_rotr_w; ++ break; ++ case 0x7: ++ op = la_op_rotr_d; ++ break; ++ } ++ break; ++ case 0x7: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_mul_w; ++ break; ++ case 0x1: ++ op = la_op_mulh_w; ++ break; ++ case 0x2: ++ op = la_op_mulh_wu; ++ break; ++ case 0x3: ++ op = la_op_mul_d; ++ break; ++ case 0x4: ++ op = la_op_mulh_d; ++ break; ++ case 0x5: ++ op = la_op_mulh_du; ++ break; ++ case 0x6: ++ op = la_op_mulw_d_w; ++ break; ++ case 0x7: ++ op = la_op_mulw_d_wu; ++ break; ++ } ++ break; ++ case 0x8: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_div_w; ++ break; ++ case 0x1: ++ op = la_op_mod_w; ++ break; ++ case 0x2: ++ op = la_op_div_wu; ++ break; ++ case 0x3: ++ op = la_op_mod_wu; ++ break; ++ case 0x4: ++ op = la_op_div_d; ++ break; ++ case 0x5: ++ op = la_op_mod_d; ++ break; ++ case 0x6: ++ op = la_op_div_du; ++ break; ++ case 0x7: ++ op = la_op_mod_du; ++ break; ++ } ++ break; ++ case 0x9: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ op = la_op_crc_w_b_w; ++ break; ++ case 0x1: ++ op = la_op_crc_w_h_w; ++ break; ++ case 0x2: ++ op = la_op_crc_w_w_w; ++ break; ++ case 0x3: ++ op = la_op_crc_w_d_w; ++ break; ++ case 0x4: ++ op = la_op_crcc_w_b_w; ++ break; ++ case 0x5: ++ op = la_op_crcc_w_h_w; ++ break; ++ case 0x6: ++ op = la_op_crcc_w_w_w; ++ break; ++ case 0x7: ++ op = la_op_crcc_w_d_w; ++ break; ++ } ++ break; ++ case 0xa: ++ switch ((insn >> 15) & 0x7) { ++ case 0x4: ++ op = la_op_break; ++ break; ++ case 0x5: ++ op = la_op_dbcl; ++ break; ++ case 0x6: ++ op = la_op_syscall; ++ break; ++ case 0x7: ++ op = la_op_hvcl; ++ break; ++ } ++ break; ++ case 0xb: ++ switch ((insn >> 17) & 0x1) { ++ case 0x0: ++ op = la_op_alsl_d; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x1: ++ switch ((insn >> 21) & 0x1) { ++ case 0x0: ++ switch ((insn >> 16) & 0x1f) { ++ case 0x0: ++ switch ((insn >> 15) & 0x1) { ++ case 0x1: ++ op = la_op_slli_w; ++ break; ++ } ++ break; ++ case 0x1: ++ op = la_op_slli_d; ++ break; ++ case 0x4: ++ switch ((insn >> 15) & 0x1) { ++ case 0x1: ++ op = la_op_srli_w; ++ break; ++ } ++ break; ++ case 0x5: ++ op = la_op_srli_d; ++ break; ++ case 0x8: ++ switch ((insn >> 15) & 0x1) { ++ case 0x1: ++ op = la_op_srai_w; ++ break; ++ } ++ break; ++ case 0x9: ++ op = la_op_srai_d; ++ break; ++ case 0xc: ++ switch ((insn >> 15) & 0x1) { ++ case 0x1: ++ op = la_op_rotri_w; ++ break; ++ } ++ break; ++ case 0xd: ++ op = la_op_rotri_d; ++ break; ++ } ++ break; ++ case 0x1: ++ switch ((insn >> 15) & 0x1) { ++ case 0x0: ++ op = la_op_bstrins_w; ++ break; ++ case 0x1: ++ op = la_op_bstrpick_w; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x2: ++ op = la_op_bstrins_d; ++ break; ++ case 0x3: ++ op = la_op_bstrpick_d; ++ break; ++ case 0x4: ++ switch ((insn >> 15) & 0x7f) { ++ case 0x1: ++ op = la_op_fadd_s; ++ break; ++ case 0x2: ++ op = la_op_fadd_d; ++ break; ++ case 0x5: ++ op = la_op_fsub_s; ++ break; ++ case 0x6: ++ op = la_op_fsub_d; ++ break; ++ case 0x9: ++ op = la_op_fmul_s; ++ break; ++ case 0xa: ++ op = la_op_fmul_d; ++ break; ++ case 0xd: ++ op = la_op_fdiv_s; ++ break; ++ case 0xe: ++ op = la_op_fdiv_d; ++ break; ++ case 0x11: ++ op = la_op_fmax_s; ++ break; ++ case 0x12: ++ op = la_op_fmax_d; ++ break; ++ case 0x15: ++ op = la_op_fmin_s; ++ break; ++ case 0x16: ++ op = la_op_fmin_d; ++ break; ++ case 0x19: ++ op = la_op_fmaxa_s; ++ break; ++ case 0x1a: ++ op = la_op_fmaxa_d; ++ break; ++ case 0x1d: ++ op = la_op_fmina_s; ++ break; ++ case 0x1e: ++ op = la_op_fmina_d; ++ break; ++ case 0x21: ++ op = la_op_fscaleb_s; ++ break; ++ case 0x22: ++ op = la_op_fscaleb_d; ++ break; ++ case 0x25: ++ op = la_op_fcopysign_s; ++ break; ++ case 0x26: ++ op = la_op_fcopysign_d; ++ break; ++ case 0x28: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x1: ++ op = la_op_fabs_s; ++ break; ++ case 0x2: ++ op = la_op_fabs_d; ++ break; ++ case 0x5: ++ op = la_op_fneg_s; ++ break; ++ case 0x6: ++ op = la_op_fneg_d; ++ break; ++ case 0x9: ++ op = la_op_flogb_s; ++ break; ++ case 0xa: ++ op = la_op_flogb_d; ++ break; ++ case 0xd: ++ op = la_op_fclass_s; ++ break; ++ case 0xe: ++ op = la_op_fclass_d; ++ break; ++ case 0x11: ++ op = la_op_fsqrt_s; ++ break; ++ case 0x12: ++ op = la_op_fsqrt_d; ++ break; ++ case 0x15: ++ op = la_op_frecip_s; ++ break; ++ case 0x16: ++ op = la_op_frecip_d; ++ break; ++ case 0x19: ++ op = la_op_frsqrt_s; ++ break; ++ case 0x1a: ++ op = la_op_frsqrt_d; ++ break; ++ } ++ break; ++ case 0x29: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x5: ++ op = la_op_fmov_s; ++ break; ++ case 0x6: ++ op = la_op_fmov_d; ++ break; ++ case 0x9: ++ op = la_op_movgr2fr_w; ++ break; ++ case 0xa: ++ op = la_op_movgr2fr_d; ++ break; ++ case 0xb: ++ op = la_op_movgr2frh_w; ++ break; ++ case 0xd: ++ op = la_op_movfr2gr_s; ++ break; ++ case 0xe: ++ op = la_op_movfr2gr_d; ++ break; ++ case 0xf: ++ op = la_op_movfrh2gr_s; ++ break; ++ case 0x10: ++ op = la_op_movgr2fcsr; ++ break; ++ case 0x12: ++ op = la_op_movfcsr2gr; ++ break; ++ case 0x14: ++ switch ((insn >> 3) & 0x3) { ++ case 0x0: ++ op = la_op_movfr2cf; ++ break; ++ } ++ break; ++ case 0x15: ++ switch ((insn >> 8) & 0x3) { ++ case 0x0: ++ op = la_op_movcf2fr; ++ break; ++ } ++ break; ++ case 0x16: ++ switch ((insn >> 3) & 0x3) { ++ case 0x0: ++ op = la_op_movgr2cf; ++ break; ++ } ++ break; ++ case 0x17: ++ switch ((insn >> 8) & 0x3) { ++ case 0x0: ++ op = la_op_movcf2gr; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x32: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x6: ++ op = la_op_fcvt_s_d; ++ break; ++ case 0x9: ++ op = la_op_fcvt_d_s; ++ break; ++ } ++ break; ++ case 0x34: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x1: ++ op = la_op_ftintrm_w_s; ++ break; ++ case 0x2: ++ op = la_op_ftintrm_w_d; ++ break; ++ case 0x9: ++ op = la_op_ftintrm_l_s; ++ break; ++ case 0xa: ++ op = la_op_ftintrm_l_d; ++ break; ++ case 0x11: ++ op = la_op_ftintrp_w_s; ++ break; ++ case 0x12: ++ op = la_op_ftintrp_w_d; ++ break; ++ case 0x19: ++ op = la_op_ftintrp_l_s; ++ break; ++ case 0x1a: ++ op = la_op_ftintrp_l_d; ++ break; ++ } ++ break; ++ case 0x35: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x1: ++ op = la_op_ftintrz_w_s; ++ break; ++ case 0x2: ++ op = la_op_ftintrz_w_d; ++ break; ++ case 0x9: ++ op = la_op_ftintrz_l_s; ++ break; ++ case 0xa: ++ op = la_op_ftintrz_l_d; ++ break; ++ case 0x11: ++ op = la_op_ftintrne_w_s; ++ break; ++ case 0x12: ++ op = la_op_ftintrne_w_d; ++ break; ++ case 0x19: ++ op = la_op_ftintrne_l_s; ++ break; ++ case 0x1a: ++ op = la_op_ftintrne_l_d; ++ break; ++ } ++ break; ++ case 0x36: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x1: ++ op = la_op_ftint_w_s; ++ break; ++ case 0x2: ++ op = la_op_ftint_w_d; ++ break; ++ case 0x9: ++ op = la_op_ftint_l_s; ++ break; ++ case 0xa: ++ op = la_op_ftint_l_d; ++ break; ++ } ++ break; ++ case 0x3a: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x4: ++ op = la_op_ffint_s_w; ++ break; ++ case 0x6: ++ op = la_op_ffint_s_l; ++ break; ++ case 0x8: ++ op = la_op_ffint_d_w; ++ break; ++ case 0xa: ++ op = la_op_ffint_d_l; ++ break; ++ } ++ break; ++ case 0x3c: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x11: ++ op = la_op_frint_s; ++ break; ++ case 0x12: ++ op = la_op_frint_d; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x8: ++ op = la_op_slti; ++ break; ++ case 0x9: ++ op = la_op_sltui; ++ break; ++ case 0xa: ++ op = la_op_addi_w; ++ break; ++ case 0xb: ++ op = la_op_addi_d; ++ break; ++ case 0xc: ++ op = la_op_lu52i_d; ++ break; ++ case 0xd: ++ op = la_op_addi; ++ break; ++ case 0xe: ++ op = la_op_ori; ++ break; ++ case 0xf: ++ op = la_op_xori; ++ break; ++ } ++ break; ++ case 0x1: ++ switch ((insn >> 24) & 0x3) { ++ case 0x0: ++ op = la_op_csrxchg; ++ break; ++ case 0x2: ++ switch ((insn >> 22) & 0x3) { ++ case 0x0: ++ op = la_op_cacop; ++ break; ++ case 0x1: ++ switch ((insn >> 18) & 0xf) { ++ case 0x0: ++ op = la_op_lddir; ++ break; ++ case 0x1: ++ switch (insn & 0x0000001f) { ++ case 0x00000000: ++ op = la_op_ldpte; ++ break; ++ } ++ break; ++ case 0x2: ++ switch ((insn >> 15) & 0x7) { ++ case 0x0: ++ switch ((insn >> 10) & 0x1f) { ++ case 0x0: ++ op = la_op_iocsrrd_b; ++ break; ++ case 0x1: ++ op = la_op_iocsrrd_h; ++ break; ++ case 0x2: ++ op = la_op_iocsrrd_w; ++ break; ++ case 0x3: ++ op = la_op_iocsrrd_d; ++ break; ++ case 0x4: ++ op = la_op_iocsrwr_b; ++ break; ++ case 0x5: ++ op = la_op_iocsrwr_h; ++ break; ++ case 0x6: ++ op = la_op_iocsrwr_w; ++ break; ++ case 0x7: ++ op = la_op_iocsrwr_d; ++ break; ++ case 0x8: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbclr; ++ break; ++ } ++ break; ++ case 0x9: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbflush; ++ break; ++ } ++ break; ++ case 0xa: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbsrch; ++ break; ++ } ++ break; ++ case 0xb: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbrd; ++ break; ++ } ++ break; ++ case 0xc: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbwr; ++ break; ++ } ++ break; ++ case 0xd: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_tlbfill; ++ break; ++ } ++ break; ++ case 0xe: ++ switch (insn & 0x000003ff) { ++ case 0x00000000: ++ op = la_op_ertn; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x1: ++ op = la_op_idle; ++ break; ++ case 0x3: ++ op = la_op_invtlb; ++ break; ++ } ++ break; ++ } ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x2: ++ switch ((insn >> 20) & 0x3f) { ++ case 0x1: ++ op = la_op_fmadd_s; ++ break; ++ case 0x2: ++ op = la_op_fmadd_d; ++ break; ++ case 0x5: ++ op = la_op_fmsub_s; ++ break; ++ case 0x6: ++ op = la_op_fmsub_d; ++ break; ++ case 0x9: ++ op = la_op_fnmadd_s; ++ break; ++ case 0xa: ++ op = la_op_fnmadd_d; ++ break; ++ case 0xd: ++ op = la_op_fnmsub_s; ++ break; ++ case 0xe: ++ op = la_op_fnmsub_d; ++ break; ++ } ++ break; ++ case 0x3: ++ switch ((insn >> 20) & 0x3f) { ++ case 0x1: ++ switch ((insn >> 3) & 0x3) { ++ case 0x0: ++ op = la_op_fcmp_cond_s; ++ break; ++ } ++ break; ++ case 0x2: ++ switch ((insn >> 3) & 0x3) { ++ case 0x0: ++ op = la_op_fcmp_cond_d; ++ break; ++ } ++ break; ++ case 0x10: ++ switch ((insn >> 18) & 0x3) { ++ case 0x0: ++ op = la_op_fsel; ++ break; ++ } ++ break; ++ } ++ break; ++ case 0x4: ++ op = la_op_addu16i_d; ++ break; ++ case 0x5: ++ switch ((insn >> 25) & 0x1) { ++ case 0x0: ++ op = la_op_lu12i_w; ++ break; ++ case 0x1: ++ op = la_op_lu32i_d; ++ break; ++ } ++ break; ++ case 0x6: ++ switch ((insn >> 25) & 0x1) { ++ case 0x0: ++ op = la_op_pcaddi; ++ break; ++ case 0x1: ++ op = la_op_pcalau12i; ++ break; ++ } ++ break; ++ case 0x7: ++ switch ((insn >> 25) & 0x1) { ++ case 0x0: ++ op = la_op_pcaddu12i; ++ break; ++ case 0x1: ++ op = la_op_pcaddu18i; ++ break; ++ } ++ break; ++ case 0x8: ++ switch ((insn >> 24) & 0x3) { ++ case 0x0: ++ op = la_op_ll_w; ++ break; ++ case 0x1: ++ op = la_op_sc_w; ++ break; ++ case 0x2: ++ op = la_op_ll_d; ++ break; ++ case 0x3: ++ op = la_op_sc_d; ++ break; ++ } ++ break; ++ case 0x9: ++ switch ((insn >> 24) & 0x3) { ++ case 0x0: ++ op = la_op_ldptr_w; ++ break; ++ case 0x1: ++ op = la_op_stptr_w; ++ break; ++ case 0x2: ++ op = la_op_ldptr_d; ++ break; ++ case 0x3: ++ op = la_op_stptr_d; ++ break; ++ } ++ break; ++ case 0xa: ++ switch ((insn >> 22) & 0xf) { ++ case 0x0: ++ op = la_op_ld_b; ++ break; ++ case 0x1: ++ op = la_op_ld_h; ++ break; ++ case 0x2: ++ op = la_op_ld_w; ++ break; ++ case 0x3: ++ op = la_op_ld_d; ++ break; ++ case 0x4: ++ op = la_op_st_b; ++ break; ++ case 0x5: ++ op = la_op_st_h; ++ break; ++ case 0x6: ++ op = la_op_st_w; ++ break; ++ case 0x7: ++ op = la_op_st_d; ++ break; ++ case 0x8: ++ op = la_op_ld_bu; ++ break; ++ case 0x9: ++ op = la_op_ld_hu; ++ break; ++ case 0xa: ++ op = la_op_ld_wu; ++ break; ++ case 0xb: ++ op = la_op_preld; ++ break; ++ case 0xc: ++ op = la_op_fld_s; ++ break; ++ case 0xd: ++ op = la_op_fst_s; ++ break; ++ case 0xe: ++ op = la_op_fld_d; ++ break; ++ case 0xf: ++ op = la_op_fst_d; ++ break; ++ } ++ break; ++ case 0xb: ++ switch ((insn >> 22) & 0xf) { ++ case 0x8: ++ op = la_op_ldl_w; ++ break; ++ case 0x9: ++ op = la_op_ldr_w; ++ break; ++ case 0xa: ++ op = la_op_ldl_d; ++ break; ++ case 0xb: ++ op = la_op_ldr_d; ++ break; ++ case 0xe: ++ op = la_op_stl_d; ++ break; ++ case 0xf: ++ op = la_op_str_d; ++ break; ++ } ++ break; ++ case 0xe: ++ switch ((insn >> 15) & 0x7ff) { ++ case 0x0: ++ op = la_op_ldx_b; ++ break; ++ case 0x8: ++ op = la_op_ldx_h; ++ break; ++ case 0x10: ++ op = la_op_ldx_w; ++ break; ++ case 0x18: ++ op = la_op_ldx_d; ++ break; ++ case 0x20: ++ op = la_op_stx_b; ++ break; ++ case 0x28: ++ op = la_op_stx_h; ++ break; ++ case 0x30: ++ op = la_op_stx_w; ++ break; ++ case 0x38: ++ op = la_op_stx_d; ++ break; ++ case 0x40: ++ op = la_op_ldx_bu; ++ break; ++ case 0x48: ++ op = la_op_ldx_hu; ++ break; ++ case 0x50: ++ op = la_op_ldx_wu; ++ break; ++ case 0x60: ++ op = la_op_fldx_s; ++ break; ++ case 0x68: ++ op = la_op_fldx_d; ++ break; ++ case 0x70: ++ op = la_op_fstx_s; ++ break; ++ case 0x78: ++ op = la_op_fstx_d; ++ break; ++ case 0xc0: ++ op = la_op_amswap_w; ++ break; ++ case 0xc1: ++ op = la_op_amswap_d; ++ break; ++ case 0xc2: ++ op = la_op_amadd_w; ++ break; ++ case 0xc3: ++ op = la_op_amadd_d; ++ break; ++ case 0xc4: ++ op = la_op_amand_w; ++ break; ++ case 0xc5: ++ op = la_op_amand_d; ++ break; ++ case 0xc6: ++ op = la_op_amor_w; ++ break; ++ case 0xc7: ++ op = la_op_amor_d; ++ break; ++ case 0xc8: ++ op = la_op_amxor_w; ++ break; ++ case 0xc9: ++ op = la_op_amxor_d; ++ break; ++ case 0xca: ++ op = la_op_ammax_w; ++ break; ++ case 0xcb: ++ op = la_op_ammax_d; ++ break; ++ case 0xcc: ++ op = la_op_ammin_w; ++ break; ++ case 0xcd: ++ op = la_op_ammin_d; ++ break; ++ case 0xce: ++ op = la_op_ammax_wu; ++ break; ++ case 0xcf: ++ op = la_op_ammax_du; ++ break; ++ case 0xd0: ++ op = la_op_ammin_wu; ++ break; ++ case 0xd1: ++ op = la_op_ammin_du; ++ break; ++ case 0xd2: ++ op = la_op_amswap_db_w; ++ break; ++ case 0xd3: ++ op = la_op_amswap_db_d; ++ break; ++ case 0xd4: ++ op = la_op_amadd_db_w; ++ break; ++ case 0xd5: ++ op = la_op_amadd_db_d; ++ break; ++ case 0xd6: ++ op = la_op_amand_db_w; ++ break; ++ case 0xd7: ++ op = la_op_amand_db_d; ++ break; ++ case 0xd8: ++ op = la_op_amor_db_w; ++ break; ++ case 0xd9: ++ op = la_op_amor_db_d; ++ break; ++ case 0xda: ++ op = la_op_amxor_db_w; ++ break; ++ case 0xdb: ++ op = la_op_amxor_db_d; ++ break; ++ case 0xdc: ++ op = la_op_ammax_db_w; ++ break; ++ case 0xdd: ++ op = la_op_ammax_db_d; ++ break; ++ case 0xde: ++ op = la_op_ammin_db_w; ++ break; ++ case 0xdf: ++ op = la_op_ammin_db_d; ++ break; ++ case 0xe0: ++ op = la_op_ammax_db_wu; ++ break; ++ case 0xe1: ++ op = la_op_ammax_db_du; ++ break; ++ case 0xe2: ++ op = la_op_ammin_db_wu; ++ break; ++ case 0xe3: ++ op = la_op_ammin_db_du; ++ break; ++ case 0xe4: ++ op = la_op_dbar; ++ break; ++ case 0xe5: ++ op = la_op_ibar; ++ break; ++ case 0xe8: ++ op = la_op_fldgt_s; ++ break; ++ case 0xe9: ++ op = la_op_fldgt_d; ++ break; ++ case 0xea: ++ op = la_op_fldle_s; ++ break; ++ case 0xeb: ++ op = la_op_fldle_d; ++ break; ++ case 0xec: ++ op = la_op_fstgt_s; ++ break; ++ case 0xed: ++ op = la_op_fstgt_d; ++ break; ++ case 0xee: ++ op = ls_op_fstle_s; ++ break; ++ case 0xef: ++ op = la_op_fstle_d; ++ break; ++ case 0xf0: ++ op = la_op_ldgt_b; ++ break; ++ case 0xf1: ++ op = la_op_ldgt_h; ++ break; ++ case 0xf2: ++ op = la_op_ldgt_w; ++ break; ++ case 0xf3: ++ op = la_op_ldgt_d; ++ break; ++ case 0xf4: ++ op = la_op_ldle_b; ++ break; ++ case 0xf5: ++ op = la_op_ldle_h; ++ break; ++ case 0xf6: ++ op = la_op_ldle_w; ++ break; ++ case 0xf7: ++ op = la_op_ldle_d; ++ break; ++ case 0xf8: ++ op = la_op_stgt_b; ++ break; ++ case 0xf9: ++ op = la_op_stgt_h; ++ break; ++ case 0xfa: ++ op = la_op_stgt_w; ++ break; ++ case 0xfb: ++ op = la_op_stgt_d; ++ break; ++ case 0xfc: ++ op = la_op_stle_b; ++ break; ++ case 0xfd: ++ op = la_op_stle_h; ++ break; ++ case 0xfe: ++ op = la_op_stle_w; ++ break; ++ case 0xff: ++ op = la_op_stle_d; ++ break; ++ } ++ break; ++ case 0x10: ++ op = la_op_beqz; ++ break; ++ case 0x11: ++ op = la_op_bnez; ++ break; ++ case 0x12: ++ switch ((insn >> 8) & 0x3) { ++ case 0x0: ++ op = la_op_bceqz; ++ break; ++ case 0x1: ++ op = la_op_bcnez; ++ break; ++ } ++ break; ++ case 0x13: ++ op = la_op_jirl; ++ break; ++ case 0x14: ++ op = la_op_b; ++ break; ++ case 0x15: ++ op = la_op_bl; ++ break; ++ case 0x16: ++ op = la_op_beq; ++ break; ++ case 0x17: ++ op = la_op_bne; ++ break; ++ case 0x18: ++ op = la_op_blt; ++ break; ++ case 0x19: ++ op = la_op_bge; ++ break; ++ case 0x1a: ++ op = la_op_bltu; ++ break; ++ case 0x1b: ++ op = la_op_bgeu; ++ break; ++ default: ++ op = la_op_illegal; ++ break; ++ } ++ dec->op = op; ++} ++ ++/* operand extractors */ ++#define IM_5 5 ++#define IM_8 8 ++#define IM_12 12 ++#define IM_14 14 ++#define IM_15 15 ++#define IM_16 16 ++#define IM_20 20 ++#define IM_21 21 ++#define IM_26 26 ++ ++static uint32_t operand_r1(uint32_t insn) ++{ ++ return insn & 0x1f; ++} ++ ++static uint32_t operand_r2(uint32_t insn) ++{ ++ return (insn >> 5) & 0x1f; ++} ++ ++static uint32_t operand_r3(uint32_t insn) ++{ ++ return (insn >> 10) & 0x1f; ++} ++ ++static uint32_t operand_r4(uint32_t insn) ++{ ++ return (insn >> 15) & 0x1f; ++} ++ ++static uint32_t operand_u6(uint32_t insn) ++{ ++ return (insn >> 10) & 0x3f; ++} ++ ++static uint32_t operand_bw1(uint32_t insn) ++{ ++ return (insn >> 10) & 0x1f; ++} ++ ++static uint32_t operand_bw2(uint32_t insn) ++{ ++ return (insn >> 16) & 0x1f; ++} ++ ++static uint32_t operand_bd1(uint32_t insn) ++{ ++ return (insn >> 10) & 0x3f; ++} ++ ++static uint32_t operand_bd2(uint32_t insn) ++{ ++ return (insn >> 16) & 0x3f; ++} ++ ++static uint32_t operand_sa2(uint32_t insn) ++{ ++ return (insn >> 15) & 0x3; ++} ++ ++static uint32_t operand_sa3(uint32_t insn) ++{ ++ return (insn >> 15) & 0x3; ++} ++ ++static int32_t operand_im20(uint32_t insn) ++{ ++ int32_t imm = (int32_t)((insn >> 5) & 0xfffff); ++ return imm > (1 << 19) ? imm - (1 << 20) : imm; ++} ++ ++static int32_t operand_im16(uint32_t insn) ++{ ++ int32_t imm = (int32_t)((insn >> 10) & 0xffff); ++ return imm > (1 << 15) ? imm - (1 << 16) : imm; ++} ++ ++static int32_t operand_im14(uint32_t insn) ++{ ++ int32_t imm = (int32_t)((insn >> 10) & 0x3fff); ++ return imm > (1 << 13) ? imm - (1 << 14) : imm; ++} ++ ++static int32_t operand_im12(uint32_t insn) ++{ ++ int32_t imm = (int32_t)((insn >> 10) & 0xfff); ++ return imm > (1 << 11) ? imm - (1 << 12) : imm; ++} ++ ++static int32_t operand_im8(uint32_t insn) ++{ ++ int32_t imm = (int32_t)((insn >> 10) & 0xff); ++ return imm > (1 << 7) ? imm - (1 << 8) : imm; ++} ++ ++static uint32_t operand_sd(uint32_t insn) ++{ ++ return insn & 0x3; ++} ++ ++static uint32_t operand_sj(uint32_t insn) ++{ ++ return (insn >> 5) & 0x3; ++} ++ ++static uint32_t operand_cd(uint32_t insn) ++{ ++ return insn & 0x7; ++} ++ ++static uint32_t operand_cj(uint32_t insn) ++{ ++ return (insn >> 5) & 0x7; ++} ++ ++static uint32_t operand_code(uint32_t insn) ++{ ++ return insn & 0x7fff; ++} ++ ++static int32_t operand_whint(uint32_t insn) ++{ ++ int32_t imm = (int32_t)(insn & 0x7fff); ++ return imm > (1 << 14) ? imm - (1 << 15) : imm; ++} ++ ++static int32_t operand_invop(uint32_t insn) ++{ ++ int32_t imm = (int32_t)(insn & 0x1f); ++ return imm > (1 << 4) ? imm - (1 << 5) : imm; ++} ++ ++static int32_t operand_ofs21(uint32_t insn) ++{ ++ int32_t imm = (((int32_t)insn & 0x1f) << 16) | ((insn >> 10) & 0xffff); ++ return imm > (1 << 20) ? imm - (1 << 21) : imm; ++} ++ ++static int32_t operand_ofs26(uint32_t insn) ++{ ++ int32_t imm = (((int32_t)insn & 0x3ff) << 16) | ((insn >> 10) & 0xffff); ++ return imm > (1 << 25) ? imm - (1 << 26) : imm; ++} ++ ++static uint32_t operand_fcond(uint32_t insn) ++{ ++ return (insn >> 15) & 0x1f; ++} ++ ++static uint32_t operand_sel(uint32_t insn) ++{ ++ return (insn >> 15) & 0x7; ++} ++ ++/* decode operands */ ++static void decode_insn_operands(la_decode *dec) ++{ ++ uint32_t insn = dec->insn; ++ dec->codec = opcode_la[dec->op].codec; ++ switch (dec->codec) { ++ case la_codec_illegal: ++ case la_codec_empty: ++ break; ++ case la_codec_2r: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ break; ++ case la_codec_2r_u5: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ break; ++ case la_codec_2r_u6: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_u6(insn); ++ break; ++ case la_codec_2r_2bw: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_bw1(insn); ++ dec->r4 = operand_bw2(insn); ++ break; ++ case la_codec_2r_2bd: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_bd1(insn); ++ dec->r4 = operand_bd2(insn); ++ break; ++ case la_codec_3r: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ break; ++ case la_codec_3r_rd0: ++ dec->r1 = 0; ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ break; ++ case la_codec_3r_sa2: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ dec->r4 = operand_sa2(insn); ++ break; ++ case la_codec_3r_sa3: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ dec->r4 = operand_sa3(insn); ++ break; ++ case la_codec_4r: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ dec->r4 = operand_r4(insn); ++ break; ++ case la_codec_r_im20: ++ dec->r1 = operand_r1(insn); ++ dec->imm = operand_im20(insn); ++ dec->bit = IM_20; ++ break; ++ case la_codec_2r_im16: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->imm = operand_im16(insn); ++ dec->bit = IM_16; ++ break; ++ case la_codec_2r_im14: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->imm = operand_im14(insn); ++ dec->bit = IM_14; ++ break; ++ case la_codec_im5_r_im12: ++ dec->imm2 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->imm = operand_im12(insn); ++ dec->bit = IM_12; ++ break; ++ case la_codec_2r_im12: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->imm = operand_im12(insn); ++ dec->bit = IM_12; ++ break; ++ case la_codec_2r_im8: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->imm = operand_im8(insn); ++ dec->bit = IM_8; ++ break; ++ case la_codec_r_sd: ++ dec->r1 = operand_sd(insn); ++ dec->r2 = operand_r2(insn); ++ break; ++ case la_codec_r_sj: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_sj(insn); ++ break; ++ case la_codec_r_cd: ++ dec->r1 = operand_cd(insn); ++ dec->r2 = operand_r2(insn); ++ break; ++ case la_codec_r_cj: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_cj(insn); ++ break; ++ case la_codec_r_seq: ++ dec->r1 = 0; ++ dec->r2 = operand_r1(insn); ++ dec->imm = operand_im8(insn); ++ dec->bit = IM_8; ++ break; ++ case la_codec_code: ++ dec->code = operand_code(insn); ++ break; ++ case la_codec_whint: ++ dec->imm = operand_whint(insn); ++ dec->bit = IM_15; ++ break; ++ case la_codec_invtlb: ++ dec->imm = operand_invop(insn); ++ dec->bit = IM_5; ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ break; ++ case la_codec_r_ofs21: ++ dec->imm = operand_ofs21(insn); ++ dec->bit = IM_21; ++ dec->r2 = operand_r2(insn); ++ break; ++ case la_codec_cj_ofs21: ++ dec->imm = operand_ofs21(insn); ++ dec->bit = IM_21; ++ dec->r2 = operand_cj(insn); ++ break; ++ case la_codec_ofs26: ++ dec->imm = operand_ofs26(insn); ++ dec->bit = IM_26; ++ break; ++ case la_codec_cond: ++ dec->r1 = operand_cd(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ dec->r4 = operand_fcond(insn); ++ break; ++ case la_codec_sel: ++ dec->r1 = operand_r1(insn); ++ dec->r2 = operand_r2(insn); ++ dec->r3 = operand_r3(insn); ++ dec->r4 = operand_sel(insn); ++ break; ++ } ++} ++ ++/* format instruction */ ++ ++static void append(char *s1, const char *s2, size_t n) ++{ ++ size_t l1 = strlen(s1); ++ if (n - l1 - 1 > 0) { ++ strncat(s1, s2, n - l1); ++ } ++} ++ ++static void format_insn(char *buf, size_t buflen, size_t tab, la_decode *dec) ++{ ++ char tmp[16]; ++ const char *fmt; ++ ++ fmt = opcode_la[dec->op].format; ++ while (*fmt) { ++ switch (*fmt) { ++ case 'n': /* name */ ++ append(buf, opcode_la[dec->op].name, buflen); ++ break; ++ case 's': ++ append(buf, "s", buflen); ++ break; ++ case 'd': ++ append(buf, "d", buflen); ++ break; ++ case 'e': /* illegal */ ++ snprintf(tmp, sizeof(tmp), "%x", dec->insn); ++ append(buf, tmp, buflen); ++ break; ++ case 't': ++ while (strlen(buf) < tab) { ++ append(buf, " ", buflen); ++ } ++ break; ++ case '(': ++ append(buf, "(", buflen); ++ break; ++ case ',': ++ append(buf, ",", buflen); ++ break; ++ case '.': ++ append(buf, ".", buflen); ++ break; ++ case ')': ++ append(buf, ")", buflen); ++ break; ++ case '0': /* rd */ ++ append(buf, loongarch_r_normal_name[dec->r1], buflen); ++ break; ++ case '1': /* rj */ ++ append(buf, loongarch_r_normal_name[dec->r2], buflen); ++ break; ++ case '2': /* rk */ ++ append(buf, loongarch_r_normal_name[dec->r3], buflen); ++ break; ++ case '3': /* fd */ ++ append(buf, loongarch_f_normal_name[dec->r1], buflen); ++ break; ++ case '4': /* fj */ ++ append(buf, loongarch_f_normal_name[dec->r2], buflen); ++ break; ++ case '5': /* fk */ ++ append(buf, loongarch_f_normal_name[dec->r3], buflen); ++ break; ++ case '6': /* fa */ ++ append(buf, loongarch_f_normal_name[dec->r4], buflen); ++ break; ++ case 'A': /* sd */ ++ append(buf, loongarch_cr_normal_name[dec->r1], buflen); ++ break; ++ case 'B': /* sj */ ++ append(buf, loongarch_cr_normal_name[dec->r2], buflen); ++ break; ++ case 'C': /* r3 */ ++ snprintf(tmp, sizeof(tmp), "%x", dec->r3); ++ append(buf, tmp, buflen); ++ break; ++ case 'D': /* r4 */ ++ snprintf(tmp, sizeof(tmp), "%x", dec->r4); ++ append(buf, tmp, buflen); ++ break; ++ case 'E': /* r1 */ ++ snprintf(tmp, sizeof(tmp), "%x", dec->r1); ++ append(buf, tmp, buflen); ++ break; ++ case 'F': /* fcsrd */ ++ append(buf, loongarch_r_normal_name[dec->r1], buflen); ++ break; ++ case 'G': /* fcsrs */ ++ append(buf, loongarch_r_normal_name[dec->r2], buflen); ++ break; ++ case 'H': /* cd */ ++ append(buf, loongarch_c_normal_name[dec->r1], buflen); ++ break; ++ case 'I': /* cj */ ++ append(buf, loongarch_c_normal_name[dec->r2], buflen); ++ break; ++ case 'J': /* code */ ++ snprintf(tmp, sizeof(tmp), "0x%x", dec->code); ++ append(buf, tmp, buflen); ++ break; ++ case 'K': /* cond */ ++ switch (dec->r4) { ++ case 0x0: ++ append(buf, "caf", buflen); ++ break; ++ case 0x1: ++ append(buf, "saf", buflen); ++ break; ++ case 0x2: ++ append(buf, "clt", buflen); ++ break; ++ case 0x3: ++ append(buf, "slt", buflen); ++ break; ++ case 0x4: ++ append(buf, "ceq", buflen); ++ break; ++ case 0x5: ++ append(buf, "seq", buflen); ++ break; ++ case 0x6: ++ append(buf, "cle", buflen); ++ break; ++ case 0x7: ++ append(buf, "sle", buflen); ++ break; ++ case 0x8: ++ append(buf, "cun", buflen); ++ break; ++ case 0x9: ++ append(buf, "sun", buflen); ++ break; ++ case 0xA: ++ append(buf, "cult", buflen); ++ break; ++ case 0xB: ++ append(buf, "sult", buflen); ++ break; ++ case 0xC: ++ append(buf, "cueq", buflen); ++ break; ++ case 0xD: ++ append(buf, "sueq", buflen); ++ break; ++ case 0xE: ++ append(buf, "cule", buflen); ++ break; ++ case 0xF: ++ append(buf, "sule", buflen); ++ break; ++ case 0x10: ++ append(buf, "cne", buflen); ++ break; ++ case 0x11: ++ append(buf, "sne", buflen); ++ break; ++ case 0x14: ++ append(buf, "cor", buflen); ++ break; ++ case 0x15: ++ append(buf, "sor", buflen); ++ break; ++ case 0x18: ++ append(buf, "cune", buflen); ++ break; ++ case 0x19: ++ append(buf, "sune", buflen); ++ break; ++ } ++ break; ++ case 'L': /* ca */ ++ append(buf, loongarch_c_normal_name[dec->r4], buflen); ++ break; ++ case 'M': /* cop */ ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm2) & 0x1f); ++ append(buf, tmp, buflen); ++ break; ++ case 'i': /* sixx d */ ++ snprintf(tmp, sizeof(tmp), "%d", dec->imm); ++ append(buf, tmp, buflen); ++ break; ++ case 'o': /* offset */ ++ snprintf(tmp, sizeof(tmp), "%d", (dec->imm) << 2); ++ append(buf, tmp, buflen); ++ break; ++ case 'x': /* sixx x */ ++ switch (dec->bit) { ++ case IM_5: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x1f); ++ append(buf, tmp, buflen); ++ break; ++ case IM_8: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_12: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_14: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x3fff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_15: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x7fff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_16: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xffff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_20: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfffff); ++ append(buf, tmp, buflen); ++ break; ++ default: ++ snprintf(tmp, sizeof(tmp), "0x%x", dec->imm); ++ append(buf, tmp, buflen); ++ break; ++ } ++ break; ++ case 'X': /* offset x*/ ++ switch (dec->bit) { ++ case IM_16: ++ snprintf(tmp, sizeof(tmp), "0x%x", ((dec->imm) << 2) & 0xffff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_21: ++ snprintf(tmp, sizeof(tmp), "0x%x", ++ ((dec->imm) << 2) & 0x1fffff); ++ append(buf, tmp, buflen); ++ break; ++ case IM_26: ++ snprintf(tmp, sizeof(tmp), "0x%x", ++ ((dec->imm) << 2) & 0x3ffffff); ++ append(buf, tmp, buflen); ++ break; ++ default: ++ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) << 2); ++ append(buf, tmp, buflen); ++ break; ++ } ++ break; ++ case 'p': /* pc */ ++ snprintf(tmp, sizeof(tmp), " # 0x%" PRIx32 "", ++ dec->pc + ((dec->imm) << 2)); ++ append(buf, tmp, buflen); ++ break; ++ default: ++ break; ++ } ++ fmt++; ++ } ++} ++ ++/* disassemble instruction */ ++static void disasm_insn(char *buf, size_t buflen, bfd_vma pc, ++ unsigned long int insn) ++{ ++ la_decode dec = { 0 }; ++ dec.pc = pc; ++ dec.insn = insn; ++ decode_insn_opcode(&dec); ++ decode_insn_operands(&dec); ++ format_insn(buf, buflen, 16, &dec); ++} ++ ++int print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) ++{ ++ char buf[128] = { 0 }; ++ bfd_byte buffer[INSNLEN]; ++ unsigned long insn; ++ int status; ++ ++ status = (*info->read_memory_func)(memaddr, buffer, INSNLEN, info); ++ if (status == 0) { ++ insn = (uint32_t)bfd_getl32(buffer); ++ (*info->fprintf_func)(info->stream, "%08" PRIx64 " ", insn); ++ } else { ++ (*info->memory_error_func)(status, memaddr, info); ++ return -1; ++ } ++ disasm_insn(buf, sizeof(buf), memaddr, insn); ++ (*info->fprintf_func)(info->stream, "\t%s", buf); ++ return INSNLEN; ++} +diff --git a/disas/meson.build b/disas/meson.build +index 5c5daa69a7..c337369cb1 100644 +--- a/disas/meson.build ++++ b/disas/meson.build +@@ -12,6 +12,7 @@ common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) + common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) + common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) + common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) ++common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: files('loongarch.c')) + common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) + common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) + common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) +diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml +new file mode 100644 +index 0000000000..2e515e0e36 +--- /dev/null ++++ b/gdb-xml/loongarch-base64.xml +@@ -0,0 +1,45 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/gdb-xml/loongarch-fpu.xml b/gdb-xml/loongarch-fpu.xml +new file mode 100644 +index 0000000000..d398fe3650 +--- /dev/null ++++ b/gdb-xml/loongarch-fpu.xml +@@ -0,0 +1,50 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.27.0 + diff --git a/Add-dummy-Aspeed-AST2600-Display-Port-MCU-DPMCU.patch b/Add-dummy-Aspeed-AST2600-Display-Port-MCU-DPMCU.patch new file mode 100644 index 0000000000000000000000000000000000000000..2887ce74c7a7df78e48c21cae92767e2a70d481f --- /dev/null +++ b/Add-dummy-Aspeed-AST2600-Display-Port-MCU-DPMCU.patch @@ -0,0 +1,84 @@ +From 48f112e0b8e65fccc3bf66510fafb6e9a8d58e90 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 10:50:04 +0800 +Subject: [PATCH] Add dummy Aspeed AST2600 Display Port MCU (DPMCU) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit d9e9cd59df4bc92e4cf7ad1bfa6e2a8429ff31b4 + +AST2600 Display Port MCU introduces 0x18000000~0x1803FFFF as it's memory +and io address. If guest machine try to access DPMCU memory, it will +cause a fatal error. + +Signed-off-by: Troy Lee +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Cédric Le Goater +Message-id: 20211210083034.726610-1-troy_lee@aspeedtech.com +Signed-off-by: Peter Maydell +Signed-off-by: Luo Yifan +--- + hw/arm/aspeed_ast2600.c | 8 ++++++++ + include/hw/arm/aspeed_soc.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c +index 0384357a95..e33483fb5d 100644 +--- a/hw/arm/aspeed_ast2600.c ++++ b/hw/arm/aspeed_ast2600.c +@@ -19,9 +19,11 @@ + #include "sysemu/sysemu.h" + + #define ASPEED_SOC_IOMEM_SIZE 0x00200000 ++#define ASPEED_SOC_DPMCU_SIZE 0x00040000 + + static const hwaddr aspeed_soc_ast2600_memmap[] = { + [ASPEED_DEV_SRAM] = 0x10000000, ++ [ASPEED_DEV_DPMCU] = 0x18000000, + /* 0x16000000 0x17FFFFFF : AHB BUS do LPC Bus bridge */ + [ASPEED_DEV_IOMEM] = 0x1E600000, + [ASPEED_DEV_PWM] = 0x1E610000, +@@ -44,6 +46,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { + [ASPEED_DEV_SCU] = 0x1E6E2000, + [ASPEED_DEV_XDMA] = 0x1E6E7000, + [ASPEED_DEV_ADC] = 0x1E6E9000, ++ [ASPEED_DEV_DP] = 0x1E6EB000, + [ASPEED_DEV_VIDEO] = 0x1E700000, + [ASPEED_DEV_SDHCI] = 0x1E740000, + [ASPEED_DEV_EMMC] = 0x1E750000, +@@ -104,6 +107,7 @@ static const int aspeed_soc_ast2600_irqmap[] = { + [ASPEED_DEV_ETH3] = 32, + [ASPEED_DEV_ETH4] = 33, + [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ ++ [ASPEED_DEV_DP] = 62, + }; + + static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +@@ -298,6 +302,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) + memory_region_add_subregion(get_system_memory(), + sc->memmap[ASPEED_DEV_SRAM], &s->sram); + ++ /* DPMCU */ ++ create_unimplemented_device("aspeed.dpmcu", sc->memmap[ASPEED_DEV_DPMCU], ++ ASPEED_SOC_DPMCU_SIZE); ++ + /* SCU */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { + return; +diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h +index 8139358549..18fb7eed46 100644 +--- a/include/hw/arm/aspeed_soc.h ++++ b/include/hw/arm/aspeed_soc.h +@@ -139,6 +139,8 @@ enum { + ASPEED_DEV_EMMC, + ASPEED_DEV_KCS, + ASPEED_DEV_HACE, ++ ASPEED_DEV_DPMCU, ++ ASPEED_DEV_DP, + }; + + #endif /* ASPEED_SOC_H */ +-- +2.27.0 + diff --git a/Add-flex-bison-to-debian-hexagon-cross.patch b/Add-flex-bison-to-debian-hexagon-cross.patch new file mode 100644 index 0000000000000000000000000000000000000000..1307956d7e0875f7889017d4927e67c873273303 --- /dev/null +++ b/Add-flex-bison-to-debian-hexagon-cross.patch @@ -0,0 +1,35 @@ +From 96df1be5fee763f54db9f50466f4ccf433c48ea1 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Wed, 30 Nov 2022 14:33:12 +0800 +Subject: [PATCH 03/17] Add flex/bison to `debian-hexagon-cross` + +debian-hexagon-cross contains two images, one to build the toolchain +used for building the Hexagon tests themselves, and one image to build +QEMU and run the tests. +This commit adds flex/bison to the final image that builds QEMU so that +it can also build idef-parser. +Note: This container is not built by the CI and needs to be rebuilt and +updated manually. + +Signed-off-by: Anton Johansson +Signed-off-by: jianchunfu +--- + tests/docker/dockerfiles/debian-hexagon-cross.docker | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker +index d5dc299dc1..a64e950f07 100644 +--- a/tests/docker/dockerfiles/debian-hexagon-cross.docker ++++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker +@@ -38,7 +38,7 @@ RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.lis + # Install QEMU build deps for use in CI + RUN apt update && \ + DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ +- DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy git ninja-build && \ ++ DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy bison flex git ninja-build && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt build-dep -yy --arch-only qemu + COPY --from=0 /usr/local /usr/local +-- +2.27.0 + diff --git a/Add-lbt-support-for-kvm.patch b/Add-lbt-support-for-kvm.patch new file mode 100644 index 0000000000000000000000000000000000000000..76cfd18165a25d9d636bc9ffca2de3c5847189f7 --- /dev/null +++ b/Add-lbt-support-for-kvm.patch @@ -0,0 +1,160 @@ +From c174f8c60cd372301200cdecaaae345b079cf589 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Wed, 24 May 2023 23:28:41 -0400 +Subject: [PATCH] Add lbt support for kvm. + +Add lbt registers get and put function. + +Signed-off-by: lixianglai +--- + hw/loongarch/larch_3a.c | 3 ++- + linux-headers/asm-loongarch64/kvm.h | 15 +++++++++++++ + target/loongarch64/cpu.h | 10 +++++++++ + target/loongarch64/kvm.c | 35 +++++++++++++++++++++++++++++ + 4 files changed, 62 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c +index cef1a6f3d2..95bb224664 100644 +--- a/hw/loongarch/larch_3a.c ++++ b/hw/loongarch/larch_3a.c +@@ -356,7 +356,8 @@ struct kvm_cpucfg ls3a5k_cpucfgs = { + .cpucfg[LOONGARCH_CPUCFG2] = + CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | CPUCFG2_FPVERS | + CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | CPUCFG2_CRYPTO | +- CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | CPUCFG2_LAM, ++ CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_X86BT | CPUCFG2_ARMBT | ++ CPUCFG2_MIPSBT | CPUCFG2_LSPW | CPUCFG2_LAM, + .cpucfg[LOONGARCH_CPUCFG3] = + CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | CPUCFG3_LLEXC | + CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | CPUCFG3_ICACHET | +diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h +index a473916d50..a036ea57cd 100644 +--- a/linux-headers/asm-loongarch64/kvm.h ++++ b/linux-headers/asm-loongarch64/kvm.h +@@ -82,6 +82,7 @@ struct kvm_fpu { + * Register set = 2: KVM specific registers (see definitions below). + * + * Register set = 3: FPU / MSA registers (see definitions below). ++ * Register set = 4: LBT registers (see definitions below). + * + * Other sets registers may be added in the future. Each set would + * have its own identifier in bits[31..16]. +@@ -91,6 +92,7 @@ struct kvm_fpu { + #define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) + #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) + #define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) ++#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x0000000000040000ULL) + + /* + * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. +@@ -174,6 +176,19 @@ struct kvm_fpu { + #define KVM_REG_LOONGARCH_VCPU_RESET \ + (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) + ++#define KVM_REG_LBT_SCR0 \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) ++#define KVM_REG_LBT_SCR1 \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) ++#define KVM_REG_LBT_SCR2 \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) ++#define KVM_REG_LBT_SCR3 \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) ++#define KVM_REG_LBT_FLAGS \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) ++#define KVM_REG_LBT_FTOP \ ++ (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) ++ + struct kvm_iocsr_entry { + __u32 addr; + __u32 pad; +diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h +index bf5b36d404..8a29a507b1 100644 +--- a/target/loongarch64/cpu.h ++++ b/target/loongarch64/cpu.h +@@ -75,6 +75,7 @@ typedef struct CPULOONGARCHFPUContext { + uint32_t fcsr0; + uint32_t fcsr0_rw_bitmask; + uint32_t vcsr16; ++ uint64_t ftop; + } CPULOONGARCHFPUContext; + + /* fp control and status register definition */ +@@ -196,6 +197,15 @@ struct CPULOONGARCHState { + struct { + uint64_t guest_addr; + } st; ++ struct { ++ /* scratch registers */ ++ unsigned long scr0; ++ unsigned long scr1; ++ unsigned long scr2; ++ unsigned long scr3; ++ /* loongarch eflag */ ++ unsigned long eflag; ++ } lbt; + }; + + /* +diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c +index 21f6d5695f..0a4dc86421 100644 +--- a/target/loongarch64/kvm.c ++++ b/target/loongarch64/kvm.c +@@ -1277,6 +1277,39 @@ int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu) + return 0; + } + ++ ++static int kvm_loongarch_put_lbt_registers(CPUState *cs) ++{ ++ int ret = 0; ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); ++ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); ++ ++ return ret; ++} ++ ++static int kvm_loongarch_get_lbt_registers(CPUState *cs) ++{ ++ int ret = 0; ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); ++ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); ++ ++ return ret; ++} ++ + int kvm_arch_put_registers(CPUState *cs, int level) + { + LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); +@@ -1308,6 +1341,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ kvm_loongarch_put_lbt_registers(cs); + return ret; + } + +@@ -1334,6 +1368,7 @@ int kvm_arch_get_registers(CPUState *cs) + + kvm_loongarch_get_csr_registers(cs); + kvm_loongarch_get_fpu_registers(cs); ++ kvm_loongarch_get_lbt_registers(cs); + + return ret; + } +-- +2.41.0.windows.1 + diff --git a/Add-linux-headers-and-linux-user.patch b/Add-linux-headers-and-linux-user.patch new file mode 100644 index 0000000000000000000000000000000000000000..795206c0da934a48c9c98fee361eb69c5039aab2 --- /dev/null +++ b/Add-linux-headers-and-linux-user.patch @@ -0,0 +1,1999 @@ +From 5930ad6d2fa6071dbec9a790724ac2ec364fb28f Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:16:26 -0500 +Subject: [PATCH] Add linux-headers and linux-user. + +Add linux-headers and linux-user files. + +Signed-off-by: lixianglai +--- + linux-headers/asm-loongarch64/bitsperlong.h | 25 ++ + linux-headers/asm-loongarch64/kvm.h | 351 ++++++++++++++++++++ + linux-headers/asm-loongarch64/sgidefs.h | 31 ++ + linux-headers/asm-loongarch64/unistd.h | 22 ++ + linux-headers/linux/kvm.h | 25 ++ + linux-user/elfload.c | 64 ++++ + linux-user/loongarch64/cpu_loop.c | 179 ++++++++++ + linux-user/loongarch64/meson.build | 6 + + linux-user/loongarch64/signal.c | 218 ++++++++++++ + linux-user/loongarch64/sockbits.h | 18 + + linux-user/loongarch64/syscall_nr.h | 304 +++++++++++++++++ + linux-user/loongarch64/target_cpu.h | 47 +++ + linux-user/loongarch64/target_elf.h | 24 ++ + linux-user/loongarch64/target_fcntl.h | 23 ++ + linux-user/loongarch64/target_signal.h | 40 +++ + linux-user/loongarch64/target_structs.h | 63 ++++ + linux-user/loongarch64/target_syscall.h | 63 ++++ + linux-user/loongarch64/termbits.h | 241 ++++++++++++++ + linux-user/meson.build | 1 + + linux-user/qemu.h | 2 +- + linux-user/syscall.c | 3 + + linux-user/syscall_defs.h | 10 +- + 22 files changed, 1755 insertions(+), 5 deletions(-) + create mode 100644 linux-headers/asm-loongarch64/bitsperlong.h + create mode 100644 linux-headers/asm-loongarch64/kvm.h + create mode 100644 linux-headers/asm-loongarch64/sgidefs.h + create mode 100644 linux-headers/asm-loongarch64/unistd.h + create mode 100644 linux-user/loongarch64/cpu_loop.c + create mode 100644 linux-user/loongarch64/meson.build + create mode 100644 linux-user/loongarch64/signal.c + create mode 100644 linux-user/loongarch64/sockbits.h + create mode 100644 linux-user/loongarch64/syscall_nr.h + create mode 100644 linux-user/loongarch64/target_cpu.h + create mode 100644 linux-user/loongarch64/target_elf.h + create mode 100644 linux-user/loongarch64/target_fcntl.h + create mode 100644 linux-user/loongarch64/target_signal.h + create mode 100644 linux-user/loongarch64/target_structs.h + create mode 100644 linux-user/loongarch64/target_syscall.h + create mode 100644 linux-user/loongarch64/termbits.h + +diff --git a/linux-headers/asm-loongarch64/bitsperlong.h b/linux-headers/asm-loongarch64/bitsperlong.h +new file mode 100644 +index 0000000000..a7981540d2 +--- /dev/null ++++ b/linux-headers/asm-loongarch64/bitsperlong.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef __ASM_LOONGARCH_BITSPERLONG_H ++#define __ASM_LOONGARCH_BITSPERLONG_H ++ ++#define __BITS_PER_LONG _LOONGARCH_SZLONG ++ ++#include ++ ++#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ +diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h +new file mode 100644 +index 0000000000..a473916d50 +--- /dev/null ++++ b/linux-headers/asm-loongarch64/kvm.h +@@ -0,0 +1,351 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef __LINUX_KVM_LOONGARCH_H ++#define __LINUX_KVM_LOONGARCH_H ++ ++#include ++ ++#define __KVM_HAVE_GUEST_DEBUG ++#define KVM_GUESTDBG_USE_SW_BP 0x00010000 ++#define KVM_GUESTDBG_USE_HW_BP 0x00020000 ++#define KVM_DATA_HW_BREAKPOINT_NUM 8 ++#define KVM_INST_HW_BREAKPOINT_NUM 8 ++ ++/* ++ * KVM Loongarch specific structures and definitions. ++ * ++ * Some parts derived from the x86 version of this file. ++ */ ++ ++#define __KVM_HAVE_READONLY_MEM ++ ++#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 ++#define KVM_LARCH_VCPU_PVTIME_CTRL 2 ++#define KVM_LARCH_VCPU_PVTIME_IPA 0 ++ ++/* ++ * for KVM_GET_REGS and KVM_SET_REGS ++ */ ++struct kvm_regs { ++ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ ++ __u64 gpr[32]; ++ __u64 pc; ++}; ++ ++/* ++ * for KVM_GET_CPUCFG ++ */ ++struct kvm_cpucfg { ++ /* out (KVM_GET_CPUCFG) */ ++ __u32 cpucfg[64]; ++}; ++ ++/* ++ * for KVM_GET_FPU and KVM_SET_FPU ++ */ ++struct kvm_fpu { ++ __u32 fcsr; ++ __u32 vcsr; ++ __u64 fcc; /* 8x8 */ ++ struct kvm_fpureg { ++ __u64 val64[4]; // support max 256 bits ++ } fpr[32]; ++}; ++ ++/* ++ * For LOONGARCH, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various ++ * registers. The id field is broken down as follows: ++ * ++ * bits[63..52] - As per linux/kvm.h ++ * bits[51..32] - Must be zero. ++ * bits[31..16] - Register set. ++ * ++ * Register set = 0: GP registers from kvm_regs (see definitions below). ++ * ++ * Register set = 1: CSR registers. ++ * ++ * Register set = 2: KVM specific registers (see definitions below). ++ * ++ * Register set = 3: FPU / MSA registers (see definitions below). ++ * ++ * Other sets registers may be added in the future. Each set would ++ * have its own identifier in bits[31..16]. ++ */ ++ ++#define KVM_REG_LOONGARCH_GP (KVM_REG_LOONGARCH | 0x0000000000000000ULL) ++#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) ++#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) ++#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) ++ ++/* ++ * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. ++ */ ++ ++#define KVM_REG_LOONGARCH_R0 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 0) ++#define KVM_REG_LOONGARCH_R1 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 1) ++#define KVM_REG_LOONGARCH_R2 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 2) ++#define KVM_REG_LOONGARCH_R3 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 3) ++#define KVM_REG_LOONGARCH_R4 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 4) ++#define KVM_REG_LOONGARCH_R5 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 5) ++#define KVM_REG_LOONGARCH_R6 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 6) ++#define KVM_REG_LOONGARCH_R7 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 7) ++#define KVM_REG_LOONGARCH_R8 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 8) ++#define KVM_REG_LOONGARCH_R9 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 9) ++#define KVM_REG_LOONGARCH_R10 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 10) ++#define KVM_REG_LOONGARCH_R11 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 11) ++#define KVM_REG_LOONGARCH_R12 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 12) ++#define KVM_REG_LOONGARCH_R13 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 13) ++#define KVM_REG_LOONGARCH_R14 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 14) ++#define KVM_REG_LOONGARCH_R15 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 15) ++#define KVM_REG_LOONGARCH_R16 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 16) ++#define KVM_REG_LOONGARCH_R17 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 17) ++#define KVM_REG_LOONGARCH_R18 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 18) ++#define KVM_REG_LOONGARCH_R19 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 19) ++#define KVM_REG_LOONGARCH_R20 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 20) ++#define KVM_REG_LOONGARCH_R21 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 21) ++#define KVM_REG_LOONGARCH_R22 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 22) ++#define KVM_REG_LOONGARCH_R23 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 23) ++#define KVM_REG_LOONGARCH_R24 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 24) ++#define KVM_REG_LOONGARCH_R25 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 25) ++#define KVM_REG_LOONGARCH_R26 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 26) ++#define KVM_REG_LOONGARCH_R27 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 27) ++#define KVM_REG_LOONGARCH_R28 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 28) ++#define KVM_REG_LOONGARCH_R29 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 29) ++#define KVM_REG_LOONGARCH_R30 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 30) ++#define KVM_REG_LOONGARCH_R31 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 31) ++ ++#define KVM_REG_LOONGARCH_HI (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 32) ++#define KVM_REG_LOONGARCH_LO (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 33) ++#define KVM_REG_LOONGARCH_PC (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 34) ++ ++/* ++ * KVM_REG_LOONGARCH_KVM - KVM specific control registers. ++ */ ++ ++/* ++ * CP0_Count control ++ * DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now ++ * Set 1: Master re-enable CP0_Count with unchanged bias, handling timer ++ * interrupts since COUNT_RESUME ++ * This can be used to freeze the timer to get a consistent snapshot of ++ * the CP0_Count and timer interrupt pending state, while also resuming ++ * safely without losing time or guest timer interrupts. ++ * Other: Reserved, do not change. ++ */ ++#define KVM_REG_LOONGARCH_COUNT_CTL \ ++ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 0) ++#define KVM_REG_LOONGARCH_COUNT_CTL_DC 0x00000001 ++ ++/* ++ * CP0_Count resume monotonic nanoseconds ++ * The monotonic nanosecond time of the last set of COUNT_CTL.DC (master ++ * disable). Any reads and writes of Count related registers while ++ * COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is ++ * cleared again (master enable) any timer interrupts since this time will be ++ * emulated. ++ * Modifications to times in the future are rejected. ++ */ ++#define KVM_REG_LOONGARCH_COUNT_RESUME \ ++ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1) ++/* ++ * CP0_Count rate in Hz ++ * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without ++ * discontinuities in CP0_Count. ++ */ ++#define KVM_REG_LOONGARCH_COUNT_HZ \ ++ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2) ++#define KVM_REG_LOONGARCH_COUNTER \ ++ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) ++#define KVM_REG_LOONGARCH_VCPU_RESET \ ++ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) ++ ++struct kvm_iocsr_entry { ++ __u32 addr; ++ __u32 pad; ++ __u64 data; ++}; ++ ++struct kvm_csr_entry { ++ __u32 index; ++ __u32 reserved; ++ __u64 data; ++}; ++ ++/* for KVM_GET_MSRS and KVM_SET_MSRS */ ++struct kvm_msrs { ++ __u32 ncsrs; /* number of msrs in entries */ ++ __u32 pad; ++ struct kvm_csr_entry entries[0]; ++}; ++ ++#define __KVM_HAVE_IRQ_LINE ++ ++struct kvm_debug_exit_arch { ++ __u64 epc; ++ __u32 fwps; ++ __u32 mwps; ++ __u32 exception; ++}; ++ ++/* for KVM_SET_GUEST_DEBUG */ ++struct hw_breakpoint { ++ __u64 addr; ++ __u64 mask; ++ __u32 asid; ++ __u32 ctrl; ++}; ++ ++struct kvm_guest_debug_arch { ++ struct hw_breakpoint data_breakpoint[KVM_DATA_HW_BREAKPOINT_NUM]; ++ struct hw_breakpoint inst_breakpoint[KVM_INST_HW_BREAKPOINT_NUM]; ++ int inst_bp_nums, data_bp_nums; ++}; ++ ++/* definition of registers in kvm_run */ ++struct kvm_sync_regs { ++}; ++ ++/* dummy definition */ ++struct kvm_sregs { ++}; ++ ++struct kvm_loongarch_interrupt { ++ /* in */ ++ __u32 cpu; ++ __u32 irq; ++}; ++ ++#define KVM_IRQCHIP_LS7A_IOAPIC 0x0 ++#define KVM_IRQCHIP_LS3A_GIPI 0x1 ++#define KVM_IRQCHIP_LS3A_HT_IRQ 0x2 ++#define KVM_IRQCHIP_LS3A_ROUTE 0x3 ++#define KVM_IRQCHIP_LS3A_EXTIRQ 0x4 ++#define KVM_IRQCHIP_LS3A_IPMASK 0x5 ++#define KVM_NR_IRQCHIPS 1 ++#define KVM_IRQCHIP_NUM_PINS 64 ++ ++#define KVM_MAX_CORES 256 ++#define KVM_EXTIOI_IRQS (256) ++#define KVM_EXTIOI_IRQS_BITMAP_SIZE (KVM_EXTIOI_IRQS / 8) ++/* map to ipnum per 32 irqs */ ++#define KVM_EXTIOI_IRQS_IPMAP_SIZE (KVM_EXTIOI_IRQS / 32) ++#define KVM_EXTIOI_IRQS_PER_GROUP 32 ++#define KVM_EXTIOI_IRQS_COREMAP_SIZE (KVM_EXTIOI_IRQS) ++#define KVM_EXTIOI_IRQS_NODETYPE_SIZE 16 ++ ++struct ls7a_ioapic_state { ++ __u64 int_id; ++ /* 0x020 interrupt mask register */ ++ __u64 int_mask; ++ /* 0x040 1=msi */ ++ __u64 htmsi_en; ++ /* 0x060 edge=1 level =0 */ ++ __u64 intedge; ++ /* 0x080 for clean edge int,set 1 clean,set 0 is noused */ ++ __u64 intclr; ++ /* 0x0c0 */ ++ __u64 auto_crtl0; ++ /* 0x0e0 */ ++ __u64 auto_crtl1; ++ /* 0x100 - 0x140 */ ++ __u8 route_entry[64]; ++ /* 0x200 - 0x240 */ ++ __u8 htmsi_vector[64]; ++ /* 0x300 */ ++ __u64 intisr_chip0; ++ /* 0x320 */ ++ __u64 intisr_chip1; ++ /* edge detection */ ++ __u64 last_intirr; ++ /* 0x380 interrupt request register */ ++ __u64 intirr; ++ /* 0x3a0 interrupt service register */ ++ __u64 intisr; ++ /* 0x3e0 interrupt level polarity selection register, ++ * 0 for high level tirgger ++ */ ++ __u64 int_polarity; ++}; ++ ++struct loongarch_gipi_single { ++ __u32 status; ++ __u32 en; ++ __u32 set; ++ __u32 clear; ++ __u64 buf[4]; ++}; ++ ++struct loongarch_gipiState { ++ struct loongarch_gipi_single core[KVM_MAX_CORES]; ++}; ++ ++struct kvm_loongarch_ls3a_extirq_state { ++ union ext_en_r ++ { ++ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; ++ } ext_en_r; ++ union bounce_r ++ { ++ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; ++ } bounce_r; ++ union ext_isr_r ++ { ++ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; ++ } ext_isr_r; ++ union ext_core_isr_r ++ { ++ uint64_t reg_u64[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; ++ uint32_t reg_u32[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE]; ++ } ext_core_isr_r; ++ union ip_map_r ++ { ++ uint64_t reg_u64; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_IPMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_IPMAP_SIZE]; ++ } ip_map_r; ++ union core_map_r ++ { ++ uint64_t reg_u64[KVM_EXTIOI_IRQS_COREMAP_SIZE / 8]; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_COREMAP_SIZE / 4]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_COREMAP_SIZE]; ++ } core_map_r; ++ union node_type_r ++ { ++ uint64_t reg_u64[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 4]; ++ uint32_t reg_u32[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 2]; ++ uint16_t reg_u16[KVM_EXTIOI_IRQS_NODETYPE_SIZE]; ++ uint8_t reg_u8[KVM_EXTIOI_IRQS_NODETYPE_SIZE * 2]; ++ } node_type_r; ++}; ++ ++struct loongarch_kvm_irqchip { ++ __u16 chip_id; ++ __u16 len; ++ __u16 vcpu_id; ++ __u16 reserved; ++ char data[0]; ++}; ++ ++#endif /* __LINUX_KVM_LOONGARCH_H */ +diff --git a/linux-headers/asm-loongarch64/sgidefs.h b/linux-headers/asm-loongarch64/sgidefs.h +new file mode 100644 +index 0000000000..89e8be582e +--- /dev/null ++++ b/linux-headers/asm-loongarch64/sgidefs.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef __ASM_SGIDEFS_H ++#define __ASM_SGIDEFS_H ++ ++#define _LOONGARCH_ISA_LOONGARCH32 6 ++#define _LOONGARCH_ISA_LOONGARCH64 7 ++ ++/* ++ * Subprogram calling convention ++ */ ++#define _LOONGARCH_SIM_ABILP32 1 ++#define _LOONGARCH_SIM_ABILPX32 2 ++#define _LOONGARCH_SIM_ABILP64 3 ++ ++#endif /* __ASM_SGIDEFS_H */ +diff --git a/linux-headers/asm-loongarch64/unistd.h b/linux-headers/asm-loongarch64/unistd.h +new file mode 100644 +index 0000000000..ef710673a3 +--- /dev/null ++++ b/linux-headers/asm-loongarch64/unistd.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifdef __LP64__ ++#define __ARCH_WANT_NEW_STAT ++#endif /* __LP64__ */ ++ ++#include +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 7870cd0280..c9986c1966 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2008,6 +2008,31 @@ struct kvm_stats_desc { + char name[]; + }; + ++#ifdef __loongarch__ ++struct kvm_loongarch_vcpu_state { ++ __u8 online_vcpus; ++ __u8 is_migrate; ++ __u32 cpu_freq; ++ __u32 count_ctl; ++ __u64 pending_exceptions; ++ __u64 pending_exceptions_clr; ++ __u64 core_ext_ioisr[4]; ++}; ++ ++#define KVM_CAP_LOONGARCH_FPU 800 ++#define KVM_CAP_LOONGARCH_LSX 801 ++#define KVM_CAP_LOONGARCH_VZ 802 ++#define KVM_REG_LOONGARCH 0x9000000000000000ULL ++#define KVM_LARCH_GET_VCPU_STATE \ ++ _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) ++#define KVM_LARCH_SET_VCPU_STATE \ ++ _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) ++#define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) ++#define KVM_LOONGARCH_GET_IOCSR _IOR(KVMIO, 0xc3, struct kvm_iocsr_entry) ++#define KVM_LOONGARCH_SET_IOCSR _IOW(KVMIO, 0xc4, struct kvm_iocsr_entry) ++#define KVM_LARCH_SET_CPUCFG _IOR(KVMIO, 0xc5, struct kvm_cpucfg) ++#endif ++ + #define KVM_GET_STATS_FD _IO(KVMIO, 0xce) + + /* Available with KVM_CAP_XSAVE2 */ +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 767f54c76d..2625af99dd 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -1041,6 +1041,70 @@ static uint32_t get_elf_hwcap(void) + + #endif /* TARGET_MIPS */ + ++#ifdef TARGET_LOONGARCH64 ++ ++#define ELF_START_MMAP 0x80000000 ++ ++#define ELF_CLASS ELFCLASS64 ++#define ELF_ARCH EM_LOONGARCH ++ ++#define elf_check_arch(x) ((x) == EM_LOONGARCH) ++ ++static inline void init_thread(struct target_pt_regs *regs, ++ struct image_info *infop) ++{ ++ regs->csr_crmd = 2 << 3; ++ regs->csr_era = infop->entry; ++ regs->regs[3] = infop->start_stack; ++} ++ ++/* See linux kernel: arch/mips/include/asm/elf.h. */ ++#define ELF_NREG 45 ++typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; ++ ++/* See linux kernel: arch/loongarch/include/uapi/asm/reg.h */ ++enum { ++ TARGET_EF_R0 = 0, ++ TARGET_EF_R26 = TARGET_EF_R0 + 26, ++ TARGET_EF_R27 = TARGET_EF_R0 + 27, ++ TARGET_EF_CSR_ERA = TARGET_EF_R0 + 32, ++ TARGET_EF_CSR_BADV = TARGET_EF_R0 + 33, ++ TARGET_EF_CSR_CRMD = TARGET_EF_R0 + 34, ++ TARGET_EF_CSR_ESTAT = TARGET_EF_R0 + 38 ++}; ++ ++/* See linux kernel: arch/loongarch/kernel/process.c:elf_dump_regs. */ ++static void elf_core_copy_regs(target_elf_gregset_t *regs, ++ const CPULOONGARCHState *env) ++{ ++ int i; ++ ++ (*regs)[TARGET_EF_R0] = 0; ++ ++ for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) { ++ (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]); ++ } ++ ++ (*regs)[TARGET_EF_R26] = 0; ++ (*regs)[TARGET_EF_R27] = 0; ++ (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->active_tc.PC); ++ (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV); ++ (*regs)[TARGET_EF_CSR_CRMD] = tswapreg(env->CSR_CRMD); ++ (*regs)[TARGET_EF_CSR_ESTAT] = tswapreg(env->CSR_ESTAT); ++} ++ ++#define USE_ELF_CORE_DUMP ++#define ELF_EXEC_PAGESIZE 4096 ++ ++#define ELF_HWCAP get_elf_hwcap() ++ ++static uint32_t get_elf_hwcap(void) ++{ ++ return 0; ++} ++ ++#endif /* TARGET_LOONGARCH64 */ ++ + #ifdef TARGET_MICROBLAZE + + #define ELF_START_MMAP 0x80000000 +diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c +new file mode 100644 +index 0000000000..eb455465ab +--- /dev/null ++++ b/linux-user/loongarch64/cpu_loop.c +@@ -0,0 +1,179 @@ ++/* ++ * qemu user cpu loop ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "cpu_loop-common.h" ++#include "elf.h" ++ ++/* Break codes */ ++enum { BRK_OVERFLOW = 6, BRK_DIVZERO = 7 }; ++ ++void force_sig_fault(CPULOONGARCHState *env, target_siginfo_t *info, ++ unsigned int code) ++{ ++ ++ switch (code) { ++ case BRK_OVERFLOW: ++ case BRK_DIVZERO: ++ info->si_signo = TARGET_SIGFPE; ++ info->si_errno = 0; ++ info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; ++ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ++ ret = 0; ++ break; ++ default: ++ info->si_signo = TARGET_SIGTRAP; ++ info->si_errno = 0; ++ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ++ ret = 0; ++ break; ++ } ++} ++ ++void cpu_loop(CPULOONGARCHState *env) ++{ ++ CPUState *cs = CPU(loongarch_env_get_cpu(env)); ++ target_siginfo_t info; ++ int trapnr; ++ abi_long ret; ++ ++ for (;;) { ++ cpu_exec_start(cs); ++ trapnr = cpu_exec(cs); ++ cpu_exec_end(cs); ++ process_queued_cpu_work(cs); ++ ++ switch (trapnr) { ++ case EXCP_SYSCALL: ++ env->active_tc.PC += 4; ++ ret = ++ do_syscall(env, env->active_tc.gpr[11], env->active_tc.gpr[4], ++ env->active_tc.gpr[5], env->active_tc.gpr[6], ++ env->active_tc.gpr[7], env->active_tc.gpr[8], ++ env->active_tc.gpr[9], -1, -1); ++ if (ret == -TARGET_ERESTARTSYS) { ++ env->active_tc.PC -= 4; ++ break; ++ } ++ if (ret == -TARGET_QEMU_ESIGRETURN) { ++ /* ++ * Returning from a successful sigreturn syscall. ++ * Avoid clobbering register state. ++ */ ++ break; ++ } ++ env->active_tc.gpr[4] = ret; ++ break; ++ case EXCP_TLBL: ++ case EXCP_TLBS: ++ case EXCP_AdEL: ++ case EXCP_AdES: ++ info.si_signo = TARGET_SIGSEGV; ++ info.si_errno = 0; ++ /* XXX: check env->error_code */ ++ info.si_code = TARGET_SEGV_MAPERR; ++ info._sifields._sigfault._addr = env->CSR_BADV; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_FPDIS: ++ case EXCP_LSXDIS: ++ case EXCP_LASXDIS: ++ case EXCP_RI: ++ info.si_signo = TARGET_SIGILL; ++ info.si_errno = 0; ++ info.si_code = 0; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_INTERRUPT: ++ /* just indicate that signals should be handled asap */ ++ break; ++ case EXCP_DEBUG: ++ info.si_signo = TARGET_SIGTRAP; ++ info.si_errno = 0; ++ info.si_code = TARGET_TRAP_BRKPT; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_FPE: ++ info.si_signo = TARGET_SIGFPE; ++ info.si_errno = 0; ++ info.si_code = TARGET_FPE_FLTUNK; ++ if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INVALID) { ++ info.si_code = TARGET_FPE_FLTINV; ++ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_DIV0) { ++ info.si_code = TARGET_FPE_FLTDIV; ++ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_OVERFLOW) { ++ info.si_code = TARGET_FPE_FLTOVF; ++ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_UNDERFLOW) { ++ info.si_code = TARGET_FPE_FLTUND; ++ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INEXACT) { ++ info.si_code = TARGET_FPE_FLTRES; ++ } ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_BREAK: { ++ abi_ulong trap_instr; ++ unsigned int code; ++ ++ ret = get_user_u32(trap_instr, env->active_tc.PC); ++ if (ret != 0) { ++ goto error; ++ } ++ ++ code = trap_instr & 0x7fff; ++ force_sig_fault(env, &info, code); ++ } break; ++ case EXCP_TRAP: { ++ abi_ulong trap_instr; ++ unsigned int code = 0; ++ ++ ret = get_user_u32(trap_instr, env->active_tc.PC); ++ ++ if (ret != 0) { ++ goto error; ++ } ++ ++ /* The immediate versions don't provide a code. */ ++ if (!(trap_instr & 0xFC000000)) { ++ code = ((trap_instr >> 6) & ((1 << 10) - 1)); ++ } ++ force_sig_fault(env, &info, code); ++ } break; ++ case EXCP_ATOMIC: ++ cpu_exec_step_atomic(cs); ++ break; ++ default: ++ error: ++ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", ++ trapnr); ++ abort(); ++ } ++ process_pending_signals(env); ++ } ++} ++ ++void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ env->active_tc.gpr[i] = regs->regs[i]; ++ } ++ env->active_tc.PC = regs->csr_era & ~(target_ulong)1; ++} +diff --git a/linux-user/loongarch64/meson.build b/linux-user/loongarch64/meson.build +new file mode 100644 +index 0000000000..c4c0b4d701 +--- /dev/null ++++ b/linux-user/loongarch64/meson.build +@@ -0,0 +1,6 @@ ++syscall_nr_generators += { ++ 'loongarch64': generator(sh, ++ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', ++ '', 'TARGET_SYSCALL_OFFSET' ], ++ output: '@BASENAME@_nr.h') ++} +diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c +new file mode 100644 +index 0000000000..2f336035c9 +--- /dev/null ++++ b/linux-user/loongarch64/signal.c +@@ -0,0 +1,218 @@ ++/* ++ * Emulation of Linux signals ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "signal-common.h" ++#include "linux-user/trace.h" ++ ++#define FPU_REG_WIDTH 256 ++union fpureg ++{ ++ uint32_t val32[FPU_REG_WIDTH / 32]; ++ uint64_t val64[FPU_REG_WIDTH / 64]; ++}; ++ ++struct target_sigcontext { ++ uint64_t sc_pc; ++ uint64_t sc_regs[32]; ++ uint32_t sc_flags; ++ ++ uint32_t sc_fcsr; ++ uint32_t sc_vcsr; ++ uint64_t sc_fcc; ++ union fpureg sc_fpregs[32] __attribute__((aligned(32))); ++ ++ uint32_t sc_reserved; ++}; ++ ++struct sigframe { ++ uint32_t sf_ass[4]; /* argument save space for o32 */ ++ uint32_t sf_code[2]; /* signal trampoline */ ++ struct target_sigcontext sf_sc; ++ target_sigset_t sf_mask; ++}; ++ ++struct target_ucontext { ++ target_ulong tuc_flags; ++ target_ulong tuc_link; ++ target_stack_t tuc_stack; ++ target_ulong pad0; ++ struct target_sigcontext tuc_mcontext; ++ target_sigset_t tuc_sigmask; ++}; ++ ++struct target_rt_sigframe { ++ uint32_t rs_ass[4]; /* argument save space for o32 */ ++ uint32_t rs_code[2]; /* signal trampoline */ ++ struct target_siginfo rs_info; ++ struct target_ucontext rs_uc; ++}; ++ ++static inline void setup_sigcontext(CPULOONGARCHState *regs, ++ struct target_sigcontext *sc) ++{ ++ int i; ++ ++ __put_user(exception_resume_pc(regs), &sc->sc_pc); ++ regs->hflags &= ~LARCH_HFLAG_BMASK; ++ ++ __put_user(0, &sc->sc_regs[0]); ++ for (i = 1; i < 32; ++i) { ++ __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); ++ } ++ ++ for (i = 0; i < 32; ++i) { ++ __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); ++ } ++} ++ ++static inline void restore_sigcontext(CPULOONGARCHState *regs, ++ struct target_sigcontext *sc) ++{ ++ int i; ++ ++ __get_user(regs->CSR_ERA, &sc->sc_pc); ++ ++ for (i = 1; i < 32; ++i) { ++ __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); ++ } ++ ++ for (i = 0; i < 32; ++i) { ++ __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); ++ } ++} ++ ++/* ++ * Determine which stack to use.. ++ */ ++static inline abi_ulong get_sigframe(struct target_sigaction *ka, ++ CPULOONGARCHState *regs, ++ size_t frame_size) ++{ ++ unsigned long sp; ++ ++ /* ++ * FPU emulator may have its own trampoline active just ++ * above the user stack, 16-bytes before the next lowest ++ * 16 byte boundary. Try to avoid trashing it. ++ */ ++ sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); ++ ++ return (sp - frame_size) & ~7; ++} ++ ++void setup_rt_frame(int sig, struct target_sigaction *ka, ++ target_siginfo_t *info, target_sigset_t *set, ++ CPULOONGARCHState *env) ++{ ++ struct target_rt_sigframe *frame; ++ abi_ulong frame_addr; ++ int i; ++ ++ frame_addr = get_sigframe(ka, env, sizeof(*frame)); ++ trace_user_setup_rt_frame(env, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { ++ goto give_sigsegv; ++ } ++ ++ /* ori a7, $r0, TARGET_NR_rt_sigreturn */ ++ /* syscall 0 */ ++ __put_user(0x0380000b + (TARGET_NR_rt_sigreturn << 10), ++ &frame->rs_code[0]); ++ __put_user(0x002b0000, &frame->rs_code[1]); ++ ++ tswap_siginfo(&frame->rs_info, info); ++ ++ __put_user(0, &frame->rs_uc.tuc_flags); ++ __put_user(0, &frame->rs_uc.tuc_link); ++ target_save_altstack(&frame->rs_uc.tuc_stack, env); ++ ++ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); ++ ++ for (i = 0; i < TARGET_NSIG_WORDS; i++) { ++ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); ++ } ++ ++ /* ++ * Arguments to signal handler: ++ * ++ * a0 = signal number ++ * a1 = pointer to siginfo_t ++ * a2 = pointer to ucontext_t ++ * ++ * $25 and PC point to the signal handler, $29 points to the ++ * struct sigframe. ++ */ ++ env->active_tc.gpr[4] = sig; ++ env->active_tc.gpr[5] = ++ frame_addr + offsetof(struct target_rt_sigframe, rs_info); ++ env->active_tc.gpr[6] = ++ frame_addr + offsetof(struct target_rt_sigframe, rs_uc); ++ env->active_tc.gpr[3] = frame_addr; ++ env->active_tc.gpr[1] = ++ frame_addr + offsetof(struct target_rt_sigframe, rs_code); ++ /* ++ * The original kernel code sets CP0_ERA to the handler ++ * since it returns to userland using ertn ++ * we cannot do this here, and we must set PC directly ++ */ ++ env->active_tc.PC = env->active_tc.gpr[20] = ka->_sa_handler; ++ unlock_user_struct(frame, frame_addr, 1); ++ return; ++ ++give_sigsegv: ++ unlock_user_struct(frame, frame_addr, 1); ++ force_sigsegv(sig); ++} ++ ++long do_rt_sigreturn(CPULOONGARCHState *env) ++{ ++ struct target_rt_sigframe *frame; ++ abi_ulong frame_addr; ++ sigset_t blocked; ++ ++ frame_addr = env->active_tc.gpr[3]; ++ trace_user_do_rt_sigreturn(env, frame_addr); ++ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { ++ goto badframe; ++ } ++ ++ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); ++ set_sigmask(&blocked); ++ ++ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); ++ ++ if (do_sigaltstack( ++ frame_addr + offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), ++ 0, get_sp_from_cpustate(env)) == -EFAULT) ++ goto badframe; ++ ++ env->active_tc.PC = env->CSR_ERA; ++ /* ++ * I am not sure this is right, but it seems to work ++ * maybe a problem with nested signals ? ++ */ ++ env->CSR_ERA = 0; ++ return -TARGET_QEMU_ESIGRETURN; ++ ++badframe: ++ force_sig(TARGET_SIGSEGV); ++ return -TARGET_QEMU_ESIGRETURN; ++} +diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h +new file mode 100644 +index 0000000000..8bcbfcb060 +--- /dev/null ++++ b/linux-user/loongarch64/sockbits.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "../generic/sockbits.h" +diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h +new file mode 100644 +index 0000000000..0217ad77f9 +--- /dev/null ++++ b/linux-user/loongarch64/syscall_nr.h +@@ -0,0 +1,304 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H ++#define LINUX_USER_LOONGARCH_SYSCALL_NR_H ++ ++#define TARGET_NR_io_setup 0 ++#define TARGET_NR_io_destroy 1 ++#define TARGET_NR_io_submit 2 ++#define TARGET_NR_io_cancel 3 ++#define TARGET_NR_io_getevents 4 ++#define TARGET_NR_setxattr 5 ++#define TARGET_NR_lsetxattr 6 ++#define TARGET_NR_fsetxattr 7 ++#define TARGET_NR_getxattr 8 ++#define TARGET_NR_lgetxattr 9 ++#define TARGET_NR_fgetxattr 10 ++#define TARGET_NR_listxattr 11 ++#define TARGET_NR_llistxattr 12 ++#define TARGET_NR_flistxattr 13 ++#define TARGET_NR_removexattr 14 ++#define TARGET_NR_lremovexattr 15 ++#define TARGET_NR_fremovexattr 16 ++#define TARGET_NR_getcwd 17 ++#define TARGET_NR_lookup_dcookie 18 ++#define TARGET_NR_eventfd2 19 ++#define TARGET_NR_epoll_create1 20 ++#define TARGET_NR_epoll_ctl 21 ++#define TARGET_NR_epoll_pwait 22 ++#define TARGET_NR_dup 23 ++#define TARGET_NR_dup3 24 ++#define TARGET_NR_fcntl 25 ++#define TARGET_NR_inotify_init1 26 ++#define TARGET_NR_inotify_add_watch 27 ++#define TARGET_NR_inotify_rm_watch 28 ++#define TARGET_NR_ioctl 29 ++#define TARGET_NR_ioprio_set 30 ++#define TARGET_NR_ioprio_get 31 ++#define TARGET_NR_flock 32 ++#define TARGET_NR_mknodat 33 ++#define TARGET_NR_mkdirat 34 ++#define TARGET_NR_unlinkat 35 ++#define TARGET_NR_symlinkat 36 ++#define TARGET_NR_linkat 37 ++#define TARGET_NR_renameat 38 ++#define TARGET_NR_umount2 39 ++#define TARGET_NR_mount 40 ++#define TARGET_NR_pivot_root 41 ++#define TARGET_NR_nfsservctl 42 ++#define TARGET_NR_statfs 43 ++#define TARGET_NR_fstatfs 44 ++#define TARGET_NR_truncate 45 ++#define TARGET_NR_ftruncate 46 ++#define TARGET_NR_fallocate 47 ++#define TARGET_NR_faccessat 48 ++#define TARGET_NR_chdir 49 ++#define TARGET_NR_fchdir 50 ++#define TARGET_NR_chroot 51 ++#define TARGET_NR_fchmod 52 ++#define TARGET_NR_fchmodat 53 ++#define TARGET_NR_fchownat 54 ++#define TARGET_NR_fchown 55 ++#define TARGET_NR_openat 56 ++#define TARGET_NR_close 57 ++#define TARGET_NR_vhangup 58 ++#define TARGET_NR_pipe2 59 ++#define TARGET_NR_quotactl 60 ++#define TARGET_NR_getdents64 61 ++#define TARGET_NR_lseek 62 ++#define TARGET_NR_read 63 ++#define TARGET_NR_write 64 ++#define TARGET_NR_readv 65 ++#define TARGET_NR_writev 66 ++#define TARGET_NR_pread64 67 ++#define TARGET_NR_pwrite64 68 ++#define TARGET_NR_preadv 69 ++#define TARGET_NR_pwritev 70 ++#define TARGET_NR_sendfile 71 ++#define TARGET_NR_pselect6 72 ++#define TARGET_NR_ppoll 73 ++#define TARGET_NR_signalfd4 74 ++#define TARGET_NR_vmsplice 75 ++#define TARGET_NR_splice 76 ++#define TARGET_NR_tee 77 ++#define TARGET_NR_readlinkat 78 ++#define TARGET_NR_newfstatat 79 ++#define TARGET_NR_fstat 80 ++#define TARGET_NR_sync 81 ++#define TARGET_NR_fsync 82 ++#define TARGET_NR_fdatasync 83 ++#define TARGET_NR_sync_file_range 84 ++#define TARGET_NR_timerfd_create 85 ++#define TARGET_NR_timerfd_settime 86 ++#define TARGET_NR_timerfd_gettime 87 ++#define TARGET_NR_utimensat 88 ++#define TARGET_NR_acct 89 ++#define TARGET_NR_capget 90 ++#define TARGET_NR_capset 91 ++#define TARGET_NR_personality 92 ++#define TARGET_NR_exit 93 ++#define TARGET_NR_exit_group 94 ++#define TARGET_NR_waitid 95 ++#define TARGET_NR_set_tid_address 96 ++#define TARGET_NR_unshare 97 ++#define TARGET_NR_futex 98 ++#define TARGET_NR_set_robust_list 99 ++#define TARGET_NR_get_robust_list 100 ++#define TARGET_NR_nanosleep 101 ++#define TARGET_NR_getitimer 102 ++#define TARGET_NR_setitimer 103 ++#define TARGET_NR_kexec_load 104 ++#define TARGET_NR_init_module 105 ++#define TARGET_NR_delete_module 106 ++#define TARGET_NR_timer_create 107 ++#define TARGET_NR_timer_gettime 108 ++#define TARGET_NR_timer_getoverrun 109 ++#define TARGET_NR_timer_settime 110 ++#define TARGET_NR_timer_delete 111 ++#define TARGET_NR_clock_settime 112 ++#define TARGET_NR_clock_gettime 113 ++#define TARGET_NR_clock_getres 114 ++#define TARGET_NR_clock_nanosleep 115 ++#define TARGET_NR_syslog 116 ++#define TARGET_NR_ptrace 117 ++#define TARGET_NR_sched_setparam 118 ++#define TARGET_NR_sched_setscheduler 119 ++#define TARGET_NR_sched_getscheduler 120 ++#define TARGET_NR_sched_getparam 121 ++#define TARGET_NR_sched_setaffinity 122 ++#define TARGET_NR_sched_getaffinity 123 ++#define TARGET_NR_sched_yield 124 ++#define TARGET_NR_sched_get_priority_max 125 ++#define TARGET_NR_sched_get_priority_min 126 ++#define TARGET_NR_sched_rr_get_interval 127 ++#define TARGET_NR_restart_syscall 128 ++#define TARGET_NR_kill 129 ++#define TARGET_NR_tkill 130 ++#define TARGET_NR_tgkill 131 ++#define TARGET_NR_sigaltstack 132 ++#define TARGET_NR_rt_sigsuspend 133 ++#define TARGET_NR_rt_sigaction 134 ++#define TARGET_NR_rt_sigprocmask 135 ++#define TARGET_NR_rt_sigpending 136 ++#define TARGET_NR_rt_sigtimedwait 137 ++#define TARGET_NR_rt_sigqueueinfo 138 ++#define TARGET_NR_rt_sigreturn 139 ++#define TARGET_NR_setpriority 140 ++#define TARGET_NR_getpriority 141 ++#define TARGET_NR_reboot 142 ++#define TARGET_NR_setregid 143 ++#define TARGET_NR_setgid 144 ++#define TARGET_NR_setreuid 145 ++#define TARGET_NR_setuid 146 ++#define TARGET_NR_setresuid 147 ++#define TARGET_NR_getresuid 148 ++#define TARGET_NR_setresgid 149 ++#define TARGET_NR_getresgid 150 ++#define TARGET_NR_setfsuid 151 ++#define TARGET_NR_setfsgid 152 ++#define TARGET_NR_times 153 ++#define TARGET_NR_setpgid 154 ++#define TARGET_NR_getpgid 155 ++#define TARGET_NR_getsid 156 ++#define TARGET_NR_setsid 157 ++#define TARGET_NR_getgroups 158 ++#define TARGET_NR_setgroups 159 ++#define TARGET_NR_uname 160 ++#define TARGET_NR_sethostname 161 ++#define TARGET_NR_setdomainname 162 ++#define TARGET_NR_getrlimit 163 ++#define TARGET_NR_setrlimit 164 ++#define TARGET_NR_getrusage 165 ++#define TARGET_NR_umask 166 ++#define TARGET_NR_prctl 167 ++#define TARGET_NR_getcpu 168 ++#define TARGET_NR_gettimeofday 169 ++#define TARGET_NR_settimeofday 170 ++#define TARGET_NR_adjtimex 171 ++#define TARGET_NR_getpid 172 ++#define TARGET_NR_getppid 173 ++#define TARGET_NR_getuid 174 ++#define TARGET_NR_geteuid 175 ++#define TARGET_NR_getgid 176 ++#define TARGET_NR_getegid 177 ++#define TARGET_NR_gettid 178 ++#define TARGET_NR_sysinfo 179 ++#define TARGET_NR_mq_open 180 ++#define TARGET_NR_mq_unlink 181 ++#define TARGET_NR_mq_timedsend 182 ++#define TARGET_NR_mq_timedreceive 183 ++#define TARGET_NR_mq_notify 184 ++#define TARGET_NR_mq_getsetattr 185 ++#define TARGET_NR_msgget 186 ++#define TARGET_NR_msgctl 187 ++#define TARGET_NR_msgrcv 188 ++#define TARGET_NR_msgsnd 189 ++#define TARGET_NR_semget 190 ++#define TARGET_NR_semctl 191 ++#define TARGET_NR_semtimedop 192 ++#define TARGET_NR_semop 193 ++#define TARGET_NR_shmget 194 ++#define TARGET_NR_shmctl 195 ++#define TARGET_NR_shmat 196 ++#define TARGET_NR_shmdt 197 ++#define TARGET_NR_socket 198 ++#define TARGET_NR_socketpair 199 ++#define TARGET_NR_bind 200 ++#define TARGET_NR_listen 201 ++#define TARGET_NR_accept 202 ++#define TARGET_NR_connect 203 ++#define TARGET_NR_getsockname 204 ++#define TARGET_NR_getpeername 205 ++#define TARGET_NR_sendto 206 ++#define TARGET_NR_recvfrom 207 ++#define TARGET_NR_setsockopt 208 ++#define TARGET_NR_getsockopt 209 ++#define TARGET_NR_shutdown 210 ++#define TARGET_NR_sendmsg 211 ++#define TARGET_NR_recvmsg 212 ++#define TARGET_NR_readahead 213 ++#define TARGET_NR_brk 214 ++#define TARGET_NR_munmap 215 ++#define TARGET_NR_mremap 216 ++#define TARGET_NR_add_key 217 ++#define TARGET_NR_request_key 218 ++#define TARGET_NR_keyctl 219 ++#define TARGET_NR_clone 220 ++#define TARGET_NR_execve 221 ++#define TARGET_NR_mmap 222 ++#define TARGET_NR_fadvise64 223 ++#define TARGET_NR_swapon 224 ++#define TARGET_NR_swapoff 225 ++#define TARGET_NR_mprotect 226 ++#define TARGET_NR_msync 227 ++#define TARGET_NR_mlock 228 ++#define TARGET_NR_munlock 229 ++#define TARGET_NR_mlockall 230 ++#define TARGET_NR_munlockall 231 ++#define TARGET_NR_mincore 232 ++#define TARGET_NR_madvise 233 ++#define TARGET_NR_remap_file_pages 234 ++#define TARGET_NR_mbind 235 ++#define TARGET_NR_get_mempolicy 236 ++#define TARGET_NR_set_mempolicy 237 ++#define TARGET_NR_migrate_pages 238 ++#define TARGET_NR_move_pages 239 ++#define TARGET_NR_rt_tgsigqueueinfo 240 ++#define TARGET_NR_perf_event_open 241 ++#define TARGET_NR_accept4 242 ++#define TARGET_NR_recvmmsg 243 ++#define TARGET_NR_arch_specific_syscall 244 ++#define TARGET_NR_wait4 260 ++#define TARGET_NR_prlimit64 261 ++#define TARGET_NR_fanotify_init 262 ++#define TARGET_NR_fanotify_mark 263 ++#define TARGET_NR_name_to_handle_at 264 ++#define TARGET_NR_open_by_handle_at 265 ++#define TARGET_NR_clock_adjtime 266 ++#define TARGET_NR_syncfs 267 ++#define TARGET_NR_setns 268 ++#define TARGET_NR_sendmmsg 269 ++#define TARGET_NR_process_vm_readv 270 ++#define TARGET_NR_process_vm_writev 271 ++#define TARGET_NR_kcmp 272 ++#define TARGET_NR_finit_module 273 ++#define TARGET_NR_sched_setattr 274 ++#define TARGET_NR_sched_getattr 275 ++#define TARGET_NR_renameat2 276 ++#define TARGET_NR_seccomp 277 ++#define TARGET_NR_getrandom 278 ++#define TARGET_NR_memfd_create 279 ++#define TARGET_NR_bpf 280 ++#define TARGET_NR_execveat 281 ++#define TARGET_NR_userfaultfd 282 ++#define TARGET_NR_membarrier 283 ++#define TARGET_NR_mlock2 284 ++#define TARGET_NR_copy_file_range 285 ++#define TARGET_NR_preadv2 286 ++#define TARGET_NR_pwritev2 287 ++#define TARGET_NR_pkey_mprotect 288 ++#define TARGET_NR_pkey_alloc 289 ++#define TARGET_NR_pkey_free 290 ++#define TARGET_NR_statx 291 ++#define TARGET_NR_io_pgetevents 292 ++#define TARGET_NR_rseq 293 ++#define TARGET_NR_kexec_file_load 294 ++ ++#define TARGET_NR_syscalls (TARGET_NR_kexec_file_load + 1) ++ ++#endif +diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h +new file mode 100644 +index 0000000000..c4bdb4648b +--- /dev/null ++++ b/linux-user/loongarch64/target_cpu.h +@@ -0,0 +1,47 @@ ++/* ++ * loongarch specific CPU ABI and functions for linux-user ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_CPU_H ++#define LOONGARCH_TARGET_CPU_H ++ ++static inline void cpu_clone_regs_child(CPULOONGARCHState *env, ++ target_ulong newsp, unsigned flags) ++{ ++ if (newsp) { ++ env->active_tc.gpr[3] = newsp; ++ } ++ env->active_tc.gpr[7] = 0; ++ env->active_tc.gpr[4] = 0; ++} ++ ++static inline void cpu_clone_regs_parent(CPULOONGARCHState *env, ++ unsigned flags) ++{ ++} ++ ++static inline void cpu_set_tls(CPULOONGARCHState *env, target_ulong newtls) ++{ ++ env->active_tc.gpr[2] = newtls; ++} ++ ++static inline abi_ulong get_sp_from_cpustate(CPULOONGARCHState *state) ++{ ++ return state->active_tc.gpr[3]; ++} ++#endif +diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h +new file mode 100644 +index 0000000000..2290a9a6d1 +--- /dev/null ++++ b/linux-user/loongarch64/target_elf.h +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_ELF_H ++#define LOONGARCH_TARGET_ELF_H ++static inline const char *cpu_get_model(uint32_t eflags) ++{ ++ return "Loongson-3A5000"; ++} ++#endif +diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h +new file mode 100644 +index 0000000000..9a2bc1cef5 +--- /dev/null ++++ b/linux-user/loongarch64/target_fcntl.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_FCNTL_H ++#define LOONGARCH_TARGET_FCNTL_H ++ ++#include "../generic/fcntl.h" ++ ++#endif /* LOONGARCH_TARGET_FCNTL_H */ +diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h +new file mode 100644 +index 0000000000..be98151723 +--- /dev/null ++++ b/linux-user/loongarch64/target_signal.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_SIGNAL_H ++#define LOONGARCH_TARGET_SIGNAL_H ++ ++/* this struct defines a stack used during syscall handling */ ++ ++typedef struct target_sigaltstack { ++ abi_long ss_sp; ++ abi_int ss_flags; ++ abi_ulong ss_size; ++} target_stack_t; ++ ++/* ++ * sigaltstack controls ++ */ ++#define TARGET_SS_ONSTACK 1 ++#define TARGET_SS_DISABLE 2 ++ ++#define TARGET_MINSIGSTKSZ 2048 ++#define TARGET_SIGSTKSZ 8192 ++ ++#include "../generic/signal.h" ++ ++#endif /* LOONGARCH_TARGET_SIGNAL_H */ +diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h +new file mode 100644 +index 0000000000..53e7b3e0e2 +--- /dev/null ++++ b/linux-user/loongarch64/target_structs.h +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_STRUCTS_H ++#define LOONGARCH_TARGET_STRUCTS_H ++ ++struct target_ipc_perm { ++ abi_int __key; /* Key. */ ++ abi_uint uid; /* Owner's user ID. */ ++ abi_uint gid; /* Owner's group ID. */ ++ abi_uint cuid; /* Creator's user ID. */ ++ abi_uint cgid; /* Creator's group ID. */ ++ abi_uint mode; /* Read/write permission. */ ++ abi_ushort __seq; /* Sequence number. */ ++ abi_ushort __pad1; ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++struct target_shmid_ds { ++ struct target_ipc_perm shm_perm; /* operation permission struct */ ++ abi_long shm_segsz; /* size of segment in bytes */ ++ abi_ulong shm_atime; /* time of last shmat() */ ++ abi_ulong shm_dtime; /* time of last shmdt() */ ++ abi_ulong shm_ctime; /* time of last change by shmctl() */ ++ abi_int shm_cpid; /* pid of creator */ ++ abi_int shm_lpid; /* pid of last shmop */ ++ abi_ulong shm_nattch; /* number of current attaches */ ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++#define TARGET_SEMID64_DS ++ ++/* ++ * The semid64_ds structure for the MIPS architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ */ ++struct target_semid64_ds { ++ struct target_ipc_perm sem_perm; ++ abi_ulong sem_otime; ++ abi_ulong sem_ctime; ++ abi_ulong sem_nsems; ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++#endif +diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h +new file mode 100644 +index 0000000000..6acc015b85 +--- /dev/null ++++ b/linux-user/loongarch64/target_syscall.h +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TARGET_SYSCALL_H ++#define LOONGARCH_TARGET_SYSCALL_H ++ ++/* ++ * this struct defines the way the registers are stored on the ++ * stack during a system call. ++ */ ++ ++struct target_pt_regs { ++ /* Saved main processor registers. */ ++ target_ulong regs[32]; ++ ++ /* Saved special registers. */ ++ /* Saved special registers. */ ++ target_ulong csr_crmd; ++ target_ulong csr_prmd; ++ target_ulong csr_euen; ++ target_ulong csr_ecfg; ++ target_ulong csr_estat; ++ target_ulong csr_era; ++ target_ulong csr_badvaddr; ++ target_ulong orig_a0; ++ target_ulong __last[0]; ++}; ++ ++#define UNAME_MACHINE "loongarch" ++#define UNAME_MINIMUM_RELEASE "2.6.32" ++ ++#define TARGET_CLONE_BACKWARDS ++#define TARGET_MINSIGSTKSZ 2048 ++#define TARGET_MLOCKALL_MCL_CURRENT 1 ++#define TARGET_MLOCKALL_MCL_FUTURE 2 ++ ++#define TARGET_FORCE_SHMLBA ++ ++static inline abi_ulong target_shmlba(CPULOONGARCHState *env) ++{ ++ return 0x40000; ++} ++ ++#define TARGET_PR_SET_FP_MODE 45 ++#define TARGET_PR_GET_FP_MODE 46 ++#define TARGET_PR_FP_MODE_FR (1 << 0) ++#define TARGET_PR_FP_MODE_FRE (1 << 1) ++ ++#endif /* LOONGARCH_TARGET_SYSCALL_H */ +diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h +new file mode 100644 +index 0000000000..dd251e14b3 +--- /dev/null ++++ b/linux-user/loongarch64/termbits.h +@@ -0,0 +1,241 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LINUX_USER_LOONGARCH_TERMBITS_H ++#define LINUX_USER_LOONGARCH_TERMBITS_H ++ ++#define TARGET_NCCS 19 ++ ++struct target_termios { ++ unsigned int c_iflag; /* input mode flags */ ++ unsigned int c_oflag; /* output mode flags */ ++ unsigned int c_cflag; /* control mode flags */ ++ unsigned int c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[TARGET_NCCS]; /* control characters */ ++}; ++ ++/* c_iflag bits */ ++#define TARGET_IGNBRK 0000001 ++#define TARGET_BRKINT 0000002 ++#define TARGET_IGNPAR 0000004 ++#define TARGET_PARMRK 0000010 ++#define TARGET_INPCK 0000020 ++#define TARGET_ISTRIP 0000040 ++#define TARGET_INLCR 0000100 ++#define TARGET_IGNCR 0000200 ++#define TARGET_ICRNL 0000400 ++#define TARGET_IUCLC 0001000 ++#define TARGET_IXON 0002000 ++#define TARGET_IXANY 0004000 ++#define TARGET_IXOFF 0010000 ++#define TARGET_IMAXBEL 0020000 ++#define TARGET_IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define TARGET_OPOST 0000001 ++#define TARGET_OLCUC 0000002 ++#define TARGET_ONLCR 0000004 ++#define TARGET_OCRNL 0000010 ++#define TARGET_ONOCR 0000020 ++#define TARGET_ONLRET 0000040 ++#define TARGET_OFILL 0000100 ++#define TARGET_OFDEL 0000200 ++#define TARGET_NLDLY 0000400 ++#define TARGET_NL0 0000000 ++#define TARGET_NL1 0000400 ++#define TARGET_CRDLY 0003000 ++#define TARGET_CR0 0000000 ++#define TARGET_CR1 0001000 ++#define TARGET_CR2 0002000 ++#define TARGET_CR3 0003000 ++#define TARGET_TABDLY 0014000 ++#define TARGET_TAB0 0000000 ++#define TARGET_TAB1 0004000 ++#define TARGET_TAB2 0010000 ++#define TARGET_TAB3 0014000 ++#define TARGET_XTABS 0014000 ++#define TARGET_BSDLY 0020000 ++#define TARGET_BS0 0000000 ++#define TARGET_BS1 0020000 ++#define TARGET_VTDLY 0040000 ++#define TARGET_VT0 0000000 ++#define TARGET_VT1 0040000 ++#define TARGET_FFDLY 0100000 ++#define TARGET_FF0 0000000 ++#define TARGET_FF1 0100000 ++ ++/* c_cflag bit meaning */ ++#define TARGET_CBAUD 0010017 ++#define TARGET_B0 0000000 /* hang up */ ++#define TARGET_B50 0000001 ++#define TARGET_B75 0000002 ++#define TARGET_B110 0000003 ++#define TARGET_B134 0000004 ++#define TARGET_B150 0000005 ++#define TARGET_B200 0000006 ++#define TARGET_B300 0000007 ++#define TARGET_B600 0000010 ++#define TARGET_B1200 0000011 ++#define TARGET_B1800 0000012 ++#define TARGET_B2400 0000013 ++#define TARGET_B4800 0000014 ++#define TARGET_B9600 0000015 ++#define TARGET_B19200 0000016 ++#define TARGET_B38400 0000017 ++#define TARGET_EXTA B19200 ++#define TARGET_EXTB B38400 ++#define TARGET_CSIZE 0000060 ++#define TARGET_CS5 0000000 ++#define TARGET_CS6 0000020 ++#define TARGET_CS7 0000040 ++#define TARGET_CS8 0000060 ++#define TARGET_CSTOPB 0000100 ++#define TARGET_CREAD 0000200 ++#define TARGET_PARENB 0000400 ++#define TARGET_PARODD 0001000 ++#define TARGET_HUPCL 0002000 ++#define TARGET_CLOCAL 0004000 ++#define TARGET_CBAUDEX 0010000 ++#define TARGET_B57600 0010001 ++#define TARGET_B115200 0010002 ++#define TARGET_B230400 0010003 ++#define TARGET_B460800 0010004 ++#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ ++#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define TARGET_CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define TARGET_ISIG 0000001 ++#define TARGET_ICANON 0000002 ++#define TARGET_XCASE 0000004 ++#define TARGET_ECHO 0000010 ++#define TARGET_ECHOE 0000020 ++#define TARGET_ECHOK 0000040 ++#define TARGET_ECHONL 0000100 ++#define TARGET_NOFLSH 0000200 ++#define TARGET_TOSTOP 0000400 ++#define TARGET_ECHOCTL 0001000 ++#define TARGET_ECHOPRT 0002000 ++#define TARGET_ECHOKE 0004000 ++#define TARGET_FLUSHO 0010000 ++#define TARGET_PENDIN 0040000 ++#define TARGET_IEXTEN 0100000 ++ ++/* c_cc character offsets */ ++#define TARGET_VINTR 0 ++#define TARGET_VQUIT 1 ++#define TARGET_VERASE 2 ++#define TARGET_VKILL 3 ++#define TARGET_VEOF 4 ++#define TARGET_VTIME 5 ++#define TARGET_VMIN 6 ++#define TARGET_VSWTC 7 ++#define TARGET_VSTART 8 ++#define TARGET_VSTOP 9 ++#define TARGET_VSUSP 10 ++#define TARGET_VEOL 11 ++#define TARGET_VREPRINT 12 ++#define TARGET_VDISCARD 13 ++#define TARGET_VWERASE 14 ++#define TARGET_VLNEXT 15 ++#define TARGET_VEOL2 16 ++ ++/* ioctls */ ++ ++#define TARGET_TCGETS 0x5401 ++#define TARGET_TCSETS 0x5402 ++#define TARGET_TCSETSW 0x5403 ++#define TARGET_TCSETSF 0x5404 ++#define TARGET_TCGETA 0x5405 ++#define TARGET_TCSETA 0x5406 ++#define TARGET_TCSETAW 0x5407 ++#define TARGET_TCSETAF 0x5408 ++#define TARGET_TCSBRK 0x5409 ++#define TARGET_TCXONC 0x540A ++#define TARGET_TCFLSH 0x540B ++ ++#define TARGET_TIOCEXCL 0x540C ++#define TARGET_TIOCNXCL 0x540D ++#define TARGET_TIOCSCTTY 0x540E ++#define TARGET_TIOCGPGRP 0x540F ++#define TARGET_TIOCSPGRP 0x5410 ++#define TARGET_TIOCOUTQ 0x5411 ++#define TARGET_TIOCSTI 0x5412 ++#define TARGET_TIOCGWINSZ 0x5413 ++#define TARGET_TIOCSWINSZ 0x5414 ++#define TARGET_TIOCMGET 0x5415 ++#define TARGET_TIOCMBIS 0x5416 ++#define TARGET_TIOCMBIC 0x5417 ++#define TARGET_TIOCMSET 0x5418 ++#define TARGET_TIOCGSOFTCAR 0x5419 ++#define TARGET_TIOCSSOFTCAR 0x541A ++#define TARGET_FIONREAD 0x541B ++#define TARGET_TIOCINQ TARGET_FIONREAD ++#define TARGET_TIOCLINUX 0x541C ++#define TARGET_TIOCCONS 0x541D ++#define TARGET_TIOCGSERIAL 0x541E ++#define TARGET_TIOCSSERIAL 0x541F ++#define TARGET_TIOCPKT 0x5420 ++#define TARGET_FIONBIO 0x5421 ++#define TARGET_TIOCNOTTY 0x5422 ++#define TARGET_TIOCSETD 0x5423 ++#define TARGET_TIOCGETD 0x5424 ++#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ ++#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ ++/* Get Pty Number (of pty-mux device) */ ++#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) ++/* Lock/unlock Pty */ ++#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) ++/* Safely open the slave */ ++#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) ++ ++#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ ++#define TARGET_FIOCLEX 0x5451 ++#define TARGET_FIOASYNC 0x5452 ++#define TARGET_TIOCSERCONFIG 0x5453 ++#define TARGET_TIOCSERGWILD 0x5454 ++#define TARGET_TIOCSERSWILD 0x5455 ++#define TARGET_TIOCGLCKTRMIOS 0x5456 ++#define TARGET_TIOCSLCKTRMIOS 0x5457 ++#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ ++#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++/* wait for a change on serial input line(s) */ ++#define TARGET_TIOCMIWAIT 0x545C ++/* read serial port inline interrupt counts */ ++#define TARGET_TIOCGICOUNT 0x545D ++#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ ++#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ ++ ++/* Used for packet mode */ ++#define TARGET_TIOCPKT_DATA 0 ++#define TARGET_TIOCPKT_FLUSHREAD 1 ++#define TARGET_TIOCPKT_FLUSHWRITE 2 ++#define TARGET_TIOCPKT_STOP 4 ++#define TARGET_TIOCPKT_START 8 ++#define TARGET_TIOCPKT_NOSTOP 16 ++#define TARGET_TIOCPKT_DOSTOP 32 ++ ++#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++ ++#endif +diff --git a/linux-user/meson.build b/linux-user/meson.build +index 4f4196ed13..8b8edefa6e 100644 +--- a/linux-user/meson.build ++++ b/linux-user/meson.build +@@ -40,3 +40,4 @@ subdir('sparc') + subdir('sw64') + subdir('x86_64') + subdir('xtensa') ++subdir('loongarch64') +diff --git a/linux-user/qemu.h b/linux-user/qemu.h +index 5c713fa8ab..66ddb25d1c 100644 +--- a/linux-user/qemu.h ++++ b/linux-user/qemu.h +@@ -61,7 +61,7 @@ struct image_info { + /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */ + uint32_t note_flags; + +-#ifdef TARGET_MIPS ++#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) + int fp_abi; + int interp_fp_abi; + #endif +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index fce2c03259..a544d04524 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -1614,6 +1614,9 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, + #elif defined(TARGET_MIPS) + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; + return host_pipe[0]; ++#elif defined(TARGET_LOONGARCH64) ++ ((CPULOONGARCHState *)cpu_env)->active_tc.gpr[5] = host_pipe[1]; ++ return host_pipe[0]; + #elif defined(TARGET_SH4) + ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; + return host_pipe[0]; +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index 0b13975937..04ca5fe7a0 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -74,7 +74,7 @@ + || defined(TARGET_M68K) || defined(TARGET_CRIS) \ + || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ + || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ +- || defined(TARGET_XTENSA) ++ || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) + + #define TARGET_IOC_SIZEBITS 14 + #define TARGET_IOC_DIRBITS 2 +@@ -450,7 +450,7 @@ struct target_dirent64 { + #define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ + #define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ + +-#ifdef TARGET_MIPS ++#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) + #define TARGET_NSIG 128 + #else + #define TARGET_NSIG 64 +@@ -2133,7 +2133,8 @@ struct target_stat64 { + abi_ulong __unused5; + }; + +-#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) ++#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || \ ++ defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64) + + /* These are the asm-generic versions of the stat and stat64 structures */ + +@@ -2161,7 +2162,7 @@ struct target_stat { + unsigned int __unused5; + }; + +-#if !defined(TARGET_RISCV64) ++#if !(defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)) + #define TARGET_HAS_STRUCT_STAT64 + struct target_stat64 { + uint64_t st_dev; +@@ -2331,6 +2332,7 @@ struct target_statfs64 { + }; + #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ + defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ ++ defined(TARGET_LOONGARCH64) || \ + defined(TARGET_RISCV)) && !defined(TARGET_ABI32) + struct target_statfs { + abi_long f_type; +-- +2.27.0 + diff --git a/Add-loongarch-machine.patch b/Add-loongarch-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..10380b7c8e52482d8f17d7bcffb6a59adbeda492 --- /dev/null +++ b/Add-loongarch-machine.patch @@ -0,0 +1,6181 @@ +From 810369434538d64a4118c3ec70d4c3daf479bd52 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:14:21 -0500 +Subject: [PATCH] Add loongarch machine. + +1.Add loongarch ACPI table support. +2.Add loongarch apic support. +3.Add loongarch ipi support. +4.Add loongarch hotplug support. +5.Add loongarch board simulation. +6.Add loongarch interrupt support. +7.Add loongarch north bridge simulation. +8.Add loongarch iocsr device simulation. +9.Add loongarch system bus support. + +Signed-off-by: lixianglai +--- + hw/loongarch/Kconfig | 17 + + hw/loongarch/acpi-build.c | 827 ++++++++++++ + hw/loongarch/acpi-build.h | 32 + + hw/loongarch/apic.c | 689 ++++++++++ + hw/loongarch/ioapic.c | 419 ++++++ + hw/loongarch/iocsr.c | 227 ++++ + hw/loongarch/ipi.c | 284 ++++ + hw/loongarch/larch_3a.c | 2063 +++++++++++++++++++++++++++++ + hw/loongarch/larch_hotplug.c | 377 ++++++ + hw/loongarch/larch_int.c | 87 ++ + hw/loongarch/ls7a_nb.c | 289 ++++ + hw/loongarch/meson.build | 15 + + hw/loongarch/sysbus-fdt.c | 178 +++ + include/disas/dis-asm.h | 3 +- + include/elf.h | 2 + + include/hw/loongarch/bios.h | 24 + + include/hw/loongarch/cpudevs.h | 71 + + include/hw/loongarch/larch.h | 164 +++ + include/hw/loongarch/ls7a.h | 167 +++ + include/hw/loongarch/sysbus-fdt.h | 33 + + include/qemu/osdep.h | 4 + + 21 files changed, 5971 insertions(+), 1 deletion(-) + create mode 100644 hw/loongarch/Kconfig + create mode 100644 hw/loongarch/acpi-build.c + create mode 100644 hw/loongarch/acpi-build.h + create mode 100644 hw/loongarch/apic.c + create mode 100644 hw/loongarch/ioapic.c + create mode 100644 hw/loongarch/iocsr.c + create mode 100644 hw/loongarch/ipi.c + create mode 100644 hw/loongarch/larch_3a.c + create mode 100644 hw/loongarch/larch_hotplug.c + create mode 100644 hw/loongarch/larch_int.c + create mode 100644 hw/loongarch/ls7a_nb.c + create mode 100644 hw/loongarch/meson.build + create mode 100644 hw/loongarch/sysbus-fdt.c + create mode 100644 include/hw/loongarch/bios.h + create mode 100644 include/hw/loongarch/cpudevs.h + create mode 100644 include/hw/loongarch/larch.h + create mode 100644 include/hw/loongarch/ls7a.h + create mode 100644 include/hw/loongarch/sysbus-fdt.h + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +new file mode 100644 +index 0000000000..3fe2677fda +--- /dev/null ++++ b/hw/loongarch/Kconfig +@@ -0,0 +1,17 @@ ++config LS7A_APIC ++ bool ++ ++config LS7A_RTC ++ bool ++ ++config LOONGSON3A ++ bool ++ ++config MEM_HOTPLUG ++ bool ++ ++config ACPI_LOONGARCH ++ bool ++ ++config E1000E_PCI ++ bool +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +new file mode 100644 +index 0000000000..4dd128a05e +--- /dev/null ++++ b/hw/loongarch/acpi-build.c +@@ -0,0 +1,827 @@ ++/* ++ * Support for generating ACPI tables and passing them to Guests ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qapi/qmp/qnum.h" ++#include "acpi-build.h" ++#include "qemu-common.h" ++#include "qemu/bitmap.h" ++#include "qemu/error-report.h" ++#include "hw/pci/pci.h" ++#include "hw/boards.h" ++#include "hw/core/cpu.h" ++#include "target/loongarch64/cpu.h" ++#include "hw/misc/pvpanic.h" ++#include "hw/timer/hpet.h" ++#include "hw/acpi/acpi-defs.h" ++#include "hw/acpi/acpi.h" ++#include "hw/acpi/cpu.h" ++#include "hw/nvram/fw_cfg.h" ++#include "hw/acpi/bios-linker-loader.h" ++#include "hw/loader.h" ++#include "hw/isa/isa.h" ++#include "hw/block/fdc.h" ++#include "hw/acpi/memory_hotplug.h" ++#include "sysemu/tpm.h" ++#include "hw/acpi/tpm.h" ++#include "hw/acpi/vmgenid.h" ++#include "sysemu/tpm_backend.h" ++#include "hw/rtc/mc146818rtc_regs.h" ++#include "sysemu/numa.h" ++#include "sysemu/runstate.h" ++#include "sysemu/reset.h" ++#include "migration/vmstate.h" ++#include "hw/mem/memory-device.h" ++#include "hw/acpi/utils.h" ++#include "hw/acpi/pci.h" ++/* Supported chipsets: */ ++#include "hw/acpi/aml-build.h" ++#include "hw/loongarch/larch.h" ++#include "hw/loongarch/ls7a.h" ++#include "hw/platform-bus.h" ++ ++#include "hw/acpi/ipmi.h" ++#include "hw/acpi/ls7a.h" ++ ++/* ++ * These are used to size the ACPI tables for -M pc-i440fx-1.7 and ++ * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows ++ * a little bit, there should be plenty of free space since the DSDT ++ * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1. ++ */ ++#define ACPI_BUILD_ALIGN_SIZE 0x1000 ++#define ACPI_BUILD_TABLE_SIZE 0x20000 ++ ++/* #define DEBUG_ACPI_BUILD */ ++#ifdef DEBUG_ACPI_BUILD ++#define ACPI_BUILD_DPRINTF(fmt, ...) \ ++ do { \ ++ printf("ACPI_BUILD: " fmt, ##__VA_ARGS__); \ ++ } while (0) ++#else ++#define ACPI_BUILD_DPRINTF(fmt, ...) ++#endif ++ ++/* Default IOAPIC ID */ ++#define ACPI_BUILD_IOAPIC_ID 0x0 ++ ++/* PCI fw r3.0 MCFG table. */ ++/* Subtable */ ++ ++typedef struct AcpiMiscInfo { ++ bool is_piix4; ++ bool has_hpet; ++ TPMVersion tpm_version; ++ const unsigned char *dsdt_code; ++ unsigned dsdt_size; ++ uint16_t pvpanic_port; ++ uint16_t applesmc_io_base; ++} AcpiMiscInfo; ++ ++typedef struct AcpiBuildPciBusHotplugState { ++ GArray *device_table; ++ GArray *notify_table; ++ struct AcpiBuildPciBusHotplugState *parent; ++ bool pcihp_bridge_en; ++} AcpiBuildPciBusHotplugState; ++ ++static void init_common_fadt_data(AcpiFadtData *data) ++{ ++ AmlAddressSpace as = AML_AS_SYSTEM_MEMORY; ++ uint64_t base = LS7A_ACPI_REG_BASE; ++ AcpiFadtData fadt = { ++ .rev = 3, ++ .flags = (1 << ACPI_FADT_F_WBINVD) | (1 << ACPI_FADT_F_PROC_C1) | ++ (1 << ACPI_FADT_F_SLP_BUTTON) | ++ (1 << ACPI_FADT_F_TMR_VAL_EXT) | ++ (1 << ACPI_FADT_F_RESET_REG_SUP), ++ /* C2 state not supported */ ++ .plvl2_lat = 0xfff, ++ /* C3 state not supported */ ++ .plvl3_lat = 0xfff, ++ .smi_cmd = 0x00, ++ .sci_int = ACPI_SCI_IRQ, ++ .acpi_enable_cmd = 0x00, ++ .acpi_disable_cmd = 0x00, ++ .pm1a_evt = { .space_id = as, ++ .bit_width = 8 * 8, ++ .address = base + LS7A_PM_EVT_BLK }, ++ .pm1a_cnt = { .space_id = as, ++ .bit_width = 4 * 8, ++ .address = base + LS7A_PM_CNT_BLK }, ++ .pm_tmr = { .space_id = as, ++ .bit_width = 4 * 8, ++ .address = base + LS7A_PM_TMR_BLK }, ++ .gpe0_blk = { .space_id = as, ++ .bit_width = 8 * 8, ++ .address = base + LS7A_GPE0_STS_REG }, ++ .reset_reg = { .space_id = as, ++ .bit_width = 4 * 8, ++ .address = base + LS7A_GPE0_RESET_REG }, ++ .reset_val = 0x1, ++ }; ++ *data = fadt; ++} ++ ++static void acpi_align_size(GArray *blob, unsigned align) ++{ ++ /* ++ * Align size to multiple of given size. This reduces the chance ++ * we need to change size in the future (breaking cross version migration). ++ */ ++ g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); ++} ++ ++/* FACS */ ++static void build_facs(GArray *table_data) ++{ ++ const char *sig = "FACS"; ++ const uint8_t reserved[40] = {}; ++ ++ g_array_append_vals(table_data, sig, 4); /* Signature */ ++ build_append_int_noprefix(table_data, 64, 4); /* Length */ ++ build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */ ++ build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */ ++ build_append_int_noprefix(table_data, 0, 4); /* Global Lock */ ++ build_append_int_noprefix(table_data, 0, 4); /* Flags */ ++ g_array_append_vals(table_data, reserved, 40); /* Reserved */ ++} ++ ++void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *apic_ids, GArray *entry, ++ bool force_enabled) ++{ ++ uint32_t apic_id = apic_ids->cpus[uid].arch_id; ++ /* Flags – Local APIC Flags */ ++ uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? 1 : 0; ++ ++ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */ ++ build_append_int_noprefix(entry, 0, 1); /* Type */ ++ build_append_int_noprefix(entry, 8, 1); /* Length */ ++ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */ ++ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */ ++ build_append_int_noprefix(entry, flags, 4); /* Flags */ ++} ++ ++static void build_ioapic(GArray *entry, uint8_t id, uint32_t addr, ++ uint32_t irq) ++{ ++ /* Rev 1.0b, 5.2.8.2 IO APIC */ ++ build_append_int_noprefix(entry, 1, 1); /* Type */ ++ build_append_int_noprefix(entry, 12, 1); /* Length */ ++ build_append_int_noprefix(entry, id, 1); /* IO APIC ID */ ++ build_append_int_noprefix(entry, 0, 1); /* Reserved */ ++ build_append_int_noprefix(entry, addr, 4); /* IO APIC Address */ ++ build_append_int_noprefix(entry, irq, 4); /* System Vector Base */ ++} ++ ++static void build_madt(GArray *table_data, BIOSLinker *linker, ++ LoongarchMachineState *lsms) ++{ ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ MachineClass *mc = MACHINE_GET_CLASS(lsms); ++ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(lsms)); ++ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(lsms->acpi_dev); ++ AcpiDeviceIf *adev = ACPI_DEVICE_IF(lsms->acpi_dev); ++ int i; ++ AcpiTable table = { .sig = "APIC", ++ .rev = 1, ++ .oem_id = lsms->oem_id, ++ .oem_table_id = lsms->oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ ++ /* Local APIC Address */ ++ build_append_int_noprefix(table_data, 0, 4); ++ build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ ++ ++ for (i = 0; i < apic_ids->len; i++) { ++ adevc->madt_cpu(adev, i, apic_ids, table_data, false); ++ } ++ ++ build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID, lsmc->ls7a_ioapic_reg_base, ++ LOONGARCH_PCH_IRQ_BASE); ++ ++ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ ++ build_append_int_noprefix(table_data, 3, 1); /* Type */ ++ build_append_int_noprefix(table_data, 6, 1); /* Length */ ++ /* ACPI Processor ID */ ++ build_append_int_noprefix(table_data, 0xFF, 1); /* all processors */ ++ build_append_int_noprefix(table_data, 0, 2); /* Flags */ ++ /* Local APIC INTI# */ ++ build_append_int_noprefix(table_data, 1, 1); /* ACPI_LINT1 */ ++ ++ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ ++ build_append_int_noprefix(table_data, 4, 1); /* Type */ ++ build_append_int_noprefix(table_data, 6, 1); /* Length */ ++ /* ACPI Processor ID */ ++ build_append_int_noprefix(table_data, 0xFF, 1); /* all processors */ ++ build_append_int_noprefix(table_data, 0, 2); /* Flags */ ++ /* Local APIC INTI# */ ++ build_append_int_noprefix(table_data, 1, 1); /* ACPI_LINT1 */ ++ ++ acpi_table_end(linker, &table); ++} ++ ++static void build_srat(GArray *table_data, BIOSLinker *linker, ++ MachineState *machine) ++{ ++ uint64_t i, mem_len, mem_base; ++ MachineClass *mc = MACHINE_GET_CLASS(machine); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); ++ int nb_numa_nodes = machine->numa_state->num_nodes; ++ NodeInfo *numa_info = machine->numa_state->nodes; ++ AcpiTable table = { .sig = "SRAT", ++ .rev = 1, ++ .oem_id = lsms->oem_id, ++ .oem_table_id = lsms->oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ build_append_int_noprefix(table_data, 1, 4); /* Reserved */ ++ build_append_int_noprefix(table_data, 0, 8); /* Reserved */ ++ ++ for (i = 0; i < apic_ids->len; ++i) { ++ /* 5.2.15.1 Processor Local APIC/SAPIC Affinity Structure */ ++ build_append_int_noprefix(table_data, 0, 1); /* Type */ ++ build_append_int_noprefix(table_data, 16, 1); /* Length */ ++ /* Proximity Domain [7:0] */ ++ build_append_int_noprefix(table_data, apic_ids->cpus[i].props.node_id, ++ 1); ++ build_append_int_noprefix(table_data, apic_ids->cpus[i].arch_id, ++ 1); /* APIC ID */ ++ /* Flags, Table 5-36 */ ++ build_append_int_noprefix(table_data, 1, 4); ++ build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */ ++ /* Proximity Domain [31:8] */ ++ build_append_int_noprefix(table_data, 0, 3); ++ build_append_int_noprefix(table_data, 0, 4); /* Reserved */ ++ } ++ ++ /* node0 */ ++ mem_base = (uint64_t)0; ++ mem_len = 0x10000000; ++ build_srat_memory(table_data, mem_base, mem_len, 0, MEM_AFFINITY_ENABLED); ++ mem_base = 0x90000000; ++ if (!nb_numa_nodes) { ++ mem_len = machine->ram_size - 0x10000000; ++ } else { ++ mem_len = numa_info[0].node_mem - 0x10000000; ++ } ++ ++ build_srat_memory(table_data, mem_base, mem_len, 0, MEM_AFFINITY_ENABLED); ++ mem_base += mem_len; ++ ++ /* node1 ~ nodemax */ ++ for (i = 1; i < nb_numa_nodes; ++i) { ++ mem_len = numa_info[i].node_mem; ++ build_srat_memory(table_data, mem_base, mem_len, i, ++ MEM_AFFINITY_ENABLED); ++ mem_base += mem_len; ++ } ++ ++ if (lsms->hotplug_memory_size) { ++ build_srat_memory(table_data, machine->device_memory->base, ++ lsms->hotplug_memory_size, 0, ++ MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); ++ } ++ ++ acpi_table_end(linker, &table); ++} ++ ++typedef struct AcpiBuildState { ++ /* Copy of table in RAM (for patching). */ ++ MemoryRegion *table_mr; ++ /* Is table patched? */ ++ uint8_t patched; ++ void *rsdp; ++ MemoryRegion *rsdp_mr; ++ MemoryRegion *linker_mr; ++} AcpiBuildState; ++ ++static void build_ls7a_pci0_int(Aml *table) ++{ ++ Aml *sb_scope = aml_scope("_SB"); ++ Aml *pci0_scope = aml_scope("PCI0"); ++ Aml *prt_pkg = aml_varpackage(128); ++ int slot, pin; ++ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ for (pin = 0; pin < PCI_NUM_PINS; pin++) { ++ Aml *pkg = aml_package(4); ++ aml_append(pkg, aml_int((slot << 16) | 0xFFFF)); ++ aml_append(pkg, aml_int(pin)); ++ aml_append(pkg, aml_int(0)); ++ aml_append(pkg, aml_int(LOONGARCH_PCH_IRQ_BASE + 16 + ++ (slot * 4 + pin) % 16)); ++ aml_append(prt_pkg, pkg); ++ } ++ } ++ aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg)); ++ ++ aml_append(sb_scope, pci0_scope); ++ ++ aml_append(table, sb_scope); ++} ++ ++static void build_dbg_aml(Aml *table) ++{ ++ Aml *field; ++ Aml *method; ++ Aml *while_ctx; ++ Aml *scope = aml_scope("\\"); ++ Aml *buf = aml_local(0); ++ Aml *len = aml_local(1); ++ Aml *idx = aml_local(2); ++ ++ aml_append(scope, aml_operation_region("DBG", AML_SYSTEM_IO, ++ aml_int(0x0402), 0x01)); ++ field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); ++ aml_append(field, aml_named_field("DBGB", 8)); ++ aml_append(scope, field); ++ ++ method = aml_method("DBUG", 1, AML_NOTSERIALIZED); ++ ++ aml_append(method, aml_to_hexstring(aml_arg(0), buf)); ++ aml_append(method, aml_to_buffer(buf, buf)); ++ aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len)); ++ aml_append(method, aml_store(aml_int(0), idx)); ++ ++ while_ctx = aml_while(aml_lless(idx, len)); ++ aml_append(while_ctx, ++ aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB"))); ++ aml_append(while_ctx, aml_increment(idx)); ++ aml_append(method, while_ctx); ++ ++ aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB"))); ++ aml_append(scope, method); ++ ++ aml_append(table, scope); ++} ++ ++static Aml *build_ls7a_osc_method(void) ++{ ++ Aml *if_ctx; ++ Aml *if_ctx2; ++ Aml *else_ctx; ++ Aml *method; ++ Aml *a_cwd1 = aml_name("CDW1"); ++ Aml *a_ctrl = aml_local(0); ++ ++ method = aml_method("_OSC", 4, AML_NOTSERIALIZED); ++ aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); ++ ++ if_ctx = aml_if(aml_equal( ++ aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); ++ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); ++ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); ++ ++ aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); ++ ++ /* ++ * Always allow native PME, AER (no dependencies) ++ * Allow SHPC (PCI bridges can have SHPC controller) ++ */ ++ aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); ++ ++ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); ++ /* Unknown revision */ ++ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); ++ aml_append(if_ctx, if_ctx2); ++ ++ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); ++ /* Capabilities bits were masked */ ++ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); ++ aml_append(if_ctx, if_ctx2); ++ ++ /* Update DWORD3 in the buffer */ ++ aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); ++ aml_append(method, if_ctx); ++ ++ else_ctx = aml_else(); ++ /* Unrecognized UUID */ ++ aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); ++ aml_append(method, else_ctx); ++ ++ aml_append(method, aml_return(aml_arg(3))); ++ return method; ++} ++ ++static void build_ls7a_rtc_device_aml(Aml *table) ++{ ++ Aml *dev; ++ Aml *crs; ++ uint32_t rtc_irq = LS7A_RTC_IRQ; ++ ++ Aml *scope = aml_scope("_SB"); ++ dev = aml_device("RTC"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("LOON0001"))); ++ crs = aml_resource_template(); ++ aml_append(crs, aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, ++ AML_MAX_FIXED, AML_NON_CACHEABLE, ++ AML_READ_WRITE, 0, LS7A_RTC_REG_BASE, ++ LS7A_RTC_REG_BASE + LS7A_RTC_LEN - 1, 0, ++ LS7A_RTC_LEN)); ++ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, ++ AML_EXCLUSIVE, &rtc_irq, 1)); ++ ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++ aml_append(table, scope); ++} ++ ++static void build_ls7a_uart_device_aml(Aml *table) ++{ ++ Aml *dev; ++ Aml *crs; ++ Aml *pkg0, *pkg1, *pkg2; ++ uint32_t uart_irq = LS7A_UART_IRQ; ++ ++ Aml *scope = aml_scope("_SB"); ++ dev = aml_device("COMA"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(0))); ++ aml_append(dev, aml_name_decl("_CCA", aml_int(1))); ++ crs = aml_resource_template(); ++ aml_append(crs, aml_qword_memory( ++ AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, ++ AML_NON_CACHEABLE, AML_READ_WRITE, 0, LS7A_UART_BASE, ++ LS7A_UART_BASE + LS7A_UART_LEN - 1, 0, 0x8)); ++ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, ++ AML_EXCLUSIVE, &uart_irq, 1)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ pkg0 = aml_package(0x2); ++ aml_append(pkg0, aml_int(0x01F78A40)); ++ aml_append(pkg0, aml_string("clock-frenquency")); ++ pkg1 = aml_package(0x1); ++ aml_append(pkg1, pkg0); ++ pkg2 = aml_package(0x2); ++ aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); ++ aml_append(pkg2, pkg1); ++ ++ aml_append(dev, aml_name_decl("_DSD", pkg2)); ++ ++ aml_append(scope, dev); ++ aml_append(table, scope); ++} ++ ++#ifdef CONFIG_TPM ++static void acpi_dsdt_add_tpm(Aml *scope, LoongarchMachineState *vms) ++{ ++ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); ++ hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; ++ SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); ++ MemoryRegion *sbdev_mr; ++ hwaddr tpm_base; ++ ++ if (!sbdev) { ++ return; ++ } ++ ++ tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); ++ assert(tpm_base != -1); ++ ++ tpm_base += pbus_base; ++ ++ sbdev_mr = sysbus_mmio_get_region(sbdev, 0); ++ ++ Aml *dev = aml_device("TPM0"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); ++ aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(0))); ++ ++ Aml *crs = aml_resource_template(); ++ aml_append(crs, aml_memory32_fixed(tpm_base, ++ (uint32_t)memory_region_size(sbdev_mr), ++ AML_READ_WRITE)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++} ++#endif ++ ++static void build_dsdt(GArray *table_data, BIOSLinker *linker, ++ MachineState *machine) ++{ ++ Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg; ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ uint32_t nr_mem = machine->ram_slots; ++ uint64_t base = LS7A_ACPI_REG_BASE; ++ int root_bus_limit = PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1); ++ AcpiTable table = { .sig = "DSDT", ++ .rev = 1, ++ .oem_id = lsms->oem_id, ++ .oem_table_id = lsms->oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ dsdt = init_aml_allocator(); ++ ++ build_dbg_aml(dsdt); ++ ++ sb_scope = aml_scope("_SB"); ++ dev = aml_device("PCI0"); ++ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); ++ aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); ++ aml_append(dev, aml_name_decl("_ADR", aml_int(0))); ++ aml_append(dev, aml_name_decl("_BBN", aml_int(0))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(1))); ++ aml_append(dev, build_ls7a_osc_method()); ++ aml_append(sb_scope, dev); ++ ++#ifdef CONFIG_TPM ++ acpi_dsdt_add_tpm(sb_scope, lsms); ++#endif ++ aml_append(dsdt, sb_scope); ++ ++ build_ls7a_pci0_int(dsdt); ++ build_ls7a_rtc_device_aml(dsdt); ++ build_ls7a_uart_device_aml(dsdt); ++ ++ if (lsms->acpi_dev) { ++ CPUHotplugFeatures opts = { .acpi_1_compatible = true, ++ .has_legacy_cphp = false }; ++ build_cpus_aml(dsdt, machine, opts, CPU_HOTPLUG_BASE, "\\_SB.PCI0", ++ "\\_GPE._E02", AML_SYSTEM_MEMORY); ++ ++ build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03", ++ AML_SYSTEM_MEMORY, MEMORY_HOTPLUG_BASE); ++ } ++ ++ scope = aml_scope("_GPE"); ++ { ++ aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); ++ } ++ aml_append(dsdt, scope); ++ ++ scope = aml_scope("\\_SB.PCI0"); ++ /* build PCI0._CRS */ ++ crs = aml_resource_template(); ++ aml_append(crs, aml_word_bus_number( ++ AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, 0x0000, ++ 0x0, root_bus_limit, 0x0000, root_bus_limit + 1)); ++ aml_append(crs, aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, ++ AML_ENTIRE_RANGE, 0x0000, 0x4000, 0xFFFF, ++ 0x0000, 0xC000)); ++ aml_append(crs, ++ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, ++ AML_CACHEABLE, AML_READ_WRITE, 0, 0x40000000, ++ 0x7FFFFFFF, 0, 0x40000000)); ++ aml_append(scope, aml_name_decl("_CRS", crs)); ++ ++ /* reserve GPE0 block resources */ ++ dev = aml_device("GPE0"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); ++ aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources"))); ++ /* device present, functioning, decoding, not shown in UI */ ++ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); ++ crs = aml_resource_template(); ++ aml_append(crs, ++ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, ++ AML_CACHEABLE, AML_READ_WRITE, 0, ++ base + LS7A_GPE0_STS_REG, ++ base + LS7A_GPE0_STS_REG + 0x3, 0, 0x4)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++ aml_append(dsdt, scope); ++ ++ scope = aml_scope("\\"); ++ pkg = aml_package(4); ++ aml_append(pkg, aml_int(7)); /* PM1a_CNT.SLP_TYP */ ++ aml_append(pkg, aml_int(7)); /* PM1b_CNT.SLP_TYP not impl. */ ++ aml_append(pkg, aml_int(0)); /* reserved */ ++ aml_append(pkg, aml_int(0)); /* reserved */ ++ aml_append(scope, aml_name_decl("_S5", pkg)); ++ aml_append(dsdt, scope); ++ ++ /* copy AML table into ACPI tables blob and patch header there */ ++ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); ++ acpi_table_end(linker, &table); ++ free_aml_allocator(); ++} ++ ++static void acpi_build(AcpiBuildTables *tables, MachineState *machine) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ GArray *table_offsets; ++ AcpiFadtData fadt_data; ++ unsigned facs, rsdt, fadt, dsdt; ++ uint8_t *u; ++ size_t aml_len = 0; ++ GArray *tables_blob = tables->table_data; ++ ++ init_common_fadt_data(&fadt_data); ++ ++ table_offsets = g_array_new(false, true, sizeof(uint32_t)); /* clear */ ++ ACPI_BUILD_DPRINTF("init ACPI tables\n"); ++ ++ bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, ++ tables_blob, 64, false /* high memory */); ++ ++ /* ++ * FACS is pointed to by FADT. ++ * We place it first since it's the only table that has alignment ++ * requirements. ++ */ ++ facs = tables_blob->len; ++ build_facs(tables_blob); ++ ++ /* DSDT is pointed to by FADT */ ++ dsdt = tables_blob->len; ++ build_dsdt(tables_blob, tables->linker, MACHINE(qdev_get_machine())); ++ ++ /* ++ * Count the size of the DSDT and SSDT, we will need it for legacy ++ * sizing of ACPI tables. ++ */ ++ aml_len += tables_blob->len - dsdt; ++ ++ /* ACPI tables pointed to by RSDT */ ++ fadt = tables_blob->len; ++ acpi_add_table(table_offsets, tables_blob); ++ fadt_data.facs_tbl_offset = &facs; ++ fadt_data.dsdt_tbl_offset = &dsdt; ++ fadt_data.xdsdt_tbl_offset = &dsdt; ++ build_fadt(tables_blob, tables->linker, &fadt_data, "LOONGS", "TP-R00"); ++ aml_len += tables_blob->len - fadt; ++ ++ acpi_add_table(table_offsets, tables_blob); ++ build_madt(tables_blob, tables->linker, lsms); ++ ++ acpi_add_table(table_offsets, tables_blob); ++ build_srat(tables_blob, tables->linker, machine); ++ if (machine->numa_state->have_numa_distance) { ++ acpi_add_table(table_offsets, tables_blob); ++ build_slit(tables_blob, tables->linker, machine, lsms->oem_id, ++ lsms->oem_table_id); ++ } ++ ++ if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { ++ acpi_add_table(table_offsets, tables_blob); ++ build_tpm2(tables_blob, tables->linker, tables->tcpalog, lsms->oem_id, ++ lsms->oem_table_id); ++ } ++ ++ /* Build mcfg */ ++ acpi_add_table(table_offsets, tables_blob); ++ { ++ AcpiMcfgInfo mcfg = { ++ .base = LS_PCIECFG_BASE, ++ .size = LS_PCIECFG_SIZE, ++ }; ++ build_mcfg(tables_blob, tables->linker, &mcfg, lsms->oem_id, ++ lsms->oem_table_id); ++ } ++ ++ /* Add tables supplied by user (if any) */ ++ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { ++ unsigned len = acpi_table_len(u); ++ ++ acpi_add_table(table_offsets, tables_blob); ++ g_array_append_vals(tables_blob, u, len); ++ } ++ ++ /* RSDT is pointed to by RSDP */ ++ rsdt = tables_blob->len; ++ build_rsdt(tables_blob, tables->linker, table_offsets, "LOONGS", "TP-R00"); ++ ++ /* RSDP is in FSEG memory, so allocate it separately */ ++ { ++ AcpiRsdpData rsdp_data = { ++ .revision = 0, ++ .oem_id = lsms->oem_id, ++ .xsdt_tbl_offset = NULL, ++ .rsdt_tbl_offset = &rsdt, ++ }; ++ build_rsdp(tables->rsdp, tables->linker, &rsdp_data); ++ } ++ acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); ++ ++ /* Cleanup memory that's no longer used. */ ++ g_array_free(table_offsets, true); ++} ++ ++static void acpi_ram_update(MemoryRegion *mr, GArray *data) ++{ ++ uint32_t size = acpi_data_len(data); ++ ++ /* ++ * Make sure RAM size is correct - ++ * in case it got changed e.g. by migration ++ */ ++ memory_region_ram_resize(mr, size, &error_abort); ++ ++ memcpy(memory_region_get_ram_ptr(mr), data->data, size); ++ memory_region_set_dirty(mr, 0, size); ++} ++ ++static void acpi_build_update(void *build_opaque) ++{ ++ AcpiBuildState *build_state = build_opaque; ++ AcpiBuildTables tables; ++ ++ /* No state to update or already patched? Nothing to do. */ ++ if (!build_state || build_state->patched) { ++ return; ++ } ++ build_state->patched = 1; ++ ++ acpi_build_tables_init(&tables); ++ ++ acpi_build(&tables, MACHINE(qdev_get_machine())); ++ ++ acpi_ram_update(build_state->table_mr, tables.table_data); ++ ++ if (build_state->rsdp) { ++ memcpy(build_state->rsdp, tables.rsdp->data, ++ acpi_data_len(tables.rsdp)); ++ } else { ++ acpi_ram_update(build_state->rsdp_mr, tables.rsdp); ++ } ++ ++ acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); ++ acpi_build_tables_cleanup(&tables, true); ++} ++ ++static void acpi_build_reset(void *build_opaque) ++{ ++ AcpiBuildState *build_state = build_opaque; ++ build_state->patched = 0; ++} ++ ++static const VMStateDescription vmstate_acpi_build = { ++ .name = "acpi_build", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]){ VMSTATE_UINT8(patched, AcpiBuildState), ++ VMSTATE_END_OF_LIST() }, ++}; ++ ++void loongarch_acpi_setup(void) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); ++ AcpiBuildTables tables; ++ AcpiBuildState *build_state; ++ ++ if (!lsms->fw_cfg) { ++ ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); ++ return; ++ } ++ ++ if (!lsms->acpi_build_enabled) { ++ ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); ++ return; ++ } ++ ++ if (!loongarch_is_acpi_enabled(lsms)) { ++ ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); ++ return; ++ } ++ ++ build_state = g_malloc0(sizeof *build_state); ++ ++ acpi_build_tables_init(&tables); ++ acpi_build(&tables, MACHINE(lsms)); ++ ++ /* Now expose it all to Guest */ ++ build_state->table_mr = ++ acpi_add_rom_blob(acpi_build_update, build_state, tables.table_data, ++ ACPI_BUILD_TABLE_FILE); ++ assert(build_state->table_mr != NULL); ++ ++ build_state->linker_mr = ++ acpi_add_rom_blob(acpi_build_update, build_state, ++ tables.linker->cmd_blob, "etc/table-loader"); ++ ++ fw_cfg_add_file(lsms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, ++ acpi_data_len(tables.tcpalog)); ++ ++ build_state->rsdp = NULL; ++ build_state->rsdp_mr = acpi_add_rom_blob( ++ acpi_build_update, build_state, tables.rsdp, ACPI_BUILD_RSDP_FILE); ++ ++ qemu_register_reset(acpi_build_reset, build_state); ++ acpi_build_reset(build_state); ++ vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); ++ ++ /* ++ * Cleanup tables but don't free the memory: we track it ++ * in build_state. ++ */ ++ acpi_build_tables_cleanup(&tables, false); ++} +diff --git a/hw/loongarch/acpi-build.h b/hw/loongarch/acpi-build.h +new file mode 100644 +index 0000000000..97d53a9258 +--- /dev/null ++++ b/hw/loongarch/acpi-build.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_LARCH_ACPI_BUILD_H ++#define HW_LARCH_ACPI_BUILD_H ++ ++#define EFI_ACPI_OEM_ID "LARCH" ++#define EFI_ACPI_OEM_TABLE_ID "LARCH" /* OEM table id 8 bytes long */ ++#define EFI_ACPI_OEM_REVISION 0x00000002 ++#define EFI_ACPI_CREATOR_ID "LINUX" ++#define EFI_ACPI_CREATOR_REVISION 0x01000013 ++ ++#define ACPI_COMPATIBLE_1_0 0 ++#define ACPI_COMPATIBLE_2_0 1 ++ ++void loongarch_acpi_setup(void); ++ ++#endif +diff --git a/hw/loongarch/apic.c b/hw/loongarch/apic.c +new file mode 100644 +index 0000000000..9e762cf0fe +--- /dev/null ++++ b/hw/loongarch/apic.c +@@ -0,0 +1,689 @@ ++/* ++ * Loongarch 3A5000 interrupt controller emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "hw/boards.h" ++#include "hw/irq.h" ++#include "hw/loongarch/cpudevs.h" ++#include "hw/sysbus.h" ++#include "qemu/host-utils.h" ++#include "qemu/error-report.h" ++#include "sysemu/kvm.h" ++#include "hw/hw.h" ++#include "hw/irq.h" ++#include "target/loongarch64/cpu.h" ++#include "exec/address-spaces.h" ++#include "hw/loongarch/larch.h" ++#include "migration/vmstate.h" ++ ++#define DEBUG_APIC 0 ++ ++#define DPRINTF(fmt, ...) \ ++ do { \ ++ if (DEBUG_APIC) { \ ++ fprintf(stderr, "APIC: " fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define APIC_OFFSET 0x400 ++#define APIC_BASE (0x1f010000ULL) ++#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET) ++#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET) ++#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET) ++#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET) ++#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET) ++#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET) ++#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET) ++#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET) ++#define EXTIOI_ISR_START (0x700 - APIC_OFFSET) ++#define EXTIOI_ISR_END (0x720 - APIC_OFFSET) ++#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) ++#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) ++#define EXTIOI_COREISR_START (0x10000) ++#define EXTIOI_COREISR_END (EXTIOI_COREISR_START + 0x10000) ++ ++static int ext_irq_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ apicState *apic = opaque; ++ struct loongarch_kvm_irqchip *chip; ++ struct kvm_loongarch_ls3a_extirq_state *kstate; ++ int ret, length, i, vcpuid; ++#endif ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++#ifdef CONFIG_KVM ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct kvm_loongarch_ls3a_extirq_state); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; ++ chip->len = length; ++ ++ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ ++ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; ++ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { ++ apic->ext_en[i] = kstate->ext_en_r.reg_u8[i]; ++ apic->ext_bounce[i] = kstate->bounce_r.reg_u8[i]; ++ apic->ext_isr[i] = kstate->ext_isr_r.reg_u8[i]; ++ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { ++ apic->ext_coreisr[vcpuid][i] = ++ kstate->ext_core_isr_r.reg_u8[vcpuid][i]; ++ } ++ } ++ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { ++ apic->ext_ipmap[i] = kstate->ip_map_r.reg_u8[i]; ++ } ++ for (i = 0; i < EXTIOI_IRQS; i++) { ++ apic->ext_coremap[i] = kstate->core_map_r.reg_u8[i]; ++ } ++ for (i = 0; i < 16; i++) { ++ apic->ext_nodetype[i] = kstate->node_type_r.reg_u16[i]; ++ } ++ g_free(chip); ++#endif ++ return 0; ++} ++ ++static int ext_irq_post_load(void *opaque, int version) ++{ ++#ifdef CONFIG_KVM ++ apicState *apic = opaque; ++ struct loongarch_kvm_irqchip *chip; ++ struct kvm_loongarch_ls3a_extirq_state *kstate; ++ int ret, length, i, vcpuid; ++#endif ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++#ifdef CONFIG_KVM ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct kvm_loongarch_ls3a_extirq_state); ++ chip = g_malloc0(length); ++ ++ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; ++ chip->len = length; ++ ++ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; ++ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { ++ kstate->ext_en_r.reg_u8[i] = apic->ext_en[i]; ++ kstate->bounce_r.reg_u8[i] = apic->ext_bounce[i]; ++ kstate->ext_isr_r.reg_u8[i] = apic->ext_isr[i]; ++ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { ++ kstate->ext_core_isr_r.reg_u8[vcpuid][i] = ++ apic->ext_coreisr[vcpuid][i]; ++ } ++ } ++ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { ++ kstate->ip_map_r.reg_u8[i] = apic->ext_ipmap[i]; ++ } ++ for (i = 0; i < EXTIOI_IRQS; i++) { ++ kstate->core_map_r.reg_u8[i] = apic->ext_coremap[i]; ++ } ++ for (i = 0; i < 16; i++) { ++ kstate->node_type_r.reg_u16[i] = apic->ext_nodetype[i]; ++ } ++ ++ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ g_free(chip); ++#endif ++ return 0; ++} ++ ++typedef struct nodeApicState { ++ unsigned long addr; ++ int nodeid; ++ apicState *apic; ++} nodeApicState; ++ ++static void ioapic_update_irq(void *opaque, int irq, int level) ++{ ++ apicState *s = opaque; ++ uint8_t ipnum, cpu, cpu_ipnum; ++ unsigned long found1, found2; ++ uint8_t reg_count, reg_bit; ++ ++ reg_count = irq / 32; ++ reg_bit = irq % 32; ++ ++ ipnum = s->ext_sw_ipmap[irq]; ++ cpu = s->ext_sw_coremap[irq]; ++ cpu_ipnum = cpu * LS3A_INTC_IP + ipnum; ++ if (level == 1) { ++ if (test_bit(reg_bit, ((void *)s->ext_en + 0x4 * reg_count)) == ++ false) { ++ return; ++ } ++ ++ if (test_bit(reg_bit, ((void *)s->ext_isr + 0x4 * reg_count)) == ++ false) { ++ return; ++ } ++ bitmap_set(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, ++ 1); ++ found1 = ++ find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), ++ EXTIOI_IRQS, 0); ++ bitmap_set(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), ++ reg_bit, 1); ++ if (found1 >= EXTIOI_IRQS) { ++ qemu_set_irq(s->parent_irq[cpu][ipnum], level); ++ } ++ } else { ++ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); ++ bitmap_clear(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, ++ 1); ++ found1 = ++ find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), ++ EXTIOI_IRQS, 0); ++ found1 += reg_count * 32; ++ bitmap_clear(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), ++ reg_bit, 1); ++ found2 = ++ find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), ++ EXTIOI_IRQS, 0); ++ if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) { ++ qemu_set_irq(s->parent_irq[cpu][ipnum], level); ++ } ++ } ++} ++ ++static void ioapic_setirq(void *opaque, int irq, int level) ++{ ++ apicState *s = opaque; ++ uint8_t reg_count, reg_bit; ++ ++ reg_count = irq / 32; ++ reg_bit = irq % 32; ++ ++ if (level) { ++ bitmap_set(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); ++ } else { ++ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); ++ } ++ ++ ioapic_update_irq(s, irq, level); ++} ++ ++static uint32_t apic_readb(void *opaque, hwaddr addr) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint8_t ret; ++ int cpu; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ ret = 0; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ ret = *(uint8_t *)((void *)state->ext_en + off); ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ ret = *(uint8_t *)((void *)state->ext_bounce + off); ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ ret = *(uint8_t *)((void *)state->ext_isr + off); ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ ret = *(uint8_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ off -= EXTIOI_IPMAP_START; ++ ret = *(uint8_t *)((void *)state->ext_ipmap + off); ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ off -= EXTIOI_COREMAP_START; ++ ret = *(uint8_t *)((void *)state->ext_coremap + off); ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ ret = *(uint8_t *)((void *)state->ext_nodetype + off); ++ } ++ ++ DPRINTF("readb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); ++ return ret; ++} ++ ++static uint32_t apic_readw(void *opaque, hwaddr addr) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint16_t ret; ++ int cpu; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ ret = 0; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ ret = *(uint16_t *)((void *)state->ext_en + off); ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ ret = *(uint16_t *)((void *)state->ext_bounce + off); ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ ret = *(uint16_t *)((void *)state->ext_isr + off); ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ ret = *(uint16_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ off -= EXTIOI_IPMAP_START; ++ ret = *(uint16_t *)((void *)state->ext_ipmap + off); ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ off -= EXTIOI_COREMAP_START; ++ ret = *(uint16_t *)((void *)state->ext_coremap + off); ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ ret = *(uint16_t *)((void *)state->ext_nodetype + off); ++ } ++ ++ DPRINTF("readw reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); ++ return ret; ++} ++ ++static uint32_t apic_readl(void *opaque, hwaddr addr) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint32_t ret; ++ int cpu; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ ret = 0; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ ret = *(uint32_t *)((void *)state->ext_en + off); ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ ret = *(uint32_t *)((void *)state->ext_bounce + off); ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ ret = *(uint32_t *)((void *)state->ext_isr + off); ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ ret = *(uint32_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ off -= EXTIOI_IPMAP_START; ++ ret = *(uint32_t *)((void *)state->ext_ipmap + off); ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ off -= EXTIOI_COREMAP_START; ++ ret = *(uint32_t *)((void *)state->ext_coremap + off); ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ ret = *(uint32_t *)((void *)state->ext_nodetype + off); ++ } ++ ++ DPRINTF("readl reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); ++ return ret; ++} ++ ++static void apic_writeb(void *opaque, hwaddr addr, uint32_t val) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint8_t old; ++ int cpu, i, ipnum, level, mask; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ old = *(uint8_t *)((void *)state->ext_en + off); ++ if (old != val) { ++ *(uint8_t *)((void *)state->ext_en + off) = val; ++ old = old ^ val; ++ mask = 0x1; ++ for (i = 0; i < 8; i++) { ++ if (old & mask) { ++ level = !!(val & (0x1 << i)); ++ ioapic_update_irq(state, i + off * 8, level); ++ } ++ mask = mask << 1; ++ } ++ } ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ *(uint8_t *)((void *)state->ext_bounce + off) = val; ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ old = *(uint8_t *)((void *)state->ext_isr + off); ++ *(uint8_t *)((void *)state->ext_isr + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 8; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ off = off & 0x1f; ++ old = *(uint8_t *)((void *)state->ext_coreisr[cpu] + off); ++ *(uint8_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 8; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ off -= EXTIOI_IPMAP_START; ++ val = val & 0xf; ++ *(uint8_t *)((void *)state->ext_ipmap + off) = val; ++ ipnum = 0; ++ for (i = 0; i < 4; i++) { ++ if (val & (0x1 << i)) { ++ ipnum = i; ++ break; ++ } ++ } ++ if (val) { ++ for (i = 0; i < 32; i++) { ++ cpu = off * 32 + i; ++ state->ext_sw_ipmap[cpu] = ipnum; ++ } ++ } ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ off -= EXTIOI_COREMAP_START; ++ val = val & 0xff; ++ *(uint8_t *)((void *)state->ext_coremap + off) = val; ++ state->ext_sw_coremap[off] = val; ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ *(uint8_t *)((void *)state->ext_nodetype + off) = val; ++ } ++ ++ DPRINTF("writeb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); ++} ++ ++static void apic_writew(void *opaque, hwaddr addr, uint32_t val) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint16_t old; ++ int cpu, i, level, mask; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ old = *(uint16_t *)((void *)state->ext_en + off); ++ if (old != val) { ++ *(uint16_t *)((void *)state->ext_en + off) = val; ++ old = old ^ val; ++ mask = 0x1; ++ for (i = 0; i < 16; i++) { ++ if (old & mask) { ++ level = !!(val & (0x1 << i)); ++ ioapic_update_irq(state, i + off * 8, level); ++ } ++ mask = mask << 1; ++ } ++ } ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ *(uint16_t *)((void *)state->ext_bounce + off) = val; ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ old = *(uint16_t *)((void *)state->ext_isr + off); ++ *(uint16_t *)((void *)state->ext_isr + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 16; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ off = off & 0x1f; ++ old = *(uint16_t *)((void *)state->ext_coreisr[cpu] + off); ++ *(uint16_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 16; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ apic_writeb(opaque, addr, val & 0xff); ++ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); ++ ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ apic_writeb(opaque, addr, val & 0xff); ++ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); ++ ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ *(uint16_t *)((void *)state->ext_nodetype + off) = val; ++ } ++ ++ DPRINTF("writew reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); ++} ++ ++static void apic_writel(void *opaque, hwaddr addr, uint32_t val) ++{ ++ nodeApicState *node; ++ apicState *state; ++ unsigned long off; ++ uint32_t old; ++ int cpu, i, level, mask; ++ ++ node = (nodeApicState *)opaque; ++ state = node->apic; ++ off = addr & 0xfffff; ++ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { ++ off -= EXTIOI_ENABLE_START; ++ old = *(uint32_t *)((void *)state->ext_en + off); ++ if (old != val) { ++ *(uint32_t *)((void *)state->ext_en + off) = val; ++ old = old ^ val; ++ mask = 0x1; ++ for (i = 0; i < 32; i++) { ++ if (old & mask) { ++ level = !!(val & (0x1 << i)); ++ ioapic_update_irq(state, i + off * 8, level); ++ } ++ mask = mask << 1; ++ } ++ } ++ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { ++ off -= EXTIOI_BOUNCE_START; ++ *(uint32_t *)((void *)state->ext_bounce + off) = val; ++ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { ++ off -= EXTIOI_ISR_START; ++ old = *(uint32_t *)((void *)state->ext_isr + off); ++ *(uint32_t *)((void *)state->ext_isr + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 32; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { ++ off -= EXTIOI_COREISR_START; ++ cpu = (off >> 8) & 0xff; ++ off = off & 0x1f; ++ old = *(uint32_t *)((void *)state->ext_coreisr[cpu] + off); ++ *(uint32_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; ++ mask = 0x1; ++ for (i = 0; i < 32; i++) { ++ if ((old & mask) && (val & mask)) { ++ ioapic_update_irq(state, i + off * 8, 0); ++ } ++ mask = mask << 1; ++ } ++ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { ++ apic_writeb(opaque, addr, val & 0xff); ++ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); ++ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); ++ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); ++ ++ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { ++ apic_writeb(opaque, addr, val & 0xff); ++ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); ++ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); ++ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); ++ ++ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { ++ off -= EXTIOI_NODETYPE_START; ++ *(uint32_t *)((void *)state->ext_nodetype + off) = val; ++ } ++ ++ DPRINTF("writel reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); ++} ++ ++static uint64_t apic_readfn(void *opaque, hwaddr addr, unsigned size) ++{ ++ switch (size) { ++ case 1: ++ return apic_readb(opaque, addr); ++ case 2: ++ return apic_readw(opaque, addr); ++ case 4: ++ return apic_readl(opaque, addr); ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void apic_writefn(void *opaque, hwaddr addr, uint64_t value, ++ unsigned size) ++{ ++ switch (size) { ++ case 1: ++ apic_writeb(opaque, addr, value); ++ break; ++ case 2: ++ apic_writew(opaque, addr, value); ++ break; ++ case 4: ++ apic_writel(opaque, addr, value); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static const VMStateDescription vmstate_apic = { ++ .name = "apic", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = ext_irq_pre_save, ++ .post_load = ext_irq_post_load, ++ .fields = ++ (VMStateField[]){ ++ VMSTATE_UINT8_ARRAY(ext_en, apicState, EXTIOI_IRQS_BITMAP_SIZE), ++ VMSTATE_UINT8_ARRAY(ext_bounce, apicState, ++ EXTIOI_IRQS_BITMAP_SIZE), ++ VMSTATE_UINT8_ARRAY(ext_isr, apicState, EXTIOI_IRQS_BITMAP_SIZE), ++ VMSTATE_UINT8_2DARRAY(ext_coreisr, apicState, MAX_CORES, ++ EXTIOI_IRQS_BITMAP_SIZE), ++ VMSTATE_UINT8_ARRAY(ext_ipmap, apicState, EXTIOI_IRQS_IPMAP_SIZE), ++ VMSTATE_UINT8_ARRAY(ext_coremap, apicState, EXTIOI_IRQS), ++ VMSTATE_UINT16_ARRAY(ext_nodetype, apicState, 16), ++ VMSTATE_UINT64(ext_control, apicState), ++ VMSTATE_UINT8_ARRAY(ext_sw_ipmap, apicState, EXTIOI_IRQS), ++ VMSTATE_UINT8_ARRAY(ext_sw_coremap, apicState, EXTIOI_IRQS), ++ VMSTATE_UINT8_2DARRAY(ext_ipisr, apicState, ++ MAX_CORES *LS3A_INTC_IP, ++ EXTIOI_IRQS_BITMAP_SIZE), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static const MemoryRegionOps apic_ops = { ++ .read = apic_readfn, ++ .write = apic_writefn, ++ .impl.min_access_size = 1, ++ .impl.max_access_size = 4, ++ .valid.min_access_size = 1, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++}; ++ ++int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu) ++{ ++ apicState *apic; ++ nodeApicState *node; ++ MemoryRegion *iomem; ++ unsigned long base; ++ int pin; ++ char str[32]; ++ ++ if (ms->apic == NULL) { ++ apic = g_malloc0(sizeof(apicState)); ++ vmstate_register(NULL, 0, &vmstate_apic, apic); ++ apic->irq = qemu_allocate_irqs(ioapic_setirq, apic, EXTIOI_IRQS); ++ ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ /* cpu_pin[9:2] <= intc_pin[7:0] */ ++ apic->parent_irq[cpu][pin] = env->irq[pin + 2]; ++ } ++ ms->apic = apic; ++ ++ if (cpu == 0) { ++ base = APIC_BASE; ++ node = g_malloc0(sizeof(nodeApicState)); ++ node->apic = ms->apic; ++ node->addr = base; ++ ++ iomem = g_new(MemoryRegion, 1); ++ sprintf(str, "apic%d", cpu); ++ /* extioi addr 0x1f010000~0x1f02ffff */ ++ memory_region_init_io(iomem, NULL, &apic_ops, node, str, 0x20000); ++ memory_region_add_subregion(get_system_memory(), base, iomem); ++ } ++ ++ } else { ++ if (cpu != 0) { ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ ms->apic->parent_irq[cpu][pin] = env->irq[pin + 2]; ++ } ++ } ++ } ++ return 0; ++} +diff --git a/hw/loongarch/ioapic.c b/hw/loongarch/ioapic.c +new file mode 100644 +index 0000000000..102102781f +--- /dev/null ++++ b/hw/loongarch/ioapic.c +@@ -0,0 +1,419 @@ ++/* ++ * LS7A1000 Northbridge IOAPIC support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "hw/irq.h" ++#include "qemu/log.h" ++#include "sysemu/kvm.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++ ++#define DEBUG_LS7A_APIC 0 ++ ++#define DPRINTF(fmt, ...) \ ++ do { \ ++ if (DEBUG_LS7A_APIC) { \ ++ fprintf(stderr, "IOAPIC: " fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define TYPE_LS7A_APIC "ioapic" ++#define LS7A_APIC(obj) OBJECT_CHECK(LS7AApicState, (obj), TYPE_LS7A_APIC) ++ ++#define LS7A_IOAPIC_ROUTE_ENTRY_OFFSET 0x100 ++#define LS7A_IOAPIC_INT_ID_OFFSET 0x00 ++#define LS7A_INT_ID_VAL 0x7000000UL ++#define LS7A_INT_ID_VER 0x1f0001UL ++#define LS7A_IOAPIC_INT_MASK_OFFSET 0x20 ++#define LS7A_IOAPIC_INT_EDGE_OFFSET 0x60 ++#define LS7A_IOAPIC_INT_CLEAR_OFFSET 0x80 ++#define LS7A_IOAPIC_INT_STATUS_OFFSET 0x3a0 ++#define LS7A_IOAPIC_INT_POL_OFFSET 0x3e0 ++#define LS7A_IOAPIC_HTMSI_EN_OFFSET 0x40 ++#define LS7A_IOAPIC_HTMSI_VEC_OFFSET 0x200 ++#define LS7A_AUTO_CTRL0_OFFSET 0xc0 ++#define LS7A_AUTO_CTRL1_OFFSET 0xe0 ++ ++typedef struct LS7AApicState { ++ SysBusDevice parent_obj; ++ qemu_irq parent_irq[257]; ++ uint64_t int_id; ++ uint64_t int_mask; /*0x020 interrupt mask register*/ ++ uint64_t htmsi_en; /*0x040 1=msi*/ ++ uint64_t intedge; /*0x060 edge=1 level =0*/ ++ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ ++ uint64_t auto_crtl0; /*0x0c0*/ ++ uint64_t auto_crtl1; /*0x0e0*/ ++ uint8_t route_entry[64]; /*0x100 - 0x140*/ ++ uint8_t htmsi_vector[64]; /*0x200 - 0x240*/ ++ uint64_t intisr_chip0; /*0x300*/ ++ uint64_t intisr_chip1; /*0x320*/ ++ uint64_t last_intirr; /* edge detection */ ++ uint64_t intirr; /* 0x380 interrupt request register */ ++ uint64_t intisr; /* 0x3a0 interrupt service register */ ++ /* ++ * 0x3e0 interrupt level polarity ++ * selection register 0 for high level tirgger ++ */ ++ uint64_t int_polarity; ++ MemoryRegion iomem; ++} LS7AApicState; ++ ++static void update_irq(LS7AApicState *s) ++{ ++ int i; ++ if ((s->intirr & (~s->int_mask)) & (~s->htmsi_en)) { ++ DPRINTF("7a update irqline up\n"); ++ s->intisr = (s->intirr & (~s->int_mask) & (~s->htmsi_en)); ++ qemu_set_irq(s->parent_irq[256], 1); ++ } else { ++ DPRINTF("7a update irqline down\n"); ++ s->intisr &= (~s->htmsi_en); ++ qemu_set_irq(s->parent_irq[256], 0); ++ } ++ if (s->htmsi_en) { ++ for (i = 0; i < 64; i++) { ++ if ((((~s->intisr) & s->intirr) & s->htmsi_en) & (1ULL << i)) { ++ s->intisr |= 1ULL << i; ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1); ++ } else if (((~(s->intisr | s->intirr)) & s->htmsi_en) & ++ (1ULL << i)) { ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0); ++ } ++ } ++ } ++} ++ ++static void irq_handler(void *opaque, int irq, int level) ++{ ++ LS7AApicState *s = opaque; ++ ++ assert(irq < 64); ++ uint64_t mask = 1ULL << irq; ++ DPRINTF("------ %s irq %d %d\n", __func__, irq, level); ++ ++ if (s->intedge & mask) { ++ /* edge triggered */ ++ /*TODO*/ ++ } else { ++ /* level triggered */ ++ if (level) { ++ s->intirr |= mask; ++ } else { ++ s->intirr &= ~mask; ++ } ++ } ++ update_irq(s); ++} ++ ++static uint64_t ls7a_apic_reg_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ LS7AApicState *a = opaque; ++ uint64_t val = 0; ++ uint64_t offset; ++ int64_t offset_tmp; ++ offset = addr & 0xfff; ++ if (8 == size) { ++ switch (offset) { ++ case LS7A_IOAPIC_INT_ID_OFFSET: ++ val = LS7A_INT_ID_VER; ++ val = (val << 32) + LS7A_INT_ID_VAL; ++ break; ++ case LS7A_IOAPIC_INT_MASK_OFFSET: ++ val = a->int_mask; ++ break; ++ case LS7A_IOAPIC_INT_STATUS_OFFSET: ++ val = a->intisr & (~a->int_mask); ++ break; ++ case LS7A_IOAPIC_INT_EDGE_OFFSET: ++ val = a->intedge; ++ break; ++ case LS7A_IOAPIC_INT_POL_OFFSET: ++ val = a->int_polarity; ++ break; ++ case LS7A_IOAPIC_HTMSI_EN_OFFSET: ++ val = a->htmsi_en; ++ break; ++ case LS7A_AUTO_CTRL0_OFFSET: ++ case LS7A_AUTO_CTRL1_OFFSET: ++ break; ++ default: ++ break; ++ } ++ } else if (1 == size) { ++ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { ++ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; ++ if (offset_tmp >= 0 && offset_tmp < 64) { ++ val = a->htmsi_vector[offset_tmp]; ++ } ++ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { ++ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; ++ if (offset_tmp >= 0 && offset_tmp < 64) { ++ val = a->route_entry[offset_tmp]; ++ DPRINTF("addr %lx val %lx\n", addr, val); ++ } ++ } ++ } ++ DPRINTF(TARGET_FMT_plx " val %lx\n", addr, val); ++ return val; ++} ++ ++static void ls7a_apic_reg_write(void *opaque, hwaddr addr, uint64_t data, ++ unsigned size) ++{ ++ LS7AApicState *a = opaque; ++ int64_t offset_tmp; ++ uint64_t offset; ++ offset = addr & 0xfff; ++ DPRINTF(TARGET_FMT_plx " size %d val %lx\n", addr, size, data); ++ if (8 == size) { ++ switch (offset) { ++ case LS7A_IOAPIC_INT_MASK_OFFSET: ++ a->int_mask = data; ++ update_irq(a); ++ break; ++ case LS7A_IOAPIC_INT_STATUS_OFFSET: ++ a->intisr = data; ++ break; ++ case LS7A_IOAPIC_INT_EDGE_OFFSET: ++ a->intedge = data; ++ break; ++ case LS7A_IOAPIC_INT_CLEAR_OFFSET: ++ a->intisr &= (~data); ++ update_irq(a); ++ break; ++ case LS7A_IOAPIC_INT_POL_OFFSET: ++ a->int_polarity = data; ++ break; ++ case LS7A_IOAPIC_HTMSI_EN_OFFSET: ++ a->htmsi_en = data; ++ break; ++ case LS7A_AUTO_CTRL0_OFFSET: ++ case LS7A_AUTO_CTRL1_OFFSET: ++ break; ++ default: ++ break; ++ } ++ } else if (1 == size) { ++ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { ++ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; ++ if (offset_tmp >= 0 && offset_tmp < 64) { ++ a->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); ++ } ++ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { ++ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; ++ if (offset_tmp >= 0 && offset_tmp < 64) { ++ a->route_entry[offset_tmp] = (uint8_t)(data & 0xff); ++ } ++ } ++ } ++} ++ ++static const MemoryRegionOps ls7a_apic_ops = { ++ .read = ls7a_apic_reg_read, ++ .write = ls7a_apic_reg_write, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++}; ++ ++static int kvm_ls7a_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ LS7AApicState *s = opaque; ++ struct loongarch_kvm_irqchip *chip; ++ struct ls7a_ioapic_state *state; ++ int ret, i, length; ++ ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++ ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct ls7a_ioapic_state); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; ++ chip->len = length; ++ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ state = (struct ls7a_ioapic_state *)chip->data; ++ s->int_id = state->int_id; ++ s->int_mask = state->int_mask; ++ s->htmsi_en = state->htmsi_en; ++ s->intedge = state->intedge; ++ s->intclr = state->intclr; ++ s->auto_crtl0 = state->auto_crtl0; ++ s->auto_crtl1 = state->auto_crtl1; ++ for (i = 0; i < 64; i++) { ++ s->route_entry[i] = state->route_entry[i]; ++ s->htmsi_vector[i] = state->htmsi_vector[i]; ++ } ++ s->intisr_chip0 = state->intisr_chip0; ++ s->intisr_chip1 = state->intisr_chip1; ++ s->intirr = state->intirr; ++ s->intisr = state->intisr; ++ s->int_polarity = state->int_polarity; ++ g_free(chip); ++#endif ++ return 0; ++} ++ ++static int kvm_ls7a_post_load(void *opaque, int version) ++{ ++#ifdef CONFIG_KVM ++ LS7AApicState *s = opaque; ++ struct loongarch_kvm_irqchip *chip; ++ struct ls7a_ioapic_state *state; ++ int ret, i, length; ++ ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct ls7a_ioapic_state); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; ++ chip->len = length; ++ ++ state = (struct ls7a_ioapic_state *)chip->data; ++ state->int_id = s->int_id; ++ state->int_mask = s->int_mask; ++ state->htmsi_en = s->htmsi_en; ++ state->intedge = s->intedge; ++ state->intclr = s->intclr; ++ state->auto_crtl0 = s->auto_crtl0; ++ state->auto_crtl1 = s->auto_crtl1; ++ for (i = 0; i < 64; i++) { ++ state->route_entry[i] = s->route_entry[i]; ++ state->htmsi_vector[i] = s->htmsi_vector[i]; ++ } ++ state->intisr_chip0 = s->intisr_chip0; ++ state->intisr_chip1 = s->intisr_chip1; ++ state->last_intirr = 0; ++ state->intirr = s->intirr; ++ state->intisr = s->intisr; ++ state->int_polarity = s->int_polarity; ++ ++ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ g_free(chip); ++#endif ++ return 0; ++} ++ ++static void ls7a_apic_reset(DeviceState *d) ++{ ++ LS7AApicState *s = LS7A_APIC(d); ++ int i; ++ ++ s->int_id = 0x001f000107000000; ++ s->int_mask = 0xffffffffffffffff; ++ s->htmsi_en = 0x0; ++ s->intedge = 0x0; ++ s->intclr = 0x0; ++ s->auto_crtl0 = 0x0; ++ s->auto_crtl1 = 0x0; ++ for (i = 0; i < 64; i++) { ++ s->route_entry[i] = 0x1; ++ s->htmsi_vector[i] = 0x0; ++ } ++ s->intisr_chip0 = 0x0; ++ s->intisr_chip1 = 0x0; ++ s->intirr = 0x0; ++ s->intisr = 0x0; ++ s->int_polarity = 0x0; ++ kvm_ls7a_post_load(s, 0); ++} ++ ++static void ls7a_apic_init(Object *obj) ++{ ++ DeviceState *dev = DEVICE(obj); ++ LS7AApicState *s = LS7A_APIC(obj); ++ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); ++ int tmp; ++ memory_region_init_io(&s->iomem, obj, &ls7a_apic_ops, s, TYPE_LS7A_APIC, ++ 0x1000); ++ sysbus_init_mmio(sbd, &s->iomem); ++ for (tmp = 0; tmp < 257; tmp++) { ++ sysbus_init_irq(sbd, &s->parent_irq[tmp]); ++ } ++ qdev_init_gpio_in(dev, irq_handler, 64); ++} ++ ++static const VMStateDescription vmstate_ls7a_apic = { ++ .name = TYPE_LS7A_APIC, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_ls7a_pre_save, ++ .post_load = kvm_ls7a_post_load, ++ .fields = ++ (VMStateField[]){ VMSTATE_UINT64(int_mask, LS7AApicState), ++ VMSTATE_UINT64(htmsi_en, LS7AApicState), ++ VMSTATE_UINT64(intedge, LS7AApicState), ++ VMSTATE_UINT64(intclr, LS7AApicState), ++ VMSTATE_UINT64(auto_crtl0, LS7AApicState), ++ VMSTATE_UINT64(auto_crtl1, LS7AApicState), ++ VMSTATE_UINT8_ARRAY(route_entry, LS7AApicState, 64), ++ VMSTATE_UINT8_ARRAY(htmsi_vector, LS7AApicState, 64), ++ VMSTATE_UINT64(intisr_chip0, LS7AApicState), ++ VMSTATE_UINT64(intisr_chip1, LS7AApicState), ++ VMSTATE_UINT64(last_intirr, LS7AApicState), ++ VMSTATE_UINT64(intirr, LS7AApicState), ++ VMSTATE_UINT64(intisr, LS7AApicState), ++ VMSTATE_UINT64(int_polarity, LS7AApicState), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static void ls7a_apic_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->reset = ls7a_apic_reset; ++ dc->vmsd = &vmstate_ls7a_apic; ++} ++ ++static const TypeInfo ls7a_apic_info = { ++ .name = TYPE_LS7A_APIC, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(LS7AApicState), ++ .instance_init = ls7a_apic_init, ++ .class_init = ls7a_apic_class_init, ++}; ++ ++static void ls7a_apic_register_types(void) ++{ ++ type_register_static(&ls7a_apic_info); ++} ++ ++type_init(ls7a_apic_register_types) +diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c +new file mode 100644 +index 0000000000..a1eb54bdd2 +--- /dev/null ++++ b/hw/loongarch/iocsr.c +@@ -0,0 +1,227 @@ ++/* ++ * LOONGARCH IOCSR support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "qemu/log.h" ++#include "sysemu/kvm.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "hw/boards.h" ++#include "hw/loongarch/larch.h" ++ ++#define BIT_ULL(nr) (1ULL << (nr)) ++#define LOONGARCH_IOCSR_FEATURES 0x8 ++#define IOCSRF_TEMP BIT_ULL(0) ++#define IOCSRF_NODECNT BIT_ULL(1) ++#define IOCSRF_MSI BIT_ULL(2) ++#define IOCSRF_EXTIOI BIT_ULL(3) ++#define IOCSRF_CSRIPI BIT_ULL(4) ++#define IOCSRF_FREQCSR BIT_ULL(5) ++#define IOCSRF_FREQSCALE BIT_ULL(6) ++#define IOCSRF_DVFSV1 BIT_ULL(7) ++#define IOCSRF_GMOD BIT_ULL(9) ++#define IOCSRF_VM BIT_ULL(11) ++#define LOONGARCH_IOCSR_VENDOR 0x10 ++#define LOONGARCH_IOCSR_CPUNAME 0x20 ++#define LOONGARCH_IOCSR_NODECNT 0x408 ++#define LOONGARCH_IOCSR_MISC_FUNC 0x420 ++#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) ++#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) ++ ++enum { ++ IOCSR_FEATURES, ++ IOCSR_VENDOR, ++ IOCSR_CPUNAME, ++ IOCSR_NODECNT, ++ IOCSR_MISC_FUNC, ++ IOCSR_MAX ++}; ++ ++#ifdef CONFIG_KVM ++static uint32_t iocsr_array[IOCSR_MAX] = { ++ [IOCSR_FEATURES] = LOONGARCH_IOCSR_FEATURES, ++ [IOCSR_VENDOR] = LOONGARCH_IOCSR_VENDOR, ++ [IOCSR_CPUNAME] = LOONGARCH_IOCSR_CPUNAME, ++ [IOCSR_NODECNT] = LOONGARCH_IOCSR_NODECNT, ++ [IOCSR_MISC_FUNC] = LOONGARCH_IOCSR_MISC_FUNC, ++}; ++#endif ++ ++#define TYPE_IOCSR "iocsr" ++#define IOCSR(obj) OBJECT_CHECK(IOCSRState, (obj), TYPE_IOCSR) ++ ++typedef struct IOCSRState { ++ SysBusDevice parent_obj; ++ uint64_t iocsr_val[IOCSR_MAX]; ++} IOCSRState; ++ ++IOCSRState iocsr_init = { .iocsr_val = { ++ IOCSRF_NODECNT | IOCSRF_MSI | IOCSRF_EXTIOI | ++ IOCSRF_CSRIPI | IOCSRF_GMOD | IOCSRF_VM, ++ 0x6e6f73676e6f6f4c, /* Loongson */ ++ 0x303030354133, /*3A5000*/ ++ 0x4, ++ 0x0, ++ } }; ++ ++static int kvm_iocsr_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ IOCSRState *s = opaque; ++ struct kvm_iocsr_entry entry; ++ int i = 0; ++ ++ if ((!kvm_enabled())) { ++ return 0; ++ } ++ ++ for (i = 0; i < IOCSR_MAX; i++) { ++ entry.addr = iocsr_array[i]; ++ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_GET_IOCSR, &entry); ++ s->iocsr_val[i] = entry.data; ++ } ++#endif ++ return 0; ++} ++ ++static int kvm_iocsr_post_load(void *opaque, int version) ++{ ++#ifdef CONFIG_KVM ++ IOCSRState *s = opaque; ++ struct kvm_iocsr_entry entry; ++ int i = 0; ++ ++ if (!kvm_enabled()) { ++ return 0; ++ } ++ ++ for (i = 0; i < IOCSR_MAX; i++) { ++ entry.addr = iocsr_array[i]; ++ entry.data = s->iocsr_val[i]; ++ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_SET_IOCSR, &entry); ++ } ++#endif ++ return 0; ++} ++ ++static void iocsr_reset(DeviceState *d) ++{ ++ IOCSRState *s = IOCSR(d); ++ int i; ++ ++ for (i = 0; i < IOCSR_MAX; i++) { ++ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; ++ } ++ kvm_iocsr_post_load(s, 0); ++} ++ ++static void init_vendor_cpuname(uint64_t *vendor, uint64_t *cpu_name, ++ char *cpuname) ++{ ++ int i = 0, len = 0; ++ char *index = NULL, *index_end = NULL; ++ char *vendor_c = (char *)vendor; ++ char *cpu_name_c = (char *)cpu_name; ++ ++ index = strstr(cpuname, "-"); ++ len = strlen(cpuname); ++ if ((index == NULL) || (len <= 0)) { ++ return; ++ } ++ ++ *vendor = 0; ++ *cpu_name = 0; ++ index_end = cpuname + len; ++ ++ while (((cpuname + i) < index) && (i < sizeof(uint64_t))) { ++ vendor_c[i] = cpuname[i]; ++ i++; ++ } ++ ++ index += 1; ++ i = 0; ++ ++ while (((index + i) < index_end) && (i < sizeof(uint64_t))) { ++ cpu_name_c[i] = index[i]; ++ i++; ++ } ++ ++ return; ++} ++ ++static void iocsr_instance_init(Object *obj) ++{ ++ IOCSRState *s = IOCSR(obj); ++ int i; ++ LoongarchMachineState *lsms; ++ LoongarchMachineClass *lsmc; ++ Object *machine = qdev_get_machine(); ++ ObjectClass *mc = object_get_class(machine); ++ ++ /* 'lams' should be initialized */ ++ if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { ++ return; ++ } ++ ++ lsms = LoongarchMACHINE(machine); ++ lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ ++ init_vendor_cpuname((uint64_t *)&iocsr_init.iocsr_val[IOCSR_VENDOR], ++ (uint64_t *)&iocsr_init.iocsr_val[IOCSR_CPUNAME], ++ lsmc->cpu_name); ++ ++ for (i = 0; i < IOCSR_MAX; i++) { ++ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; ++ } ++} ++ ++static const VMStateDescription vmstate_iocsr = { ++ .name = TYPE_IOCSR, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_iocsr_pre_save, ++ .post_load = kvm_iocsr_post_load, ++ .fields = (VMStateField[]){ VMSTATE_UINT64_ARRAY(iocsr_val, IOCSRState, ++ IOCSR_MAX), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static void iocsr_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->reset = iocsr_reset; ++ dc->vmsd = &vmstate_iocsr; ++} ++ ++static const TypeInfo iocsr_info = { ++ .name = TYPE_IOCSR, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(IOCSRState), ++ .instance_init = iocsr_instance_init, ++ .class_init = iocsr_class_init, ++}; ++ ++static void iocsr_register_types(void) ++{ ++ type_register_static(&iocsr_info); ++} ++ ++type_init(iocsr_register_types) +diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c +new file mode 100644 +index 0000000000..affa97392e +--- /dev/null ++++ b/hw/loongarch/ipi.c +@@ -0,0 +1,284 @@ ++/* ++ * LOONGARCH IPI support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/units.h" ++#include "qapi/error.h" ++#include "hw/hw.h" ++#include "hw/irq.h" ++#include "hw/loongarch/cpudevs.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/cpus.h" ++#include "sysemu/kvm.h" ++#include "hw/core/cpu.h" ++#include "qemu/log.h" ++#include "hw/loongarch/bios.h" ++#include "elf.h" ++#include "linux/kvm.h" ++#include "hw/loongarch/larch.h" ++#include "hw/loongarch/ls7a.h" ++#include "migration/vmstate.h" ++ ++static int gipi_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ gipiState *state = opaque; ++ struct loongarch_gipiState *kstate; ++ struct loongarch_kvm_irqchip *chip; ++ int ret, i, j, length; ++#endif ++ ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++ ++#ifdef CONFIG_KVM ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct loongarch_gipiState); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; ++ chip->len = length; ++ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ ++ kstate = (struct loongarch_gipiState *)chip->data; ++ ++ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { ++ state->core[i].status = kstate->core[i].status; ++ state->core[i].en = kstate->core[i].en; ++ state->core[i].set = kstate->core[i].set; ++ state->core[i].clear = kstate->core[i].clear; ++ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { ++ state->core[i].buf[j] = kstate->core[i].buf[j]; ++ } ++ } ++ g_free(chip); ++#endif ++ ++ return 0; ++} ++ ++static int gipi_post_load(void *opaque, int version) ++{ ++#ifdef CONFIG_KVM ++ gipiState *state = opaque; ++ struct loongarch_gipiState *kstate; ++ struct loongarch_kvm_irqchip *chip; ++ int ret, i, j, length; ++#endif ++ ++ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { ++ return 0; ++ } ++ ++#ifdef CONFIG_KVM ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct loongarch_gipiState); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; ++ chip->len = length; ++ kstate = (struct loongarch_gipiState *)chip->data; ++ ++ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { ++ kstate->core[i].status = state->core[i].status; ++ kstate->core[i].en = state->core[i].en; ++ kstate->core[i].set = state->core[i].set; ++ kstate->core[i].clear = state->core[i].clear; ++ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { ++ kstate->core[i].buf[j] = state->core[i].buf[j]; ++ } ++ } ++ ++ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); ++ if (ret < 0) { ++ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); ++ abort(); ++ } ++ g_free(chip); ++#endif ++ return 0; ++} ++ ++static const VMStateDescription vmstate_gipi_core = { ++ .name = "gipi-single", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .fields = ++ (VMStateField[]){ ++ VMSTATE_UINT32(status, gipi_core), VMSTATE_UINT32(en, gipi_core), ++ VMSTATE_UINT32(set, gipi_core), VMSTATE_UINT32(clear, gipi_core), ++ VMSTATE_UINT64_ARRAY(buf, gipi_core, MAX_GIPI_MBX_NUM), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static const VMStateDescription vmstate_gipi = { ++ .name = "gipi", ++ .pre_save = gipi_pre_save, ++ .post_load = gipi_post_load, ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .fields = (VMStateField[]){ VMSTATE_STRUCT_ARRAY( ++ core, gipiState, MAX_GIPI_CORE_NUM, 0, ++ vmstate_gipi_core, gipi_core), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static void gipi_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) ++{ ++ gipi_core *s = opaque; ++ gipi_core *ss; ++ void *pbuf; ++ uint32_t cpu, action_data, mailaddr; ++ LoongarchMachineState *ms = LoongarchMACHINE(qdev_get_machine()); ++ ++ if ((size != 4) && (size != 8)) { ++ hw_error("size not 4 and not 8"); ++ } ++ addr &= 0xff; ++ switch (addr) { ++ case CORE0_STATUS_OFF: ++ hw_error("CORE0_STATUS_OFF Can't be write\n"); ++ break; ++ case CORE0_EN_OFF: ++ s->en = val; ++ break; ++ case CORE0_IPI_SEND: ++ cpu = (val >> 16) & 0x3ff; ++ action_data = 1UL << (val & 0x1f); ++ ss = &ms->gipi->core[cpu]; ++ ss->status |= action_data; ++ if (ss->status != 0) { ++ qemu_irq_raise(ss->irq); ++ } ++ break; ++ case CORE0_MAIL_SEND: ++ cpu = (val >> 16) & 0x3ff; ++ mailaddr = (val >> 2) & 0x7; ++ ss = &ms->gipi->core[cpu]; ++ pbuf = (void *)ss->buf + mailaddr * 4; ++ *(unsigned int *)pbuf = (val >> 32); ++ break; ++ case CORE0_SET_OFF: ++ hw_error("CORE0_SET_OFF Can't be write\n"); ++ break; ++ case CORE0_CLEAR_OFF: ++ s->status ^= val; ++ if (s->status == 0) { ++ qemu_irq_lower(s->irq); ++ } ++ break; ++ case 0x20 ... 0x3c: ++ pbuf = (void *)s->buf + (addr - 0x20); ++ if (size == 1) { ++ *(unsigned char *)pbuf = (unsigned char)val; ++ } else if (size == 2) { ++ *(unsigned short *)pbuf = (unsigned short)val; ++ } else if (size == 4) { ++ *(unsigned int *)pbuf = (unsigned int)val; ++ } else if (size == 8) { ++ *(unsigned long *)pbuf = (unsigned long)val; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static uint64_t gipi_readl(void *opaque, hwaddr addr, unsigned size) ++{ ++ gipi_core *s = opaque; ++ uint64_t ret = 0; ++ void *pbuf; ++ ++ addr &= 0xff; ++ if ((size != 4) && (size != 8)) { ++ hw_error("size not 4 and not 8 size:%d\n", size); ++ } ++ switch (addr) { ++ case CORE0_STATUS_OFF: ++ ret = s->status; ++ break; ++ case CORE0_EN_OFF: ++ ret = s->en; ++ break; ++ case CORE0_SET_OFF: ++ ret = 0; ++ break; ++ case CORE0_CLEAR_OFF: ++ ret = 0; ++ break; ++ case 0x20 ... 0x3c: ++ pbuf = (void *)s->buf + (addr - 0x20); ++ if (size == 1) { ++ ret = *(unsigned char *)pbuf; ++ } else if (size == 2) { ++ ret = *(unsigned short *)pbuf; ++ } else if (size == 4) { ++ ret = *(unsigned int *)pbuf; ++ } else if (size == 8) { ++ ret = *(unsigned long *)pbuf; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static const MemoryRegionOps gipi_ops = { ++ .read = gipi_readl, ++ .write = gipi_writel, ++ .valid = { ++ .min_access_size = 4, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 4, ++ .max_access_size = 8, ++ }, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++}; ++ ++int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu) ++{ ++ hwaddr addr; ++ MemoryRegion *region; ++ char str[32]; ++ ++ if (ms->gipi == NULL) { ++ ms->gipi = g_malloc0(sizeof(gipiState)); ++ vmstate_register(NULL, 0, &vmstate_gipi, ms->gipi); ++ } ++ ++ ms->gipi->core[cpu].irq = parent; ++ ++ addr = SMP_GIPI_MAILBOX | (cpu << 8); ++ region = g_new(MemoryRegion, 1); ++ sprintf(str, "gipi%d", cpu); ++ memory_region_init_io(region, NULL, &gipi_ops, &ms->gipi->core[cpu], str, ++ 0x100); ++ memory_region_add_subregion(get_system_memory(), addr, region); ++ return 0; ++} +diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c +new file mode 100644 +index 0000000000..fe786008ac +--- /dev/null ++++ b/hw/loongarch/larch_3a.c +@@ -0,0 +1,2063 @@ ++/* ++ * QEMU loongarch 3a develop board emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/units.h" ++#include "qapi/error.h" ++#include "qemu/datadir.h" ++#include "hw/hw.h" ++#include "hw/loongarch/cpudevs.h" ++#include "hw/i386/pc.h" ++#include "hw/char/serial.h" ++#include "hw/isa/isa.h" ++#include "hw/qdev-core.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/runstate.h" ++#include "sysemu/reset.h" ++#include "migration/vmstate.h" ++#include "sysemu/cpus.h" ++#include "hw/boards.h" ++#include "qemu/log.h" ++#include "hw/loongarch/bios.h" ++#include "hw/loader.h" ++#include "elf.h" ++#include "exec/address-spaces.h" ++#include "hw/ide.h" ++#include "hw/pci/pci_host.h" ++#include "hw/pci/msi.h" ++#include "linux/kvm.h" ++#include "sysemu/kvm.h" ++#include "sysemu/numa.h" ++#include "hw/rtc/mc146818rtc.h" ++#include "hw/irq.h" ++#include "net/net.h" ++#include "hw/platform-bus.h" ++#include "hw/timer/i8254.h" ++#include "hw/loongarch/larch.h" ++#include "hw/loongarch/ls7a.h" ++#include "hw/nvram/fw_cfg.h" ++#include "hw/firmware/smbios.h" ++#include "acpi-build.h" ++#include ++#include ++#include "sysemu/block-backend.h" ++#include "hw/block/flash.h" ++#include "sysemu/device_tree.h" ++#include "qapi/visitor.h" ++#include "qapi/qapi-visit-common.h" ++#include "sysemu/tpm.h" ++#include "hw/loongarch/sysbus-fdt.h" ++ ++#include ++ ++#define DMA64_SUPPORTED 0x2 ++#define MAX_IDE_BUS 2 ++ ++#define BOOTPARAM_PHYADDR 0x0ff00000ULL ++#define BOOTPARAM_ADDR (0x9000000000000000ULL + BOOTPARAM_PHYADDR) ++#define SMBIOS_PHYSICAL_ADDRESS 0x0fe00000 ++#define SMBIOS_SIZE_LIMIT 0x200000 ++#define RESERVED_SIZE_LIMIT 0x1100000 ++#define COMMAND_LINE_SIZE 4096 ++#define FW_CONF_ADDR 0x0fff0000 ++ ++#define PHYS_TO_VIRT(x) ((x) | 0x9000000000000000ULL) ++ ++#define TARGET_REALPAGE_MASK (TARGET_PAGE_MASK << 2) ++ ++#ifdef CONFIG_KVM ++#define LS_ISA_IO_SIZE 0x02000000 ++#else ++#define LS_ISA_IO_SIZE 0x00010000 ++#endif ++ ++#ifdef CONFIG_KVM ++#define align(x) (((x) + 63) & ~63) ++#else ++#define align(x) (((x) + 15) & ~15) ++#endif ++ ++#define DEBUG_LOONGARCH3A 0 ++#define FLASH_SECTOR_SIZE 4096 ++ ++#define DPRINTF(fmt, ...) \ ++ do { \ ++ if (DEBUG_LOONGARCH3A) { \ ++ fprintf(stderr, fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define DEFINE_LS3A5K_MACHINE(suffix, name, optionfn) \ ++ static void ls3a5k_init_##suffix(MachineState *machine) \ ++ { \ ++ ls3a5k_init(machine); \ ++ } \ ++ DEFINE_LOONGARCH_MACHINE(suffix, name, ls3a5k_init_##suffix, optionfn) ++ ++struct efi_memory_map_loongarch { ++ uint16_t vers; /* version of efi_memory_map */ ++ uint32_t nr_map; /* number of memory_maps */ ++ uint32_t mem_freq; /* memory frequence */ ++ struct mem_map { ++ uint32_t node_id; /* node_id which memory attached to */ ++ uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ ++ uint64_t mem_start; /* memory map start address */ ++ uint32_t mem_size; /* each memory_map size, not the total size */ ++ } map[128]; ++} __attribute__((packed)); ++ ++enum loongarch_cpu_type { Loongson3 = 0x1, Loongson3_comp = 0x2 }; ++ ++struct GlobalProperty loongarch_compat[] = { ++ { ++ .driver = "rtl8139", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "e1000", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "virtio-net-pci", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "qxl-vga", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "VGA", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "cirrus-vga", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "virtio-vga", ++ .property = "romfile", ++ .value = "", ++ }, ++ { ++ .driver = "vmware-svga", ++ .property = "romfile", ++ .value = "", ++ }, ++}; ++const size_t loongarch_compat_len = G_N_ELEMENTS(loongarch_compat); ++ ++/* ++ * Capability and feature descriptor structure for LOONGARCH CPU ++ */ ++struct efi_cpuinfo_loongarch { ++ uint16_t vers; /* version of efi_cpuinfo_loongarch */ ++ uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ ++ enum loongarch_cpu_type cputype; /* 3A, 3B, etc. */ ++ uint32_t total_node; /* num of total numa nodes */ ++ uint16_t cpu_startup_core_id; /* Core id */ ++ uint16_t reserved_cores_mask; ++ uint32_t cpu_clock_freq; /* cpu_clock */ ++ uint32_t nr_cpus; ++} __attribute__((packed)); ++ ++#define MAX_UARTS 64 ++struct uart_device { ++ uint32_t iotype; /* see include/linux/serial_core.h */ ++ uint32_t uartclk; ++ uint32_t int_offset; ++ uint64_t uart_base; ++} __attribute__((packed)); ++ ++#define MAX_SENSORS 64 ++#define SENSOR_TEMPER 0x00000001 ++#define SENSOR_VOLTAGE 0x00000002 ++#define SENSOR_FAN 0x00000004 ++struct sensor_device { ++ char name[32]; /* a formal name */ ++ char label[64]; /* a flexible description */ ++ uint32_t type; /* SENSOR_* */ ++ uint32_t id; /* instance id of a sensor-class */ ++ /* ++ * see arch/loongarch/include/ ++ * asm/mach-loongarch/loongarch_hwmon.h ++ */ ++ uint32_t fan_policy; ++ uint32_t fan_percent; /* only for constant speed policy */ ++ uint64_t base_addr; /* base address of device registers */ ++} __attribute__((packed)); ++ ++struct system_loongarch { ++ uint16_t vers; /* version of system_loongarch */ ++ uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ ++ uint32_t sing_double_channel; /* 1:single; 2:double */ ++ uint32_t nr_uarts; ++ struct uart_device uarts[MAX_UARTS]; ++ uint32_t nr_sensors; ++ struct sensor_device sensors[MAX_SENSORS]; ++ char has_ec; ++ char ec_name[32]; ++ uint64_t ec_base_addr; ++ char has_tcm; ++ char tcm_name[32]; ++ uint64_t tcm_base_addr; ++ uint64_t workarounds; /* see workarounds.h */ ++} __attribute__((packed)); ++ ++struct irq_source_routing_table { ++ uint16_t vers; ++ uint16_t size; ++ uint16_t rtr_bus; ++ uint16_t rtr_devfn; ++ uint32_t vendor; ++ uint32_t device; ++ uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ ++ uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ ++ uint64_t ht_enable; /* irqs used in this PIC */ ++ uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ ++ uint64_t pci_mem_start_addr; ++ uint64_t pci_mem_end_addr; ++ uint64_t pci_io_start_addr; ++ uint64_t pci_io_end_addr; ++ uint64_t pci_config_addr; ++ uint32_t dma_mask_bits; ++ uint16_t dma_noncoherent; ++} __attribute__((packed)); ++ ++struct interface_info { ++ uint16_t vers; /* version of the specificition */ ++ uint16_t size; ++ uint8_t flag; ++ char description[64]; ++} __attribute__((packed)); ++ ++#define MAX_RESOURCE_NUMBER 128 ++struct resource_loongarch { ++ uint64_t start; /* resource start address */ ++ uint64_t end; /* resource end address */ ++ char name[64]; ++ uint32_t flags; ++}; ++ ++struct archdev_data { ++}; /* arch specific additions */ ++ ++struct board_devices { ++ char name[64]; /* hold the device name */ ++ uint32_t num_resources; /* number of device_resource */ ++ /* for each device's resource */ ++ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; ++ /* arch specific additions */ ++ struct archdev_data archdata; ++}; ++ ++struct loongarch_special_attribute { ++ uint16_t vers; /* version of this special */ ++ char special_name[64]; /* special_atribute_name */ ++ uint32_t loongarch_special_type; /* type of special device */ ++ /* for each device's resource */ ++ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; ++}; ++ ++struct loongarch_params { ++ uint64_t memory_offset; /* efi_memory_map_loongarch struct offset */ ++ uint64_t cpu_offset; /* efi_cpuinfo_loongarch struct offset */ ++ uint64_t system_offset; /* system_loongarch struct offset */ ++ uint64_t irq_offset; /* irq_source_routing_table struct offset */ ++ uint64_t interface_offset; /* interface_info struct offset */ ++ uint64_t special_offset; /* loongarch_special_attribute struct offset */ ++ uint64_t boarddev_table_offset; /* board_devices offset */ ++}; ++ ++struct smbios_tables { ++ uint16_t vers; /* version of smbios */ ++ uint64_t vga_bios; /* vga_bios address */ ++ struct loongarch_params lp; ++}; ++ ++struct efi_reset_system_t { ++ uint64_t ResetCold; ++ uint64_t ResetWarm; ++ uint64_t ResetType; ++ uint64_t Shutdown; ++ uint64_t DoSuspend; /* NULL if not support */ ++}; ++ ++struct efi_loongarch { ++ uint64_t mps; /* MPS table */ ++ uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ ++ uint64_t acpi20; /* ACPI table (ACPI 2.0) */ ++ struct smbios_tables smbios; /* SM BIOS table */ ++ uint64_t sal_systab; /* SAL system table */ ++ uint64_t boot_info; /* boot info table */ ++}; ++ ++struct boot_params { ++ struct efi_loongarch efi; ++ struct efi_reset_system_t reset_system; ++}; ++ ++static struct _loaderparams { ++ unsigned long ram_size; ++ const char *kernel_filename; ++ const char *kernel_cmdline; ++ const char *initrd_filename; ++ unsigned long a0, a1, a2; ++} loaderparams; ++ ++static struct _firmware_config { ++ unsigned long ram_size; ++ unsigned int mem_freq; ++ unsigned int cpu_nr; ++ unsigned int cpu_clock_freq; ++} fw_config; ++ ++struct la_memmap_entry { ++ uint64_t address; ++ uint64_t length; ++ uint32_t type; ++ uint32_t reserved; ++}; ++ ++static void *boot_params_buf; ++static void *boot_params_p; ++static struct la_memmap_entry *la_memmap_table; ++static unsigned la_memmap_entries; ++ ++CPULOONGARCHState *cpu_states[LOONGARCH_MAX_VCPUS]; ++ ++struct kvm_cpucfg ls3a5k_cpucfgs = { ++ .cpucfg[LOONGARCH_CPUCFG0] = CPUCFG0_3A5000_PRID, ++ .cpucfg[LOONGARCH_CPUCFG1] = ++ CPUCFG1_ISGR64 | CPUCFG1_PAGING | CPUCFG1_IOCSR | CPUCFG1_PABITS | ++ CPUCFG1_VABITS | CPUCFG1_UAL | CPUCFG1_RI | CPUCFG1_XI | CPUCFG1_RPLV | ++ CPUCFG1_HUGEPG | CPUCFG1_IOCSRBRD, ++ .cpucfg[LOONGARCH_CPUCFG2] = ++ CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | CPUCFG2_FPVERS | ++ CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | CPUCFG2_CRYPTO | ++ CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | CPUCFG2_LAM, ++ .cpucfg[LOONGARCH_CPUCFG3] = ++ CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | CPUCFG3_LLEXC | ++ CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | CPUCFG3_ICACHET | ++ CPUCFG3_SPW_LVL | CPUCFG3_SPW_HG_HF | CPUCFG3_RVA | CPUCFG3_RVAMAX, ++ .cpucfg[LOONGARCH_CPUCFG4] = CCFREQ_100M, ++ .cpucfg[LOONGARCH_CPUCFG5] = CPUCFG5_CCMUL | CPUCFG5_CCDIV, ++ .cpucfg[LOONGARCH_CPUCFG6] = CPUCFG6_PMP | CPUCFG6_PAMVER | CPUCFG6_PMNUM | ++ CPUCFG6_PMBITS | CPUCFG6_UPM, ++ .cpucfg[LOONGARCH_CPUCFG16] = CPUCFG16_L1_IUPRE | CPUCFG16_L1_DPRE | ++ CPUCFG16_L2_IUPRE | CPUCFG16_L2_IUUNIFY | ++ CPUCFG16_L2_IUPRIV | CPUCFG16_L3_IUPRE | ++ CPUCFG16_L3_IUUNIFY | CPUCFG16_L3_IUINCL, ++ .cpucfg[LOONGARCH_CPUCFG17] = ++ CPUCFG17_L1I_WAYS_M | CPUCFG17_L1I_SETS_M | CPUCFG17_L1I_SIZE_M, ++ .cpucfg[LOONGARCH_CPUCFG18] = ++ CPUCFG18_L1D_WAYS_M | CPUCFG18_L1D_SETS_M | CPUCFG18_L1D_SIZE_M, ++ .cpucfg[LOONGARCH_CPUCFG19] = ++ CPUCFG19_L2_WAYS_M | CPUCFG19_L2_SETS_M | CPUCFG19_L2_SIZE_M, ++ .cpucfg[LOONGARCH_CPUCFG20] = ++ CPUCFG20_L3_WAYS_M | CPUCFG20_L3_SETS_M | CPUCFG20_L3_SIZE_M, ++}; ++ ++bool loongarch_is_acpi_enabled(LoongarchMachineState *vms) ++{ ++ if (vms->acpi == ON_OFF_AUTO_OFF) { ++ return false; ++ } ++ return true; ++} ++ ++static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(obj); ++ OnOffAuto acpi = lsms->acpi; ++ ++ visit_type_OnOffAuto(v, name, &acpi, errp); ++} ++ ++static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(obj); ++ ++ visit_type_OnOffAuto(v, name, &lsms->acpi, errp); ++} ++ ++int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) ++{ ++ int i; ++ ++ for (i = 0; i < la_memmap_entries; i++) { ++ if (la_memmap_table[i].address == address) { ++ fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n", ++ __func__, address, length); ++ return 0; ++ } ++ } ++ ++ la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table, ++ la_memmap_entries + 1); ++ la_memmap_table[la_memmap_entries].address = cpu_to_le64(address); ++ la_memmap_table[la_memmap_entries].length = cpu_to_le64(length); ++ la_memmap_table[la_memmap_entries].type = cpu_to_le32(type); ++ la_memmap_entries++; ++ ++ return la_memmap_entries; ++} ++ ++static ram_addr_t get_hotplug_membase(ram_addr_t ram_size) ++{ ++ ram_addr_t sstart; ++ ++ if (ram_size <= 0x10000000) { ++ sstart = 0x90000000; ++ } else { ++ sstart = 0x90000000 + ROUND_UP((ram_size - 0x10000000), ++ LOONGARCH_HOTPLUG_MEM_ALIGN); ++ } ++ return sstart; ++} ++ ++static struct efi_memory_map_loongarch *init_memory_map(void *g_map) ++{ ++ struct efi_memory_map_loongarch *emap = g_map; ++ ++ emap->nr_map = 4; ++ emap->mem_freq = 266000000; ++ ++ emap->map[0].node_id = 0; ++ emap->map[0].mem_type = 1; ++ emap->map[0].mem_start = 0x0; ++#ifdef CONFIG_KVM ++ emap->map[0].mem_size = ++ (loaderparams.ram_size > 0x10000000 ? 256 ++ : (loaderparams.ram_size >> 20)) - ++ 18; ++#else ++ emap->map[0].mem_size = atoi(getenv("memsize")); ++#endif ++ ++ emap->map[1].node_id = 0; ++ emap->map[1].mem_type = 2; ++ emap->map[1].mem_start = 0x90000000; ++#ifdef CONFIG_KVM ++ emap->map[1].mem_size = (loaderparams.ram_size > 0x10000000 ++ ? (loaderparams.ram_size >> 20) - 256 ++ : 0); ++#else ++ emap->map[1].mem_size = atoi(getenv("highmemsize")); ++#endif ++ ++ /* support for smbios */ ++ emap->map[2].node_id = 0; ++ emap->map[2].mem_type = 10; ++ emap->map[2].mem_start = SMBIOS_PHYSICAL_ADDRESS; ++ emap->map[2].mem_size = SMBIOS_SIZE_LIMIT >> 20; ++ ++ emap->map[3].node_id = 0; ++ emap->map[3].mem_type = 3; ++ emap->map[3].mem_start = 0xee00000; ++ emap->map[3].mem_size = RESERVED_SIZE_LIMIT >> 20; ++ ++ return emap; ++} ++ ++static uint64_t get_host_cpu_freq(void) ++{ ++ int fd = 0; ++ char buf[1024]; ++ uint64_t freq = 0, size = 0; ++ char *buf_p; ++ ++ fd = open("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", ++ O_RDONLY); ++ if (fd == -1) { ++ fprintf(stderr, "/sys/devices/system/cpu/cpu0/cpufreq/ \ ++ cpuinfo_max_freq not exist!\n"); ++ fprintf(stderr, "Trying /proc/cpuinfo...\n"); ++ } else { ++ size = read(fd, buf, 16); ++ if (size == -1) { ++ fprintf(stderr, "read err...\n"); ++ } ++ close(fd); ++ freq = (uint64_t)atoi(buf); ++ return freq * 1000; ++ } ++ ++ fd = open("/proc/cpuinfo", O_RDONLY); ++ if (fd == -1) { ++ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); ++ return 0; ++ } ++ ++ size = read(fd, buf, 1024); ++ if (size == -1) { ++ fprintf(stderr, "read err...\n"); ++ } ++ close(fd); ++ ++ buf_p = strstr(buf, "MHz"); ++ if (buf_p) { ++ while (*buf_p != ':') { ++ buf_p++; ++ } ++ buf_p += 2; ++ } else { ++ buf_p = strstr(buf, "name"); ++ while (*buf_p != '@') { ++ buf_p++; ++ } ++ buf_p += 2; ++ } ++ ++ memcpy(buf, buf_p, 12); ++ buf_p = buf; ++ while ((*buf_p >= '0') && (*buf_p <= '9')) { ++ buf_p++; ++ } ++ *buf_p = '\0'; ++ ++ freq = (uint64_t)atoi(buf); ++ return freq * 1000 * 1000; ++} ++ ++static char *get_host_cpu_model_name(void) ++{ ++ int fd = 0; ++ int size = 0; ++ static char buf[1024]; ++ char *buf_p; ++ ++ fd = open("/proc/cpuinfo", O_RDONLY); ++ if (fd == -1) { ++ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); ++ return 0; ++ } ++ ++ size = read(fd, buf, 1024); ++ if (size == -1) { ++ fprintf(stderr, "read err...\n"); ++ } ++ close(fd); ++ buf_p = strstr(buf, "Name"); ++ if (!buf_p) { ++ buf_p = strstr(buf, "name"); ++ } ++ if (!buf_p) { ++ fprintf(stderr, "Can't find cpu name\n"); ++ return 0; ++ } ++ ++ while (*buf_p != ':') { ++ buf_p++; ++ } ++ buf_p = buf_p + 2; ++ memcpy(buf, buf_p, 40); ++ buf_p = buf; ++ while (*buf_p != '\n') { ++ buf_p++; ++ } ++ ++ *(buf_p) = '\0'; ++ ++ return buf; ++} ++ ++static void fw_conf_init(unsigned long ramsize) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ int smp_cpus = ms->smp.cpus; ++ fw_config.ram_size = ramsize; ++ fw_config.mem_freq = 266000000; ++ fw_config.cpu_nr = smp_cpus; ++ fw_config.cpu_clock_freq = get_host_cpu_freq(); ++} ++ ++static struct efi_cpuinfo_loongarch *init_cpu_info(void *g_cpuinfo_loongarch) ++{ ++ struct efi_cpuinfo_loongarch *c = g_cpuinfo_loongarch; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ int smp_cpus = ms->smp.cpus; ++ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ ++ if (strstr(lsmc->cpu_name, "5000")) { ++ c->processor_id = 0x14c010; ++ } ++ c->cputype = Loongson3_comp; ++ c->cpu_clock_freq = get_host_cpu_freq(); ++ if (!c->cpu_clock_freq) { ++ c->cpu_clock_freq = 200000000; ++ } ++ c->total_node = 1; ++ c->nr_cpus = smp_cpus; ++ c->cpu_startup_core_id = 0; ++ c->reserved_cores_mask = 0xffff & (0xffff << smp_cpus); ++ ++ return c; ++} ++ ++static struct system_loongarch *init_system_loongarch(void *g_sysitem) ++{ ++ struct system_loongarch *s = g_sysitem; ++ ++ s->ccnuma_smp = 1; ++ s->ccnuma_smp = 0; ++ s->sing_double_channel = 1; ++ ++ return s; ++} ++ ++enum loongarch_irq_source_enum { HT, I8259, UNKNOWN }; ++ ++static struct irq_source_routing_table *init_irq_source(void *g_irq_source) ++{ ++ struct irq_source_routing_table *irq_info = g_irq_source; ++ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ ++ irq_info->PIC_type = HT; ++ irq_info->ht_int_bit = 1 << 24; ++ irq_info->ht_enable = 0x0000d17b; ++ irq_info->node_id = 0; ++ ++ irq_info->pci_mem_start_addr = PCIE_MEMORY_BASE; ++ irq_info->pci_mem_end_addr = ++ irq_info->pci_mem_start_addr + PCIE_MEMORY_SIZE - 1; ++ ++ if (strstr(lsmc->cpu_name, "5000")) { ++ irq_info->pci_io_start_addr = LS3A5K_ISA_IO_BASE; ++ } ++ irq_info->dma_noncoherent = 1; ++ return irq_info; ++} ++ ++static struct interface_info *init_interface_info(void *g_interface) ++{ ++ struct interface_info *inter = g_interface; ++ int flashsize = 0x80000; ++ ++ inter->vers = 0x0001; ++ inter->size = flashsize / 0x400; ++ inter->flag = 1; ++ ++ strcpy(inter->description, "PMON_Version_v2.1"); ++ ++ return inter; ++} ++ ++static struct board_devices *board_devices_info(void *g_board) ++{ ++ struct board_devices *bd = g_board; ++ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ ++ if (!strcmp(lsmc->bridge_name, "ls7a")) { ++ strcpy(bd->name, "Loongarch-3A-7A-1w-V1.03-demo"); ++ } ++ bd->num_resources = 10; ++ ++ return bd; ++} ++ ++static struct loongarch_special_attribute *init_special_info(void *g_special) ++{ ++ struct loongarch_special_attribute *special = g_special; ++ char update[11] = "2013-01-01"; ++ int VRAM_SIZE = 0x20000; ++ ++ strcpy(special->special_name, update); ++ special->resource[0].flags = 0; ++ special->resource[0].start = 0; ++ special->resource[0].end = VRAM_SIZE; ++ strcpy(special->resource[0].name, "SPMODULE"); ++ special->resource[0].flags |= DMA64_SUPPORTED; ++ ++ return special; ++} ++ ++static void init_loongarch_params(struct loongarch_params *lp) ++{ ++ void *p = boot_params_p; ++ ++ lp->memory_offset = ++ (unsigned long long)init_memory_map(p) - (unsigned long long)lp; ++ p += align(sizeof(struct efi_memory_map_loongarch)); ++ ++ lp->cpu_offset = ++ (unsigned long long)init_cpu_info(p) - (unsigned long long)lp; ++ p += align(sizeof(struct efi_cpuinfo_loongarch)); ++ ++ lp->system_offset = ++ (unsigned long long)init_system_loongarch(p) - (unsigned long long)lp; ++ p += align(sizeof(struct system_loongarch)); ++ ++ lp->irq_offset = ++ (unsigned long long)init_irq_source(p) - (unsigned long long)lp; ++ p += align(sizeof(struct irq_source_routing_table)); ++ ++ lp->interface_offset = ++ (unsigned long long)init_interface_info(p) - (unsigned long long)lp; ++ p += align(sizeof(struct interface_info)); ++ ++ lp->boarddev_table_offset = ++ (unsigned long long)board_devices_info(p) - (unsigned long long)lp; ++ p += align(sizeof(struct board_devices)); ++ ++ lp->special_offset = ++ (unsigned long long)init_special_info(p) - (unsigned long long)lp; ++ p += align(sizeof(struct loongarch_special_attribute)); ++ ++ boot_params_p = p; ++} ++ ++static void init_smbios(struct smbios_tables *smbios) ++{ ++ smbios->vers = 1; ++ smbios->vga_bios = 1; ++ init_loongarch_params(&(smbios->lp)); ++} ++ ++static void init_efi(struct efi_loongarch *efi) ++{ ++ init_smbios(&(efi->smbios)); ++} ++ ++static int init_boot_param(struct boot_params *bp) ++{ ++ init_efi(&(bp->efi)); ++ ++ return 0; ++} ++ ++static unsigned int ls3a5k_aui_boot_code[] = { ++ 0x0380200d, /* ori $r13,$r0,0x8 */ ++ 0x0400002d, /* csrwr $r13,0x0 */ ++ 0x0401000e, /* csrrd $r14,0x40 */ ++ 0x0343fdce, /* andi $r14,$r14,0xff */ ++ 0x143fc02c, /* lu12i.w $r12,261889(0x1fe01) */ ++ 0x1600000c, /* lu32i.d $r12,0 */ ++ 0x0320018c, /* lu52i.d $r12,$r12,-1792(0x800) */ ++ 0x03400dcf, /* andi $r15,$r14,0x3 */ ++ 0x004121ef, /* slli.d $r15,$r15,0x8 */ ++ 0x00153d8c, /* or $r12,$r12,$r15 */ ++ 0x034031d0, /* andi $r16,$r14,0xc */ ++ 0x0041aa10, /* slli.d $r16,$r16,0x2a */ ++ 0x0015418c, /* or $r12,$r12,$r16 */ ++ 0x28808184, /* ld.w $r4,$r12,32(0x20) */ ++ 0x43fffc9f, /* beqz $r4,0 -4 */ ++ 0x28c08184, /* ld.d $r4,$r12,32(0x20) */ ++ 0x28c0a183, /* ld.d $r3,$r12,40(0x28) */ ++ 0x28c0c182, /* ld.d $r2,$r12,48(0x30) */ ++ 0x28c0e185, /* ld.d $r5,$r12,56(0x38) */ ++ 0x4c000080, /* jirl $r0,$r4,0 */ ++}; ++ ++static int set_bootparam_uefi(ram_addr_t initrd_offset, long initrd_size) ++{ ++ long params_size; ++ char memenv[32]; ++ char highmemenv[32]; ++ void *params_buf; ++ unsigned long *parg_env; ++ int ret = 0; ++ ++ /* Allocate params_buf for command line. */ ++ params_size = 0x100000; ++ params_buf = g_malloc0(params_size); ++ ++ /* ++ * Layout of params_buf looks like this: ++ * argv[0], argv[1], 0, env[0], env[1], ...env[i], 0, ++ * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0 ++ */ ++ parg_env = (void *)params_buf; ++ ++ ret = (3 + 1) * sizeof(target_ulong); ++ *parg_env++ = (BOOTPARAM_ADDR + ret); ++ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "g")); ++ ++ /* argv1 */ ++ *parg_env++ = BOOTPARAM_ADDR + ret; ++ if (initrd_size > 0) ++ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, ++ "rd_start=0x%llx rd_size=%li %s", ++ PHYS_TO_VIRT((uint32_t)initrd_offset), ++ initrd_size, loaderparams.kernel_cmdline)); ++ else ++ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "%s", ++ loaderparams.kernel_cmdline)); ++ ++ /* argv2 */ ++ *parg_env++ = 0; ++ ++ /* env */ ++ sprintf(memenv, "%lu", ++ loaderparams.ram_size > 0x10000000 ++ ? 256 ++ : (loaderparams.ram_size >> 20)); ++ sprintf(highmemenv, "%lu", ++ loaderparams.ram_size > 0x10000000 ++ ? (loaderparams.ram_size >> 20) - 256 ++ : 0); ++ ++ setenv("memsize", memenv, 1); ++ setenv("highmemsize", highmemenv, 1); ++ ++ ret = ((ret + 32) & ~31); ++ ++ boot_params_buf = (void *)(params_buf + ret); ++ boot_params_p = boot_params_buf + align(sizeof(struct boot_params)); ++ init_boot_param(boot_params_buf); ++ rom_add_blob_fixed("params", params_buf, params_size, BOOTPARAM_PHYADDR); ++ loaderparams.a0 = 2; ++ loaderparams.a1 = BOOTPARAM_ADDR; ++ loaderparams.a2 = BOOTPARAM_ADDR + ret; ++ ++ return 0; ++} ++ ++static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) ++{ ++ return addr & 0x1fffffffll; ++} ++ ++static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg, uint64_t highram_size, ++ uint64_t phyAddr_initrd) ++{ ++ int64_t entry, kernel_low, kernel_high; ++ long initrd_size = 0; ++ uint64_t initrd_offset = 0; ++ void *cmdline_buf; ++ int ret = 0; ++ ++ ret = load_elf(loaderparams.kernel_filename, NULL, ++ cpu_loongarch_virt_to_phys, NULL, (uint64_t *)&entry, ++ (uint64_t *)&kernel_low, (uint64_t *)&kernel_high, NULL, 0, ++ EM_LOONGARCH, 1, 0); ++ ++ if (0 > ret) { ++ error_report("kernel image load error"); ++ exit(1); ++ } ++ ++ fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, entry); ++ ++ if (loaderparams.initrd_filename) { ++ initrd_size = get_image_size(loaderparams.initrd_filename); ++ if (0 < initrd_size) { ++ if (initrd_size > highram_size) { ++ error_report("initrd size is too big, should below %ld MB", ++ highram_size / MiB); ++ /*prevent write io memory address space*/ ++ exit(1); ++ } ++ initrd_offset = ++ (phyAddr_initrd - initrd_size) & TARGET_REALPAGE_MASK; ++ initrd_size = load_image_targphys( ++ loaderparams.initrd_filename, initrd_offset, ++ loaderparams.ram_size - initrd_offset); ++ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_offset); ++ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); ++ } else { ++ error_report("initrd image size is error"); ++ } ++ } ++ ++ cmdline_buf = g_malloc0(COMMAND_LINE_SIZE); ++ if (initrd_size > 0) ++ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, ++ "rd_start=0x%llx rd_size=%li %s", ++ PHYS_TO_VIRT(initrd_offset), initrd_size, ++ loaderparams.kernel_cmdline)); ++ else ++ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s", ++ loaderparams.kernel_cmdline)); ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret); ++ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf); ++ ++ return; ++} ++ ++static int64_t load_kernel(void) ++{ ++ int64_t entry, kernel_low, kernel_high; ++ long initrd_size = 0; ++ ram_addr_t initrd_offset = 0; ++ ++ load_elf(loaderparams.kernel_filename, NULL, cpu_loongarch_virt_to_phys, ++ NULL, (uint64_t *)&entry, (uint64_t *)&kernel_low, ++ (uint64_t *)&kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); ++ ++ if (loaderparams.initrd_filename) { ++ initrd_size = get_image_size(loaderparams.initrd_filename); ++ ++ if (initrd_size > 0) { ++ initrd_offset = (kernel_high * 4 + ~TARGET_REALPAGE_MASK) & ++ TARGET_REALPAGE_MASK; ++ initrd_size = load_image_targphys( ++ loaderparams.initrd_filename, initrd_offset, ++ loaderparams.ram_size - initrd_offset); ++ } ++ } ++ set_bootparam_uefi(initrd_offset, initrd_size); ++ ++ return entry; ++} ++ ++static void main_cpu_reset(void *opaque) ++{ ++ ResetData *s = (ResetData *)opaque; ++ CPULOONGARCHState *env = &s->cpu->env; ++ ++ cpu_reset(CPU(s->cpu)); ++ env->active_tc.PC = s->vector; ++ env->active_tc.gpr[4] = loaderparams.a0; ++ env->active_tc.gpr[5] = loaderparams.a1; ++ env->active_tc.gpr[6] = loaderparams.a2; ++} ++ ++void slave_cpu_reset(void *opaque) ++{ ++ ResetData *s = (ResetData *)opaque; ++ ++ cpu_reset(CPU(s->cpu)); ++} ++ ++/* KVM_IRQ_LINE irq field index values */ ++#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24 ++#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff ++#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16 ++#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff ++#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0 ++#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff ++ ++/* irq_type field */ ++#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0 ++#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1 ++#define KVM_LOONGARCH_IRQ_TYPE_HT 2 ++#define KVM_LOONGARCH_IRQ_TYPE_MSI 3 ++#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4 ++ ++static void legacy_set_irq(void *opaque, int irq, int level) ++{ ++ qemu_irq *pic = opaque; ++ ++ qemu_set_irq(pic[irq], level); ++} ++ ++typedef struct ls3a_intctlstate { ++ uint8_t nodecounter_reg[0x100]; ++ uint8_t pm_reg[0x100]; ++ uint8_t msi_reg[0x8]; ++ CPULOONGARCHState **env; ++ DeviceState *apicdev; ++ qemu_irq *ioapic_irq; ++#ifdef CONFIG_KVM ++ struct loongarch_kvm_irqchip chip; ++#endif ++} ls3a_intctlstate; ++ ++typedef struct ls3a_func_args { ++ ls3a_intctlstate *state; ++ uint64_t base; ++ uint32_t mask; ++ uint8_t *mem; ++} ls3a_func_args; ++ ++static uint64_t ls3a_msi_mem_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ return 0; ++} ++ ++static void ls3a_msi_mem_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ struct kvm_msi msi; ++ apicState *apic; ++ ++ apic = (apicState *)opaque; ++ msi.address_lo = 0; ++ msi.address_hi = 0; ++ msi.data = val & 0xff; ++ msi.flags = 0; ++ memset(msi.pad, 0, sizeof(msi.pad)); ++ ++ if (kvm_irqchip_in_kernel()) { ++ kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); ++ } else { ++ qemu_set_irq(apic->irq[msi.data], 1); ++ } ++} ++ ++static const MemoryRegionOps ls3a_msi_ops = { ++ .read = ls3a_msi_mem_read, ++ .write = ls3a_msi_mem_write, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++}; ++ ++static const VMStateDescription vmstate_ls3a_msi = { ++ .name = "ls3a-msi", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .fields = ++ (VMStateField[]){ VMSTATE_UINT8_ARRAY(msi_reg, ls3a_intctlstate, 0x8), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static void ioapic_handler(void *opaque, int irq, int level) ++{ ++ apicState *apic; ++ int kvm_irq; ++ ++ apic = (apicState *)opaque; ++ ++ if (kvm_irqchip_in_kernel()) { ++ kvm_irq = ++ (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) | ++ (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } else { ++ qemu_set_irq(apic->irq[irq], level); ++ } ++} ++ ++static void *ls3a_intctl_init(MachineState *machine, CPULOONGARCHState *env[]) ++{ ++ qemu_irq *irqhandler; ++ ls3a_intctlstate *s; ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ LoongarchMachineClass *mc = LoongarchMACHINE_GET_CLASS(lsms); ++ DeviceState *dev; ++ SysBusDevice *busdev; ++ MemoryRegion *address_space_mem = get_system_memory(); ++ MemoryRegion *iomem = NULL; ++#ifdef CONFIG_KVM ++ int i; ++#endif ++ ++ s = g_malloc0(sizeof(ls3a_intctlstate)); ++ ++ if (!s) { ++ return NULL; ++ } ++ ++ /*Add MSI mmio memory*/ ++ iomem = g_new(MemoryRegion, 1); ++ memory_region_init_io(iomem, NULL, &ls3a_msi_ops, lsms->apic, "ls3a_msi", ++ 0x8); ++ memory_region_add_subregion(address_space_mem, MSI_ADDR_LOW, iomem); ++ vmstate_register(NULL, 0, &vmstate_ls3a_msi, s); ++ ++ s->env = env; ++ ++ if (!strcmp(mc->bridge_name, "ls7a")) { ++ if (lsms->apic_xrupt_override) { ++ DPRINTF("irqchip in kernel %d\n", kvm_irqchip_in_kernel()); ++#ifdef CONFIG_KVM ++ if (kvm_has_gsi_routing()) { ++ for (i = 0; i < 32; ++i) { ++ kvm_irqchip_add_irq_route(kvm_state, i, 0, i); ++ } ++ kvm_gsi_routing_allowed = true; ++ } ++ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); ++#endif ++ } ++ ++ irqhandler = qemu_allocate_irqs(ioapic_handler, lsms->apic, 64); ++ dev = qdev_new("ioapic"); ++ busdev = SYS_BUS_DEVICE(dev); ++ sysbus_realize_and_unref(busdev, &error_fatal); ++ sysbus_mmio_map(busdev, 0, mc->ls7a_ioapic_reg_base); ++ s->ioapic_irq = irqhandler; ++ s->apicdev = dev; ++ return s->ioapic_irq; ++ } ++ return NULL; ++} ++ ++/* Network support */ ++static void network_init(PCIBus *pci_bus) ++{ ++ int i; ++ ++ for (i = 0; i < nb_nics; i++) { ++ NICInfo *nd = &nd_table[i]; ++ ++ if (!nd->model) { ++ nd->model = g_strdup("virtio-net-pci"); ++ } ++ ++ pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); ++ } ++} ++ ++void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ unsigned int id; ++ int smp_cpus = machine->smp.cpus; ++ id = cpu->id; ++ qemu_unregister_reset(slave_cpu_reset, lsms->reset_info[id]); ++ g_free(lsms->reset_info[id]); ++ lsms->reset_info[id] = NULL; ++ ++ smp_cpus -= 1; ++ if (lsms->fw_cfg) { ++ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); ++ } ++ ++ qemu_del_vm_change_state_handler(cpu->cpuStateEntry); ++} ++ ++LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, LOONGARCHCPU *cpu, ++ Error **errp) ++{ ++ CPULOONGARCHState *env; ++ unsigned int id; ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ int smp_cpus = machine->smp.cpus; ++ id = cpu->id; ++ env = &cpu->env; ++ cpu_states[id] = env; ++ env->CSR_TMID |= id; ++ ++ lsms = LoongarchMACHINE(machine); ++ lsms->reset_info[id] = g_malloc0(sizeof(ResetData)); ++ lsms->reset_info[id]->cpu = cpu; ++ lsms->reset_info[id]->vector = env->active_tc.PC; ++ qemu_register_reset(slave_cpu_reset, lsms->reset_info[id]); ++ ++ /* Init CPU internal devices */ ++ cpu_init_irq(cpu); ++ cpu_loongarch_clock_init(cpu); ++ ++ smp_cpus += 1; ++ if (lsms->fw_cfg) { ++ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); ++ } ++ cpu_init_ipi(lsms, env->irq[12], id); ++ cpu_init_apic(lsms, env, id); ++ ++ return cpu; ++} ++ ++static void fw_cfg_boot_set(void *opaque, const char *boot_device, ++ Error **errp) ++{ ++ fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); ++} ++ ++static FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, ++ LoongarchMachineState *lsms) ++{ ++ FWCfgState *fw_cfg; ++ uint64_t *numa_fw_cfg; ++ int i; ++ const CPUArchIdList *cpus; ++ MachineClass *mc = MACHINE_GET_CLASS(lsms); ++ MachineState *ms = MACHINE(OBJECT(lsms)); ++ int max_cpus = ms->smp.max_cpus; ++ int smp_cpus = ms->smp.cpus; ++ int nb_numa_nodes = ms->numa_state->num_nodes; ++ NodeInfo *numa_info = ms->numa_state->nodes; ++ ++ fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL); ++ fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); ++ fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); ++ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); ++ ++ /* ++ * allocate memory for the NUMA channel: one (64bit) word for the number ++ * of nodes, one word for each VCPU->node and one word for each node to ++ * hold the amount of memory. ++ */ ++ numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); ++ numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); ++ cpus = mc->possible_cpu_arch_ids(MACHINE(lsms)); ++ for (i = 0; i < cpus->len; i++) { ++ unsigned int apic_id = cpus->cpus[i].arch_id; ++ assert(apic_id < max_cpus); ++ numa_fw_cfg[apic_id + 1] = cpu_to_le64(cpus->cpus[i].props.node_id); ++ } ++ for (i = 0; i < nb_numa_nodes; i++) { ++ numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(numa_info[i].node_mem); ++ } ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, ++ (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg)); ++ ++ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); ++ return fw_cfg; ++} ++ ++static void loongarch_build_smbios(LoongarchMachineState *lsms) ++{ ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ MachineState *ms = MACHINE(OBJECT(lsms)); ++ uint8_t *smbios_tables, *smbios_anchor; ++ size_t smbios_tables_len, smbios_anchor_len; ++ const char *product = "QEMU Virtual Machine"; ++ ms->smp.cores = 4; ++ ++ if (!lsms->fw_cfg) { ++ return; ++ } ++ ++ if (kvm_enabled()) { ++ if (strstr(lsmc->cpu_name, "5000")) { ++ product = "KVM"; ++ } ++ } else { ++ product = "Loongarch-3A5K-7A1000-TCG"; ++ } ++ ++ smbios_set_defaults("Loongson", product, lsmc->cpu_name, false, true, ++ SMBIOS_ENTRY_POINT_30); ++ ++ smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len, ++ &smbios_anchor, &smbios_anchor_len, &error_fatal); ++ ++ if (smbios_anchor) { ++ fw_cfg_add_file(lsms->fw_cfg, "etc/smbios/smbios-tables", ++ smbios_tables, smbios_tables_len); ++ fw_cfg_add_file(lsms->fw_cfg, "etc/smbios/smbios-anchor", ++ smbios_anchor, smbios_anchor_len); ++ } ++} ++ ++static void loongarch_machine_done(Notifier *notifier, void *data) ++{ ++ LoongarchMachineState *lsms = ++ container_of(notifier, LoongarchMachineState, machine_done); ++ ++ platform_bus_add_all_fdt_nodes( ++ lsms->fdt, NULL, VIRT_PLATFORM_BUS_BASEADDRESS, VIRT_PLATFORM_BUS_SIZE, ++ VIRT_PLATFORM_BUS_IRQ); ++ ++ qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); ++ /* load fdt */ ++ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); ++ memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); ++ memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); ++ rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); ++ ++ loongarch_acpi_setup(); ++ loongarch_build_smbios(lsms); ++} ++ ++#ifdef CONFIG_TCG ++#define FEATURE_REG 0x1fe00008 ++#define VENDOR_REG 0x1fe00010 ++#define CPUNAME_REG 0x1fe00020 ++#define OTHER_FUNC_REG 0x1fe00420 ++#define _str(x) #x ++#define str(x) _str(x) ++#define SIMPLE_OPS(ADDR, SIZE) \ ++ ({ \ ++ MemoryRegion *iomem = g_new(MemoryRegion, 1); \ ++ memory_region_init_io(iomem, NULL, &loongarch_qemu_ops, (void *)ADDR, \ ++ str(ADDR), SIZE); \ ++ memory_region_add_subregion_overlap(address_space_mem, ADDR, iomem, \ ++ 1); \ ++ }) ++ ++static int reg180; ++ ++static void loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ addr = ((hwaddr)(long)opaque) + addr; ++ addr = addr & 0xffffffff; ++ switch (addr) { ++ case 0x1fe00180: ++ reg180 = val; ++ break; ++ } ++} ++ ++static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t feature = 0UL; ++ addr = ((hwaddr)(long)opaque) + addr; ++ addr = addr & 0xffffffff; ++ switch (addr) { ++ case 0x1fe00180: ++ return reg180; ++ case 0x1001041c: ++ return 0xa800; ++ case FEATURE_REG: ++ feature |= 1UL << 2 | 1UL << 3 | 1UL << 4 | 1UL << 11; ++ return feature; ++ case VENDOR_REG: ++ return *(uint64_t *)"Loongson-3A5000"; ++ case CPUNAME_REG: ++ return *(uint64_t *)"3A5000"; ++ case 0x10013ffc: ++ return 0x80; ++ } ++ return 0; ++} ++ ++static const MemoryRegionOps loongarch_qemu_ops = { ++ .read = loongarch_qemu_read, ++ .write = loongarch_qemu_write, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++ .valid = { ++ .min_access_size = 4, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 4, ++ .max_access_size = 8, ++ }, ++}; ++#endif ++ ++static void loongarch_system_flash_cleanup_unused(LoongarchMachineState *lsms) ++{ ++ char *prop_name; ++ int i; ++ Object *dev_obj; ++ ++ for (i = 0; i < ARRAY_SIZE(lsms->flash); i++) { ++ dev_obj = OBJECT(lsms->flash[i]); ++ if (!object_property_get_bool(dev_obj, "realized", &error_abort)) { ++ prop_name = g_strdup_printf("pflash%d", i); ++ object_property_del(OBJECT(lsms), prop_name); ++ g_free(prop_name); ++ object_unparent(dev_obj); ++ lsms->flash[i] = NULL; ++ } ++ } ++} ++ ++static bool loongarch_system_flash_init(LoongarchMachineState *lsms) ++{ ++ int i = 0; ++ int64_t size = 0; ++ PFlashCFI01 *pflash = NULL; ++ BlockBackend *pflash_blk; ++ ++ for (i = 0; i < ARRAY_SIZE(lsms->flash); i++) { ++ pflash_blk = NULL; ++ pflash = NULL; ++ ++ pflash = lsms->flash[i]; ++ pflash_cfi01_legacy_drive(pflash, drive_get(IF_PFLASH, 0, i)); ++ ++ pflash_blk = pflash_cfi01_get_blk(pflash); ++ /*The pflash0 must be exist, or not support boot by pflash*/ ++ if (pflash_blk == NULL) { ++ if (i == 0) { ++ return false; ++ } else { ++ break; ++ } ++ } ++ ++ size = blk_getlength(pflash_blk); ++ if (size == 0 || size % FLASH_SECTOR_SIZE != 0) { ++ error_report("system firmware block device %s has invalid size " ++ "%" PRId64, ++ blk_name(pflash_blk), size); ++ error_report("its size must be a non-zero multiple of 0x%x", ++ FLASH_SECTOR_SIZE); ++ exit(1); ++ } ++ qdev_prop_set_uint32(DEVICE(pflash), "num-blocks", ++ size / FLASH_SECTOR_SIZE); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(pflash), &error_fatal); ++ if (i == 0) { ++ sysbus_mmio_map(SYS_BUS_DEVICE(pflash), 0, LS_BIOS_BASE); ++ } else { ++ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(pflash), 0, ++ LS_BIOS_VAR_BASE, 1); ++ } ++ } ++ ++ return true; ++} ++ ++static void ls3a5k_bios_init(LoongarchMachineState *lsms, ram_addr_t ram_size, ++ uint64_t highram_size, uint64_t phyAddr_initrd, ++ const char *kernel_filename, ++ const char *kernel_cmdline, ++ const char *initrd_filename) ++{ ++ MemoryRegion *bios; ++ bool fw_cfg_used = false; ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ char *filename; ++ int bios_size; ++ const char *bios_name; ++ ++ bios_name = MACHINE(lsms)->firmware; ++ if (kernel_filename) { ++ loaderparams.ram_size = ram_size; ++ loaderparams.kernel_filename = kernel_filename; ++ loaderparams.kernel_cmdline = kernel_cmdline; ++ loaderparams.initrd_filename = initrd_filename; ++ } ++ ++ if (loongarch_system_flash_init(lsms)) { ++ fw_cfg_used = true; ++ } else { ++ bios = g_new(MemoryRegion, 1); ++ memory_region_init_ram(bios, NULL, "loongarch.bios", LS_BIOS_SIZE, ++ &error_fatal); ++ memory_region_set_readonly(bios, true); ++ memory_region_add_subregion(get_system_memory(), LS_BIOS_BASE, bios); ++ ++ /* BIOS load */ ++ if (bios_name) { ++ if (access(bios_name, R_OK) == 0) { ++ load_image_targphys(bios_name, LS_BIOS_BASE, LS_BIOS_SIZE); ++ } else { ++ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); ++ load_image_targphys(filename, LS_BIOS_BASE, LS_BIOS_SIZE); ++ g_free(filename); ++ } ++ fw_cfg_used = true; ++ } else { ++ if (strstr(lsmc->cpu_name, "5000")) { ++ bios_size = sizeof(ls3a5k_aui_boot_code); ++ rom_add_blob_fixed("bios", ls3a5k_aui_boot_code, bios_size, ++ LS_BIOS_BASE); ++ } ++ ++ if (kernel_filename) { ++ lsms->reset_info[0]->vector = load_kernel(); ++ } ++ } ++ } ++ ++ loongarch_system_flash_cleanup_unused(lsms); ++ ++ if (fw_cfg_used) { ++ lsms->fw_cfg = loongarch_fw_cfg_init(ram_size, lsms); ++ rom_set_fw(lsms->fw_cfg); ++ fw_conf_init(ram_size); ++ rom_add_blob_fixed("fw_conf", (void *)&fw_config, sizeof(fw_config), ++ FW_CONF_ADDR); ++ ++ if (kernel_filename) { ++ fw_cfg_add_kernel_info(lsms->fw_cfg, highram_size, phyAddr_initrd); ++ } ++ } ++ ++ if (lsms->fw_cfg != NULL) { ++ fw_cfg_add_file(lsms->fw_cfg, "etc/memmap", la_memmap_table, ++ sizeof(struct la_memmap_entry) * (la_memmap_entries)); ++ } ++ ++ return; ++} ++ ++static void create_fdt(LoongarchMachineState *lsms) ++{ ++ lsms->fdt = create_device_tree(&lsms->fdt_size); ++ if (!lsms->fdt) { ++ error_report("create_device_tree() failed"); ++ exit(1); ++ } ++ ++ /* Header */ ++ qemu_fdt_setprop_string(lsms->fdt, "/", "compatible", ++ "linux,dummy-loongson3"); ++ qemu_fdt_setprop_cell(lsms->fdt, "/", "#address-cells", 0x2); ++ qemu_fdt_setprop_cell(lsms->fdt, "/", "#size-cells", 0x2); ++} ++ ++static void fdt_add_cpu_nodes(const LoongarchMachineState *lsms) ++{ ++ int num; ++ const MachineState *ms = MACHINE(lsms); ++ int smp_cpus = ms->smp.cpus; ++ ++ qemu_fdt_add_subnode(lsms->fdt, "/cpus"); ++ qemu_fdt_setprop_cell(lsms->fdt, "/cpus", "#address-cells", 0x1); ++ qemu_fdt_setprop_cell(lsms->fdt, "/cpus", "#size-cells", 0x0); ++ ++ /* cpu nodes */ ++ for (num = smp_cpus - 1; num >= 0; num--) { ++ char *nodename = g_strdup_printf("/cpus/cpu@%d", num); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num)); ++ ++ qemu_fdt_add_subnode(lsms->fdt, nodename); ++ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "cpu"); ++ qemu_fdt_setprop_string(lsms->fdt, nodename, "compatible", ++ cpu->dtb_compatible); ++ qemu_fdt_setprop_cell(lsms->fdt, nodename, "reg", num); ++ qemu_fdt_setprop_cell(lsms->fdt, nodename, "phandle", ++ qemu_fdt_alloc_phandle(lsms->fdt)); ++ g_free(nodename); ++ } ++ ++ /*cpu map */ ++ qemu_fdt_add_subnode(lsms->fdt, "/cpus/cpu-map"); ++ ++ for (num = smp_cpus - 1; num >= 0; num--) { ++ char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num); ++ char *map_path; ++ ++ if (ms->smp.threads > 1) { ++ map_path = ++ g_strdup_printf("/cpus/cpu-map/socket%d/core%d/thread%d", ++ num / (ms->smp.cores * ms->smp.threads), ++ (num / ms->smp.threads) % ms->smp.cores, ++ num % ms->smp.threads); ++ } else { ++ map_path = ++ g_strdup_printf("/cpus/cpu-map/socket%d/core%d", ++ num / ms->smp.cores, num % ms->smp.cores); ++ } ++ qemu_fdt_add_path(lsms->fdt, map_path); ++ qemu_fdt_setprop_phandle(lsms->fdt, map_path, "cpu", cpu_path); ++ ++ g_free(map_path); ++ g_free(cpu_path); ++ } ++} ++ ++static void fdt_add_fw_cfg_node(const LoongarchMachineState *lsms) ++{ ++ char *nodename; ++ hwaddr base = FW_CFG_ADDR; ++ ++ nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); ++ qemu_fdt_add_subnode(lsms->fdt, nodename); ++ qemu_fdt_setprop_string(lsms->fdt, nodename, "compatible", ++ "qemu,fw-cfg-mmio"); ++ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", 2, base, 2, 0x8); ++ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); ++ g_free(nodename); ++} ++ ++static void fdt_add_pcie_node(const LoongarchMachineState *lsms) ++{ ++ char *nodename; ++ hwaddr base_mmio = PCIE_MEMORY_BASE; ++ hwaddr size_mmio = PCIE_MEMORY_SIZE; ++ hwaddr base_pio = LS3A5K_ISA_IO_BASE; ++ hwaddr size_pio = LS_ISA_IO_SIZE; ++ hwaddr base_pcie = LS_PCIECFG_BASE; ++ hwaddr size_pcie = LS_PCIECFG_SIZE; ++ hwaddr base = base_pcie; ++ ++ nodename = g_strdup_printf("/pcie@%" PRIx64, base); ++ qemu_fdt_add_subnode(lsms->fdt, nodename); ++ qemu_fdt_setprop_string(lsms->fdt, nodename, "compatible", ++ "pci-host-ecam-generic"); ++ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "pci"); ++ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#address-cells", 3); ++ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#size-cells", 2); ++ qemu_fdt_setprop_cell(lsms->fdt, nodename, "linux,pci-domain", 0); ++ qemu_fdt_setprop_cells(lsms->fdt, nodename, "bus-range", 0, ++ PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1)); ++ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); ++ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", 2, base_pcie, 2, ++ size_pcie); ++ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "ranges", 1, ++ FDT_PCI_RANGE_IOPORT, 2, 0, 2, base_pio, 2, ++ size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, ++ 2, base_mmio, 2, size_mmio); ++ g_free(nodename); ++} ++ ++static void create_platform_bus(LoongarchMachineState *s, qemu_irq *pic) ++{ ++ DeviceState *dev; ++ SysBusDevice *sysbus; ++ int i; ++ MemoryRegion *sysmem = get_system_memory(); ++ ++ dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); ++ dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); ++ qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); ++ qdev_prop_set_uint32(dev, "mmio_size", VIRT_PLATFORM_BUS_SIZE); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ++ s->platform_bus_dev = dev; ++ ++ sysbus = SYS_BUS_DEVICE(dev); ++ for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { ++ int irq = VIRT_PLATFORM_BUS_IRQ + i; ++ sysbus_connect_irq(sysbus, i, pic[irq - LOONGARCH_PCH_IRQ_BASE]); ++ } ++ ++ memory_region_add_subregion(sysmem, VIRT_PLATFORM_BUS_BASEADDRESS, ++ sysbus_mmio_get_region(sysbus, 0)); ++} ++ ++static void ls3a5k_init(MachineState *args) ++{ ++ int i; ++ const char *cpu_model = args->cpu_type; ++ const char *kernel_filename = args->kernel_filename; ++ const char *kernel_cmdline = args->kernel_cmdline; ++ const char *initrd_filename = args->initrd_filename; ++ ++ ram_addr_t ram_size = args->ram_size; ++ MemoryRegion *address_space_mem = get_system_memory(); ++ ram_addr_t offset = 0; ++ MemoryRegion *isa_io = g_new(MemoryRegion, 1); ++ MemoryRegion *isa_mem = g_new(MemoryRegion, 1); ++ MachineState *machine = args; ++ MachineClass *mc = MACHINE_GET_CLASS(machine); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ int smp_cpus = machine->smp.cpus; ++ int nb_numa_nodes = machine->numa_state->num_nodes; ++ NodeInfo *numa_info = machine->numa_state->nodes; ++ LOONGARCHCPU *cpu; ++ CPULOONGARCHState *env; ++ qemu_irq *ls7a_apic = NULL; ++ qemu_irq *pirq = NULL; ++ PCIBus *pci_bus = NULL; ++ char *ramName = NULL; ++ uint64_t lowram_size = 0, highram_size = 0, phyAddr = 0, memmap_size = 0, ++ highram_end_addr = 0; ++ ++ CPUArchIdList *possible_cpus; ++ if (strstr(lsmc->cpu_name, "5000")) { ++ if (strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000")) && ++ strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("host"))) { ++ error_report("machine type %s does not match cpu type %s", ++ lsmc->cpu_name, cpu_model); ++ exit(1); ++ } ++ if (kvm_enabled()) { ++ kvm_vm_ioctl(kvm_state, KVM_LARCH_SET_CPUCFG, ls3a5k_cpucfgs); ++ } ++ } ++ ++ create_fdt(lsms); ++ ++ DPRINTF("isa 0x%lx\n", lsmc->isa_io_base); ++ DPRINTF("cpu_name %s bridge_name %s\n", lsmc->cpu_name, lsmc->bridge_name); ++ ++ /* init CPUs */ ++ mc->possible_cpu_arch_ids(machine); ++ possible_cpus = machine->possible_cpus; ++ ++ for (i = 0; i < smp_cpus; i++) { ++ Object *obj = NULL; ++ Error *local_err = NULL; ++ ++ obj = object_new(possible_cpus->cpus[i].type); ++ ++ object_property_set_uint(obj, "id", possible_cpus->cpus[i].arch_id, ++ &local_err); ++ object_property_set_bool(obj, "realized", true, &local_err); ++ ++ object_unref(obj); ++ error_propagate(&error_fatal, local_err); ++ ++ cpu = LOONGARCH_CPU(CPU(obj)); ++ if (cpu == NULL) { ++ fprintf(stderr, "Unable to find CPU definition\n"); ++ exit(1); ++ } ++ ++ env = &cpu->env; ++ cpu_states[i] = env; ++ env->CSR_TMID |= i; ++ ++ lsms->reset_info[i] = g_malloc0(sizeof(ResetData)); ++ lsms->reset_info[i]->cpu = cpu; ++ lsms->reset_info[i]->vector = env->active_tc.PC; ++ if (i == 0) { ++ qemu_register_reset(main_cpu_reset, lsms->reset_info[i]); ++ } else { ++ qemu_register_reset(slave_cpu_reset, lsms->reset_info[i]); ++ } ++ ++ /* Init CPU internal devices */ ++ cpu_init_irq(cpu); ++ cpu_loongarch_clock_init(cpu); ++ cpu_init_ipi(lsms, env->irq[12], i); ++ cpu_init_apic(lsms, env, i); ++ } ++ ++ lsms->hotpluged_cpu_num = 0; ++ fdt_add_cpu_nodes(lsms); ++ env = cpu_states[0]; ++ ++ /* node0 mem*/ ++ phyAddr = (uint64_t)0; ++ MemoryRegion *lowmem = g_new(MemoryRegion, 1); ++ ramName = g_strdup_printf("loongarch_ls3a.node%d.lowram", 0); ++ ++ lowram_size = MIN(ram_size, 256 * 0x100000); ++ memory_region_init_alias(lowmem, NULL, ramName, machine->ram, 0, ++ lowram_size); ++ memory_region_add_subregion(address_space_mem, phyAddr, lowmem); ++ ++ offset += lowram_size; ++ if (nb_numa_nodes > 0) { ++ highram_size = numa_info[0].node_mem - 256 * MiB; ++ if (numa_info[0].node_mem > GiB) { ++ memmap_size = numa_info[0].node_mem - GiB; ++ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); ++ } ++ } else { ++ highram_size = ram_size - 256 * MiB; ++ if (ram_size > GiB) { ++ memmap_size = ram_size - GiB; ++ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); ++ } ++ } ++ ++ phyAddr = (uint64_t)0x90000000; ++ MemoryRegion *highmem = g_new(MemoryRegion, 1); ++ ramName = g_strdup_printf("loongarch_ls3a.node%d.highram", 0); ++ memory_region_init_alias(highmem, NULL, ramName, machine->ram, offset, ++ highram_size); ++ memory_region_add_subregion(address_space_mem, phyAddr, highmem); ++ offset += highram_size; ++ phyAddr += highram_size; ++ ++ /* initrd address use high mem from high to low */ ++ highram_end_addr = phyAddr; ++ /* node1~ nodemax */ ++ for (i = 1; i < nb_numa_nodes; i++) { ++ MemoryRegion *nodemem = g_new(MemoryRegion, 1); ++ ramName = g_strdup_printf("loongarch_ls3a.node%d.ram", i); ++ memory_region_init_alias(nodemem, NULL, ramName, machine->ram, offset, ++ numa_info[i].node_mem); ++ memory_region_add_subregion(address_space_mem, phyAddr, nodemem); ++ la_memmap_add_entry(phyAddr, numa_info[i].node_mem, SYSTEM_RAM); ++ offset += numa_info[i].node_mem; ++ phyAddr += numa_info[i].node_mem; ++ } ++ ++ fdt_add_fw_cfg_node(lsms); ++ ls3a5k_bios_init(lsms, ram_size, highram_size, highram_end_addr, ++ kernel_filename, kernel_cmdline, initrd_filename); ++ ++ lsms->machine_done.notify = loongarch_machine_done; ++ qemu_add_machine_init_done_notifier(&lsms->machine_done); ++ /*vmstate_register_ram_global(bios);*/ ++ ++ /* initialize hotplug memory address space */ ++ lsms->hotplug_memory_size = 0; ++ ++ /* always allocate the device memory information */ ++ machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); ++ if (machine->ram_size < machine->maxram_size) { ++ int max_memslots; ++ ++ lsms->hotplug_memory_size = machine->maxram_size - machine->ram_size; ++ /* ++ * Limit the number of hotpluggable memory slots to half the number ++ * slots that KVM supports, leaving the other half for PCI and other ++ * devices. However ensure that number of slots doesn't drop below 32. ++ */ ++ max_memslots = LOONGARCH_MAX_RAM_SLOTS; ++ if (kvm_enabled()) { ++ max_memslots = kvm_get_max_memslots() / 2; ++ } ++ ++ if (machine->ram_slots == 0) ++ machine->ram_slots = ++ lsms->hotplug_memory_size / LOONGARCH_HOTPLUG_MEM_ALIGN; ++ ++ if (machine->ram_slots > max_memslots) { ++ error_report("Specified number of memory slots %" PRIu64 ++ " exceeds max supported %d", ++ machine->ram_slots, max_memslots); ++ exit(1); ++ } ++ ++ lsms->ram_slots = machine->ram_slots; ++ ++ machine->device_memory->base = get_hotplug_membase(machine->ram_size); ++ memory_region_init(&machine->device_memory->mr, OBJECT(lsms), ++ "device-memory", lsms->hotplug_memory_size); ++ memory_region_add_subregion(get_system_memory(), ++ machine->device_memory->base, ++ &machine->device_memory->mr); ++ } ++ ++ memory_region_init_alias(isa_io, NULL, "isa-io", get_system_io(), 0, ++ LS_ISA_IO_SIZE); ++ memory_region_init(isa_mem, NULL, "isa-mem", PCIE_MEMORY_SIZE); ++ memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, ++ isa_io); ++ memory_region_add_subregion(get_system_memory(), PCIE_MEMORY_BASE, ++ isa_mem); ++ ++ if (!strcmp(lsmc->bridge_name, "ls7a")) { ++ /*Initialize the 7A IO interrupt subsystem*/ ++ DeviceState *ls7a_dev; ++ lsms->apic_xrupt_override = kvm_irqchip_in_kernel(); ++ ls7a_apic = ls3a_intctl_init(machine, cpu_states); ++ if (!ls7a_apic) { ++ perror("Init 7A APIC failed\n"); ++ exit(1); ++ } ++ pci_bus = ls7a_init(machine, ls7a_apic, &ls7a_dev); ++ ++ object_property_add_link( ++ OBJECT(machine), LOONGARCH_MACHINE_ACPI_DEVICE_PROP, ++ TYPE_HOTPLUG_HANDLER, (Object **)&lsms->acpi_dev, ++ object_property_allow_set_link, OBJ_PROP_LINK_STRONG); ++ object_property_set_link(OBJECT(machine), ++ LOONGARCH_MACHINE_ACPI_DEVICE_PROP, ++ OBJECT(ls7a_dev), &error_abort); ++ ++ create_platform_bus(lsms, ls7a_apic); ++ ++#ifdef CONFIG_KVM ++ if (kvm_enabled()) { ++ kvm_direct_msi_allowed = ++ (kvm_check_extension(kvm_state, KVM_CAP_SIGNAL_MSI) > 0); ++ } else { ++ kvm_direct_msi_allowed = 0; ++ } ++ msi_nonbroken = kvm_direct_msi_allowed; ++#else ++ msi_nonbroken = true; ++#endif ++ sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, ++ ls7a_apic[LS7A_RTC_IRQ - LOONGARCH_PCH_IRQ_BASE]); ++ } ++ ++ /*Initialize the CPU serial device*/ ++ ++ if (serial_hd(0)) { ++ pirq = qemu_allocate_irqs( ++ legacy_set_irq, ++ ls7a_apic + (LS7A_UART_IRQ - LOONGARCH_PCH_IRQ_BASE), 1); ++ serial_mm_init(address_space_mem, LS7A_UART_BASE, 0, pirq[0], 115200, ++ serial_hd(0), DEVICE_NATIVE_ENDIAN); ++ } ++ ++ /*network card*/ ++ network_init(pci_bus); ++ /* VGA setup. Don't bother loading the bios. */ ++ pci_vga_init(pci_bus); ++ ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(qdev_new("iocsr")), &error_fatal); ++ ++#ifdef CONFIG_TCG ++ int nb_nodes = (smp_cpus - 1) / 4; ++ for (i = 0; i <= nb_nodes; i++) { ++ uint64_t off = (uint64_t)i << 44; ++ SIMPLE_OPS(((hwaddr)0x1fe00180 | off), 0x8); ++ SIMPLE_OPS(((hwaddr)0x1fe0019c | off), 0x8); ++ SIMPLE_OPS(((hwaddr)0x1fe001d0 | off), 0x8); ++ SIMPLE_OPS(((hwaddr)FEATURE_REG | off), 0x8); ++ SIMPLE_OPS(((hwaddr)VENDOR_REG | off), 0x8); ++ SIMPLE_OPS(((hwaddr)CPUNAME_REG | off), 0x8); ++ SIMPLE_OPS(((hwaddr)OTHER_FUNC_REG | off), 0x8); ++ } ++ ++ SIMPLE_OPS(0x1001041c, 0x4); ++ SIMPLE_OPS(0x10002000, 0x14); ++ SIMPLE_OPS(0x10013ffc, 0x4); ++#endif ++ ++ fdt_add_pcie_node(lsms); ++} ++ ++static const CPUArchIdList *loongarch_possible_cpu_arch_ids(MachineState *ms) ++{ ++ int i; ++ int max_cpus = ms->smp.max_cpus; ++ ++ if (ms->possible_cpus) { ++ /* ++ * make sure that max_cpus hasn't changed since the first use, i.e. ++ * -smp hasn't been parsed after it ++ */ ++ assert(ms->possible_cpus->len == max_cpus); ++ return ms->possible_cpus; ++ } ++ ++ ms->possible_cpus = ++ g_malloc0(sizeof(CPUArchIdList) + sizeof(CPUArchId) * max_cpus); ++ ms->possible_cpus->len = max_cpus; ++ for (i = 0; i < ms->possible_cpus->len; i++) { ++ ms->possible_cpus->cpus[i].type = ms->cpu_type; ++ ms->possible_cpus->cpus[i].vcpus_count = 1; ++ ms->possible_cpus->cpus[i].props.has_core_id = true; ++ ms->possible_cpus->cpus[i].props.core_id = i; ++ ms->possible_cpus->cpus[i].arch_id = i; ++ } ++ return ms->possible_cpus; ++} ++ ++static PFlashCFI01 *loongarch_pflash_create(LoongarchMachineState *lsms, ++ const char *name, ++ const char *alias_prop_name) ++{ ++ DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); ++ ++ qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); ++ qdev_prop_set_uint8(dev, "width", 1); ++ qdev_prop_set_string(dev, "name", name); ++ object_property_add_child(OBJECT(lsms), name, OBJECT(dev)); ++ object_property_add_alias(OBJECT(lsms), alias_prop_name, OBJECT(dev), ++ "drive"); ++ return PFLASH_CFI01(dev); ++} ++ ++static void loongarch_system_flash_create(LoongarchMachineState *lsms) ++{ ++ lsms->flash[0] = loongarch_pflash_create(lsms, "system.flash0", "pflash0"); ++ lsms->flash[1] = loongarch_pflash_create(lsms, "system.flash1", "pflash1"); ++} ++ ++static void loongarch_machine_initfn(Object *obj) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(obj); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ lsms->acpi_build_enabled = lsmc->has_acpi_build; ++ loongarch_system_flash_create(lsms); ++ lsms->oem_id = g_strndup(EFI_ACPI_OEM_ID, 6); ++ lsms->oem_table_id = g_strndup(EFI_ACPI_OEM_TABLE_ID, 6); ++} ++ ++static void ls3a5k_ls7a_machine_options(MachineClass *m) ++{ ++ char *cpu_name = get_host_cpu_model_name(); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(m); ++ m->desc = "Loongarch3a5k LS7A1000 machine"; ++ m->max_cpus = LOONGARCH_MAX_VCPUS; ++ m->alias = "loongson7a"; ++ m->is_default = 1; ++ lsmc->isa_io_base = LS3A5K_ISA_IO_BASE; ++ lsmc->pciecfg_base = LS_PCIECFG_BASE; ++ lsmc->ls7a_ioapic_reg_base = LS3A5K_LS7A_IOAPIC_REG_BASE; ++ lsmc->node_shift = 44; ++ strncpy(lsmc->cpu_name, cpu_name, sizeof(lsmc->cpu_name) - 1); ++ lsmc->cpu_name[sizeof(lsmc->cpu_name) - 1] = 0; ++ strncpy(lsmc->bridge_name, "ls7a", sizeof(lsmc->bridge_name) - 1); ++ lsmc->bridge_name[sizeof(lsmc->bridge_name) - 1] = 0; ++ compat_props_add(m->compat_props, loongarch_compat, loongarch_compat_len); ++} ++ ++static void ls3a_board_reset(MachineState *ms) ++{ ++ qemu_devices_reset(); ++#ifdef CONFIG_KVM ++ struct loongarch_kvm_irqchip *chip; ++ int length; ++ ++ if (!kvm_enabled()) { ++ return; ++ } ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct loongarch_gipiState); ++ chip = g_malloc0(length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; ++ chip->len = length; ++ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); ++ ++ length = sizeof(struct loongarch_kvm_irqchip) + ++ sizeof(struct ls7a_ioapic_state); ++ chip = g_realloc(chip, length); ++ memset(chip, 0, length); ++ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; ++ chip->len = length; ++ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); ++ ++ g_free(chip); ++#endif ++} ++ ++static CpuInstanceProperties ls3a_cpu_index_to_props(MachineState *ms, ++ unsigned cpu_index) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ ++ assert(cpu_index < possible_cpus->len); ++ return possible_cpus->cpus[cpu_index].props; ++} ++ ++static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) ++{ ++ int nb_numa_nodes = ms->numa_state->num_nodes; ++ int smp_cores = ms->smp.cores; ++ return idx / smp_cores % nb_numa_nodes; ++} ++ ++static void loongarch_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(oc); ++ ++ lsmc->get_hotplug_handler = mc->get_hotplug_handler; ++ lsmc->has_acpi_build = true; ++ mc->get_hotplug_handler = loongarch_get_hotpug_handler; ++ mc->has_hotpluggable_cpus = true; ++ mc->cpu_index_to_instance_props = ls3a_cpu_index_to_props; ++ mc->possible_cpu_arch_ids = loongarch_possible_cpu_arch_ids; ++ mc->get_default_cpu_node_id = ls3a_get_default_cpu_node_id; ++ mc->default_ram_size = 1 * GiB; ++ mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000"); ++ mc->default_ram_id = "loongarch_ls3a.ram"; ++ ++#ifdef CONFIG_TPM ++ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); ++#endif ++ ++ mc->reset = ls3a_board_reset; ++ mc->max_cpus = LOONGARCH_MAX_VCPUS; ++ hc->pre_plug = loongarch_machine_device_pre_plug; ++ hc->plug = loongarch_machine_device_plug; ++ hc->unplug = longson_machine_device_unplug; ++ hc->unplug_request = loongarch_machine_device_unplug_request; ++ ++ object_class_property_add(oc, "acpi", "OnOffAuto", loongarch_get_acpi, ++ loongarch_set_acpi, NULL, NULL); ++ object_class_property_set_description(oc, "acpi", "Enable ACPI"); ++} ++ ++static const TypeInfo loongarch_info = { ++ .name = TYPE_LOONGARCH_MACHINE, ++ .parent = TYPE_MACHINE, ++ .abstract = true, ++ .instance_size = sizeof(LoongarchMachineState), ++ .instance_init = loongarch_machine_initfn, ++ .class_size = sizeof(LoongarchMachineClass), ++ .class_init = loongarch_class_init, ++ .interfaces = (InterfaceInfo[]){ { TYPE_HOTPLUG_HANDLER }, {} }, ++}; ++ ++static void loongarch_machine_register_types(void) ++{ ++ type_register_static(&loongarch_info); ++} ++ ++type_init(loongarch_machine_register_types) ++ ++ DEFINE_LS3A5K_MACHINE(loongson7a_v1_0, "loongson7a_v1.0", ++ ls3a5k_ls7a_machine_options); +diff --git a/hw/loongarch/larch_hotplug.c b/hw/loongarch/larch_hotplug.c +new file mode 100644 +index 0000000000..52f13af7b3 +--- /dev/null ++++ b/hw/loongarch/larch_hotplug.c +@@ -0,0 +1,377 @@ ++/* ++ * Hotplug emulation on Loongarch system. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qemu-common.h" ++#include "qemu/queue.h" ++#include "qemu/units.h" ++#include "qemu/cutils.h" ++#include "qemu/bcd.h" ++#include "hw/hotplug.h" ++#include "hw/loongarch/cpudevs.h" ++#include "hw/mem/memory-device.h" ++#include "sysemu/numa.h" ++#include "sysemu/cpus.h" ++#include "hw/loongarch/larch.h" ++#include "hw/cpu/core.h" ++#include "hw/nvram/fw_cfg.h" ++#include "hw/platform-bus.h" ++ ++/* find cpu slot in machine->possible_cpus by core_id */ ++static CPUArchId *loongarch_find_cpu_slot(MachineState *ms, uint32_t id, ++ int *idx) ++{ ++ int index = id; ++ ++ if (index >= ms->possible_cpus->len) { ++ return NULL; ++ } ++ if (idx) { ++ *idx = index; ++ } ++ return &ms->possible_cpus->cpus[index]; ++} ++ ++static void loongarch_memory_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ Error *local_err = NULL; ++ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); ++ HotplugHandlerClass *hhc; ++ uint64_t size; ++ ++ size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); ++ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { ++ error_setg(&local_err, ++ "Hotplugged memory size must be a multiple of " ++ "%lld MB", ++ LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); ++ goto out; ++ } ++ ++ pc_dimm_plug(PC_DIMM(dev), MACHINE(lsms)); ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &error_abort); ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_memory_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ Error *local_err = NULL; ++ HotplugHandlerClass *hhc; ++ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); ++ ++ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { ++ error_setg( ++ &local_err, ++ "memory hotplug is not enabled: missing acpi device or acpi disabled"); ++ goto out; ++ } ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); ++ ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ CPUArchId *found_cpu; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); ++ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); ++ ++ if (local_err) { ++ goto out; ++ } ++ ++ loongarch_cpu_destroy(machine, cpu); ++ ++ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); ++ found_cpu->cpu = NULL; ++ object_unparent(OBJECT(dev)); ++ lsms->hotpluged_cpu_num -= 1; ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_memory_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ Error *local_err = NULL; ++ HotplugHandlerClass *hhc; ++ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); ++ ++ if (local_err) { ++ goto out; ++ } ++ ++ pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); ++ object_unparent(OBJECT(dev)); ++ ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineState *ms = MACHINE(OBJECT(hotplug_dev)); ++ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); ++ LoongarchMachineState *lsms = LoongarchMACHINE(ms); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); ++ CPUArchId *cpu_slot; ++ Error *local_err = NULL; ++ int index; ++ int free_index = lsms->hotpluged_cpu_num + ms->smp.cpus; ++ int max_cpus = ms->smp.max_cpus; ++ ++ if (dev->hotplugged && !mc->has_hotpluggable_cpus) { ++ error_setg(&local_err, "CPU hotplug not supported for this machine"); ++ goto out; ++ } ++ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ return; ++ } ++ ++ /* if ID is not set, set it based on core properties */ ++ if (cpu->id == UNASSIGNED_CPU_ID) { ++ if ((cpu->core_id) > (max_cpus - 1)) { ++ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", ++ cpu->core_id, max_cpus - 1); ++ return; ++ } ++ ++ if (free_index > (max_cpus - 1)) { ++ error_setg(errp, "The maximum number of CPUs cannot exceed %u.", ++ max_cpus); ++ return; ++ } ++ ++ if (cpu->core_id != free_index) { ++ error_setg(errp, "Invalid CPU core-id: %u must be :%u", ++ cpu->core_id, free_index); ++ return; ++ } ++ ++ cpu->id = cpu->core_id; ++ } ++ ++ cpu_slot = loongarch_find_cpu_slot(MACHINE(hotplug_dev), cpu->id, &index); ++ if (!cpu_slot) { ++ error_setg(&local_err, "core id %d out of range", cpu->id); ++ goto out; ++ } ++ ++ if (cpu_slot->cpu) { ++ error_setg(&local_err, "core %d already populated", cpu->id); ++ goto out; ++ } ++ ++ numa_cpu_pre_plug(cpu_slot, dev, &local_err); ++ ++ return; ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_memory_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ PCDIMMDevice *dimm = PC_DIMM(dev); ++ Error *local_err = NULL; ++ uint64_t size; ++ ++ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { ++ error_setg( ++ errp, ++ "memory hotplug is not enabled: missing acpi device or acpi disabled"); ++ return; ++ } ++ ++ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { ++ error_setg(errp, ++ "Hotplugged memory size must be a multiple of " ++ "%lld MB", ++ LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); ++ return; ++ } ++ ++ pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp); ++} ++ ++static void loongarch_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ CPUArchId *found_cpu; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); ++ ++ if (lsms->acpi_dev) { ++ loongarch_cpu_create(machine, cpu, errp); ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ } ++ ++ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); ++ found_cpu->cpu = OBJECT(dev); ++ lsms->hotpluged_cpu_num += 1; ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void loongarch_cpu_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); ++ Error *local_err = NULL; ++ HotplugHandlerClass *hhc; ++ int idx = -1; ++ ++ if (!lsms->acpi_dev) { ++ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); ++ goto out; ++ } ++ ++ loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, &idx); ++ assert(idx != -1); ++ if (idx == 0) { ++ error_setg(&local_err, "Boot CPU is unpluggable"); ++ goto out; ++ } ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); ++ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); ++ ++ if (local_err) { ++ goto out; ++ } ++ ++out: ++ error_propagate(errp, local_err); ++} ++ ++void longson_machine_device_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); ++ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ loongarch_memory_unplug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ if (!mc->has_hotpluggable_cpus) { ++ error_setg(errp, "CPU hot unplug not supported on this machine"); ++ return; ++ } ++ loongarch_cpu_unplug(hotplug_dev, dev, errp); ++ } else { ++ error_setg(errp, ++ "acpi: device unplug for not supported device" ++ " type: %s", ++ object_get_typename(OBJECT(dev))); ++ } ++ ++ return; ++} ++ ++void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ loongarch_memory_unplug_request(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ loongarch_cpu_unplug_request(hotplug_dev, dev, errp); ++ } ++} ++ ++HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, ++ DeviceState *dev) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || ++ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) || ++ object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) { ++ return HOTPLUG_HANDLER(machine); ++ } ++ return NULL; ++} ++ ++void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ loongarch_memory_pre_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ loongarch_cpu_pre_plug(hotplug_dev, dev, errp); ++ } ++} ++ ++void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); ++ ++ if (lsms->platform_bus_dev) { ++ MachineClass *mc = MACHINE_GET_CLASS(lsms); ++ ++ if (device_is_dynamic_sysbus(mc, dev)) { ++ platform_bus_link_device( ++ PLATFORM_BUS_DEVICE(lsms->platform_bus_dev), ++ SYS_BUS_DEVICE(dev)); ++ } ++ } ++ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ loongarch_memory_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ loongarch_cpu_plug(hotplug_dev, dev, errp); ++ } ++} +diff --git a/hw/loongarch/larch_int.c b/hw/loongarch/larch_int.c +new file mode 100644 +index 0000000000..ff3750e982 +--- /dev/null ++++ b/hw/loongarch/larch_int.c +@@ -0,0 +1,87 @@ ++/* ++ * QEMU LOONGARCH interrupt support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/main-loop.h" ++#include "hw/hw.h" ++#include "hw/irq.h" ++#include "hw/loongarch/cpudevs.h" ++#include "cpu.h" ++#include "sysemu/kvm.h" ++#include "kvm_larch.h" ++#ifdef CONFIG_KVM ++#include ++#endif ++ ++static void cpu_irq_request(void *opaque, int irq, int level) ++{ ++ LOONGARCHCPU *cpu = opaque; ++ CPULOONGARCHState *env = &cpu->env; ++ CPUState *cs = CPU(cpu); ++ bool locked = false; ++ ++ if (irq < 0 || irq > 13) { ++ return; ++ } ++ ++ /* Make sure locking works even if BQL is already held by the caller */ ++ if (!qemu_mutex_iothread_locked()) { ++ locked = true; ++ qemu_mutex_lock_iothread(); ++ } ++ ++ if (level) { ++ env->CSR_ESTAT |= 1 << irq; ++ } else { ++ env->CSR_ESTAT &= ~(1 << irq); ++ } ++ ++ if (kvm_enabled()) { ++ if (irq == 2) { ++ kvm_loongarch_set_interrupt(cpu, irq, level); ++ } else if (irq == 3) { ++ kvm_loongarch_set_interrupt(cpu, irq, level); ++ } else if (irq == 12) { ++ kvm_loongarch_set_ipi_interrupt(cpu, irq, level); ++ } ++ } ++ ++ if (env->CSR_ESTAT & CSR_ESTAT_IPMASK) { ++ cpu_interrupt(cs, CPU_INTERRUPT_HARD); ++ } else { ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); ++ } ++ ++ if (locked) { ++ qemu_mutex_unlock_iothread(); ++ } ++} ++ ++void cpu_init_irq(LOONGARCHCPU *cpu) ++{ ++ CPULOONGARCHState *env = &cpu->env; ++ qemu_irq *qi; ++ int i; ++ ++ qi = qemu_allocate_irqs(cpu_irq_request, loongarch_env_get_cpu(env), ++ N_IRQS); ++ for (i = 0; i < N_IRQS; i++) { ++ env->irq[i] = qi[i]; ++ } ++} +diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c +new file mode 100644 +index 0000000000..933b3f2869 +--- /dev/null ++++ b/hw/loongarch/ls7a_nb.c +@@ -0,0 +1,289 @@ ++/* ++ * Loongarch 7A1000 north bridge support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++ ++#include "hw/hw.h" ++#include "hw/irq.h" ++#include "hw/sysbus.h" ++#include "hw/pci/pci.h" ++#include "hw/i386/pc.h" ++#include "hw/pci/pci_host.h" ++#include "hw/pci/pcie_host.h" ++#include "sysemu/sysemu.h" ++#include "exec/address-spaces.h" ++#include "qapi/error.h" ++#include "hw/loongarch/cpudevs.h" ++#include "hw/acpi/ls7a.h" ++#include "hw/i386/pc.h" ++#include "hw/isa/isa.h" ++#include "hw/boards.h" ++#include "qemu/log.h" ++#include "hw/loongarch/bios.h" ++#include "hw/loader.h" ++#include "elf.h" ++#include "exec/address-spaces.h" ++#include "exec/memory.h" ++#include "hw/pci/pci_bridge.h" ++#include "hw/pci/pci_bus.h" ++#include "linux/kvm.h" ++#include "sysemu/kvm.h" ++#include "sysemu/runstate.h" ++#include "sysemu/reset.h" ++#include "migration/vmstate.h" ++#include "hw/loongarch/larch.h" ++#include "hw/loongarch/ls7a.h" ++ ++#undef DEBUG_LS7A ++ ++#ifdef DEBUG_LS7A ++#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__) ++#else ++#define DPRINTF(fmt, ...) ++#endif ++ ++static void ls7a_reset(void *opaque) ++{ ++ uint64_t wmask; ++ wmask = ~(-1); ++ ++ PCIDevice *dev = opaque; ++ pci_set_word(dev->config + PCI_VENDOR_ID, 0x0014); ++ pci_set_word(dev->wmask + PCI_VENDOR_ID, wmask & 0xffff); ++ pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); ++ pci_set_word(dev->config + PCI_DEVICE_ID, 0x7a00); ++ pci_set_word(dev->wmask + PCI_DEVICE_ID, wmask & 0xffff); ++ pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); ++ pci_set_word(dev->config + 0x4, 0x0000); ++ pci_set_word(dev->config + PCI_STATUS, 0x0010); ++ pci_set_word(dev->wmask + PCI_STATUS, wmask & 0xffff); ++ pci_set_word(dev->cmask + PCI_STATUS, 0xffff); ++ pci_set_byte(dev->config + PCI_REVISION_ID, 0x0); ++ pci_set_byte(dev->wmask + PCI_REVISION_ID, wmask & 0xff); ++ pci_set_byte(dev->cmask + PCI_REVISION_ID, 0xff); ++ pci_set_byte(dev->config + 0x9, 0x00); ++ pci_set_byte(dev->wmask + 0x9, wmask & 0xff); ++ pci_set_byte(dev->cmask + 0x9, 0xff); ++ pci_set_byte(dev->config + 0xa, 0x00); ++ pci_set_byte(dev->wmask + 0xa, wmask & 0xff); ++ pci_set_byte(dev->cmask + 0xa, 0xff); ++ pci_set_byte(dev->config + 0xb, 0x06); ++ pci_set_byte(dev->wmask + 0xb, wmask & 0xff); ++ pci_set_byte(dev->cmask + 0xb, 0xff); ++ pci_set_byte(dev->config + 0xc, 0x00); ++ pci_set_byte(dev->wmask + 0xc, wmask & 0xff); ++ pci_set_byte(dev->cmask + 0xc, 0xff); ++ pci_set_byte(dev->config + 0xe, 0x80); ++ pci_set_byte(dev->wmask + 0xe, wmask & 0xff); ++ pci_set_byte(dev->cmask + 0xe, 0xff); ++} ++ ++static const VMStateDescription vmstate_ls7a_pcie = { ++ .name = "LS7A_PCIE", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]){ VMSTATE_PCI_DEVICE(dev, LS7APCIState), ++ VMSTATE_STRUCT(pm, LS7APCIState, 0, ++ vmstate_ls7a_pm, LS7APCIPMRegs), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin) ++{ ++ PCIINTxRoute route; ++ ++ route.irq = pin; ++ route.mode = PCI_INTX_ENABLED; ++ return route; ++} ++ ++static int pci_ls7a_map_irq(PCIDevice *d, int irq_num) ++{ ++ int irq; ++ ++ irq = 16 + ((PCI_SLOT(d->devfn) * 4 + irq_num) & 0xf); ++ return irq; ++} ++ ++static void pci_ls7a_set_irq(void *opaque, int irq_num, int level) ++{ ++ qemu_irq *pic = opaque; ++ DPRINTF("------ %s irq %d %d\n", __func__, irq_num, level); ++ qemu_set_irq(pic[irq_num], level); ++} ++ ++static void ls7a_pcie_realize(PCIDevice *dev, Error **errp) ++{ ++ LS7APCIState *s = PCIE_LS7A(dev); ++ /* Ls7a North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */ ++ pci_config_set_prog_interface(dev->config, 0x00); ++ ++ /* set the default value of north bridge pci config */ ++ qemu_register_reset(ls7a_reset, s); ++} ++ ++static AddressSpace *ls7a_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) ++{ ++ return &address_space_memory; ++} ++ ++static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, ++ qemu_irq *pic) ++{ ++ LoongarchMachineState *lsms = LoongarchMACHINE(machine); ++ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); ++ PCIExpressHost *e; ++ PCIHostState *phb; ++ ++ e = PCIE_HOST_BRIDGE(dev); ++ phb = PCI_HOST_BRIDGE(e); ++ phb->bus = pci_register_root_bus( ++ dev, "pcie.0", pci_ls7a_set_irq, pci_ls7a_map_irq, pic, ++ get_system_memory(), get_system_io(), (1 << 3), 128, TYPE_PCIE_BUS); ++ pcie_host_mmcfg_update(e, true, lsmc->pciecfg_base, LS_PCIECFG_SIZE); ++ DPRINTF("------ %d\n", __LINE__); ++ ++ pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); ++ ++ return phb->bus; ++} ++ ++PCIBus *ls7a_init(MachineState *machine, qemu_irq *pic, DeviceState **ls7a_dev) ++{ ++ DeviceState *dev; ++ PCIHostState *phb; ++ LS7APCIState *pbs; ++ PCIDevice *pcid; ++ PCIBus *pci_bus; ++ PCIExpressHost *e; ++ ++ /*1. init the HT PCI CFG*/ ++ DPRINTF("------ %d\n", __LINE__); ++ dev = qdev_new(TYPE_LS7A_PCIE_HOST_BRIDGE); ++ e = PCIE_HOST_BRIDGE(dev); ++ phb = PCI_HOST_BRIDGE(e); ++ ++ DPRINTF("------ %d\n", __LINE__); ++ pci_bus = pci_ls7a_init(machine, dev, pic); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ++ phb->bus = pci_bus; ++ /* set the pcihost pointer after rs780_pcihost_initfn is called */ ++ DPRINTF("------ %d\n", __LINE__); ++ pcid = pci_new(PCI_DEVFN(0, 0), TYPE_PCIE_LS7A); ++ pbs = PCIE_LS7A(pcid); ++ pbs->pciehost = LS7A_PCIE_HOST_BRIDGE(dev); ++ pbs->pciehost->pci_dev = pbs; ++ ++ if (ls7a_dev) { ++ *ls7a_dev = DEVICE(pcid); ++ } ++ ++ pci_realize_and_unref(pcid, phb->bus, &error_fatal); ++ ++ /* IOMMU */ ++ pci_setup_iommu(phb->bus, ls7a_pci_dma_iommu, NULL); ++ ++ ls7a_pm_init(&pbs->pm, pic); ++ DPRINTF("------ %d\n", __LINE__); ++ /*3. init the north bridge VGA,not do now*/ ++ return pci_bus; ++} ++ ++LS7APCIState *get_ls7a_type(Object *obj) ++{ ++ LS7APCIState *pbs; ++ ++ pbs = PCIE_LS7A(obj); ++ return pbs; ++} ++ ++static void ls7a_pcie_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ++ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); ++ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); ++ ++ k->realize = ls7a_pcie_realize; ++ k->vendor_id = 0x0014; ++ k->device_id = 0x7a00; ++ k->revision = 0x00; ++ k->class_id = PCI_CLASS_BRIDGE_HOST; ++ dc->desc = "LS7A1000 PCIE Host bridge"; ++ dc->vmsd = &vmstate_ls7a_pcie; ++ /* ++ * PCI-facing part of the host bridge, not usable without the ++ * host-facing part, which can't be device_add'ed, yet. ++ */ ++ dc->user_creatable = false; ++ hc->plug = ls7a_pm_device_plug_cb; ++ hc->unplug_request = ls7a_pm_device_unplug_request_cb; ++ hc->unplug = ls7a_pm_device_unplug_cb; ++ adevc->ospm_status = ls7a_pm_ospm_status; ++ adevc->send_event = ls7a_send_gpe; ++ adevc->madt_cpu = ls7a_madt_cpu_entry; ++} ++ ++static void ls7a_pci_add_properties(LS7APCIState *ls7a) ++{ ++ ls7a_pm_add_properties(OBJECT(ls7a), &ls7a->pm, NULL); ++} ++ ++static void ls7a_pci_initfn(Object *obj) ++{ ++ LS7APCIState *ls7a = get_ls7a_type(obj); ++ ++ ls7a_pci_add_properties(ls7a); ++} ++ ++static const TypeInfo ls7a_pcie_device_info = { ++ .name = TYPE_PCIE_LS7A, ++ .parent = TYPE_PCI_DEVICE, ++ .instance_size = sizeof(LS7APCIState), ++ .class_init = ls7a_pcie_class_init, ++ .instance_init = ls7a_pci_initfn, ++ .interfaces = ++ (InterfaceInfo[]){ ++ { TYPE_HOTPLUG_HANDLER }, ++ { TYPE_ACPI_DEVICE_IF }, ++ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, ++ {}, ++ }, ++}; ++ ++static void ls7a_pciehost_class_init(ObjectClass *klass, void *data) ++{ ++ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); ++ k->parent_class.fw_name = "pci"; ++} ++ ++static const TypeInfo ls7a_pciehost_info = { ++ .name = TYPE_LS7A_PCIE_HOST_BRIDGE, ++ .parent = TYPE_PCIE_HOST_BRIDGE, ++ .instance_size = sizeof(LS7APCIEHost), ++ .class_init = ls7a_pciehost_class_init, ++}; ++ ++static void ls7a_register_types(void) ++{ ++ type_register_static(&ls7a_pciehost_info); ++ type_register_static(&ls7a_pcie_device_info); ++} ++ ++type_init(ls7a_register_types) +diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build +new file mode 100644 +index 0000000000..ca4d5567b5 +--- /dev/null ++++ b/hw/loongarch/meson.build +@@ -0,0 +1,15 @@ ++loongarch_ss = ss.source_set() ++loongarch_ss.add(files('larch_3a.c'), fdt) ++loongarch_ss.add(files( ++ 'larch_int.c', ++ 'larch_hotplug.c', ++ 'ls7a_nb.c', ++ 'ioapic.c', ++ 'acpi-build.c', ++ 'ipi.c', ++ 'apic.c', ++ 'iocsr.c', ++ 'sysbus-fdt.c', ++)) ++ ++hw_arch += {'loongarch64': loongarch_ss} +diff --git a/hw/loongarch/sysbus-fdt.c b/hw/loongarch/sysbus-fdt.c +new file mode 100644 +index 0000000000..05b4dda33a +--- /dev/null ++++ b/hw/loongarch/sysbus-fdt.c +@@ -0,0 +1,178 @@ ++/* ++ * Loongarch Platform Bus device tree generation helpers ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include ++#include "qemu/error-report.h" ++#include "sysemu/device_tree.h" ++#include "hw/platform-bus.h" ++#include "hw/display/ramfb.h" ++#include "hw/loongarch/sysbus-fdt.h" ++#include "sysemu/tpm.h" ++ ++/* ++ * internal struct that contains the information to create dynamic ++ * sysbus device node ++ */ ++typedef struct PlatformBusFDTData { ++ void *fdt; /* device tree handle */ ++ int irq_start; /* index of the first IRQ usable by platform bus devices */ ++ const char *pbus_node_name; /* name of the platform bus node */ ++ PlatformBusDevice *pbus; ++} PlatformBusFDTData; ++ ++/* struct that allows to match a device and create its FDT node */ ++typedef struct BindingEntry { ++ const char *typename; ++ const char *compat; ++ int (*add_fn)(SysBusDevice *sbdev, void *opaque); ++ bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo); ++} BindingEntry; ++ ++static int no_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ return 0; ++} ++ ++/* Device type based matching */ ++static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry) ++{ ++ return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename); ++} ++ ++#define TYPE_BINDING(type, add_fn) \ ++ { \ ++ (type), NULL, (add_fn), NULL \ ++ } ++ ++#ifdef CONFIG_TPM ++/* ++ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS ++ * ++ * See kernel documentation: ++ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt ++ * Optional interrupt for command completion is not exposed ++ */ ++static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ PlatformBusFDTData *data = opaque; ++ PlatformBusDevice *pbus = data->pbus; ++ void *fdt = data->fdt; ++ const char *parent_node = data->pbus_node_name; ++ char *nodename; ++ uint32_t reg_attr[2]; ++ uint64_t mmio_base; ++ ++ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); ++ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); ++ qemu_fdt_add_subnode(fdt, nodename); ++ ++ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); ++ ++ reg_attr[0] = cpu_to_be32(mmio_base); ++ reg_attr[1] = cpu_to_be32(0x5000); ++ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); ++ ++ g_free(nodename); ++ ++ return 0; ++} ++#endif ++ ++/* list of supported dynamic sysbus bindings */ ++static const BindingEntry bindings[] = { ++#ifdef CONFIG_TPM ++ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), ++#endif ++ TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), ++ TYPE_BINDING("", NULL), /* last element */ ++}; ++ ++/** ++ * add_fdt_node - add the device tree node of a dynamic sysbus device ++ * ++ * @sbdev: handle to the sysbus device ++ * @opaque: handle to the PlatformBusFDTData ++ * ++ * Checks the sysbus type belongs to the list of device types that ++ * are dynamically instantiable and if so call the node creation ++ * function. ++ */ ++static void add_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(bindings); i++) { ++ const BindingEntry *iter = &bindings[i]; ++ ++ if (type_match(sbdev, iter)) { ++ if (!iter->match_fn || iter->match_fn(sbdev, iter)) { ++ ret = iter->add_fn(sbdev, opaque); ++ assert(!ret); ++ return; ++ } ++ } ++ } ++ error_report("Device %s can not be dynamically instantiated", ++ qdev_fw_name(DEVICE(sbdev))); ++ exit(1); ++} ++ ++void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, ++ hwaddr bus_size, int irq_start) ++{ ++ const char platcomp[] = "qemu,platform\0simple-bus"; ++ PlatformBusDevice *pbus; ++ DeviceState *dev; ++ gchar *node; ++ ++ assert(fdt); ++ ++ node = g_strdup_printf("/platform@%" PRIx64, addr); ++ ++ /* Create a /platform node that we can put all devices into */ ++ qemu_fdt_add_subnode(fdt, node); ++ qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); ++ ++ /* ++ * Our platform bus region is less than 32bits, so 1 cell is enough for ++ * address and size ++ */ ++ qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); ++ qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); ++ qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, bus_size); ++ if (intc != NULL) { ++ qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc); ++ } ++ dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); ++ pbus = PLATFORM_BUS_DEVICE(dev); ++ ++ PlatformBusFDTData data = { ++ .fdt = fdt, ++ .irq_start = irq_start, ++ .pbus_node_name = node, ++ .pbus = pbus, ++ }; ++ ++ /* Loop through all dynamic sysbus devices and create their node */ ++ foreach_dynamic_sysbus_device(add_fdt_node, &data); ++ ++ g_free(node); ++} +diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h +index 4590bcc968..b165453fa1 100644 +--- a/include/disas/dis-asm.h ++++ b/include/disas/dis-asm.h +@@ -336,7 +336,7 @@ typedef struct disassemble_info { + Returns an errno value or 0 for success. */ + int (*read_memory_func) + (bfd_vma memaddr, bfd_byte *myaddr, int length, +- struct disassemble_info *info); ++ struct disassemble_info *info); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and +@@ -465,6 +465,7 @@ int print_insn_riscv32 (bfd_vma, disassemble_info*); + int print_insn_riscv64 (bfd_vma, disassemble_info*); + int print_insn_rx(bfd_vma, disassemble_info *); + int print_insn_hexagon(bfd_vma, disassemble_info *); ++int print_insn_loongarch(bfd_vma, disassemble_info*); + + #ifdef CONFIG_CAPSTONE + bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); +diff --git a/include/elf.h b/include/elf.h +index 79c188b62f..cd7808f37a 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -182,6 +182,8 @@ typedef struct mips_elf_abiflags_v0 { + + #define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */ + ++#define EM_LOONGARCH 258 /* Loongarch */ ++ + /* + * This is an interim value that we will use until the committee comes + * up with a final number. +diff --git a/include/hw/loongarch/bios.h b/include/hw/loongarch/bios.h +new file mode 100644 +index 0000000000..8e0f6c7d64 +--- /dev/null ++++ b/include/hw/loongarch/bios.h +@@ -0,0 +1,24 @@ ++/* ++ * bios on Loongarch system. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/units.h" ++#include "cpu.h" ++ ++#define BIOS_SIZE (4 * MiB) ++#define BIOS_FILENAME "loongarch_bios.bin" +diff --git a/include/hw/loongarch/cpudevs.h b/include/hw/loongarch/cpudevs.h +new file mode 100644 +index 0000000000..ea4007f8fa +--- /dev/null ++++ b/include/hw/loongarch/cpudevs.h +@@ -0,0 +1,71 @@ ++/* ++ * cpu device emulation on Loongarch system. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_LOONGARCH_CPUDEVS_H ++#define HW_LOONGARCH_CPUDEVS_H ++ ++#include "target/loongarch64/cpu-qom.h" ++ ++/* Definitions for LOONGARCH CPU internal devices. */ ++#define MAX_GIPI_CORE_NUM 256 ++#define MAX_GIPI_MBX_NUM 4 ++ ++#define LS3A_INTC_IP 8 ++#define MAX_CORES 256 ++#define EXTIOI_IRQS (256) ++#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) ++/* map to ipnum per 32 irqs */ ++#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) ++ ++typedef struct gipi_core { ++ uint32_t status; ++ uint32_t en; ++ uint32_t set; ++ uint32_t clear; ++ uint64_t buf[MAX_GIPI_MBX_NUM]; ++ qemu_irq irq; ++} gipi_core; ++ ++typedef struct gipiState { ++ gipi_core core[MAX_GIPI_CORE_NUM]; ++} gipiState; ++ ++typedef struct apicState { ++ /* hardware state */ ++ uint8_t ext_en[EXTIOI_IRQS_BITMAP_SIZE]; ++ uint8_t ext_bounce[EXTIOI_IRQS_BITMAP_SIZE]; ++ uint8_t ext_isr[EXTIOI_IRQS_BITMAP_SIZE]; ++ uint8_t ext_coreisr[MAX_CORES][EXTIOI_IRQS_BITMAP_SIZE]; ++ uint8_t ext_ipmap[EXTIOI_IRQS_IPMAP_SIZE]; ++ uint8_t ext_coremap[EXTIOI_IRQS]; ++ uint16_t ext_nodetype[16]; ++ uint64_t ext_control; ++ ++ /* software state */ ++ uint8_t ext_sw_ipmap[EXTIOI_IRQS]; ++ uint8_t ext_sw_coremap[EXTIOI_IRQS]; ++ uint8_t ext_ipisr[MAX_CORES * LS3A_INTC_IP][EXTIOI_IRQS_BITMAP_SIZE]; ++ ++ qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP]; ++ qemu_irq *irq; ++} apicState; ++ ++void cpu_init_irq(LOONGARCHCPU *cpu); ++void cpu_loongarch_clock_init(LOONGARCHCPU *cpu); ++#endif +diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h +new file mode 100644 +index 0000000000..a9f8dea9f5 +--- /dev/null ++++ b/include/hw/loongarch/larch.h +@@ -0,0 +1,164 @@ ++/* ++ * Hotplug emulation on Loongarch system. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_LOONGARCH_H ++#define HW_LOONGARCH_H ++ ++#include "target/loongarch64/cpu.h" ++#include "qemu-common.h" ++#include "exec/memory.h" ++#include "hw/mem/pc-dimm.h" ++#include "hw/hotplug.h" ++#include "hw/boards.h" ++#include "hw/acpi/acpi.h" ++#include "qemu/notify.h" ++#include "qemu/error-report.h" ++#include "qemu/queue.h" ++#include "hw/acpi/memory_hotplug.h" ++#include "hw/loongarch/cpudevs.h" ++#include "hw/block/flash.h" ++ ++#define LOONGARCH_MAX_VCPUS 256 ++#define LOONGARCH_MAX_PFLASH 2 ++/* 256MB alignment for hotplug memory region */ ++#define LOONGARCH_HOTPLUG_MEM_ALIGN (1ULL << 28) ++#define LOONGARCH_MAX_RAM_SLOTS 10 ++ ++/* Memory types: */ ++#define SYSTEM_RAM 1 ++#define SYSTEM_RAM_RESERVED 2 ++#define ACPI_TABLE 3 ++#define ACPI_NVS 4 ++#define SYSTEM_PMEM 5 ++ ++#define MAX_MEM_MAP 128 ++ ++typedef struct LoongarchMachineClass { ++ /*< private >*/ ++ MachineClass parent_class; ++ ++ /* Methods: */ ++ HotplugHandler *(*get_hotplug_handler)(MachineState *machine, ++ DeviceState *dev); ++ ++ bool has_acpi_build; ++ ++ /* save different cpu address*/ ++ uint64_t isa_io_base; ++ uint64_t ht_control_regs_base; ++ uint64_t hpet_mmio_addr; ++ uint64_t smbus_cfg_base; ++ uint64_t pciecfg_base; ++ uint64_t ls7a_ioapic_reg_base; ++ uint32_t node_shift; ++ char cpu_name[40]; ++ char bridge_name[16]; ++ ++} LoongarchMachineClass; ++ ++typedef struct ResetData { ++ LOONGARCHCPU *cpu; ++ uint64_t vector; ++} ResetData; ++ ++typedef struct LoongarchMachineState { ++ /*< private >*/ ++ MachineState parent_obj; ++ ++ /* */ ++ ram_addr_t hotplug_memory_size; ++ ++ /* State for other subsystems/APIs: */ ++ Notifier machine_done; ++ /* Pointers to devices and objects: */ ++ HotplugHandler *acpi_dev; ++ int ram_slots; ++ ResetData *reset_info[LOONGARCH_MAX_VCPUS]; ++ DeviceState *rtc; ++ gipiState *gipi; ++ apicState *apic; ++ ++ FWCfgState *fw_cfg; ++ bool acpi_build_enabled; ++ bool apic_xrupt_override; ++ CPUArchIdList *possible_cpus; ++ PFlashCFI01 *flash[LOONGARCH_MAX_PFLASH]; ++ void *fdt; ++ int fdt_size; ++ unsigned int hotpluged_cpu_num; ++ DeviceState *platform_bus_dev; ++ OnOffAuto acpi; ++ char *oem_id; ++ char *oem_table_id; ++} LoongarchMachineState; ++ ++#define LOONGARCH_MACHINE_ACPI_DEVICE_PROP "loongarch-acpi-device" ++#define TYPE_LOONGARCH_MACHINE "loongarch-machine" ++ ++#define LoongarchMACHINE(obj) \ ++ OBJECT_CHECK(LoongarchMachineState, (obj), TYPE_LOONGARCH_MACHINE) ++#define LoongarchMACHINE_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(LoongarchMachineClass, (obj), TYPE_LOONGARCH_MACHINE) ++#define LoongarchMACHINE_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(LoongarchMachineClass, (klass), TYPE_LOONGARCH_MACHINE) ++ ++#define DEFINE_LOONGARCH_MACHINE(suffix, namestr, initfn, optsfn) \ ++ static void loongarch_machine_##suffix##_class_init(ObjectClass *oc, \ ++ void *data) \ ++ { \ ++ MachineClass *mc = MACHINE_CLASS(oc); \ ++ optsfn(mc); \ ++ mc->init = initfn; \ ++ } \ ++ static const TypeInfo loongarch_machine_type_##suffix = { \ ++ .name = namestr TYPE_MACHINE_SUFFIX, \ ++ .parent = TYPE_LOONGARCH_MACHINE, \ ++ .class_init = loongarch_machine_##suffix##_class_init, \ ++ }; \ ++ static void loongarch_machine_init_##suffix(void) \ ++ { \ ++ type_register(&loongarch_machine_type_##suffix); \ ++ } \ ++ type_init(loongarch_machine_init_##suffix) ++ ++void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp); ++void longson_machine_device_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp); ++HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, ++ DeviceState *dev); ++void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp); ++void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp); ++ ++LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, LOONGARCHCPU *cpu, ++ Error **errp); ++void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu); ++int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu); ++int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu); ++int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type); ++bool loongarch_is_acpi_enabled(LoongarchMachineState *vms); ++ ++/* acpi-build.c */ ++void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *apic_ids, GArray *entry, ++ bool force_enabled); ++void slave_cpu_reset(void *opaque); ++#endif +diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h +new file mode 100644 +index 0000000000..e1f3c8d032 +--- /dev/null ++++ b/include/hw/loongarch/ls7a.h +@@ -0,0 +1,167 @@ ++/* ++ * Acpi emulation on Loongarch system. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_LS7A_H ++#define HW_LS7A_H ++ ++#include "hw/hw.h" ++#include "hw/isa/isa.h" ++#include "hw/sysbus.h" ++#include "hw/isa/apm.h" ++#include "hw/pci/pci.h" ++#include "hw/pci/pcie_host.h" ++#include "hw/pci/pci_bridge.h" ++#include "hw/acpi/acpi.h" ++#include "hw/acpi/ls7a.h" ++#include "hw/pci/pci_bus.h" ++ ++/* LS7A PCH Registers (Misc, Confreg) */ ++#define LS7A_PCH_REG_BASE 0x10000000UL ++#define LS3A5K_LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) ++#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) ++#define LS7A_ACPI_REG_BASE (LS7A_MISC_REG_BASE + 0x00050000) ++ ++#define LOONGARCH_PCH_IRQ_BASE 64 ++#define LS7A_UART_IRQ (LOONGARCH_PCH_IRQ_BASE + 2) ++#define LS7A_RTC_IRQ (LOONGARCH_PCH_IRQ_BASE + 3) ++#define LS7A_SCI_IRQ (LOONGARCH_PCH_IRQ_BASE + 4) ++#define LS7A_ACPI_IO_BASE 0x800 ++#define LS7A_ACPI_IO_SIZE 0x100 ++#define LS7A_PM_EVT_BLK (0x0C) /* 4 bytes */ ++#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */ ++#define LS7A_GPE0_STS_REG (0x28) /* 4 bytes */ ++#define LS7A_GPE0_ENA_REG (0x2C) /* 4 bytes */ ++#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */ ++#define LS7A_PM_TMR_BLK (0x18) /* 4 bytes */ ++#define LS7A_GPE0_LEN (8) ++#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) ++#define LS7A_RTC_LEN (0x100) ++ ++#define ACPI_IO_BASE (LS7A_ACPI_REG_BASE) ++#define ACPI_GPE0_LEN (LS7A_GPE0_LEN) ++#define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE) ++#define ACPI_SCI_IRQ (LS7A_SCI_IRQ) ++ ++#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 ++#define VIRT_PLATFORM_BUS_SIZE 0x02000000 ++#define VIRT_PLATFORM_BUS_NUM_IRQS 2 ++#define VIRT_PLATFORM_BUS_IRQ (LOONGARCH_PCH_IRQ_BASE + 5) ++ ++#define LS3A5K_ISA_IO_BASE 0x18000000UL ++#define LS_BIOS_BASE 0x1c000000 ++#define LS_BIOS_VAR_BASE 0x1c3a0000 ++#define LS_BIOS_SIZE (4 * 1024 * 1024) ++#define LS_FDT_BASE 0x1c400000 ++#define LS_FDT_SIZE 0x00100000 ++ ++#define FW_CFG_ADDR 0x1e020000 ++#define LS7A_REG_BASE 0x1FE00000 ++#define LS7A_UART_BASE 0x1fe001e0 ++#define LS7A_UART_LEN 0x8 ++#define SMP_GIPI_MAILBOX 0x1f000000ULL ++#define CORE0_STATUS_OFF 0x000 ++#define CORE0_EN_OFF 0x004 ++#define CORE0_SET_OFF 0x008 ++#define CORE0_CLEAR_OFF 0x00c ++#define CORE0_BUF_20 0x020 ++#define CORE0_BUF_28 0x028 ++#define CORE0_BUF_30 0x030 ++#define CORE0_BUF_38 0x038 ++#define CORE0_IPI_SEND 0x040 ++#define CORE0_MAIL_SEND 0x048 ++#define INT_ROUTER_REGS_BASE 0x1fe01400UL ++#define INT_ROUTER_REGS_SIZE 0x100 ++#define INT_ROUTER_REGS_SYS_INT0 0x00 ++#define INT_ROUTER_REGS_SYS_INT1 0x01 ++#define INT_ROUTER_REGS_SYS_INT2 0x02 ++#define INT_ROUTER_REGS_SYS_INT3 0x03 ++#define INT_ROUTER_REGS_PCI_INT0 0x04 ++#define INT_ROUTER_REGS_PCI_INT1 0x05 ++#define INT_ROUTER_REGS_PCI_INT2 0x06 ++#define INT_ROUTER_REGS_PCI_INT3 0x07 ++#define INT_ROUTER_REGS_MATRIX_INT0 0x08 ++#define INT_ROUTER_REGS_MATRIX_INT1 0x09 ++#define INT_ROUTER_REGS_LPC_INT 0x0a ++#define INT_ROUTER_REGS_MC0 0x0b ++#define INT_ROUTER_REGS_MC1 0x0c ++#define INT_ROUTER_REGS_BARRIER 0x0d ++#define INT_ROUTER_REGS_THSENS_INT 0x0e ++#define INT_ROUTER_REGS_PCI_PERR 0x0f ++#define INT_ROUTER_REGS_HT0_INT0 0x10 ++#define INT_ROUTER_REGS_HT0_INT1 0x11 ++#define INT_ROUTER_REGS_HT0_INT2 0x12 ++#define INT_ROUTER_REGS_HT0_INT3 0x13 ++#define INT_ROUTER_REGS_HT0_INT4 0x14 ++#define INT_ROUTER_REGS_HT0_INT5 0x15 ++#define INT_ROUTER_REGS_HT0_INT6 0x16 ++#define INT_ROUTER_REGS_HT0_INT7 0x17 ++#define INT_ROUTER_REGS_HT1_INT0 0x18 ++#define INT_ROUTER_REGS_HT1_INT1 0x19 ++#define INT_ROUTER_REGS_HT1_INT2 0x1a ++#define INT_ROUTER_REGS_HT1_INT3 0x1b ++#define INT_ROUTER_REGS_HT1_INT4 0x1c ++#define INT_ROUTER_REGS_HT1_INT5 0x1d ++#define INT_ROUTER_REGS_HT1_INT6 0x1e ++#define INT_ROUTER_REGS_HT1_INT7 0x1f ++#define INT_ROUTER_REGS_ISR 0x20 ++#define INT_ROUTER_REGS_EN 0x24 ++#define INT_ROUTER_REGS_EN_SET 0x28 ++#define INT_ROUTER_REGS_EN_CLR 0x2c ++#define INT_ROUTER_REGS_EDGE 0x38 ++#define INT_ROUTER_REGS_CORE0_INTISR 0x40 ++#define INT_ROUTER_REGS_CORE1_INTISR 0x48 ++#define INT_ROUTER_REGS_CORE2_INTISR 0x50 ++#define INT_ROUTER_REGS_CORE3_INTISR 0x58 ++ ++#define LS_PCIECFG_BASE 0x20000000 ++#define LS_PCIECFG_SIZE 0x08000000 ++#define MSI_ADDR_LOW 0x2FF00000 ++#define MSI_ADDR_HI 0x0 ++ ++#define PCIE_MEMORY_BASE 0x40000000 ++#define PCIE_MEMORY_SIZE 0x40000000 ++ ++typedef struct LS7APCIState LS7APCIState; ++typedef struct LS7APCIEHost { ++ PCIExpressHost parent_obj; ++ LS7APCIState *pci_dev; ++} LS7APCIEHost; ++ ++struct LS7APCIState { ++ PCIDevice dev; ++ ++ LS7APCIEHost *pciehost; ++ ++ /* LS7A registers */ ++ MemoryRegion iomem; ++ LS7APCIPMRegs pm; ++}; ++ ++#define TYPE_LS7A_PCIE_HOST_BRIDGE "ls7a1000-pciehost" ++#define LS7A_PCIE_HOST_BRIDGE(obj) \ ++ OBJECT_CHECK(LS7APCIEHost, (obj), TYPE_LS7A_PCIE_HOST_BRIDGE) ++ ++#define TYPE_PCIE_LS7A "ls7a1000_pcie" ++#define PCIE_LS7A(obj) OBJECT_CHECK(LS7APCIState, (obj), TYPE_PCIE_LS7A) ++ ++PCIBus *ls7a_init(MachineState *machine, qemu_irq *irq, ++ DeviceState **ls7a_dev); ++LS7APCIState *get_ls7a_type(Object *obj); ++ ++#endif /* HW_LS7A_H */ +diff --git a/include/hw/loongarch/sysbus-fdt.h b/include/hw/loongarch/sysbus-fdt.h +new file mode 100644 +index 0000000000..6bf53097e1 +--- /dev/null ++++ b/include/hw/loongarch/sysbus-fdt.h +@@ -0,0 +1,33 @@ ++/* ++ * Dynamic sysbus device tree node generation API ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef HW_ARM_SYSBUS_FDT_H ++#define HW_ARM_SYSBUS_FDT_H ++ ++#include "exec/hwaddr.h" ++ ++/** ++ * platform_bus_add_all_fdt_nodes - create all the platform bus nodes ++ * ++ * builds the parent platform bus node and all the nodes of dynamic ++ * sysbus devices attached to it. ++ */ ++void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, ++ hwaddr bus_size, int irq_start); ++#endif +diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h +index 60718fc342..fd9e53f623 100644 +--- a/include/qemu/osdep.h ++++ b/include/qemu/osdep.h +@@ -533,6 +533,10 @@ static inline void qemu_cleanup_generic_vfree(void *p) + Valgrind does not support alignments larger than 1 MiB, + therefore we need special code which handles running on Valgrind. */ + # define QEMU_VMALLOC_ALIGN (512 * 4096) ++#elif defined(__linux__) && defined(__loongarch__) ++ /* Use 32 MiB alignment so transparent hugepages can be used by KVM. */ ++#define QEMU_VMALLOC_ALIGN (qemu_real_host_page_size * \ ++ qemu_real_host_page_size / 8) + #elif defined(__linux__) && defined(__s390x__) + /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ + # define QEMU_VMALLOC_ALIGN (256 * 4096) +-- +2.27.0 + diff --git a/Add-target-loongarch64.patch b/Add-target-loongarch64.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d6324c6acb305a1661b580e4a052e18dfdf51ab --- /dev/null +++ b/Add-target-loongarch64.patch @@ -0,0 +1,15466 @@ +From 9aefc417ef8c705503b51b844b489598448656d0 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:15:39 -0500 +Subject: [PATCH] Add target/loongarch64. + +1.Add loongarch cpu simulation. +2.Add loongarch csr simulation. +3.Add loongarch fpu support. +4.Add loongarch gdb support. +5.Add loongarhch kvm support. +6.Add loongarch stable timer. +7.Add loongarch tcg related support. + +Signed-off-by: lixianglai +--- + target/Kconfig | 1 + + target/loongarch64/Kconfig | 2 + + target/loongarch64/arch_dump.c | 179 ++ + target/loongarch64/cpu-csr.h | 880 ++++++++ + target/loongarch64/cpu-param.h | 46 + + target/loongarch64/cpu-qom.h | 54 + + target/loongarch64/cpu.c | 575 +++++ + target/loongarch64/cpu.h | 359 +++ + target/loongarch64/csr_helper.c | 697 ++++++ + target/loongarch64/fpu.c | 25 + + target/loongarch64/fpu_helper.c | 891 ++++++++ + target/loongarch64/fpu_helper.h | 127 ++ + target/loongarch64/gdbstub.c | 164 ++ + target/loongarch64/helper.c | 726 +++++++ + target/loongarch64/helper.h | 178 ++ + target/loongarch64/insn.decode | 532 +++++ + target/loongarch64/instmap.h | 217 ++ + target/loongarch64/internal.h | 207 ++ + target/loongarch64/kvm.c | 1366 ++++++++++++ + target/loongarch64/kvm_larch.h | 49 + + target/loongarch64/larch-defs.h | 42 + + target/loongarch64/machine.c | 423 ++++ + target/loongarch64/meson.build | 35 + + target/loongarch64/op_helper.c | 485 +++++ + target/loongarch64/stabletimer.c | 117 + + target/loongarch64/tlb_helper.c | 641 ++++++ + target/loongarch64/trans.inc.c | 3482 ++++++++++++++++++++++++++++++ + target/loongarch64/translate.c | 2705 +++++++++++++++++++++++ + target/meson.build | 1 + + 29 files changed, 15206 insertions(+) + create mode 100644 target/loongarch64/Kconfig + create mode 100644 target/loongarch64/arch_dump.c + create mode 100644 target/loongarch64/cpu-csr.h + create mode 100644 target/loongarch64/cpu-param.h + create mode 100644 target/loongarch64/cpu-qom.h + create mode 100644 target/loongarch64/cpu.c + create mode 100644 target/loongarch64/cpu.h + create mode 100644 target/loongarch64/csr_helper.c + create mode 100644 target/loongarch64/fpu.c + create mode 100644 target/loongarch64/fpu_helper.c + create mode 100644 target/loongarch64/fpu_helper.h + create mode 100644 target/loongarch64/gdbstub.c + create mode 100644 target/loongarch64/helper.c + create mode 100644 target/loongarch64/helper.h + create mode 100644 target/loongarch64/insn.decode + create mode 100644 target/loongarch64/instmap.h + create mode 100644 target/loongarch64/internal.h + create mode 100644 target/loongarch64/kvm.c + create mode 100644 target/loongarch64/kvm_larch.h + create mode 100644 target/loongarch64/larch-defs.h + create mode 100644 target/loongarch64/machine.c + create mode 100644 target/loongarch64/meson.build + create mode 100644 target/loongarch64/op_helper.c + create mode 100644 target/loongarch64/stabletimer.c + create mode 100644 target/loongarch64/tlb_helper.c + create mode 100644 target/loongarch64/trans.inc.c + create mode 100644 target/loongarch64/translate.c + +diff --git a/target/Kconfig b/target/Kconfig +index a8d6cb1e97..b2abc7b60b 100644 +--- a/target/Kconfig ++++ b/target/Kconfig +@@ -4,6 +4,7 @@ source avr/Kconfig + source cris/Kconfig + source hppa/Kconfig + source i386/Kconfig ++source loongarch64/Kconfig + source m68k/Kconfig + source microblaze/Kconfig + source mips/Kconfig +diff --git a/target/loongarch64/Kconfig b/target/loongarch64/Kconfig +new file mode 100644 +index 0000000000..46b26b1a85 +--- /dev/null ++++ b/target/loongarch64/Kconfig +@@ -0,0 +1,2 @@ ++config LOONGARCH64 ++ bool +diff --git a/target/loongarch64/arch_dump.c b/target/loongarch64/arch_dump.c +new file mode 100644 +index 0000000000..adce817d54 +--- /dev/null ++++ b/target/loongarch64/arch_dump.c +@@ -0,0 +1,179 @@ ++/* ++ * Support for writing ELF notes for RM architectures ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "elf.h" ++#include "sysemu/dump.h" ++#include "internal.h" ++ ++/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ ++struct loongarch_user_regs { ++ uint64_t gpr[32]; ++ uint64_t lo; ++ uint64_t hi; ++ uint64_t csr_era; ++ uint64_t csr_badvaddr; ++ uint64_t csr_crmd; ++ uint64_t csr_ecfg; ++ uint64_t pad[7]; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360); ++ ++/* struct elf_prstatus from include/uapi/linux/elfcore.h */ ++struct loongarch_elf_prstatus { ++ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ ++ uint32_t pr_pid; ++ /* ++ * 76 == offsetof(struct elf_prstatus, pr_reg) - ++ * offsetof(struct elf_prstatus, pr_ppid) ++ */ ++ char pad2[76]; ++ struct loongarch_user_regs pr_reg; ++ uint32_t pr_fpvalid; ++ char pad3[4]; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480); ++ ++/* ++ * struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h ++ * ++ * While the vregs member of user_fpsimd_state is of type __uint128_t, ++ * QEMU uses an array of uint64_t, where the high half of the 128-bit ++ * value is always in the 2n+1'th index. Thus we also break the 128- ++ * bit values into two halves in this reproduction of user_fpsimd_state. ++ */ ++ ++struct loongarch_fpu_struct { ++ uint64_t fpr[32]; ++ unsigned int fir; ++ unsigned int fcsr; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 264); ++ ++struct loongarch_note { ++ Elf64_Nhdr hdr; ++ char name[8]; /* align_up(sizeof("CORE"), 4) */ ++ union ++ { ++ struct loongarch_elf_prstatus prstatus; ++ struct loongarch_fpu_struct fpu; ++ }; ++} QEMU_PACKED; ++ ++#define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus) ++#define LOONGARCH_PRSTATUS_NOTE_SIZE \ ++ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_elf_prstatus)) ++#define LOONGARCH_PRFPREG_NOTE_SIZE \ ++ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_fpu_struct)) ++ ++static void loongarch_note_init(struct loongarch_note *note, DumpState *s, ++ const char *name, Elf64_Word namesz, ++ Elf64_Word type, Elf64_Word descsz) ++{ ++ memset(note, 0, sizeof(*note)); ++ ++ note->hdr.n_namesz = cpu_to_dump32(s, namesz); ++ note->hdr.n_descsz = cpu_to_dump32(s, descsz); ++ note->hdr.n_type = cpu_to_dump32(s, type); ++ ++ memcpy(note->name, name, namesz); ++} ++ ++static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, ++ CPULOONGARCHState *env, int cpuid, ++ DumpState *s) ++{ ++ struct loongarch_note note; ++ int ret, i; ++ ++ loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); ++ ++ note.fpu.fcsr = cpu_to_dump64(s, env->active_fpu.fcsr0); ++ ++ for (i = 0; i < 32; ++i) { ++ note.fpu.fpr[i] = cpu_to_dump64(s, env->active_fpu.fpr[i].fd); ++ } ++ ++ ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, ++ int cpuid, void *opaque) ++{ ++ struct loongarch_note note; ++ CPULOONGARCHState *env = &LOONGARCH_CPU(cs)->env; ++ DumpState *s = opaque; ++ int ret, i; ++ ++ loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, ++ sizeof(note.prstatus)); ++ ++ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); ++ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); ++ ++ for (i = 0; i < 32; ++i) { ++ note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->active_tc.gpr[i]); ++ } ++ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); ++ note.prstatus.pr_reg.csr_badvaddr = cpu_to_dump64(s, env->CSR_BADV); ++ note.prstatus.pr_reg.csr_crmd = cpu_to_dump64(s, env->CSR_CRMD); ++ note.prstatus.pr_reg.csr_ecfg = cpu_to_dump64(s, env->CSR_ECFG); ++ ++ ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ return ret; ++} ++ ++int cpu_get_dump_info(ArchDumpInfo *info, ++ const GuestPhysBlockList *guest_phys_blocks) ++{ ++ info->d_machine = EM_LOONGARCH; ++ info->d_endian = ELFDATA2LSB; ++ info->d_class = ELFCLASS64; ++ ++ return 0; ++} ++ ++ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) ++{ ++ size_t note_size = 0; ++ ++ if (class == ELFCLASS64) { ++ note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE; ++ } ++ ++ return note_size * nr_cpus; ++} +diff --git a/target/loongarch64/cpu-csr.h b/target/loongarch64/cpu-csr.h +new file mode 100644 +index 0000000000..278a66c395 +--- /dev/null ++++ b/target/loongarch64/cpu-csr.h +@@ -0,0 +1,880 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef _CPU_CSR_H_ ++#define _CPU_CSR_H_ ++ ++/* basic CSR register */ ++#define LOONGARCH_CSR_CRMD 0x0 /* 32 current mode info */ ++#define CSR_CRMD_DACM_SHIFT 7 ++#define CSR_CRMD_DACM_WIDTH 2 ++#define CSR_CRMD_DACM (0x3UL << CSR_CRMD_DACM_SHIFT) ++#define CSR_CRMD_DACF_SHIFT 5 ++#define CSR_CRMD_DACF_WIDTH 2 ++#define CSR_CRMD_DACF (0x3UL << CSR_CRMD_DACF_SHIFT) ++#define CSR_CRMD_PG_SHIFT 4 ++#define CSR_CRMD_PG (0x1UL << CSR_CRMD_PG_SHIFT) ++#define CSR_CRMD_DA_SHIFT 3 ++#define CSR_CRMD_DA (0x1UL << CSR_CRMD_DA_SHIFT) ++#define CSR_CRMD_IE_SHIFT 2 ++#define CSR_CRMD_IE (0x1UL << CSR_CRMD_IE_SHIFT) ++#define CSR_CRMD_PLV_SHIFT 0 ++#define CSR_CRMD_PLV_WIDTH 2 ++#define CSR_CRMD_PLV (0x3UL << CSR_CRMD_PLV_SHIFT) ++ ++#define PLV_USER 3 ++#define PLV_KERN 0 ++#define PLV_MASK 0x3 ++ ++#define LOONGARCH_CSR_PRMD 0x1 /* 32 prev-exception mode info */ ++#define CSR_PRMD_PIE_SHIFT 2 ++#define CSR_PRMD_PIE (0x1UL << CSR_PRMD_PIE_SHIFT) ++#define CSR_PRMD_PPLV_SHIFT 0 ++#define CSR_PRMD_PPLV_WIDTH 2 ++#define CSR_PRMD_PPLV (0x3UL << CSR_PRMD_PPLV_SHIFT) ++ ++#define LOONGARCH_CSR_EUEN 0x2 /* 32 coprocessor enable */ ++#define CSR_EUEN_LBTEN_SHIFT 3 ++#define CSR_EUEN_LBTEN (0x1UL << CSR_EUEN_LBTEN_SHIFT) ++#define CSR_EUEN_LASXEN_SHIFT 2 ++#define CSR_EUEN_LASXEN (0x1UL << CSR_EUEN_LASXEN_SHIFT) ++#define CSR_EUEN_LSXEN_SHIFT 1 ++#define CSR_EUEN_LSXEN (0x1UL << CSR_EUEN_LSXEN_SHIFT) ++#define CSR_EUEN_FPEN_SHIFT 0 ++#define CSR_EUEN_FPEN (0x1UL << CSR_EUEN_FPEN_SHIFT) ++ ++#define LOONGARCH_CSR_MISC 0x3 /* 32 misc config */ ++ ++#define LOONGARCH_CSR_ECFG 0x4 /* 32 exception config */ ++#define CSR_ECFG_VS_SHIFT 16 ++#define CSR_ECFG_VS_WIDTH 3 ++#define CSR_ECFG_VS (0x7UL << CSR_ECFG_VS_SHIFT) ++#define CSR_ECFG_IM_SHIFT 0 ++#define CSR_ECFG_IM_WIDTH 13 ++#define CSR_ECFG_IM (0x1fffUL << CSR_ECFG_IM_SHIFT) ++ ++#define CSR_ECFG_IPMASK 0x00001fff ++ ++#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ ++#define CSR_ESTAT_ESUBCODE_SHIFT 22 ++#define CSR_ESTAT_ESUBCODE_WIDTH 9 ++#define CSR_ESTAT_ESUBCODE (0x1ffULL << CSR_ESTAT_ESUBCODE_SHIFT) ++#define CSR_ESTAT_EXC_SH 16 ++#define CSR_ESTAT_EXC_WIDTH 5 ++#define CSR_ESTAT_EXC (0x1fULL << CSR_ESTAT_EXC_SH) ++#define CSR_ESTAT_IS_SHIFT 0 ++#define CSR_ESTAT_IS_WIDTH 15 ++#define CSR_ESTAT_IS (0x7fffULL << CSR_ESTAT_IS_SHIFT) ++ ++#define CSR_ESTAT_IPMASK 0x00001fff ++ ++#define EXCODE_IP 64 ++#define EXCCODE_RSV 0 ++#define EXCCODE_TLBL 1 ++#define EXCCODE_TLBS 2 ++#define EXCCODE_TLBI 3 ++#define EXCCODE_MOD 4 ++#define EXCCODE_TLBRI 5 ++#define EXCCODE_TLBXI 6 ++#define EXCCODE_TLBPE 7 ++#define EXCCODE_ADE 8 ++#define EXCCODE_UNALIGN 9 ++#define EXCCODE_OOB 10 ++#define EXCCODE_SYS 11 ++#define EXCCODE_BP 12 ++#define EXCCODE_RI 13 ++#define EXCCODE_IPE 14 ++#define EXCCODE_FPDIS 15 ++#define EXCCODE_LSXDIS 16 ++#define EXCCODE_LASXDIS 17 ++#define EXCCODE_FPE 18 ++#define EXCCODE_WATCH 19 ++#define EXCCODE_BTDIS 20 ++#define EXCCODE_BTE 21 ++#define EXCCODE_PSI 22 ++#define EXCCODE_HYP 23 ++#define EXCCODE_FC 24 ++#define EXCCODE_SE 25 ++ ++#define LOONGARCH_CSR_ERA 0x6 /* 64 error PC */ ++#define LOONGARCH_CSR_BADV 0x7 /* 64 bad virtual address */ ++#define LOONGARCH_CSR_BADI 0x8 /* 32 bad instruction */ ++#define LOONGARCH_CSR_EEPN 0xc /* 64 exception enter base address */ ++#define LOONGARCH_EEPN_CPUID (0x3ffULL << 0) ++ ++#define CU_FPE 1 ++#define CU_LSXE (1 << 1) ++#define CU_LASXE (1 << 2) ++#define CU_LBTE (1 << 3) ++ ++/* TLB related CSR register : start with TLB if no pagewalk */ ++/* 32 TLB Index, EHINV, PageSize, is_gtlb */ ++#define LOONGARCH_CSR_TLBIDX 0x10 ++#define CSR_TLBIDX_EHINV_SHIFT 31 ++#define CSR_TLBIDX_EHINV (0x1ULL << CSR_TLBIDX_EHINV_SHIFT) ++#define CSR_TLBIDX_PS_SHIFT 24 ++#define CSR_TLBIDX_PS_WIDTH 6 ++#define CSR_TLBIDX_PS (0x3fULL << CSR_TLBIDX_PS_SHIFT) ++#define CSR_TLBIDX_IDX_SHIFT 0 ++#define CSR_TLBIDX_IDX_WIDTH 12 ++#define CSR_TLBIDX_IDX (0xfffULL << CSR_TLBIDX_IDX_SHIFT) ++#define CSR_TLBIDX_SIZEM 0x3f000000 ++#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT ++#define CSR_TLBIDX_IDXM 0xfff ++ ++#define LOONGARCH_CSR_TLBEHI 0x11 /* 64 TLB EntryHi without ASID */ ++#define LOONGARCH_CSR_TLBELO0 0x12 /* 64 TLB EntryLo0 */ ++#define CSR_TLBLO0_RPLV_SHIFT 63 ++#define CSR_TLBLO0_RPLV (0x1ULL << CSR_TLBLO0_RPLV_SHIFT) ++#define CSR_TLBLO0_XI_SHIFT 62 ++#define CSR_TLBLO0_XI (0x1ULL << CSR_TLBLO0_XI_SHIFT) ++#define CSR_TLBLO0_RI_SHIFT 61 ++#define CSR_TLBLO0_RI (0x1ULL << CSR_TLBLO0_RI_SHIFT) ++#define CSR_TLBLO0_PPN_SHIFT 12 ++#define CSR_TLBLO0_PPN_WIDTH 36 /* ignore lower 12bits */ ++#define CSR_TLBLO0_PPN (0xfffffffffULL << CSR_TLBLO0_PPN_SHIFT) ++#define CSR_TLBLO0_GLOBAL_SHIFT 6 ++#define CSR_TLBLO0_GLOBAL (0x1ULL << CSR_TLBLO0_GLOBAL_SHIFT) ++#define CSR_TLBLO0_CCA_SHIFT 4 ++#define CSR_TLBLO0_CCA_WIDTH 2 ++#define CSR_TLBLO0_CCA (0x3ULL << CSR_TLBLO0_CCA_SHIFT) ++#define CSR_TLBLO0_PLV_SHIFT 2 ++#define CSR_TLBLO0_PLV_WIDTH 2 ++#define CSR_TLBLO0_PLV (0x3ULL << CSR_TLBLO0_PLV_SHIFT) ++#define CSR_TLBLO0_WE_SHIFT 1 ++#define CSR_TLBLO0_WE (0x1ULL << CSR_TLBLO0_WE_SHIFT) ++#define CSR_TLBLO0_V_SHIFT 0 ++#define CSR_TLBLO0_V (0x1ULL << CSR_TLBLO0_V_SHIFT) ++ ++#define LOONGARCH_CSR_TLBELO1 0x13 /* 64 TLB EntryLo1 */ ++#define CSR_TLBLO1_RPLV_SHIFT 63 ++#define CSR_TLBLO1_RPLV (0x1ULL << CSR_TLBLO1_RPLV_SHIFT) ++#define CSR_TLBLO1_XI_SHIFT 62 ++#define CSR_TLBLO1_XI (0x1ULL << CSR_TLBLO1_XI_SHIFT) ++#define CSR_TLBLO1_RI_SHIFT 61 ++#define CSR_TLBLO1_RI (0x1ULL << CSR_TLBLO1_RI_SHIFT) ++#define CSR_TLBLO1_PPN_SHIFT 12 ++#define CSR_TLBLO1_PPN_WIDTH 36 /* ignore lower 12bits */ ++#define CSR_TLBLO1_PPN (0xfffffffffULL << CSR_TLBLO1_PPN_SHIFT) ++#define CSR_TLBLO1_GLOBAL_SHIFT 6 ++#define CSR_TLBLO1_GLOBAL (0x1ULL << CSR_TLBLO1_GLOBAL_SHIFT) ++#define CSR_TLBLO1_CCA_SHIFT 4 ++#define CSR_TLBLO1_CCA_WIDTH 2 ++#define CSR_TLBLO1_CCA (0x3ULL << CSR_TLBLO1_CCA_SHIFT) ++#define CSR_TLBLO1_PLV_SHIFT 2 ++#define CSR_TLBLO1_PLV_WIDTH 2 ++#define CSR_TLBLO1_PLV (0x3ULL << CSR_TLBLO1_PLV_SHIFT) ++#define CSR_TLBLO1_WE_SHIFT 1 ++#define CSR_TLBLO1_WE (0x1ULL << CSR_TLBLO1_WE_SHIFT) ++#define CSR_TLBLO1_V_SHIFT 0 ++#define CSR_TLBLO1_V (0x1ULL << CSR_TLBLO1_V_SHIFT) ++ ++#define LOONGARCH_ENTRYLO_RI (1ULL << 61) ++#define LOONGARCH_ENTRYLO_XI (1ULL << 62) ++ ++#define LOONGARCH_CSR_TLBWIRED 0x14 /* 32 TLB wired */ ++#define LOONGARCH_CSR_GTLBC 0x15 /* guest-related TLB */ ++#define CSR_GTLBC_RID_SHIFT 16 ++#define CSR_GTLBC_RID_WIDTH 8 ++#define CSR_GTLBC_RID (0xffULL << CSR_GTLBC_RID_SHIFT) ++#define CSR_GTLBC_TOTI_SHIFT 13 ++#define CSR_GTLBC_TOTI (0x1ULL << CSR_GTLBC_TOTI_SHIFT) ++#define CSR_GTLBC_USERID_SHIFT 12 ++#define CSR_GTLBC_USERID (0x1ULL << CSR_GTLBC_USERID_SHIFT) ++#define CSR_GTLBC_GMTLBSZ_SHIFT 0 ++#define CSR_GTLBC_GMTLBSZ_WIDTH 6 ++#define CSR_GTLBC_GMTLBSZ (0x3fULL << CSR_GTLBC_GVTLBSZ_SHIFT) ++ ++#define LOONGARCH_CSR_TRGP 0x16 /* guest-related TLB */ ++#define CSR_TRGP_RID_SHIFT 16 ++#define CSR_TRGP_RID_WIDTH 8 ++#define CSR_TRGP_RID (0xffULL << CSR_TRGP_RID_SHIFT) ++#define CSR_TRGP_GTLB_SHIFT 0 ++#define CSR_TRGP_GTLB (1 << CSR_TRGP_GTLB_SHIFT) ++ ++#define LOONGARCH_CSR_ASID 0x18 /* 64 ASID */ ++#define CSR_ASID_BIT_SHIFT 16 /* ASIDBits */ ++#define CSR_ASID_BIT_WIDTH 8 ++#define CSR_ASID_BIT (0xffULL << CSR_ASID_BIT_SHIFT) ++#define CSR_ASID_ASID_SHIFT 0 ++#define CSR_ASID_ASID_WIDTH 10 ++#define CSR_ASID_ASID (0x3ffULL << CSR_ASID_ASID_SHIFT) ++ ++/* 64 page table base address when badv[47] = 0 */ ++#define LOONGARCH_CSR_PGDL 0x19 ++/* 64 page table base address when badv[47] = 1 */ ++#define LOONGARCH_CSR_PGDH 0x1a ++#define LOONGARCH_CSR_PGD 0x1b /* 64 page table base */ ++#define LOONGARCH_CSR_PWCTL0 0x1c /* 64 PWCtl0 */ ++#define CSR_PWCTL0_PTEW_SHIFT 30 ++#define CSR_PWCTL0_PTEW_WIDTH 2 ++#define CSR_PWCTL0_PTEW (0x3ULL << CSR_PWCTL0_PTEW_SHIFT) ++#define CSR_PWCTL0_DIR1WIDTH_SHIFT 25 ++#define CSR_PWCTL0_DIR1WIDTH_WIDTH 5 ++#define CSR_PWCTL0_DIR1WIDTH (0x1fULL << CSR_PWCTL0_DIR1WIDTH_SHIFT) ++#define CSR_PWCTL0_DIR1BASE_SHIFT 20 ++#define CSR_PWCTL0_DIR1BASE_WIDTH 5 ++#define CSR_PWCTL0_DIR1BASE (0x1fULL << CSR_PWCTL0_DIR1BASE_SHIFT) ++#define CSR_PWCTL0_DIR0WIDTH_SHIFT 15 ++#define CSR_PWCTL0_DIR0WIDTH_WIDTH 5 ++#define CSR_PWCTL0_DIR0WIDTH (0x1fULL << CSR_PWCTL0_DIR0WIDTH_SHIFT) ++#define CSR_PWCTL0_DIR0BASE_SHIFT 10 ++#define CSR_PWCTL0_DIR0BASE_WIDTH 5 ++#define CSR_PWCTL0_DIR0BASE (0x1fULL << CSR_PWCTL0_DIR0BASE_SHIFT) ++#define CSR_PWCTL0_PTWIDTH_SHIFT 5 ++#define CSR_PWCTL0_PTWIDTH_WIDTH 5 ++#define CSR_PWCTL0_PTWIDTH (0x1fULL << CSR_PWCTL0_PTWIDTH_SHIFT) ++#define CSR_PWCTL0_PTBASE_SHIFT 0 ++#define CSR_PWCTL0_PTBASE_WIDTH 5 ++#define CSR_PWCTL0_PTBASE (0x1fULL << CSR_PWCTL0_PTBASE_SHIFT) ++ ++#define LOONGARCH_CSR_PWCTL1 0x1d /* 64 PWCtl1 */ ++#define CSR_PWCTL1_DIR3WIDTH_SHIFT 18 ++#define CSR_PWCTL1_DIR3WIDTH_WIDTH 5 ++#define CSR_PWCTL1_DIR3WIDTH (0x1fULL << CSR_PWCTL1_DIR3WIDTH_SHIFT) ++#define CSR_PWCTL1_DIR3BASE_SHIFT 12 ++#define CSR_PWCTL1_DIR3BASE_WIDTH 5 ++#define CSR_PWCTL1_DIR3BASE (0x1fULL << CSR_PWCTL0_DIR3BASE_SHIFT) ++#define CSR_PWCTL1_DIR2WIDTH_SHIFT 6 ++#define CSR_PWCTL1_DIR2WIDTH_WIDTH 5 ++#define CSR_PWCTL1_DIR2WIDTH (0x1fULL << CSR_PWCTL1_DIR2WIDTH_SHIFT) ++#define CSR_PWCTL1_DIR2BASE_SHIFT 0 ++#define CSR_PWCTL1_DIR2BASE_WIDTH 5 ++#define CSR_PWCTL1_DIR2BASE (0x1fULL << CSR_PWCTL0_DIR2BASE_SHIFT) ++ ++#define LOONGARCH_CSR_STLBPGSIZE 0x1e /* 64 */ ++#define CSR_STLBPGSIZE_PS_WIDTH 6 ++#define CSR_STLBPGSIZE_PS (0x3f) ++ ++#define LOONGARCH_CSR_RVACFG 0x1f ++#define CSR_RVACFG_RDVA_WIDTH 4 ++#define CSR_RVACFG_RDVA (0xf) ++ ++/* read only CSR register : start with CPU */ ++#define LOONGARCH_CSR_CPUID 0x20 /* 32 CPU core number */ ++#define CSR_CPUID_CID_WIDTH 9 ++#define CSR_CPUID_CID (0x1ff) ++ ++#define LOONGARCH_CSR_PRCFG1 0x21 /* 32 CPU info */ ++#define CSR_CONF1_VSMAX_SHIFT 12 ++#define CSR_CONF1_VSMAX_WIDTH 3 ++#define CSR_CONF1_VSMAX (7ULL << CSR_CONF1_VSMAX_SHIFT) ++/* stable timer bits - 1, 0x2f = 47*/ ++#define CSR_CONF1_TMRBITS_SHIFT 4 ++#define CSR_CONF1_TMRBITS_WIDTH 8 ++#define CSR_CONF1_TMRBITS (0xffULL << CSR_CONF1_TMRBITS_SHIFT) ++#define CSR_CONF1_KSNUM_SHIFT 0 ++#define CSR_CONF1_KSNUM_WIDTH 4 ++#define CSR_CONF1_KSNUM (0x8) ++ ++#define LOONGARCH_CSR_PRCFG2 0x22 ++#define CSR_CONF2_PGMASK_SUPP 0x3ffff000 ++ ++#define LOONGARCH_CSR_PRCFG3 0x23 ++#define CSR_CONF3_STLBIDX_SHIFT 20 ++#define CSR_CONF3_STLBIDX_WIDTH 6 ++#define CSR_CONF3_STLBIDX (0x3fULL << CSR_CONF3_STLBIDX_SHIFT) ++#define CSR_STLB_SETS 256 ++#define CSR_CONF3_STLBWAYS_SHIFT 12 ++#define CSR_CONF3_STLBWAYS_WIDTH 8 ++#define CSR_CONF3_STLBWAYS (0xffULL << CSR_CONF3_STLBWAYS_SHIFT) ++#define CSR_STLBWAYS_SIZE 8 ++#define CSR_CONF3_MTLBSIZE_SHIFT 4 ++#define CSR_CONF3_MTLBSIZE_WIDTH 8 ++#define CSR_CONF3_MTLBSIZE (0xffULL << CSR_CONF3_MTLBSIZE_SHIFT) ++/* mean VTLB 64 index */ ++#define CSR_MTLB_SIZE 64 ++#define CSR_CONF3_TLBORG_SHIFT 0 ++#define CSR_CONF3_TLBORG_WIDTH 4 ++#define CSR_CONF3_TLBORG (0xfULL << CSR_CONF3_TLBORG_SHIFT) ++/* mean use MTLB+STLB */ ++#define TLB_ORG 2 ++ ++/* Kscratch : start with KS */ ++#define LOONGARCH_CSR_KS0 0x30 /* 64 */ ++#define LOONGARCH_CSR_KS1 0x31 /* 64 */ ++#define LOONGARCH_CSR_KS2 0x32 /* 64 */ ++#define LOONGARCH_CSR_KS3 0x33 /* 64 */ ++#define LOONGARCH_CSR_KS4 0x34 /* 64 */ ++#define LOONGARCH_CSR_KS5 0x35 /* 64 */ ++#define LOONGARCH_CSR_KS6 0x36 /* 64 */ ++#define LOONGARCH_CSR_KS7 0x37 /* 64 */ ++#define LOONGARCH_CSR_KS8 0x38 /* 64 */ ++ ++/* timer : start with TM */ ++#define LOONGARCH_CSR_TMID 0x40 /* 32 timer ID */ ++ ++#define LOONGARCH_CSR_TCFG 0x41 /* 64 timer config */ ++#define CSR_TCFG_VAL_SHIFT 2 ++#define CSR_TCFG_VAL_WIDTH 48 ++#define CSR_TCFG_VAL (0x3fffffffffffULL << CSR_TCFG_VAL_SHIFT) ++#define CSR_TCFG_PERIOD_SHIFT 1 ++#define CSR_TCFG_PERIOD (0x1ULL << CSR_TCFG_PERIOD_SHIFT) ++#define CSR_TCFG_EN (0x1) ++ ++#define LOONGARCH_CSR_TVAL 0x42 /* 64 timer ticks remain */ ++ ++#define LOONGARCH_CSR_CNTC 0x43 /* 64 timer offset */ ++ ++#define LOONGARCH_CSR_TINTCLR 0x44 /* 64 timer interrupt clear */ ++#define CSR_TINTCLR_TI_SHIFT 0 ++#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) ++ ++/* guest : start with GST */ ++#define LOONGARCH_CSR_GSTAT 0x50 /* 32 basic guest info */ ++#define CSR_GSTAT_GID_SHIFT 16 ++#define CSR_GSTAT_GID_WIDTH 8 ++#define CSR_GSTAT_GID (0xffULL << CSR_GSTAT_GID_SHIFT) ++#define CSR_GSTAT_GIDBIT_SHIFT 4 ++#define CSR_GSTAT_GIDBIT_WIDTH 6 ++#define CSR_GSTAT_GIDBIT (0x3fULL << CSR_GSTAT_GIDBIT_SHIFT) ++#define CSR_GSTAT_PVM_SHIFT 1 ++#define CSR_GSTAT_PVM (0x1ULL << CSR_GSTAT_PVM_SHIFT) ++#define CSR_GSTAT_VM_SHIFT 0 ++#define CSR_GSTAT_VM (0x1ULL << CSR_GSTAT_VM_SHIFT) ++ ++#define LOONGARCH_CSR_GCFG 0x51 /* 32 guest config */ ++#define CSR_GCFG_GPERF_SHIFT 24 ++#define CSR_GCFG_GPERF_WIDTH 3 ++#define CSR_GCFG_GPERF (0x7ULL << CSR_GCFG_GPERF_SHIFT) ++#define CSR_GCFG_GCI_SHIFT 20 ++#define CSR_GCFG_GCI_WIDTH 2 ++#define CSR_GCFG_GCI (0x3ULL << CSR_GCFG_GCI_SHIFT) ++#define CSR_GCFG_GCI_ALL (0x0ULL << CSR_GCFG_GCI_SHIFT) ++#define CSR_GCFG_GCI_HIT (0x1ULL << CSR_GCFG_GCI_SHIFT) ++#define CSR_GCFG_GCI_SECURE (0x2ULL << CSR_GCFG_GCI_SHIFT) ++#define CSR_GCFG_GCIP_SHIFT 16 ++#define CSR_GCFG_GCIP (0xfULL << CSR_GCFG_GCIP_SHIFT) ++#define CSR_GCFG_GCIP_ALL (0x1ULL << CSR_GCFG_GCIP_SHIFT) ++#define CSR_GCFG_GCIP_HIT (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 1)) ++#define CSR_GCFG_GCIP_SECURE (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 2)) ++#define CSR_GCFG_TORU_SHIFT 15 ++#define CSR_GCFG_TORU (0x1ULL << CSR_GCFG_TORU_SHIFT) ++#define CSR_GCFG_TORUP_SHIFT 14 ++#define CSR_GCFG_TORUP (0x1ULL << CSR_GCFG_TORUP_SHIFT) ++#define CSR_GCFG_TOP_SHIFT 13 ++#define CSR_GCFG_TOP (0x1ULL << CSR_GCFG_TOP_SHIFT) ++#define CSR_GCFG_TOPP_SHIFT 12 ++#define CSR_GCFG_TOPP (0x1ULL << CSR_GCFG_TOPP_SHIFT) ++#define CSR_GCFG_TOE_SHIFT 11 ++#define CSR_GCFG_TOE (0x1ULL << CSR_GCFG_TOE_SHIFT) ++#define CSR_GCFG_TOEP_SHIFT 10 ++#define CSR_GCFG_TOEP (0x1ULL << CSR_GCFG_TOEP_SHIFT) ++#define CSR_GCFG_TIT_SHIFT 9 ++#define CSR_GCFG_TIT (0x1ULL << CSR_GCFG_TIT_SHIFT) ++#define CSR_GCFG_TITP_SHIFT 8 ++#define CSR_GCFG_TITP (0x1ULL << CSR_GCFG_TITP_SHIFT) ++#define CSR_GCFG_SIT_SHIFT 7 ++#define CSR_GCFG_SIT (0x1ULL << CSR_GCFG_SIT_SHIFT) ++#define CSR_GCFG_SITP_SHIFT 6 ++#define CSR_GCFG_SITP (0x1ULL << CSR_GCFG_SITP_SHIFT) ++#define CSR_GCFG_CACTRL_SHIFT 4 ++#define CSR_GCFG_CACTRL_WIDTH 2 ++#define CSR_GCFG_CACTRL (0x3ULL << CSR_GCFG_CACTRL_SHIFT) ++#define CSR_GCFG_CACTRL_GUEST (0x0ULL << CSR_GCFG_CACTRL_SHIFT) ++#define CSR_GCFG_CACTRL_ROOT (0x1ULL << CSR_GCFG_CACTRL_SHIFT) ++#define CSR_GCFG_CACTRL_NEST (0x2ULL << CSR_GCFG_CACTRL_SHIFT) ++#define CSR_GCFG_CCCP_WIDTH 4 ++#define CSR_GCFG_CCCP (0xf) ++#define CSR_GCFG_CCCP_GUEST (0x1ULL << 0) ++#define CSR_GCFG_CCCP_ROOT (0x1ULL << 1) ++#define CSR_GCFG_CCCP_NEST (0x1ULL << 2) ++ ++#define LOONGARCH_CSR_GINTC 0x52 /* 64 guest exception control */ ++#define CSR_GINTC_HC_SHIFT 16 ++#define CSR_GINTC_HC_WIDTH 8 ++#define CSR_GINTC_HC (0xffULL << CSR_GINTC_HC_SHIFT) ++#define CSR_GINTC_PIP_SHIFT 8 ++#define CSR_GINTC_PIP_WIDTH 8 ++#define CSR_GINTC_PIP (0xffULL << CSR_GINTC_PIP_SHIFT) ++#define CSR_GINTC_VIP_SHIFT 0 ++#define CSR_GINTC_VIP_WIDTH 8 ++#define CSR_GINTC_VIP (0xff) ++ ++#define LOONGARCH_CSR_GCNTC 0x53 /* 64 guest timer offset */ ++ ++/* LLBCTL */ ++#define LOONGARCH_CSR_LLBCTL 0x60 /* 32 csr number to be changed */ ++#define CSR_LLBCTL_ROLLB_SHIFT 0 ++#define CSR_LLBCTL_ROLLB (1ULL << CSR_LLBCTL_ROLLB_SHIFT) ++#define CSR_LLBCTL_WCLLB_SHIFT 1 ++#define CSR_LLBCTL_WCLLB (1ULL << CSR_LLBCTL_WCLLB_SHIFT) ++#define CSR_LLBCTL_KLO_SHIFT 2 ++#define CSR_LLBCTL_KLO (1ULL << CSR_LLBCTL_KLO_SHIFT) ++ ++/* implement dependent */ ++#define LOONGARCH_CSR_IMPCTL1 0x80 /* 32 loongarch config */ ++#define CSR_MISPEC_SHIFT 20 ++#define CSR_MISPEC_WIDTH 8 ++#define CSR_MISPEC (0xffULL << CSR_MISPEC_SHIFT) ++#define CSR_SSEN_SHIFT 18 ++#define CSR_SSEN (1ULL << CSR_SSEN_SHIFT) ++#define CSR_SCRAND_SHIFT 17 ++#define CSR_SCRAND (1ULL << CSR_SCRAND_SHIFT) ++#define CSR_LLEXCL_SHIFT 16 ++#define CSR_LLEXCL (1ULL << CSR_LLEXCL_SHIFT) ++#define CSR_DISVC_SHIFT 15 ++#define CSR_DISVC (1ULL << CSR_DISVC_SHIFT) ++#define CSR_VCLRU_SHIFT 14 ++#define CSR_VCLRU (1ULL << CSR_VCLRU_SHIFT) ++#define CSR_DCLRU_SHIFT 13 ++#define CSR_DCLRU (1ULL << CSR_DCLRU_SHIFT) ++#define CSR_FASTLDQ_SHIFT 12 ++#define CSR_FASTLDQ (1ULL << CSR_FASTLDQ_SHIFT) ++#define CSR_USERCAC_SHIFT 11 ++#define CSR_USERCAC (1ULL << CSR_USERCAC_SHIFT) ++#define CSR_ANTI_MISPEC_SHIFT 10 ++#define CSR_ANTI_MISPEC (1ULL << CSR_ANTI_MISPEC_SHIFT) ++#define CSR_ANTI_FLUSHSFB_SHIFT 9 ++#define CSR_ANTI_FLUSHSFB (1ULL << CSR_ANTI_FLUSHSFB_SHIFT) ++#define CSR_STFILL_SHIFT 8 ++#define CSR_STFILL (1ULL << CSR_STFILL_SHIFT) ++#define CSR_LIFEP_SHIFT 7 ++#define CSR_LIFEP (1ULL << CSR_LIFEP_SHIFT) ++#define CSR_LLSYNC_SHIFT 6 ++#define CSR_LLSYNC (1ULL << CSR_LLSYNC_SHIFT) ++#define CSR_BRBTDIS_SHIFT 5 ++#define CSR_BRBTDIS (1ULL << CSR_BRBTDIS_SHIFT) ++#define CSR_RASDIS_SHIFT 4 ++#define CSR_RASDIS (1ULL << CSR_RASDIS_SHIFT) ++#define CSR_STPRE_SHIFT 2 ++#define CSR_STPRE_WIDTH 2 ++#define CSR_STPRE (3ULL << CSR_STPRE_SHIFT) ++#define CSR_INSTPRE_SHIFT 1 ++#define CSR_INSTPRE (1ULL << CSR_INSTPRE_SHIFT) ++#define CSR_DATAPRE_SHIFT 0 ++#define CSR_DATAPRE (1ULL << CSR_DATAPRE_SHIFT) ++ ++#define LOONGARCH_CSR_IMPCTL2 0x81 /* 32 Flush */ ++#define CSR_IMPCTL2_MTLB_SHIFT 0 ++#define CSR_IMPCTL2_MTLB (1ULL << CSR_IMPCTL2_MTLB_SHIFT) ++#define CSR_IMPCTL2_STLB_SHIFT 1 ++#define CSR_IMPCTL2_STLB (1ULL << CSR_IMPCTL2_STLB_SHIFT) ++#define CSR_IMPCTL2_DTLB_SHIFT 2 ++#define CSR_IMPCTL2_DTLB (1ULL << CSR_IMPCTL2_DTLB_SHIFT) ++#define CSR_IMPCTL2_ITLB_SHIFT 3 ++#define CSR_IMPCTL2_ITLB (1ULL << CSR_IMPCTL2_ITLB_SHIFT) ++#define CSR_IMPCTL2_BTAC_SHIFT 4 ++#define CSR_IMPCTL2_BTAC (1ULL << CSR_IMPCTL2_BTAC_SHIFT) ++ ++#define LOONGARCH_FLUSH_VTLB 1 ++#define LOONGARCH_FLUSH_FTLB (1 << 1) ++#define LOONGARCH_FLUSH_DTLB (1 << 2) ++#define LOONGARCH_FLUSH_ITLB (1 << 3) ++#define LOONGARCH_FLUSH_BTAC (1 << 4) ++ ++#define LOONGARCH_CSR_GNMI 0x82 ++ ++/* TLB Refill Only */ ++#define LOONGARCH_CSR_TLBRENT 0x88 /* 64 TLB refill exception address */ ++#define LOONGARCH_CSR_TLBRBADV 0x89 /* 64 TLB refill badvaddr */ ++#define LOONGARCH_CSR_TLBRERA 0x8a /* 64 TLB refill ERA */ ++#define LOONGARCH_CSR_TLBRSAVE 0x8b /* 64 KScratch for TLB refill */ ++#define LOONGARCH_CSR_TLBRELO0 0x8c /* 64 TLB refill entrylo0 */ ++#define LOONGARCH_CSR_TLBRELO1 0x8d /* 64 TLB refill entrylo1 */ ++#define LOONGARCH_CSR_TLBREHI 0x8e /* 64 TLB refill entryhi */ ++#define LOONGARCH_CSR_TLBRPRMD 0x8f /* 64 TLB refill mode info */ ++ ++/* error related */ ++#define LOONGARCH_CSR_ERRCTL 0x90 /* 32 ERRCTL */ ++#define LOONGARCH_CSR_ERRINFO 0x91 ++#define LOONGARCH_CSR_ERRINFO1 0x92 ++#define LOONGARCH_CSR_ERRENT 0x93 /* 64 error exception base */ ++#define LOONGARCH_CSR_ERRERA 0x94 /* 64 error exception PC */ ++#define LOONGARCH_CSR_ERRSAVE 0x95 /* 64 KScratch for error exception */ ++ ++#define LOONGARCH_CSR_CTAG 0x98 /* 64 TagLo + TagHi */ ++ ++/* direct map windows */ ++#define LOONGARCH_CSR_DMWIN0 0x180 /* 64 direct map win0: MEM & IF */ ++#define LOONGARCH_CSR_DMWIN1 0x181 /* 64 direct map win1: MEM & IF */ ++#define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */ ++#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */ ++#define CSR_DMW_PLV0 0x1 ++#define CSR_DMW_PLV1 0x2 ++#define CSR_DMW_PLV2 0x4 ++#define CSR_DMW_PLV3 0x8 ++#define CSR_DMW_BASE_SH 48 ++#define dmwin_va2pa(va) (va & (((unsigned long)1 << CSR_DMW_BASE_SH) - 1)) ++ ++/* performance counter */ ++#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */ ++#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */ ++#define LOONGARCH_CSR_PERFCTRL1 0x202 /* 32 perf event 1 config */ ++#define LOONGARCH_CSR_PERFCNTR1 0x203 /* 64 perf event 1 count value */ ++#define LOONGARCH_CSR_PERFCTRL2 0x204 /* 32 perf event 2 config */ ++#define LOONGARCH_CSR_PERFCNTR2 0x205 /* 64 perf event 2 count value */ ++#define LOONGARCH_CSR_PERFCTRL3 0x206 /* 32 perf event 3 config */ ++#define LOONGARCH_CSR_PERFCNTR3 0x207 /* 64 perf event 3 count value */ ++#define CSR_PERFCTRL_PLV0 (1ULL << 16) ++#define CSR_PERFCTRL_PLV1 (1ULL << 17) ++#define CSR_PERFCTRL_PLV2 (1ULL << 18) ++#define CSR_PERFCTRL_PLV3 (1ULL << 19) ++#define CSR_PERFCTRL_IE (1ULL << 20) ++#define CSR_PERFCTRL_EVENT 0x3ff ++ ++/* debug */ ++#define LOONGARCH_CSR_MWPC 0x300 /* data breakpoint config */ ++#define LOONGARCH_CSR_MWPS 0x301 /* data breakpoint status */ ++ ++#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */ ++#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */ ++#define LOONGARCH_CSR_DB0CTL 0x312 /* data breakpoint 0 control */ ++#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */ ++ ++#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */ ++#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */ ++#define LOONGARCH_CSR_DB1CTL 0x31a /* data breakpoint 1 control */ ++#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */ ++ ++#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */ ++#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */ ++#define LOONGARCH_CSR_DB2CTL 0x322 /* data breakpoint 2 control */ ++#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */ ++ ++#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */ ++#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */ ++#define LOONGARCH_CSR_DB3CTL 0x32a /* data breakpoint 3 control */ ++#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */ ++ ++#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */ ++#define LOONGARCH_CSR_FWPS 0x381 /* instruction breakpoint status */ ++ ++#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */ ++#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */ ++#define LOONGARCH_CSR_IB0CTL 0x392 /* inst breakpoint 0 control */ ++#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */ ++#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */ ++#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */ ++#define LOONGARCH_CSR_IB1CTL 0x39a /* inst breakpoint 1 control */ ++#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */ ++ ++#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */ ++#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */ ++#define LOONGARCH_CSR_IB2CTL 0x3a2 /* inst breakpoint 2 control */ ++#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */ ++ ++#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */ ++#define LOONGARCH_CSR_IB3MASK 0x3a9 /* inst breakpoint 3 mask */ ++#define LOONGARCH_CSR_IB3CTL 0x3aa /* inst breakpoint 3 control */ ++#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */ ++ ++#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */ ++#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */ ++#define LOONGARCH_CSR_IB4CTL 0x3b2 /* inst breakpoint 4 control */ ++#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */ ++ ++#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */ ++#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */ ++#define LOONGARCH_CSR_IB5CTL 0x3ba /* inst breakpoint 5 control */ ++#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */ ++ ++#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */ ++#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */ ++#define LOONGARCH_CSR_IB6CTL 0x3c2 /* inst breakpoint 6 control */ ++#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */ ++ ++#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */ ++#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */ ++#define LOONGARCH_CSR_IB7CTL 0x3ca /* inst breakpoint 7 control */ ++#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */ ++ ++#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */ ++#define CSR_DEBUG_DM 0 ++#define CSR_DEBUG_DMVER 1 ++#define CSR_DEBUG_DINT 8 ++#define CSR_DEBUG_DBP 9 ++#define CSR_DEBUG_DIB 10 ++#define CSR_DEBUG_DDB 11 ++ ++#define LOONGARCH_CSR_DERA 0x501 /* debug era */ ++#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ ++ ++#define LOONGARCH_CSR_PRID 0xc0 /* 32 LOONGARCH CP0 PRID */ ++ ++#define LOONGARCH_CPUCFG0 0x0 ++#define CPUCFG0_3A5000_PRID 0x0014c010 ++ ++#define LOONGARCH_CPUCFG1 0x1 ++#define CPUCFG1_ISGR32 BIT(0) ++#define CPUCFG1_ISGR64 BIT(1) ++#define CPUCFG1_PAGING BIT(2) ++#define CPUCFG1_IOCSR BIT(3) ++#define CPUCFG1_PABITS (47 << 4) ++#define CPUCFG1_VABITS (47 << 12) ++#define CPUCFG1_UAL BIT(20) ++#define CPUCFG1_RI BIT(21) ++#define CPUCFG1_XI BIT(22) ++#define CPUCFG1_RPLV BIT(23) ++#define CPUCFG1_HUGEPG BIT(24) ++#define CPUCFG1_IOCSRBRD BIT(25) ++#define CPUCFG1_MSGINT BIT(26) ++ ++#define LOONGARCH_CPUCFG2 0x2 ++#define CPUCFG2_FP BIT(0) ++#define CPUCFG2_FPSP BIT(1) ++#define CPUCFG2_FPDP BIT(2) ++#define CPUCFG2_FPVERS (0 << 3) ++#define CPUCFG2_LSX BIT(6) ++#define CPUCFG2_LASX BIT(7) ++#define CPUCFG2_COMPLEX BIT(8) ++#define CPUCFG2_CRYPTO BIT(9) ++#define CPUCFG2_LVZP BIT(10) ++#define CPUCFG2_LVZVER (0 << 11) ++#define CPUCFG2_LLFTP BIT(14) ++#define CPUCFG2_LLFTPREV (1 << 15) ++#define CPUCFG2_X86BT BIT(18) ++#define CPUCFG2_ARMBT BIT(19) ++#define CPUCFG2_MIPSBT BIT(20) ++#define CPUCFG2_LSPW BIT(21) ++#define CPUCFG2_LAM BIT(22) ++ ++#define LOONGARCH_CPUCFG3 0x3 ++#define CPUCFG3_CCDMA BIT(0) ++#define CPUCFG3_SFB BIT(1) ++#define CPUCFG3_UCACC BIT(2) ++#define CPUCFG3_LLEXC BIT(3) ++#define CPUCFG3_SCDLY BIT(4) ++#define CPUCFG3_LLDBAR BIT(5) ++#define CPUCFG3_ITLBT BIT(6) ++#define CPUCFG3_ICACHET BIT(7) ++#define CPUCFG3_SPW_LVL (4 << 8) ++#define CPUCFG3_SPW_HG_HF BIT(11) ++#define CPUCFG3_RVA BIT(12) ++#define CPUCFG3_RVAMAX (7 << 13) ++ ++#define LOONGARCH_CPUCFG4 0x4 ++#define CCFREQ_100M 100000000 /* 100M */ ++ ++#define LOONGARCH_CPUCFG5 0x5 ++#define CPUCFG5_CCMUL 1 ++#define CPUCFG5_CCDIV (1 << 16) ++ ++#define LOONGARCH_CPUCFG6 0x6 ++#define CPUCFG6_PMP BIT(0) ++#define CPUCFG6_PAMVER (1 << 1) ++#define CPUCFG6_PMNUM (3 << 4) ++#define CPUCFG6_PMBITS (63 << 8) ++#define CPUCFG6_UPM BIT(14) ++ ++#define LOONGARCH_CPUCFG16 0x10 ++#define CPUCFG16_L1_IUPRE BIT(0) ++#define CPUCFG16_L1_UNIFY BIT(1) ++#define CPUCFG16_L1_DPRE BIT(2) ++#define CPUCFG16_L2_IUPRE BIT(3) ++#define CPUCFG16_L2_IUUNIFY BIT(4) ++#define CPUCFG16_L2_IUPRIV BIT(5) ++#define CPUCFG16_L2_IUINCL BIT(6) ++#define CPUCFG16_L2_DPRE BIT(7) ++#define CPUCFG16_L2_DPRIV BIT(8) ++#define CPUCFG16_L2_DINCL BIT(9) ++#define CPUCFG16_L3_IUPRE BIT(10) ++#define CPUCFG16_L3_IUUNIFY BIT(11) ++#define CPUCFG16_L3_IUPRIV BIT(12) ++#define CPUCFG16_L3_IUINCL BIT(13) ++#define CPUCFG16_L3_DPRE BIT(14) ++#define CPUCFG16_L3_DPRIV BIT(15) ++#define CPUCFG16_L3_DINCL BIT(16) ++ ++#define LOONGARCH_CPUCFG17 0x11 ++#define CPUCFG17_L1I_WAYS_M (3 << 0) ++#define CPUCFG17_L1I_SETS_M (8 << 16) ++#define CPUCFG17_L1I_SIZE_M (6 << 24) ++ ++#define LOONGARCH_CPUCFG18 0x12 ++#define CPUCFG18_L1D_WAYS_M (3 << 0) ++#define CPUCFG18_L1D_SETS_M (8 << 16) ++#define CPUCFG18_L1D_SIZE_M (6 << 24) ++ ++#define LOONGARCH_CPUCFG19 0x13 ++#define CPUCFG19_L2_WAYS_M (0xf << 0) ++#define CPUCFG19_L2_SETS_M (8 << 16) ++#define CPUCFG19_L2_SIZE_M (6 << 24) ++ ++#define LOONGARCH_CPUCFG20 0x14 ++#define CPUCFG20_L3_WAYS_M (0xf << 0) ++#define CPUCFG20_L3_SETS_M (0xe << 16) ++#define CPUCFG20_L3_SIZE_M (0x6 << 24) ++ ++#define LOONGARCH_PAGE_HUGE 0x40 ++#define LOONGARCH_HUGE_GLOBAL 0x1000 ++#define LOONGARCH_HUGE_GLOBAL_SH 12 ++ ++/* ++ * All CSR register ++ * ++ * default value in target/loongarch/cpu.c ++ * reset function in target/loongarch/translate.c:cpu_state_reset() ++ * ++ * This macro will be used only twice. ++ * > In target/loongarch/cpu.h:CPULOONGARCHState ++ * > In target/loongarch/internal.h:loongarch_def_t ++ * ++ * helper_function to rd/wr: ++ * > declare in target/loongarch/helper.h ++ * > realize in target/loongarch/op_helper.c ++ * ++ * during translate: ++ * > gen_csr_rdl() ++ * > gen_csr_wrl() ++ * > gen_csr_rdq() ++ * > gen_csr_wrq() ++ */ ++#define CPU_LOONGARCH_CSR \ ++ uint64_t CSR_CRMD; \ ++ uint64_t CSR_PRMD; \ ++ uint64_t CSR_EUEN; \ ++ uint64_t CSR_MISC; \ ++ uint64_t CSR_ECFG; \ ++ uint64_t CSR_ESTAT; \ ++ uint64_t CSR_ERA; \ ++ uint64_t CSR_BADV; \ ++ uint64_t CSR_BADI; \ ++ uint64_t CSR_EEPN; \ ++ uint64_t CSR_TLBIDX; \ ++ uint64_t CSR_TLBEHI; \ ++ uint64_t CSR_TLBELO0; \ ++ uint64_t CSR_TLBELO1; \ ++ uint64_t CSR_TLBWIRED; \ ++ uint64_t CSR_GTLBC; \ ++ uint64_t CSR_TRGP; \ ++ uint64_t CSR_ASID; \ ++ uint64_t CSR_PGDL; \ ++ uint64_t CSR_PGDH; \ ++ uint64_t CSR_PGD; \ ++ uint64_t CSR_PWCTL0; \ ++ uint64_t CSR_PWCTL1; \ ++ uint64_t CSR_STLBPGSIZE; \ ++ uint64_t CSR_RVACFG; \ ++ uint64_t CSR_CPUID; \ ++ uint64_t CSR_PRCFG1; \ ++ uint64_t CSR_PRCFG2; \ ++ uint64_t CSR_PRCFG3; \ ++ uint64_t CSR_KS0; \ ++ uint64_t CSR_KS1; \ ++ uint64_t CSR_KS2; \ ++ uint64_t CSR_KS3; \ ++ uint64_t CSR_KS4; \ ++ uint64_t CSR_KS5; \ ++ uint64_t CSR_KS6; \ ++ uint64_t CSR_KS7; \ ++ uint64_t CSR_KS8; \ ++ uint64_t CSR_TMID; \ ++ uint64_t CSR_TCFG; \ ++ uint64_t CSR_TVAL; \ ++ uint64_t CSR_CNTC; \ ++ uint64_t CSR_TINTCLR; \ ++ uint64_t CSR_GSTAT; \ ++ uint64_t CSR_GCFG; \ ++ uint64_t CSR_GINTC; \ ++ uint64_t CSR_GCNTC; \ ++ uint64_t CSR_LLBCTL; \ ++ uint64_t CSR_IMPCTL1; \ ++ uint64_t CSR_IMPCTL2; \ ++ uint64_t CSR_GNMI; \ ++ uint64_t CSR_TLBRENT; \ ++ uint64_t CSR_TLBRBADV; \ ++ uint64_t CSR_TLBRERA; \ ++ uint64_t CSR_TLBRSAVE; \ ++ uint64_t CSR_TLBRELO0; \ ++ uint64_t CSR_TLBRELO1; \ ++ uint64_t CSR_TLBREHI; \ ++ uint64_t CSR_TLBRPRMD; \ ++ uint64_t CSR_ERRCTL; \ ++ uint64_t CSR_ERRINFO; \ ++ uint64_t CSR_ERRINFO1; \ ++ uint64_t CSR_ERRENT; \ ++ uint64_t CSR_ERRERA; \ ++ uint64_t CSR_ERRSAVE; \ ++ uint64_t CSR_CTAG; \ ++ uint64_t CSR_DMWIN0; \ ++ uint64_t CSR_DMWIN1; \ ++ uint64_t CSR_DMWIN2; \ ++ uint64_t CSR_DMWIN3; \ ++ uint64_t CSR_PERFCTRL0; \ ++ uint64_t CSR_PERFCNTR0; \ ++ uint64_t CSR_PERFCTRL1; \ ++ uint64_t CSR_PERFCNTR1; \ ++ uint64_t CSR_PERFCTRL2; \ ++ uint64_t CSR_PERFCNTR2; \ ++ uint64_t CSR_PERFCTRL3; \ ++ uint64_t CSR_PERFCNTR3; \ ++ uint64_t CSR_MWPC; \ ++ uint64_t CSR_MWPS; \ ++ uint64_t CSR_DB0ADDR; \ ++ uint64_t CSR_DB0MASK; \ ++ uint64_t CSR_DB0CTL; \ ++ uint64_t CSR_DB0ASID; \ ++ uint64_t CSR_DB1ADDR; \ ++ uint64_t CSR_DB1MASK; \ ++ uint64_t CSR_DB1CTL; \ ++ uint64_t CSR_DB1ASID; \ ++ uint64_t CSR_DB2ADDR; \ ++ uint64_t CSR_DB2MASK; \ ++ uint64_t CSR_DB2CTL; \ ++ uint64_t CSR_DB2ASID; \ ++ uint64_t CSR_DB3ADDR; \ ++ uint64_t CSR_DB3MASK; \ ++ uint64_t CSR_DB3CTL; \ ++ uint64_t CSR_DB3ASID; \ ++ uint64_t CSR_FWPC; \ ++ uint64_t CSR_FWPS; \ ++ uint64_t CSR_IB0ADDR; \ ++ uint64_t CSR_IB0MASK; \ ++ uint64_t CSR_IB0CTL; \ ++ uint64_t CSR_IB0ASID; \ ++ uint64_t CSR_IB1ADDR; \ ++ uint64_t CSR_IB1MASK; \ ++ uint64_t CSR_IB1CTL; \ ++ uint64_t CSR_IB1ASID; \ ++ uint64_t CSR_IB2ADDR; \ ++ uint64_t CSR_IB2MASK; \ ++ uint64_t CSR_IB2CTL; \ ++ uint64_t CSR_IB2ASID; \ ++ uint64_t CSR_IB3ADDR; \ ++ uint64_t CSR_IB3MASK; \ ++ uint64_t CSR_IB3CTL; \ ++ uint64_t CSR_IB3ASID; \ ++ uint64_t CSR_IB4ADDR; \ ++ uint64_t CSR_IB4MASK; \ ++ uint64_t CSR_IB4CTL; \ ++ uint64_t CSR_IB4ASID; \ ++ uint64_t CSR_IB5ADDR; \ ++ uint64_t CSR_IB5MASK; \ ++ uint64_t CSR_IB5CTL; \ ++ uint64_t CSR_IB5ASID; \ ++ uint64_t CSR_IB6ADDR; \ ++ uint64_t CSR_IB6MASK; \ ++ uint64_t CSR_IB6CTL; \ ++ uint64_t CSR_IB6ASID; \ ++ uint64_t CSR_IB7ADDR; \ ++ uint64_t CSR_IB7MASK; \ ++ uint64_t CSR_IB7CTL; \ ++ uint64_t CSR_IB7ASID; \ ++ uint64_t CSR_DEBUG; \ ++ uint64_t CSR_DERA; \ ++ uint64_t CSR_DESAVE; ++ ++#define LOONGARCH_CSR_32(_R, _S) \ ++ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U32 | (8 * (_R) + (_S))) ++ ++#define LOONGARCH_CSR_64(_R, _S) \ ++ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U64 | (8 * (_R) + (_S))) ++ ++#define KVM_IOC_CSRID(id) LOONGARCH_CSR_64(id, 0) ++ ++#endif +diff --git a/target/loongarch64/cpu-param.h b/target/loongarch64/cpu-param.h +new file mode 100644 +index 0000000000..b5acb6b91e +--- /dev/null ++++ b/target/loongarch64/cpu-param.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef CPU_PARAM_H ++#define CPU_PARAM_H ++ ++/* If we want to use host float regs... */ ++/* #define USE_HOST_FLOAT_REGS */ ++ ++/* Real pages are variable size... */ ++#define TARGET_PAGE_BITS 14 ++ ++#define LOONGARCH_TLB_MAX 2112 ++ ++#define TARGET_LONG_BITS 64 ++#define TARGET_PHYS_ADDR_SPACE_BITS 48 ++#define TARGET_VIRT_ADDR_SPACE_BITS 48 ++ ++/* ++ * bit definitions for insn_flags (ISAs/ASEs flags) ++ * ------------------------------------------------ ++ */ ++#define ISA_LARCH32 0x00000001ULL ++#define ISA_LARCH64 0x00000002ULL ++#define INSN_LOONGARCH 0x00010000ULL ++ ++#define CPU_LARCH32 (ISA_LARCH32) ++#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) ++ ++#define NB_MMU_MODES 4 ++ ++#endif /* QEMU_LOONGARCH_DEFS_H */ +diff --git a/target/loongarch64/cpu-qom.h b/target/loongarch64/cpu-qom.h +new file mode 100644 +index 0000000000..43541c34e5 +--- /dev/null ++++ b/target/loongarch64/cpu-qom.h +@@ -0,0 +1,54 @@ ++/* ++ * QEMU LOONGARCH CPU ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef QEMU_LOONGARCH_CPU_QOM_H ++#define QEMU_LOONGARCH_CPU_QOM_H ++ ++#include "hw/core/cpu.h" ++ ++#define TYPE_LOONGARCH_CPU "loongarch-cpu" ++ ++#define LOONGARCH_CPU_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(LOONGARCHCPUClass, (klass), TYPE_LOONGARCH_CPU) ++#define LOONGARCH_CPU(obj) \ ++ OBJECT_CHECK(LOONGARCHCPU, (obj), TYPE_LOONGARCH_CPU) ++#define LOONGARCH_CPU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(LOONGARCHCPUClass, (obj), TYPE_LOONGARCH_CPU) ++ ++/** ++ * LOONGARCHCPUClass: ++ * @parent_realize: The parent class' realize handler. ++ * @parent_reset: The parent class' reset handler. ++ * ++ * A LOONGARCH CPU model. ++ */ ++typedef struct LOONGARCHCPUClass { ++ /*< private >*/ ++ CPUClass parent_class; ++ /*< public >*/ ++ ++ DeviceRealize parent_realize; ++ DeviceUnrealize parent_unrealize; ++ DeviceReset parent_reset; ++ const struct loongarch_def_t *cpu_def; ++} LOONGARCHCPUClass; ++ ++typedef struct LOONGARCHCPU LOONGARCHCPU; ++ ++#endif +diff --git a/target/loongarch64/cpu.c b/target/loongarch64/cpu.c +new file mode 100644 +index 0000000000..ce04d8064f +--- /dev/null ++++ b/target/loongarch64/cpu.c +@@ -0,0 +1,575 @@ ++/* ++ * QEMU LOONGARCH CPU ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qapi/visitor.h" ++#include "cpu.h" ++#include "internal.h" ++#include "kvm_larch.h" ++#include "qemu-common.h" ++#include "hw/qdev-properties.h" ++#include "sysemu/kvm.h" ++#include "exec/exec-all.h" ++#include "sysemu/arch_init.h" ++#include "cpu-csr.h" ++#include "qemu/qemu-print.h" ++#include "qapi/qapi-commands-machine-target.h" ++#ifdef CONFIG_TCG ++#include "hw/core/tcg-cpu-ops.h" ++#endif /* CONFIG_TCG */ ++ ++#define LOONGARCH_CONFIG1 \ ++ ((0x8 << CSR_CONF1_KSNUM_SHIFT) | (0x2f << CSR_CONF1_TMRBITS_SHIFT) | \ ++ (0x7 << CSR_CONF1_VSMAX_SHIFT)) ++ ++#define LOONGARCH_CONFIG3 \ ++ ((0x2 << CSR_CONF3_TLBORG_SHIFT) | (0x3f << CSR_CONF3_MTLBSIZE_SHIFT) | \ ++ (0x7 << CSR_CONF3_STLBWAYS_SHIFT) | (0x8 << CSR_CONF3_STLBIDX_SHIFT)) ++ ++/* LOONGARCH CPU definitions */ ++const loongarch_def_t loongarch_defs[] = { ++ { ++ .name = "Loongson-3A5000", ++ ++ /* for LoongISA CSR */ ++ .CSR_PRCFG1 = LOONGARCH_CONFIG1, ++ .CSR_PRCFG2 = 0x3ffff000, ++ .CSR_PRCFG3 = LOONGARCH_CONFIG3, ++ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | ++ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | ++ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT), ++ .CSR_ECFG = 0x7 << 16, ++ .CSR_STLBPGSIZE = 0xe, ++ .CSR_RVACFG = 0x0, ++ .CSR_ASID = 0xa0000, ++ .FCSR0 = 0x0, ++ .FCSR0_rw_bitmask = 0x1f1f03df, ++ .PABITS = 48, ++ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, ++ .mmu_type = MMU_TYPE_LS3A5K, ++ }, ++ { ++ .name = "host", ++ ++ /* for LoongISA CSR */ ++ .CSR_PRCFG1 = LOONGARCH_CONFIG1, ++ .CSR_PRCFG2 = 0x3ffff000, ++ .CSR_PRCFG3 = LOONGARCH_CONFIG3, ++ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | ++ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | ++ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT), ++ .CSR_ECFG = 0x7 << 16, ++ .CSR_STLBPGSIZE = 0xe, ++ .CSR_RVACFG = 0x0, ++ .FCSR0 = 0x0, ++ .FCSR0_rw_bitmask = 0x1f1f03df, ++ .PABITS = 48, ++ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, ++ .mmu_type = MMU_TYPE_LS3A5K, ++ }, ++}; ++const int loongarch_defs_number = ARRAY_SIZE(loongarch_defs); ++ ++void loongarch_cpu_list(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { ++ qemu_printf("LOONGARCH '%s'\n", loongarch_defs[i].name); ++ } ++} ++ ++CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) ++{ ++ CpuDefinitionInfoList *cpu_list = NULL; ++ const loongarch_def_t *def; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { ++ CpuDefinitionInfoList *entry; ++ CpuDefinitionInfo *info; ++ ++ def = &loongarch_defs[i]; ++ info = g_malloc0(sizeof(*info)); ++ info->name = g_strdup(def->name); ++ ++ entry = g_malloc0(sizeof(*entry)); ++ entry->value = info; ++ entry->next = cpu_list; ++ cpu_list = entry; ++ } ++ ++ return cpu_list; ++} ++ ++static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ env->active_tc.PC = value & ~(target_ulong)1; ++} ++ ++static bool loongarch_cpu_has_work(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ bool has_work = false; ++ ++ /* ++ * It is implementation dependent if non-enabled ++ * interrupts wake-up the CPU, however most of the implementations only ++ * check for interrupts that can be taken. ++ */ ++ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && ++ cpu_loongarch_hw_interrupts_pending(env)) { ++ has_work = true; ++ } ++ ++ return has_work; ++} ++ ++const char *const regnames[] = { ++ "r0", "ra", "tp", "sp", "a0", "a1", "a2", "a3", "a4", "a5", "a6", ++ "a7", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "x0", ++ "fp", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", ++}; ++ ++const char *const fregnames[] = { ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", ++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", ++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", ++}; ++ ++static void fpu_dump_state(CPULOONGARCHState *env, FILE *f, ++ fprintf_function fpu_fprintf, int flags) ++{ ++ int i; ++ int is_fpu64 = 1; ++ ++#define printfpr(fp) \ ++ do { \ ++ if (is_fpu64) \ ++ fpu_fprintf( \ ++ f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu: %13g\n", \ ++ (fp)->w[FP_ENDIAN_IDX], (fp)->d, (double)(fp)->fd, \ ++ (double)(fp)->fs[FP_ENDIAN_IDX], \ ++ (double)(fp)->fs[!FP_ENDIAN_IDX]); \ ++ else { \ ++ fpr_t tmp; \ ++ tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ ++ tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ ++ fpu_fprintf(f, \ ++ "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu:%13g\n", \ ++ tmp.w[FP_ENDIAN_IDX], tmp.d, (double)tmp.fd, \ ++ (double)tmp.fs[FP_ENDIAN_IDX], \ ++ (double)tmp.fs[!FP_ENDIAN_IDX]); \ ++ } \ ++ } while (0) ++ ++ fpu_fprintf(f, "FCSR0 0x%08x SR.FR %d fp_status 0x%02x\n", ++ env->active_fpu.fcsr0, is_fpu64, ++ get_float_exception_flags(&env->active_fpu.fp_status)); ++ for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { ++ fpu_fprintf(f, "%3s: ", fregnames[i]); ++ printfpr(&env->active_fpu.fpr[i]); ++ } ++ ++#undef printfpr ++} ++ ++void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int i; ++ ++ qemu_fprintf(f, "pc:\t %lx\n", env->active_tc.PC); ++ for (i = 0; i < 32; i++) { ++ if ((i & 3) == 0) { ++ qemu_fprintf(f, "GPR%02d:", i); ++ } ++ qemu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], ++ env->active_tc.gpr[i]); ++ if ((i & 3) == 3) { ++ qemu_fprintf(f, "\n"); ++ } ++ } ++ qemu_fprintf(f, "EUEN 0x%lx\n", env->CSR_EUEN); ++ qemu_fprintf(f, "ESTAT 0x%lx\n", env->CSR_ESTAT); ++ qemu_fprintf(f, "ERA 0x%lx\n", env->CSR_ERA); ++ qemu_fprintf(f, "CRMD 0x%lx\n", env->CSR_CRMD); ++ qemu_fprintf(f, "PRMD 0x%lx\n", env->CSR_PRMD); ++ qemu_fprintf(f, "BadVAddr 0x%lx\n", env->CSR_BADV); ++ qemu_fprintf(f, "TLB refill ERA 0x%lx\n", env->CSR_TLBRERA); ++ qemu_fprintf(f, "TLB refill BadV 0x%lx\n", env->CSR_TLBRBADV); ++ qemu_fprintf(f, "EEPN 0x%lx\n", env->CSR_EEPN); ++ qemu_fprintf(f, "BadInstr 0x%lx\n", env->CSR_BADI); ++ qemu_fprintf(f, "PRCFG1 0x%lx\nPRCFG2 0x%lx\nPRCFG3 0x%lx\n", ++ env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); ++ if ((flags & CPU_DUMP_FPU) && (env->hflags & LARCH_HFLAG_FPU)) { ++ fpu_dump_state(env, f, qemu_fprintf, flags); ++ } ++} ++ ++void cpu_state_reset(CPULOONGARCHState *env) ++{ ++ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); ++ CPUState *cs = CPU(cpu); ++ ++ /* Reset registers to their default values */ ++ env->CSR_PRCFG1 = env->cpu_model->CSR_PRCFG1; ++ env->CSR_PRCFG2 = env->cpu_model->CSR_PRCFG2; ++ env->CSR_PRCFG3 = env->cpu_model->CSR_PRCFG3; ++ env->CSR_CRMD = env->cpu_model->CSR_CRMD; ++ env->CSR_ECFG = env->cpu_model->CSR_ECFG; ++ env->CSR_STLBPGSIZE = env->cpu_model->CSR_STLBPGSIZE; ++ env->CSR_RVACFG = env->cpu_model->CSR_RVACFG; ++ env->CSR_ASID = env->cpu_model->CSR_ASID; ++ ++ env->current_tc = 0; ++ env->active_fpu.fcsr0_rw_bitmask = env->cpu_model->FCSR0_rw_bitmask; ++ env->active_fpu.fcsr0 = env->cpu_model->FCSR0; ++ env->insn_flags = env->cpu_model->insn_flags; ++ ++#if !defined(CONFIG_USER_ONLY) ++ env->CSR_ERA = env->active_tc.PC; ++ env->active_tc.PC = env->exception_base; ++#ifdef CONFIG_TCG ++ env->tlb->tlb_in_use = env->tlb->nb_tlb; ++#endif ++ env->CSR_TLBWIRED = 0; ++ env->CSR_TMID = cs->cpu_index; ++ env->CSR_CPUID = (cs->cpu_index & 0x1ff); ++ env->CSR_EEPN |= (uint64_t)0x80000000; ++ env->CSR_TLBRENT |= (uint64_t)0x80000000; ++#endif ++ ++ /* Count register increments in debug mode, EJTAG version 1 */ ++ env->CSR_DEBUG = (1 << CSR_DEBUG_DINT) | (0x1 << CSR_DEBUG_DMVER); ++ ++ compute_hflags(env); ++ restore_fp_status(env); ++ cs->exception_index = EXCP_NONE; ++} ++ ++/* CPUClass::reset() */ ++static void loongarch_cpu_reset(DeviceState *dev) ++{ ++ CPUState *s = CPU(dev); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(s); ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(cpu); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ mcc->parent_reset(dev); ++ ++ memset(env, 0, offsetof(CPULOONGARCHState, end_reset_fields)); ++ ++ cpu_state_reset(env); ++ ++#ifndef CONFIG_USER_ONLY ++ if (kvm_enabled()) { ++ kvm_loongarch_reset_vcpu(cpu); ++ } ++#endif ++} ++ ++static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) ++{ ++ info->print_insn = print_insn_loongarch; ++} ++ ++static void fpu_init(CPULOONGARCHState *env, const loongarch_def_t *def) ++{ ++ memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); ++} ++ ++void cpu_loongarch_realize_env(CPULOONGARCHState *env) ++{ ++ env->exception_base = 0x1C000000; ++ ++#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) ++ mmu_init(env, env->cpu_model); ++#endif ++ fpu_init(env, env->cpu_model); ++} ++ ++static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) ++{ ++ CPUState *cs = CPU(dev); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); ++ Error *local_err = NULL; ++ ++ cpu_exec_realizefn(cs, &local_err); ++ if (local_err != NULL) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ cpu_loongarch_realize_env(&cpu->env); ++ ++ loongarch_cpu_register_gdb_regs_for_features(cs); ++ ++ cpu_reset(cs); ++ qemu_init_vcpu(cs); ++ ++ mcc->parent_realize(dev, errp); ++ cpu->hotplugged = 1; ++} ++ ++static void loongarch_cpu_unrealizefn(DeviceState *dev) ++{ ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); ++ ++#ifndef CONFIG_USER_ONLY ++ cpu_remove_sync(CPU(dev)); ++#endif ++ ++ mcc->parent_unrealize(dev); ++} ++ ++static void loongarch_cpu_initfn(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(obj); ++ CPULOONGARCHState *env = &cpu->env; ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(obj); ++ cpu_set_cpustate_pointers(cpu); ++ cs->env_ptr = env; ++ env->cpu_model = mcc->cpu_def; ++ cs->halted = 1; ++ cpu->dtb_compatible = "loongarch,Loongson-3A5000"; ++} ++ ++static char *loongarch_cpu_type_name(const char *cpu_model) ++{ ++ return g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); ++} ++ ++static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) ++{ ++ ObjectClass *oc; ++ char *typename; ++ ++ typename = loongarch_cpu_type_name(cpu_model); ++ oc = object_class_by_name(typename); ++ g_free(typename); ++ return oc; ++} ++ ++static int64_t loongarch_cpu_get_arch_id(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ ++ return cpu->id; ++} ++ ++static Property loongarch_cpu_properties[] = { ++ DEFINE_PROP_INT32("core-id", LOONGARCHCPU, core_id, -1), ++ DEFINE_PROP_INT32("id", LOONGARCHCPU, id, UNASSIGNED_CPU_ID), ++ DEFINE_PROP_INT32("node-id", LOONGARCHCPU, node_id, ++ CPU_UNSET_NUMA_NODE_ID), ++ ++ DEFINE_PROP_END_OF_LIST() ++}; ++ ++#ifdef CONFIG_TCG ++static void loongarch_cpu_synchronize_from_tb(CPUState *cs, ++ const TranslationBlock *tb) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ env->active_tc.PC = tb->pc; ++ env->hflags &= ~LARCH_HFLAG_BMASK; ++ env->hflags |= tb->flags & LARCH_HFLAG_BMASK; ++} ++ ++static const struct TCGCPUOps loongarch_tcg_ops = { ++ .initialize = loongarch_tcg_init, ++ .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, ++ ++ .tlb_fill = loongarch_cpu_tlb_fill, ++ .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, ++ .do_interrupt = loongarch_cpu_do_interrupt, ++ ++#ifndef CONFIG_USER_ONLY ++ .do_unaligned_access = loongarch_cpu_do_unaligned_access, ++#endif /* !CONFIG_USER_ONLY */ ++}; ++#endif /* CONFIG_TCG */ ++ ++#if !defined(CONFIG_USER_ONLY) ++static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, ++ int *prot, target_ulong real_address, int rw, ++ int access_type, int mmu_idx) ++{ ++ int user_mode = mmu_idx == LARCH_HFLAG_UM; ++ int kernel_mode = !user_mode; ++ unsigned plv, base_c, base_v, tmp; ++ ++ /* effective address (modified for KVM T&E kernel segments) */ ++ target_ulong address = real_address; ++ ++ /* Check PG */ ++ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { ++ /* DA mode */ ++ *physical = address & 0xffffffffffffUL; ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ ++ plv = kernel_mode | (user_mode << 3); ++ base_v = address >> CSR_DMW_BASE_SH; ++ /* Check direct map window 0 */ ++ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; ++ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { ++ *physical = dmwin_va2pa(address); ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ /* Check direct map window 1 */ ++ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; ++ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { ++ *physical = dmwin_va2pa(address); ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ /* Check valid extension */ ++ tmp = address >> 47; ++ if (!(tmp == 0 || tmp == 0x1ffff)) { ++ return TLBRET_BADADDR; ++ } ++ /* mapped address */ ++ return env->tlb->map_address(env, physical, prot, real_address, rw, ++ access_type); ++} ++ ++hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ hwaddr phys_addr; ++ int prot; ++ ++ if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT, ++ cpu_mmu_index(env, false)) != 0) { ++ return -1; ++ } ++ return phys_addr; ++} ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++#include "hw/core/sysemu-cpu-ops.h" ++ ++static const struct SysemuCPUOps loongarch_sysemu_ops = { ++ .write_elf64_note = loongarch_cpu_write_elf64_note, ++ .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, ++ .legacy_vmsd = &vmstate_loongarch_cpu, ++}; ++#endif ++ ++static gchar *loongarch_gdb_arch_name(CPUState *cs) ++{ ++ return g_strdup("loongarch64"); ++} ++ ++static void loongarch_cpu_class_init(ObjectClass *c, void *data) ++{ ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(c); ++ CPUClass *cc = CPU_CLASS(c); ++ DeviceClass *dc = DEVICE_CLASS(c); ++ ++ device_class_set_props(dc, loongarch_cpu_properties); ++ device_class_set_parent_realize(dc, loongarch_cpu_realizefn, ++ &mcc->parent_realize); ++ ++ device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn, ++ &mcc->parent_unrealize); ++ ++ device_class_set_parent_reset(dc, loongarch_cpu_reset, &mcc->parent_reset); ++ cc->get_arch_id = loongarch_cpu_get_arch_id; ++ ++ cc->class_by_name = loongarch_cpu_class_by_name; ++ cc->has_work = loongarch_cpu_has_work; ++ cc->dump_state = loongarch_cpu_dump_state; ++ cc->set_pc = loongarch_cpu_set_pc; ++ cc->gdb_read_register = loongarch_cpu_gdb_read_register; ++ cc->gdb_write_register = loongarch_cpu_gdb_write_register; ++ cc->disas_set_info = loongarch_cpu_disas_set_info; ++ cc->gdb_arch_name = loongarch_gdb_arch_name; ++#ifndef CONFIG_USER_ONLY ++ cc->sysemu_ops = &loongarch_sysemu_ops; ++#endif /* !CONFIG_USER_ONLY */ ++ ++ cc->gdb_num_core_regs = 35; ++ cc->gdb_core_xml_file = "loongarch-base64.xml"; ++ cc->gdb_stop_before_watchpoint = true; ++ ++ dc->user_creatable = true; ++#ifdef CONFIG_TCG ++ cc->tcg_ops = &loongarch_tcg_ops; ++#endif /* CONFIG_TCG */ ++} ++ ++static const TypeInfo loongarch_cpu_type_info = { ++ .name = TYPE_LOONGARCH_CPU, ++ .parent = TYPE_CPU, ++ .instance_size = sizeof(LOONGARCHCPU), ++ .instance_init = loongarch_cpu_initfn, ++ .abstract = true, ++ .class_size = sizeof(LOONGARCHCPUClass), ++ .class_init = loongarch_cpu_class_init, ++}; ++ ++static void loongarch_cpu_cpudef_class_init(ObjectClass *oc, void *data) ++{ ++ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(oc); ++ mcc->cpu_def = data; ++} ++ ++static void loongarch_register_cpudef_type(const struct loongarch_def_t *def) ++{ ++ char *typename = loongarch_cpu_type_name(def->name); ++ TypeInfo ti = { ++ .name = typename, ++ .parent = TYPE_LOONGARCH_CPU, ++ .class_init = loongarch_cpu_cpudef_class_init, ++ .class_data = (void *)def, ++ }; ++ ++ type_register(&ti); ++ g_free(typename); ++} ++ ++static void loongarch_cpu_register_types(void) ++{ ++ int i; ++ ++ type_register_static(&loongarch_cpu_type_info); ++ for (i = 0; i < loongarch_defs_number; i++) { ++ loongarch_register_cpudef_type(&loongarch_defs[i]); ++ } ++} ++ ++type_init(loongarch_cpu_register_types) +diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h +new file mode 100644 +index 0000000000..bf5b36d404 +--- /dev/null ++++ b/target/loongarch64/cpu.h +@@ -0,0 +1,359 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_CPU_H ++#define LOONGARCH_CPU_H ++ ++#define CPUArchState struct CPULOONGARCHState ++ ++#include "qemu-common.h" ++#include "cpu-qom.h" ++#include "larch-defs.h" ++#include "exec/cpu-defs.h" ++#include "fpu/softfloat.h" ++#include "sysemu/sysemu.h" ++#include "cpu-csr.h" ++ ++#define TCG_GUEST_DEFAULT_MO (0) ++ ++struct CPULOONGARCHState; ++typedef LOONGARCHCPU ArchCPU; ++typedef struct CPULOONGARCHTLBContext CPULOONGARCHTLBContext; ++ ++#define LASX_REG_WIDTH (256) ++typedef union lasx_reg_t lasx_reg_t; ++union lasx_reg_t ++{ ++ int64_t val64[LASX_REG_WIDTH / 64]; ++}; ++ ++typedef union fpr_t fpr_t; ++union fpr_t ++{ ++ float64 fd; /* ieee double precision */ ++ float32 fs[2]; /* ieee single precision */ ++ uint64_t d; /* binary double fixed-point */ ++ uint32_t w[2]; /* binary single fixed-point */ ++ /* FPU/LASX register mapping is not tested on big-endian hosts. */ ++ lasx_reg_t lasx; /* vector data */ ++}; ++/* ++ * define FP_ENDIAN_IDX to access the same location ++ * in the fpr_t union regardless of the host endianness ++ */ ++#if defined(HOST_WORDS_BIGENDIAN) ++#define FP_ENDIAN_IDX 1 ++#else ++#define FP_ENDIAN_IDX 0 ++#endif ++ ++typedef struct CPULOONGARCHFPUContext { ++ /* Floating point registers */ ++ fpr_t fpr[32]; ++ float_status fp_status; ++ ++ bool cf[8]; ++ /* ++ * fcsr0 ++ * 31:29 |28:24 |23:21 |20:16 |15:10 |9:8 |7 |6 |5 |4:0 ++ * Cause Flags RM DAE TM Enables ++ */ ++ uint32_t fcsr0; ++ uint32_t fcsr0_rw_bitmask; ++ uint32_t vcsr16; ++} CPULOONGARCHFPUContext; ++ ++/* fp control and status register definition */ ++#define FCSR0_M1 0xdf /* DAE, TM and Enables */ ++#define FCSR0_M2 0x1f1f0000 /* Cause and Flags */ ++#define FCSR0_M3 0x300 /* Round Mode */ ++#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ ++#define GET_FP_CAUSE(reg) (((reg) >> 24) & 0x1f) ++#define GET_FP_ENABLE(reg) (((reg) >> 0) & 0x1f) ++#define GET_FP_FLAGS(reg) (((reg) >> 16) & 0x1f) ++#define SET_FP_CAUSE(reg, v) \ ++ do { \ ++ (reg) = ((reg) & ~(0x1f << 24)) | ((v & 0x1f) << 24); \ ++ } while (0) ++#define SET_FP_ENABLE(reg, v) \ ++ do { \ ++ (reg) = ((reg) & ~(0x1f << 0)) | ((v & 0x1f) << 0); \ ++ } while (0) ++#define SET_FP_FLAGS(reg, v) \ ++ do { \ ++ (reg) = ((reg) & ~(0x1f << 16)) | ((v & 0x1f) << 16); \ ++ } while (0) ++#define UPDATE_FP_FLAGS(reg, v) \ ++ do { \ ++ (reg) |= ((v & 0x1f) << 16); \ ++ } while (0) ++#define FP_INEXACT 1 ++#define FP_UNDERFLOW 2 ++#define FP_OVERFLOW 4 ++#define FP_DIV0 8 ++#define FP_INVALID 16 ++ ++#define TARGET_INSN_START_EXTRA_WORDS 2 ++ ++typedef struct loongarch_def_t loongarch_def_t; ++ ++#define LOONGARCH_FPU_MAX 1 ++#define LOONGARCH_KSCRATCH_NUM 8 ++ ++typedef struct TCState TCState; ++struct TCState { ++ target_ulong gpr[32]; ++ target_ulong PC; ++}; ++ ++#define N_IRQS 14 ++#define IRQ_TIMER 11 ++#define IRQ_IPI 12 ++#define IRQ_UART 2 ++ ++typedef struct CPULOONGARCHState CPULOONGARCHState; ++struct CPULOONGARCHState { ++ TCState active_tc; ++ CPULOONGARCHFPUContext active_fpu; ++ ++ uint32_t current_tc; ++ uint64_t scr[4]; ++ uint32_t PABITS; ++ ++ /* LoongISA CSR register */ ++ CPU_LOONGARCH_CSR ++ uint64_t lladdr; ++ target_ulong llval; ++ uint64_t llval_wp; ++ uint32_t llnewval_wp; ++ ++ CPULOONGARCHFPUContext fpus[LOONGARCH_FPU_MAX]; ++ /* QEMU */ ++ int error_code; ++#define EXCP_TLB_NOMATCH 0x1 ++#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ ++ uint32_t hflags; /* CPU State */ ++ /* TMASK defines different execution modes */ ++#define LARCH_HFLAG_TMASK 0x5F5807FF ++ /* ++ * The KSU flags must be the lowest bits in hflags. The flag order ++ * must be the same as defined for CP0 Status. This allows to use ++ * the bits as the value of mmu_idx. ++ */ ++#define LARCH_HFLAG_KSU 0x00003 /* kernel/user mode mask */ ++#define LARCH_HFLAG_UM 0x00003 /* user mode flag */ ++#define LARCH_HFLAG_KM 0x00000 /* kernel mode flag */ ++#define LARCH_HFLAG_64 0x00008 /* 64-bit instructions enabled */ ++#define LARCH_HFLAG_FPU 0x00020 /* FPU enabled */ ++#define LARCH_HFLAG_AWRAP 0x00200 /* 32-bit compatibility address wrapping */ ++ /* ++ * If translation is interrupted between the branch instruction and ++ * the delay slot, record what type of branch it is so that we can ++ * resume translation properly. It might be possible to reduce ++ * this from three bits to two. ++ */ ++#define LARCH_HFLAG_BMASK 0x03800 ++#define LARCH_HFLAG_B 0x00800 /* Unconditional branch */ ++#define LARCH_HFLAG_BC 0x01000 /* Conditional branch */ ++#define LARCH_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ ++#define LARCH_HFLAG_LSX 0x1000000 ++#define LARCH_HFLAG_LASX 0x2000000 ++#define LARCH_HFLAG_LBT 0x40000000 ++ target_ulong btarget; /* Jump / branch target */ ++ target_ulong bcond; /* Branch condition (if needed) */ ++ ++ uint64_t insn_flags; /* Supported instruction set */ ++ int cpu_cfg[64]; ++ ++ /* Fields up to this point are cleared by a CPU reset */ ++ struct { ++ } end_reset_fields; ++ ++ /* Fields from here on are preserved across CPU reset. */ ++#if !defined(CONFIG_USER_ONLY) ++ CPULOONGARCHTLBContext *tlb; ++#endif ++ ++ const loongarch_def_t *cpu_model; ++ void *irq[N_IRQS]; ++ QEMUTimer *timer; /* Internal timer */ ++ MemoryRegion *itc_tag; /* ITC Configuration Tags */ ++ target_ulong exception_base; /* ExceptionBase input to the core */ ++ struct { ++ uint64_t guest_addr; ++ } st; ++}; ++ ++/* ++ * CPU can't have 0xFFFFFFFF APIC ID, use that value to distinguish ++ * that ID hasn't been set yet ++ */ ++#define UNASSIGNED_CPU_ID 0xFFFFFFFF ++ ++/** ++ * LOONGARCHCPU: ++ * @env: #CPULOONGARCHState ++ * ++ * A LOONGARCH CPU. ++ */ ++struct LOONGARCHCPU { ++ /*< private >*/ ++ CPUState parent_obj; ++ /*< public >*/ ++ CPUNegativeOffsetState neg; ++ CPULOONGARCHState env; ++ int32_t id; ++ int hotplugged; ++ uint8_t online_vcpus; ++ uint8_t is_migrate; ++ uint64_t counter_value; ++ uint32_t cpu_freq; ++ uint32_t count_ctl; ++ uint64_t pending_exceptions; ++ uint64_t pending_exceptions_clr; ++ uint64_t core_ext_ioisr[4]; ++ VMChangeStateEntry *cpuStateEntry; ++ int32_t node_id; /* NUMA node this CPU belongs to */ ++ int32_t core_id; ++ struct kvm_msrs *kvm_csr_buf; ++ /* 'compatible' string for this CPU for Linux device trees */ ++ const char *dtb_compatible; ++}; ++ ++static inline LOONGARCHCPU *loongarch_env_get_cpu(CPULOONGARCHState *env) ++{ ++ return container_of(env, LOONGARCHCPU, env); ++} ++ ++#define ENV_GET_CPU(e) CPU(loongarch_env_get_cpu(e)) ++ ++#define ENV_OFFSET offsetof(LOONGARCHCPU, env) ++ ++void loongarch_cpu_list(void); ++ ++#define cpu_signal_handler cpu_loongarch_signal_handler ++#define cpu_list loongarch_cpu_list ++ ++/* ++ * MMU modes definitions. We carefully match the indices with our ++ * hflags layout. ++ */ ++#define MMU_MODE0_SUFFIX _kernel ++#define MMU_MODE1_SUFFIX _super ++#define MMU_MODE2_SUFFIX _user ++#define MMU_MODE3_SUFFIX _error ++#define MMU_USER_IDX 3 ++ ++static inline int hflags_mmu_index(uint32_t hflags) ++{ ++ return hflags & LARCH_HFLAG_KSU; ++} ++ ++static inline int cpu_mmu_index(CPULOONGARCHState *env, bool ifetch) ++{ ++ return hflags_mmu_index(env->hflags); ++} ++ ++#include "exec/cpu-all.h" ++ ++/* ++ * Memory access type : ++ * may be needed for precise access rights control and precise exceptions. ++ */ ++enum { ++ /* 1 bit to define user level / supervisor access */ ++ ACCESS_USER = 0x00, ++ ACCESS_SUPER = 0x01, ++ /* 1 bit to indicate direction */ ++ ACCESS_STORE = 0x02, ++ /* Type of instruction that generated the access */ ++ ACCESS_CODE = 0x10, /* Code fetch access */ ++ ACCESS_INT = 0x20, /* Integer load/store access */ ++ ACCESS_FLOAT = 0x30, /* floating point load/store access */ ++}; ++ ++/* Exceptions */ ++enum { ++ EXCP_NONE = -1, ++ EXCP_RESET = 0, ++ EXCP_SRESET, ++ EXCP_DINT, ++ EXCP_NMI, ++ EXCP_EXT_INTERRUPT, ++ EXCP_AdEL, ++ EXCP_AdES, ++ EXCP_TLBF, ++ EXCP_IBE, ++ EXCP_SYSCALL, ++ EXCP_BREAK, ++ EXCP_FPDIS, ++ EXCP_LSXDIS, ++ EXCP_LASXDIS, ++ EXCP_RI, ++ EXCP_OVERFLOW, ++ EXCP_TRAP, ++ EXCP_FPE, ++ EXCP_LTLBL, ++ EXCP_TLBL, ++ EXCP_TLBS, ++ EXCP_DBE, ++ EXCP_TLBXI, ++ EXCP_TLBRI, ++ EXCP_TLBPE, ++ EXCP_BTDIS, ++ ++ EXCP_LAST = EXCP_BTDIS, ++}; ++ ++/* ++ * This is an internally generated WAKE request line. ++ * It is driven by the CPU itself. Raised when the MT ++ * block wants to wake a VPE from an inactive state and ++ * cleared when VPE goes from active to inactive. ++ */ ++#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 ++ ++int cpu_loongarch_signal_handler(int host_signum, void *pinfo, void *puc); ++ ++#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU ++#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX ++#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU ++ ++/* helper.c */ ++target_ulong exception_resume_pc(CPULOONGARCHState *env); ++ ++/* gdbstub.c */ ++void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); ++void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def); ++ ++static inline void cpu_get_tb_cpu_state(CPULOONGARCHState *env, ++ target_ulong *pc, ++ target_ulong *cs_base, uint32_t *flags) ++{ ++ *pc = env->active_tc.PC; ++ *cs_base = 0; ++ *flags = env->hflags & (LARCH_HFLAG_TMASK | LARCH_HFLAG_BMASK); ++} ++ ++static inline bool cpu_refill_state(CPULOONGARCHState *env) ++{ ++ return env->CSR_TLBRERA & 0x1; ++} ++ ++extern const char *const regnames[]; ++extern const char *const fregnames[]; ++#endif /* LOONGARCH_CPU_H */ +diff --git a/target/loongarch64/csr_helper.c b/target/loongarch64/csr_helper.c +new file mode 100644 +index 0000000000..093e7e54d8 +--- /dev/null ++++ b/target/loongarch64/csr_helper.c +@@ -0,0 +1,697 @@ ++/* ++ * loongarch tlb emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/main-loop.h" ++#include "cpu.h" ++#include "internal.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "sysemu/kvm.h" ++#include "hw/irq.h" ++#include "cpu-csr.h" ++#include "instmap.h" ++ ++#ifndef CONFIG_USER_ONLY ++target_ulong helper_csr_rdq(CPULOONGARCHState *env, uint64_t csr) ++{ ++ int64_t v; ++ ++#define CASE_CSR_RDQ(csr) \ ++ case LOONGARCH_CSR_##csr: { \ ++ v = env->CSR_##csr; \ ++ break; \ ++ }; ++ ++ switch (csr) { ++ CASE_CSR_RDQ(CRMD) ++ CASE_CSR_RDQ(PRMD) ++ CASE_CSR_RDQ(EUEN) ++ CASE_CSR_RDQ(MISC) ++ CASE_CSR_RDQ(ECFG) ++ CASE_CSR_RDQ(ESTAT) ++ CASE_CSR_RDQ(ERA) ++ CASE_CSR_RDQ(BADV) ++ CASE_CSR_RDQ(BADI) ++ CASE_CSR_RDQ(EEPN) ++ CASE_CSR_RDQ(TLBIDX) ++ CASE_CSR_RDQ(TLBEHI) ++ CASE_CSR_RDQ(TLBELO0) ++ CASE_CSR_RDQ(TLBELO1) ++ CASE_CSR_RDQ(TLBWIRED) ++ CASE_CSR_RDQ(GTLBC) ++ CASE_CSR_RDQ(TRGP) ++ CASE_CSR_RDQ(ASID) ++ CASE_CSR_RDQ(PGDL) ++ CASE_CSR_RDQ(PGDH) ++ CASE_CSR_RDQ(PGD) ++ CASE_CSR_RDQ(PWCTL0) ++ CASE_CSR_RDQ(PWCTL1) ++ CASE_CSR_RDQ(STLBPGSIZE) ++ CASE_CSR_RDQ(RVACFG) ++ CASE_CSR_RDQ(CPUID) ++ CASE_CSR_RDQ(PRCFG1) ++ CASE_CSR_RDQ(PRCFG2) ++ CASE_CSR_RDQ(PRCFG3) ++ CASE_CSR_RDQ(KS0) ++ CASE_CSR_RDQ(KS1) ++ CASE_CSR_RDQ(KS2) ++ CASE_CSR_RDQ(KS3) ++ CASE_CSR_RDQ(KS4) ++ CASE_CSR_RDQ(KS5) ++ CASE_CSR_RDQ(KS6) ++ CASE_CSR_RDQ(KS7) ++ CASE_CSR_RDQ(KS8) ++ CASE_CSR_RDQ(TMID) ++ CASE_CSR_RDQ(TCFG) ++ case LOONGARCH_CSR_TVAL: ++ v = cpu_loongarch_get_stable_timer_ticks(env); ++ break; ++ CASE_CSR_RDQ(CNTC) ++ CASE_CSR_RDQ(TINTCLR) ++ CASE_CSR_RDQ(GSTAT) ++ CASE_CSR_RDQ(GCFG) ++ CASE_CSR_RDQ(GINTC) ++ CASE_CSR_RDQ(GCNTC) ++ CASE_CSR_RDQ(LLBCTL) ++ CASE_CSR_RDQ(IMPCTL1) ++ CASE_CSR_RDQ(IMPCTL2) ++ CASE_CSR_RDQ(GNMI) ++ CASE_CSR_RDQ(TLBRENT) ++ CASE_CSR_RDQ(TLBRBADV) ++ CASE_CSR_RDQ(TLBRERA) ++ CASE_CSR_RDQ(TLBRSAVE) ++ CASE_CSR_RDQ(TLBRELO0) ++ CASE_CSR_RDQ(TLBRELO1) ++ CASE_CSR_RDQ(TLBREHI) ++ CASE_CSR_RDQ(TLBRPRMD) ++ CASE_CSR_RDQ(ERRCTL) ++ CASE_CSR_RDQ(ERRINFO) ++ CASE_CSR_RDQ(ERRINFO1) ++ CASE_CSR_RDQ(ERRENT) ++ CASE_CSR_RDQ(ERRERA) ++ CASE_CSR_RDQ(ERRSAVE) ++ CASE_CSR_RDQ(CTAG) ++ CASE_CSR_RDQ(DMWIN0) ++ CASE_CSR_RDQ(DMWIN1) ++ CASE_CSR_RDQ(DMWIN2) ++ CASE_CSR_RDQ(DMWIN3) ++ CASE_CSR_RDQ(PERFCTRL0) ++ CASE_CSR_RDQ(PERFCNTR0) ++ CASE_CSR_RDQ(PERFCTRL1) ++ CASE_CSR_RDQ(PERFCNTR1) ++ CASE_CSR_RDQ(PERFCTRL2) ++ CASE_CSR_RDQ(PERFCNTR2) ++ CASE_CSR_RDQ(PERFCTRL3) ++ CASE_CSR_RDQ(PERFCNTR3) ++ /* debug */ ++ CASE_CSR_RDQ(MWPC) ++ CASE_CSR_RDQ(MWPS) ++ CASE_CSR_RDQ(DB0ADDR) ++ CASE_CSR_RDQ(DB0MASK) ++ CASE_CSR_RDQ(DB0CTL) ++ CASE_CSR_RDQ(DB0ASID) ++ CASE_CSR_RDQ(DB1ADDR) ++ CASE_CSR_RDQ(DB1MASK) ++ CASE_CSR_RDQ(DB1CTL) ++ CASE_CSR_RDQ(DB1ASID) ++ CASE_CSR_RDQ(DB2ADDR) ++ CASE_CSR_RDQ(DB2MASK) ++ CASE_CSR_RDQ(DB2CTL) ++ CASE_CSR_RDQ(DB2ASID) ++ CASE_CSR_RDQ(DB3ADDR) ++ CASE_CSR_RDQ(DB3MASK) ++ CASE_CSR_RDQ(DB3CTL) ++ CASE_CSR_RDQ(DB3ASID) ++ CASE_CSR_RDQ(FWPC) ++ CASE_CSR_RDQ(FWPS) ++ CASE_CSR_RDQ(IB0ADDR) ++ CASE_CSR_RDQ(IB0MASK) ++ CASE_CSR_RDQ(IB0CTL) ++ CASE_CSR_RDQ(IB0ASID) ++ CASE_CSR_RDQ(IB1ADDR) ++ CASE_CSR_RDQ(IB1MASK) ++ CASE_CSR_RDQ(IB1CTL) ++ CASE_CSR_RDQ(IB1ASID) ++ CASE_CSR_RDQ(IB2ADDR) ++ CASE_CSR_RDQ(IB2MASK) ++ CASE_CSR_RDQ(IB2CTL) ++ CASE_CSR_RDQ(IB2ASID) ++ CASE_CSR_RDQ(IB3ADDR) ++ CASE_CSR_RDQ(IB3MASK) ++ CASE_CSR_RDQ(IB3CTL) ++ CASE_CSR_RDQ(IB3ASID) ++ CASE_CSR_RDQ(IB4ADDR) ++ CASE_CSR_RDQ(IB4MASK) ++ CASE_CSR_RDQ(IB4CTL) ++ CASE_CSR_RDQ(IB4ASID) ++ CASE_CSR_RDQ(IB5ADDR) ++ CASE_CSR_RDQ(IB5MASK) ++ CASE_CSR_RDQ(IB5CTL) ++ CASE_CSR_RDQ(IB5ASID) ++ CASE_CSR_RDQ(IB6ADDR) ++ CASE_CSR_RDQ(IB6MASK) ++ CASE_CSR_RDQ(IB6CTL) ++ CASE_CSR_RDQ(IB6ASID) ++ CASE_CSR_RDQ(IB7ADDR) ++ CASE_CSR_RDQ(IB7MASK) ++ CASE_CSR_RDQ(IB7CTL) ++ CASE_CSR_RDQ(IB7ASID) ++ CASE_CSR_RDQ(DEBUG) ++ CASE_CSR_RDQ(DERA) ++ CASE_CSR_RDQ(DESAVE) ++ default : ++ assert(0); ++ } ++ ++#undef CASE_CSR_RDQ ++ compute_hflags(env); ++ return v; ++} ++ ++target_ulong helper_csr_wrq(CPULOONGARCHState *env, target_ulong val, ++ uint64_t csr) ++{ ++ int64_t old_v, v; ++ old_v = -1; ++ v = val; ++ ++#define CASE_CSR_WRQ(csr) \ ++ case LOONGARCH_CSR_##csr: { \ ++ old_v = env->CSR_##csr; \ ++ env->CSR_##csr = v; \ ++ break; \ ++ }; ++ ++ switch (csr) { ++ CASE_CSR_WRQ(CRMD) ++ CASE_CSR_WRQ(PRMD) ++ CASE_CSR_WRQ(EUEN) ++ CASE_CSR_WRQ(MISC) ++ CASE_CSR_WRQ(ECFG) ++ CASE_CSR_WRQ(ESTAT) ++ CASE_CSR_WRQ(ERA) ++ CASE_CSR_WRQ(BADV) ++ CASE_CSR_WRQ(BADI) ++ CASE_CSR_WRQ(EEPN) ++ CASE_CSR_WRQ(TLBIDX) ++ CASE_CSR_WRQ(TLBEHI) ++ CASE_CSR_WRQ(TLBELO0) ++ CASE_CSR_WRQ(TLBELO1) ++ CASE_CSR_WRQ(TLBWIRED) ++ CASE_CSR_WRQ(GTLBC) ++ CASE_CSR_WRQ(TRGP) ++ CASE_CSR_WRQ(ASID) ++ CASE_CSR_WRQ(PGDL) ++ CASE_CSR_WRQ(PGDH) ++ CASE_CSR_WRQ(PGD) ++ CASE_CSR_WRQ(PWCTL0) ++ CASE_CSR_WRQ(PWCTL1) ++ CASE_CSR_WRQ(STLBPGSIZE) ++ CASE_CSR_WRQ(RVACFG) ++ CASE_CSR_WRQ(CPUID) ++ CASE_CSR_WRQ(PRCFG1) ++ CASE_CSR_WRQ(PRCFG2) ++ CASE_CSR_WRQ(PRCFG3) ++ CASE_CSR_WRQ(KS0) ++ CASE_CSR_WRQ(KS1) ++ CASE_CSR_WRQ(KS2) ++ CASE_CSR_WRQ(KS3) ++ CASE_CSR_WRQ(KS4) ++ CASE_CSR_WRQ(KS5) ++ CASE_CSR_WRQ(KS6) ++ CASE_CSR_WRQ(KS7) ++ CASE_CSR_WRQ(KS8) ++ CASE_CSR_WRQ(TMID) ++ case LOONGARCH_CSR_TCFG: ++ old_v = env->CSR_TCFG; ++ cpu_loongarch_store_stable_timer_config(env, v); ++ break; ++ CASE_CSR_WRQ(TVAL) ++ CASE_CSR_WRQ(CNTC) ++ case LOONGARCH_CSR_TINTCLR: ++ old_v = 0; ++ qemu_irq_lower(env->irq[IRQ_TIMER]); ++ break; ++ CASE_CSR_WRQ(GSTAT) ++ CASE_CSR_WRQ(GCFG) ++ CASE_CSR_WRQ(GINTC) ++ CASE_CSR_WRQ(GCNTC) ++ CASE_CSR_WRQ(LLBCTL) ++ CASE_CSR_WRQ(IMPCTL1) ++ case LOONGARCH_CSR_IMPCTL2: ++ if (v & CSR_IMPCTL2_MTLB) { ++ ls3a5k_flush_vtlb(env); ++ } ++ if (v & CSR_IMPCTL2_STLB) { ++ ls3a5k_flush_ftlb(env); ++ } ++ break; ++ CASE_CSR_WRQ(GNMI) ++ CASE_CSR_WRQ(TLBRENT) ++ CASE_CSR_WRQ(TLBRBADV) ++ CASE_CSR_WRQ(TLBRERA) ++ CASE_CSR_WRQ(TLBRSAVE) ++ CASE_CSR_WRQ(TLBRELO0) ++ CASE_CSR_WRQ(TLBRELO1) ++ CASE_CSR_WRQ(TLBREHI) ++ CASE_CSR_WRQ(TLBRPRMD) ++ CASE_CSR_WRQ(ERRCTL) ++ CASE_CSR_WRQ(ERRINFO) ++ CASE_CSR_WRQ(ERRINFO1) ++ CASE_CSR_WRQ(ERRENT) ++ CASE_CSR_WRQ(ERRERA) ++ CASE_CSR_WRQ(ERRSAVE) ++ CASE_CSR_WRQ(CTAG) ++ CASE_CSR_WRQ(DMWIN0) ++ CASE_CSR_WRQ(DMWIN1) ++ CASE_CSR_WRQ(DMWIN2) ++ CASE_CSR_WRQ(DMWIN3) ++ CASE_CSR_WRQ(PERFCTRL0) ++ CASE_CSR_WRQ(PERFCNTR0) ++ CASE_CSR_WRQ(PERFCTRL1) ++ CASE_CSR_WRQ(PERFCNTR1) ++ CASE_CSR_WRQ(PERFCTRL2) ++ CASE_CSR_WRQ(PERFCNTR2) ++ CASE_CSR_WRQ(PERFCTRL3) ++ CASE_CSR_WRQ(PERFCNTR3) ++ /* debug */ ++ CASE_CSR_WRQ(MWPC) ++ CASE_CSR_WRQ(MWPS) ++ CASE_CSR_WRQ(DB0ADDR) ++ CASE_CSR_WRQ(DB0MASK) ++ CASE_CSR_WRQ(DB0CTL) ++ CASE_CSR_WRQ(DB0ASID) ++ CASE_CSR_WRQ(DB1ADDR) ++ CASE_CSR_WRQ(DB1MASK) ++ CASE_CSR_WRQ(DB1CTL) ++ CASE_CSR_WRQ(DB1ASID) ++ CASE_CSR_WRQ(DB2ADDR) ++ CASE_CSR_WRQ(DB2MASK) ++ CASE_CSR_WRQ(DB2CTL) ++ CASE_CSR_WRQ(DB2ASID) ++ CASE_CSR_WRQ(DB3ADDR) ++ CASE_CSR_WRQ(DB3MASK) ++ CASE_CSR_WRQ(DB3CTL) ++ CASE_CSR_WRQ(DB3ASID) ++ CASE_CSR_WRQ(FWPC) ++ CASE_CSR_WRQ(FWPS) ++ CASE_CSR_WRQ(IB0ADDR) ++ CASE_CSR_WRQ(IB0MASK) ++ CASE_CSR_WRQ(IB0CTL) ++ CASE_CSR_WRQ(IB0ASID) ++ CASE_CSR_WRQ(IB1ADDR) ++ CASE_CSR_WRQ(IB1MASK) ++ CASE_CSR_WRQ(IB1CTL) ++ CASE_CSR_WRQ(IB1ASID) ++ CASE_CSR_WRQ(IB2ADDR) ++ CASE_CSR_WRQ(IB2MASK) ++ CASE_CSR_WRQ(IB2CTL) ++ CASE_CSR_WRQ(IB2ASID) ++ CASE_CSR_WRQ(IB3ADDR) ++ CASE_CSR_WRQ(IB3MASK) ++ CASE_CSR_WRQ(IB3CTL) ++ CASE_CSR_WRQ(IB3ASID) ++ CASE_CSR_WRQ(IB4ADDR) ++ CASE_CSR_WRQ(IB4MASK) ++ CASE_CSR_WRQ(IB4CTL) ++ CASE_CSR_WRQ(IB4ASID) ++ CASE_CSR_WRQ(IB5ADDR) ++ CASE_CSR_WRQ(IB5MASK) ++ CASE_CSR_WRQ(IB5CTL) ++ CASE_CSR_WRQ(IB5ASID) ++ CASE_CSR_WRQ(IB6ADDR) ++ CASE_CSR_WRQ(IB6MASK) ++ CASE_CSR_WRQ(IB6CTL) ++ CASE_CSR_WRQ(IB6ASID) ++ CASE_CSR_WRQ(IB7ADDR) ++ CASE_CSR_WRQ(IB7MASK) ++ CASE_CSR_WRQ(IB7CTL) ++ CASE_CSR_WRQ(IB7ASID) ++ CASE_CSR_WRQ(DEBUG) ++ CASE_CSR_WRQ(DERA) ++ CASE_CSR_WRQ(DESAVE) ++ default : ++ assert(0); ++ } ++ ++ if (csr == LOONGARCH_CSR_ASID) { ++ if (old_v != v) { ++ tlb_flush(CPU(loongarch_env_get_cpu(env))); ++ } ++ } ++ ++#undef CASE_CSR_WRQ ++ compute_hflags(env); ++ return old_v; ++} ++ ++target_ulong helper_csr_xchgq(CPULOONGARCHState *env, target_ulong val, ++ target_ulong mask, uint64_t csr) ++{ ++ target_ulong v, tmp; ++ v = val & mask; ++ ++#define CASE_CSR_XCHGQ(csr) \ ++ case LOONGARCH_CSR_##csr: { \ ++ val = env->CSR_##csr; \ ++ env->CSR_##csr = (env->CSR_##csr) & (~mask); \ ++ env->CSR_##csr = (env->CSR_##csr) | v; \ ++ break; \ ++ }; ++ ++ switch (csr) { ++ CASE_CSR_XCHGQ(CRMD) ++ CASE_CSR_XCHGQ(PRMD) ++ CASE_CSR_XCHGQ(EUEN) ++ CASE_CSR_XCHGQ(MISC) ++ CASE_CSR_XCHGQ(ECFG) ++ case LOONGARCH_CSR_ESTAT: ++ val = env->CSR_ESTAT; ++ qatomic_and(&env->CSR_ESTAT, ~mask); ++ qatomic_or(&env->CSR_ESTAT, v); ++ break; ++ CASE_CSR_XCHGQ(ERA) ++ CASE_CSR_XCHGQ(BADV) ++ CASE_CSR_XCHGQ(BADI) ++ CASE_CSR_XCHGQ(EEPN) ++ CASE_CSR_XCHGQ(TLBIDX) ++ CASE_CSR_XCHGQ(TLBEHI) ++ CASE_CSR_XCHGQ(TLBELO0) ++ CASE_CSR_XCHGQ(TLBELO1) ++ CASE_CSR_XCHGQ(TLBWIRED) ++ CASE_CSR_XCHGQ(GTLBC) ++ CASE_CSR_XCHGQ(TRGP) ++ CASE_CSR_XCHGQ(ASID) ++ CASE_CSR_XCHGQ(PGDL) ++ CASE_CSR_XCHGQ(PGDH) ++ CASE_CSR_XCHGQ(PGD) ++ CASE_CSR_XCHGQ(PWCTL0) ++ CASE_CSR_XCHGQ(PWCTL1) ++ CASE_CSR_XCHGQ(STLBPGSIZE) ++ CASE_CSR_XCHGQ(RVACFG) ++ CASE_CSR_XCHGQ(CPUID) ++ CASE_CSR_XCHGQ(PRCFG1) ++ CASE_CSR_XCHGQ(PRCFG2) ++ CASE_CSR_XCHGQ(PRCFG3) ++ CASE_CSR_XCHGQ(KS0) ++ CASE_CSR_XCHGQ(KS1) ++ CASE_CSR_XCHGQ(KS2) ++ CASE_CSR_XCHGQ(KS3) ++ CASE_CSR_XCHGQ(KS4) ++ CASE_CSR_XCHGQ(KS5) ++ CASE_CSR_XCHGQ(KS6) ++ CASE_CSR_XCHGQ(KS7) ++ CASE_CSR_XCHGQ(KS8) ++ CASE_CSR_XCHGQ(TMID) ++ case LOONGARCH_CSR_TCFG: ++ val = env->CSR_TCFG; ++ tmp = val & ~mask; ++ tmp |= v; ++ cpu_loongarch_store_stable_timer_config(env, tmp); ++ break; ++ CASE_CSR_XCHGQ(TVAL) ++ CASE_CSR_XCHGQ(CNTC) ++ CASE_CSR_XCHGQ(TINTCLR) ++ CASE_CSR_XCHGQ(GSTAT) ++ CASE_CSR_XCHGQ(GCFG) ++ CASE_CSR_XCHGQ(GINTC) ++ CASE_CSR_XCHGQ(GCNTC) ++ CASE_CSR_XCHGQ(LLBCTL) ++ CASE_CSR_XCHGQ(IMPCTL1) ++ CASE_CSR_XCHGQ(IMPCTL2) ++ CASE_CSR_XCHGQ(GNMI) ++ CASE_CSR_XCHGQ(TLBRENT) ++ CASE_CSR_XCHGQ(TLBRBADV) ++ CASE_CSR_XCHGQ(TLBRERA) ++ CASE_CSR_XCHGQ(TLBRSAVE) ++ CASE_CSR_XCHGQ(TLBRELO0) ++ CASE_CSR_XCHGQ(TLBRELO1) ++ CASE_CSR_XCHGQ(TLBREHI) ++ CASE_CSR_XCHGQ(TLBRPRMD) ++ CASE_CSR_XCHGQ(ERRCTL) ++ CASE_CSR_XCHGQ(ERRINFO) ++ CASE_CSR_XCHGQ(ERRINFO1) ++ CASE_CSR_XCHGQ(ERRENT) ++ CASE_CSR_XCHGQ(ERRERA) ++ CASE_CSR_XCHGQ(ERRSAVE) ++ CASE_CSR_XCHGQ(CTAG) ++ CASE_CSR_XCHGQ(DMWIN0) ++ CASE_CSR_XCHGQ(DMWIN1) ++ CASE_CSR_XCHGQ(DMWIN2) ++ CASE_CSR_XCHGQ(DMWIN3) ++ CASE_CSR_XCHGQ(PERFCTRL0) ++ CASE_CSR_XCHGQ(PERFCNTR0) ++ CASE_CSR_XCHGQ(PERFCTRL1) ++ CASE_CSR_XCHGQ(PERFCNTR1) ++ CASE_CSR_XCHGQ(PERFCTRL2) ++ CASE_CSR_XCHGQ(PERFCNTR2) ++ CASE_CSR_XCHGQ(PERFCTRL3) ++ CASE_CSR_XCHGQ(PERFCNTR3) ++ /* debug */ ++ CASE_CSR_XCHGQ(MWPC) ++ CASE_CSR_XCHGQ(MWPS) ++ CASE_CSR_XCHGQ(DB0ADDR) ++ CASE_CSR_XCHGQ(DB0MASK) ++ CASE_CSR_XCHGQ(DB0CTL) ++ CASE_CSR_XCHGQ(DB0ASID) ++ CASE_CSR_XCHGQ(DB1ADDR) ++ CASE_CSR_XCHGQ(DB1MASK) ++ CASE_CSR_XCHGQ(DB1CTL) ++ CASE_CSR_XCHGQ(DB1ASID) ++ CASE_CSR_XCHGQ(DB2ADDR) ++ CASE_CSR_XCHGQ(DB2MASK) ++ CASE_CSR_XCHGQ(DB2CTL) ++ CASE_CSR_XCHGQ(DB2ASID) ++ CASE_CSR_XCHGQ(DB3ADDR) ++ CASE_CSR_XCHGQ(DB3MASK) ++ CASE_CSR_XCHGQ(DB3CTL) ++ CASE_CSR_XCHGQ(DB3ASID) ++ CASE_CSR_XCHGQ(FWPC) ++ CASE_CSR_XCHGQ(FWPS) ++ CASE_CSR_XCHGQ(IB0ADDR) ++ CASE_CSR_XCHGQ(IB0MASK) ++ CASE_CSR_XCHGQ(IB0CTL) ++ CASE_CSR_XCHGQ(IB0ASID) ++ CASE_CSR_XCHGQ(IB1ADDR) ++ CASE_CSR_XCHGQ(IB1MASK) ++ CASE_CSR_XCHGQ(IB1CTL) ++ CASE_CSR_XCHGQ(IB1ASID) ++ CASE_CSR_XCHGQ(IB2ADDR) ++ CASE_CSR_XCHGQ(IB2MASK) ++ CASE_CSR_XCHGQ(IB2CTL) ++ CASE_CSR_XCHGQ(IB2ASID) ++ CASE_CSR_XCHGQ(IB3ADDR) ++ CASE_CSR_XCHGQ(IB3MASK) ++ CASE_CSR_XCHGQ(IB3CTL) ++ CASE_CSR_XCHGQ(IB3ASID) ++ CASE_CSR_XCHGQ(IB4ADDR) ++ CASE_CSR_XCHGQ(IB4MASK) ++ CASE_CSR_XCHGQ(IB4CTL) ++ CASE_CSR_XCHGQ(IB4ASID) ++ CASE_CSR_XCHGQ(IB5ADDR) ++ CASE_CSR_XCHGQ(IB5MASK) ++ CASE_CSR_XCHGQ(IB5CTL) ++ CASE_CSR_XCHGQ(IB5ASID) ++ CASE_CSR_XCHGQ(IB6ADDR) ++ CASE_CSR_XCHGQ(IB6MASK) ++ CASE_CSR_XCHGQ(IB6CTL) ++ CASE_CSR_XCHGQ(IB6ASID) ++ CASE_CSR_XCHGQ(IB7ADDR) ++ CASE_CSR_XCHGQ(IB7MASK) ++ CASE_CSR_XCHGQ(IB7CTL) ++ CASE_CSR_XCHGQ(IB7ASID) ++ CASE_CSR_XCHGQ(DEBUG) ++ CASE_CSR_XCHGQ(DERA) ++ CASE_CSR_XCHGQ(DESAVE) ++ default : ++ assert(0); ++ } ++ ++#undef CASE_CSR_XCHGQ ++ compute_hflags(env); ++ return val; ++} ++ ++static target_ulong confbus_addr(CPULOONGARCHState *env, int cpuid, ++ target_ulong csr_addr) ++{ ++ target_ulong addr; ++ target_ulong node_addr; ++ int cores_per_node = ((0x60018 >> 3) & 0xff) + 1; ++ ++ switch (cores_per_node) { ++ case 4: ++ assert(cpuid < 64); ++ node_addr = ((target_ulong)(cpuid & 0x3c) << 42); ++ break; ++ case 8: ++ assert(cpuid < 128); ++ node_addr = ((target_ulong)(cpuid & 0x78) << 41) + ++ ((target_ulong)(cpuid & 0x4) << 14); ++ break; ++ case 16: ++ assert(cpuid < 256); ++ node_addr = ((target_ulong)(cpuid & 0xf0) << 40) + ++ ((target_ulong)(cpuid & 0xc) << 14); ++ break; ++ default: ++ assert(0); ++ break; ++ } ++ ++ /* ++ * per core address ++ *0x10xx => ipi ++ * 0x18xx => extioi isr ++ */ ++ if (((csr_addr & 0xff00) == 0x1000)) { ++ addr = (csr_addr & 0xff) + (target_ulong)(cpuid << 8); ++ addr = 0x800000001f000000UL + addr; ++ return addr; ++ } else if ((csr_addr & 0xff00) == 0x1800) { ++ addr = (csr_addr & 0xff) + ((target_ulong)(cpuid << 8)); ++ addr = 0x800000001f020000UL + addr; ++ return addr; ++ } else if ((csr_addr & 0xff00) >= 0x1400 && (csr_addr & 0xff00) < 0x1d00) { ++ addr = 0x800000001f010000UL + ((csr_addr & 0xfff) - 0x400); ++ return addr; ++ } else if (csr_addr == 0x408) { ++ addr = csr_addr; ++ } else { ++ addr = csr_addr + node_addr; ++ } ++ ++ addr = 0x800000001fe00000UL + addr; ++ return addr; ++} ++ ++void helper_iocsr(CPULOONGARCHState *env, target_ulong r_addr, ++ target_ulong r_val, uint32_t op) ++{ ++ target_ulong addr; ++ target_ulong val = env->active_tc.gpr[r_val]; ++ int mask; ++ ++ addr = confbus_addr(env, CPU(loongarch_env_get_cpu(env))->cpu_index, ++ env->active_tc.gpr[r_addr]); ++ ++ switch (env->active_tc.gpr[r_addr]) { ++ /* IPI send */ ++ case 0x1040: ++ if (op != OPC_LARCH_ST_W) { ++ return; ++ } ++ op = OPC_LARCH_ST_W; ++ break; ++ ++ /* Mail send */ ++ case 0x1048: ++ if (op != OPC_LARCH_ST_D) { ++ return; ++ } ++ op = OPC_LARCH_ST_D; ++ break; ++ ++ /* ANY send */ ++ case 0x1158: ++ if (op != OPC_LARCH_ST_D) { ++ return; ++ } ++ addr = confbus_addr(env, (val >> 16) & 0x3ff, val & 0xffff); ++ mask = (val >> 27) & 0xf; ++ val = (val >> 32); ++ switch (mask) { ++ case 0: ++ op = OPC_LARCH_ST_W; ++ break; ++ case 0x7: ++ op = OPC_LARCH_ST_B; ++ addr += 3; ++ val >>= 24; ++ break; ++ case 0xb: ++ op = OPC_LARCH_ST_B; ++ addr += 2; ++ val >>= 16; ++ break; ++ case 0xd: ++ op = OPC_LARCH_ST_B; ++ addr += 1; ++ val >>= 8; ++ break; ++ case 0xe: ++ op = OPC_LARCH_ST_B; ++ break; ++ case 0xc: ++ op = OPC_LARCH_ST_H; ++ break; ++ case 0x3: ++ op = OPC_LARCH_ST_H; ++ addr += 2; ++ val >>= 16; ++ break; ++ default: ++ qemu_log("Unsupported any_send mask0x%x\n", mask); ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ switch (op) { ++ case OPC_LARCH_LD_D: ++ env->active_tc.gpr[r_val] = cpu_ldq_data_ra(env, addr, GETPC()); ++ break; ++ case OPC_LARCH_LD_W: ++ env->active_tc.gpr[r_val] = cpu_ldl_data_ra(env, addr, GETPC()); ++ break; ++ case OPC_LARCH_LD_H: ++ assert(0); ++ break; ++ case OPC_LARCH_LD_B: ++ assert(0); ++ break; ++ case OPC_LARCH_ST_D: ++ cpu_stq_data_ra(env, addr, val, GETPC()); ++ break; ++ case OPC_LARCH_ST_W: ++ cpu_stl_data_ra(env, addr, val, GETPC()); ++ break; ++ case OPC_LARCH_ST_H: ++ cpu_stb_data_ra(env, addr, val, GETPC()); ++ break; ++ case OPC_LARCH_ST_B: ++ cpu_stb_data_ra(env, addr, val, GETPC()); ++ break; ++ default: ++ qemu_log("Unknown op 0x%x", op); ++ assert(0); ++ } ++} ++#endif ++ ++target_ulong helper_cpucfg(CPULOONGARCHState *env, target_ulong rj) ++{ ++ return 0; ++} +diff --git a/target/loongarch64/fpu.c b/target/loongarch64/fpu.c +new file mode 100644 +index 0000000000..f063c8bae0 +--- /dev/null ++++ b/target/loongarch64/fpu.c +@@ -0,0 +1,25 @@ ++/* ++ * loongarch float point emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "fpu/softfloat.h" ++ ++/* convert loongarch rounding mode in fcsr0 to IEEE library */ ++unsigned int ieee_rm[] = { float_round_nearest_even, float_round_to_zero, ++ float_round_up, float_round_down }; +diff --git a/target/loongarch64/fpu_helper.c b/target/loongarch64/fpu_helper.c +new file mode 100644 +index 0000000000..033bf0de84 +--- /dev/null ++++ b/target/loongarch64/fpu_helper.c +@@ -0,0 +1,891 @@ ++/* ++ * loongarch float point emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "internal.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "fpu/softfloat.h" ++ ++#define FP_TO_INT32_OVERFLOW 0x7fffffff ++#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL ++ ++#define FLOAT_CLASS_SIGNALING_NAN 0x001 ++#define FLOAT_CLASS_QUIET_NAN 0x002 ++#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 ++#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 ++#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 ++#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 ++#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 ++#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 ++#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 ++#define FLOAT_CLASS_POSITIVE_ZERO 0x200 ++ ++target_ulong helper_movfcsr2gr(CPULOONGARCHState *env, uint32_t reg) ++{ ++ target_ulong r = 0; ++ ++ switch (reg) { ++ case 0: ++ r = (uint32_t)env->active_fpu.fcsr0; ++ break; ++ case 1: ++ r = (env->active_fpu.fcsr0 & FCSR0_M1); ++ break; ++ case 2: ++ r = (env->active_fpu.fcsr0 & FCSR0_M2); ++ break; ++ case 3: ++ r = (env->active_fpu.fcsr0 & FCSR0_M3); ++ break; ++ case 16: ++ r = (uint32_t)env->active_fpu.vcsr16; ++ break; ++ default: ++ printf("%s: warning, fcsr '%d' not supported\n", __func__, reg); ++ assert(0); ++ break; ++ } ++ ++ return r; ++} ++ ++void helper_movgr2fcsr(CPULOONGARCHState *env, target_ulong arg1, ++ uint32_t fcsr, uint32_t rj) ++{ ++ switch (fcsr) { ++ case 0: ++ env->active_fpu.fcsr0 = arg1; ++ break; ++ case 1: ++ env->active_fpu.fcsr0 = ++ (arg1 & FCSR0_M1) | (env->active_fpu.fcsr0 & ~FCSR0_M1); ++ break; ++ case 2: ++ env->active_fpu.fcsr0 = ++ (arg1 & FCSR0_M2) | (env->active_fpu.fcsr0 & ~FCSR0_M2); ++ break; ++ case 3: ++ env->active_fpu.fcsr0 = ++ (arg1 & FCSR0_M3) | (env->active_fpu.fcsr0 & ~FCSR0_M3); ++ break; ++ case 16: ++ env->active_fpu.vcsr16 = arg1; ++ break; ++ default: ++ printf("%s: warning, fcsr '%d' not supported\n", __func__, fcsr); ++ assert(0); ++ break; ++ } ++ restore_fp_status(env); ++ set_float_exception_flags(0, &env->active_fpu.fp_status); ++} ++ ++void helper_movreg2cf(CPULOONGARCHState *env, uint32_t cd, target_ulong src) ++{ ++ env->active_fpu.cf[cd & 0x7] = src & 0x1; ++} ++ ++void helper_movreg2cf_i32(CPULOONGARCHState *env, uint32_t cd, uint32_t src) ++{ ++ env->active_fpu.cf[cd & 0x7] = src & 0x1; ++} ++ ++void helper_movreg2cf_i64(CPULOONGARCHState *env, uint32_t cd, uint64_t src) ++{ ++ env->active_fpu.cf[cd & 0x7] = src & 0x1; ++} ++ ++target_ulong helper_movcf2reg(CPULOONGARCHState *env, uint32_t cj) ++{ ++ return (target_ulong)env->active_fpu.cf[cj & 0x7]; ++} ++ ++int ieee_ex_to_loongarch(int xcpt) ++{ ++ int ret = 0; ++ if (xcpt) { ++ if (xcpt & float_flag_invalid) { ++ ret |= FP_INVALID; ++ } ++ if (xcpt & float_flag_overflow) { ++ ret |= FP_OVERFLOW; ++ } ++ if (xcpt & float_flag_underflow) { ++ ret |= FP_UNDERFLOW; ++ } ++ if (xcpt & float_flag_divbyzero) { ++ ret |= FP_DIV0; ++ } ++ if (xcpt & float_flag_inexact) { ++ ret |= FP_INEXACT; ++ } ++ } ++ return ret; ++} ++ ++static inline void update_fcsr0(CPULOONGARCHState *env, uintptr_t pc) ++{ ++ int tmp = ieee_ex_to_loongarch( ++ get_float_exception_flags(&env->active_fpu.fp_status)); ++ ++ SET_FP_CAUSE(env->active_fpu.fcsr0, tmp); ++ if (tmp) { ++ set_float_exception_flags(0, &env->active_fpu.fp_status); ++ ++ if (GET_FP_ENABLE(env->active_fpu.fcsr0) & tmp) { ++ do_raise_exception(env, EXCP_FPE, pc); ++ } else { ++ UPDATE_FP_FLAGS(env->active_fpu.fcsr0, tmp); ++ } ++ } ++} ++ ++/* unary operations, modifying fp status */ ++uint64_t helper_float_sqrt_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt0; ++} ++ ++uint32_t helper_float_sqrt_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst0; ++} ++ ++uint64_t helper_float_cvtd_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t fdt2; ++ ++ fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt2; ++} ++ ++uint64_t helper_float_cvtd_w(CPULOONGARCHState *env, uint32_t wt0) ++{ ++ uint64_t fdt2; ++ ++ fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt2; ++} ++ ++uint64_t helper_float_cvtd_l(CPULOONGARCHState *env, uint64_t dt0) ++{ ++ uint64_t fdt2; ++ ++ fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt2; ++} ++ ++uint64_t helper_float_cvt_l_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint64_t helper_float_cvt_l_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t dt2; ++ ++ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_cvts_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t fst2; ++ ++ fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst2; ++} ++ ++uint32_t helper_float_cvts_w(CPULOONGARCHState *env, uint32_t wt0) ++{ ++ uint32_t fst2; ++ ++ fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst2; ++} ++ ++uint32_t helper_float_cvts_l(CPULOONGARCHState *env, uint64_t dt0) ++{ ++ uint32_t fst2; ++ ++ fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst2; ++} ++ ++uint32_t helper_float_cvt_w_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint32_t helper_float_cvt_w_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t wt2; ++ ++ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint64_t helper_float_round_l_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_nearest_even, ++ &env->active_fpu.fp_status); ++ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint64_t helper_float_round_l_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_nearest_even, ++ &env->active_fpu.fp_status); ++ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_round_w_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_nearest_even, ++ &env->active_fpu.fp_status); ++ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint32_t helper_float_round_w_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_nearest_even, ++ &env->active_fpu.fp_status); ++ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint64_t helper_float_trunc_l_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint64_t helper_float_trunc_l_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t dt2; ++ ++ dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_trunc_w_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t wt2; ++ ++ wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint32_t helper_float_trunc_w_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint64_t helper_float_ceil_l_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); ++ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint64_t helper_float_ceil_l_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); ++ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_ceil_w_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); ++ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint32_t helper_float_ceil_w_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); ++ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint64_t helper_float_floor_l_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); ++ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint64_t helper_float_floor_l_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint64_t dt2; ++ ++ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); ++ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ dt2 = FP_TO_INT64_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_floor_w_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); ++ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint32_t helper_float_floor_w_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); ++ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); ++ restore_rounding_mode(env); ++ if (get_float_exception_flags(&env->active_fpu.fp_status) & ++ (float_flag_invalid | float_flag_overflow)) { ++ wt2 = FP_TO_INT32_OVERFLOW; ++ } ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++/* unary operations, not modifying fp status */ ++#define FLOAT_UNOP(name) \ ++ uint64_t helper_float_##name##_d(uint64_t fdt0) \ ++ { \ ++ return float64_##name(fdt0); \ ++ } \ ++ uint32_t helper_float_##name##_s(uint32_t fst0) \ ++ { \ ++ return float32_##name(fst0); \ ++ } ++ ++FLOAT_UNOP(abs) ++FLOAT_UNOP(chs) ++#undef FLOAT_UNOP ++ ++uint64_t helper_float_recip_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t fdt2; ++ ++ fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt2; ++} ++ ++uint32_t helper_float_recip_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t fst2; ++ ++ fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst2; ++} ++ ++uint64_t helper_float_rsqrt_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t fdt2; ++ ++ fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); ++ fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdt2; ++} ++ ++uint32_t helper_float_rsqrt_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t fst2; ++ ++ fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); ++ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fst2; ++} ++ ++uint32_t helper_float_rint_s(CPULOONGARCHState *env, uint32_t fs) ++{ ++ uint32_t fdret; ++ ++ fdret = float32_round_to_int(fs, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdret; ++} ++ ++uint64_t helper_float_rint_d(CPULOONGARCHState *env, uint64_t fs) ++{ ++ uint64_t fdret; ++ ++ fdret = float64_round_to_int(fs, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return fdret; ++} ++ ++#define FLOAT_CLASS(name, bits) \ ++ uint##bits##_t float_##name(uint##bits##_t arg, float_status *status) \ ++ { \ ++ if (float##bits##_is_signaling_nan(arg, status)) { \ ++ return FLOAT_CLASS_SIGNALING_NAN; \ ++ } else if (float##bits##_is_quiet_nan(arg, status)) { \ ++ return FLOAT_CLASS_QUIET_NAN; \ ++ } else if (float##bits##_is_neg(arg)) { \ ++ if (float##bits##_is_infinity(arg)) { \ ++ return FLOAT_CLASS_NEGATIVE_INFINITY; \ ++ } else if (float##bits##_is_zero(arg)) { \ ++ return FLOAT_CLASS_NEGATIVE_ZERO; \ ++ } else if (float##bits##_is_zero_or_denormal(arg)) { \ ++ return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ ++ } else { \ ++ return FLOAT_CLASS_NEGATIVE_NORMAL; \ ++ } \ ++ } else { \ ++ if (float##bits##_is_infinity(arg)) { \ ++ return FLOAT_CLASS_POSITIVE_INFINITY; \ ++ } else if (float##bits##_is_zero(arg)) { \ ++ return FLOAT_CLASS_POSITIVE_ZERO; \ ++ } else if (float##bits##_is_zero_or_denormal(arg)) { \ ++ return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ ++ } else { \ ++ return FLOAT_CLASS_POSITIVE_NORMAL; \ ++ } \ ++ } \ ++ } \ ++ \ ++ uint##bits##_t helper_float_##name(CPULOONGARCHState *env, \ ++ uint##bits##_t arg) \ ++ { \ ++ return float_##name(arg, &env->active_fpu.fp_status); \ ++ } ++ ++FLOAT_CLASS(class_s, 32) ++FLOAT_CLASS(class_d, 64) ++#undef FLOAT_CLASS ++ ++/* binary operations */ ++#define FLOAT_BINOP(name) \ ++ uint64_t helper_float_##name##_d(CPULOONGARCHState *env, uint64_t fdt0, \ ++ uint64_t fdt1) \ ++ { \ ++ uint64_t dt2; \ ++ \ ++ dt2 = float64_##name(fdt0, fdt1, &env->active_fpu.fp_status); \ ++ update_fcsr0(env, GETPC()); \ ++ return dt2; \ ++ } \ ++ \ ++ uint32_t helper_float_##name##_s(CPULOONGARCHState *env, uint32_t fst0, \ ++ uint32_t fst1) \ ++ { \ ++ uint32_t wt2; \ ++ \ ++ wt2 = float32_##name(fst0, fst1, &env->active_fpu.fp_status); \ ++ update_fcsr0(env, GETPC()); \ ++ return wt2; \ ++ } ++ ++FLOAT_BINOP(add) ++FLOAT_BINOP(sub) ++FLOAT_BINOP(mul) ++FLOAT_BINOP(div) ++#undef FLOAT_BINOP ++ ++uint64_t helper_float_exp2_d(CPULOONGARCHState *env, uint64_t fdt0, ++ uint64_t fdt1) ++{ ++ uint64_t dt2; ++ int64_t n = (int64_t)fdt1; ++ ++ dt2 = float64_scalbn(fdt0, n > 0x1000 ? 0x1000 : n < -0x1000 ? -0x1000 : n, ++ &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++uint32_t helper_float_exp2_s(CPULOONGARCHState *env, uint32_t fst0, ++ uint32_t fst1) ++{ ++ uint32_t wt2; ++ int32_t n = (int32_t)fst1; ++ ++ wt2 = float32_scalbn(fst0, n > 0x200 ? 0x200 : n < -0x200 ? -0x200 : n, ++ &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++#define FLOAT_MINMAX(name, bits, minmaxfunc) \ ++ uint##bits##_t helper_float_##name(CPULOONGARCHState *env, \ ++ uint##bits##_t fs, uint##bits##_t ft) \ ++ { \ ++ uint##bits##_t fdret; \ ++ \ ++ fdret = \ ++ float##bits##_##minmaxfunc(fs, ft, &env->active_fpu.fp_status); \ ++ update_fcsr0(env, GETPC()); \ ++ return fdret; \ ++ } ++ ++FLOAT_MINMAX(max_s, 32, maxnum) ++FLOAT_MINMAX(max_d, 64, maxnum) ++FLOAT_MINMAX(maxa_s, 32, maxnummag) ++FLOAT_MINMAX(maxa_d, 64, maxnummag) ++ ++FLOAT_MINMAX(min_s, 32, minnum) ++FLOAT_MINMAX(min_d, 64, minnum) ++FLOAT_MINMAX(mina_s, 32, minnummag) ++FLOAT_MINMAX(mina_d, 64, minnummag) ++#undef FLOAT_MINMAX ++ ++#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ ++ uint##bits##_t helper_float_##name(CPULOONGARCHState *env, \ ++ uint##bits##_t fs, uint##bits##_t ft, \ ++ uint##bits##_t fd) \ ++ { \ ++ uint##bits##_t fdret; \ ++ \ ++ fdret = float##bits##_muladd(fs, ft, fd, muladd_arg, \ ++ &env->active_fpu.fp_status); \ ++ update_fcsr0(env, GETPC()); \ ++ return fdret; \ ++ } ++ ++FLOAT_FMADDSUB(maddf_s, 32, 0) ++FLOAT_FMADDSUB(maddf_d, 64, 0) ++FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_c) ++FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_c) ++FLOAT_FMADDSUB(nmaddf_s, 32, float_muladd_negate_result) ++FLOAT_FMADDSUB(nmaddf_d, 64, float_muladd_negate_result) ++FLOAT_FMADDSUB(nmsubf_s, 32, ++ float_muladd_negate_result | float_muladd_negate_c) ++FLOAT_FMADDSUB(nmsubf_d, 64, ++ float_muladd_negate_result | float_muladd_negate_c) ++#undef FLOAT_FMADDSUB ++ ++/* compare operations */ ++#define FOP_CONDN_D(op, cond) \ ++ uint64_t helper_cmp_d_##op(CPULOONGARCHState *env, uint64_t fdt0, \ ++ uint64_t fdt1) \ ++ { \ ++ uint64_t c; \ ++ c = cond; \ ++ update_fcsr0(env, GETPC()); \ ++ if (c) { \ ++ return -1; \ ++ } else { \ ++ return 0; \ ++ } \ ++ } ++ ++/* ++ * NOTE: the comma operator will make "cond" to eval to false, ++ * but float64_unordered_quiet() is still called. ++ */ ++FOP_CONDN_D(af, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), ++ 0)) ++FOP_CONDN_D(un, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))) ++FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(ueq, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(ult, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(ule, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++/* ++ * NOTE: the comma operator will make "cond" to eval to false, ++ * but float64_unordered() is still called. ++ */ ++FOP_CONDN_D(saf, ++ (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) ++FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))) ++FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(une, ++ (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_le(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) ++FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status) || ++ float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))) ++ ++#define FOP_CONDN_S(op, cond) \ ++ uint32_t helper_cmp_s_##op(CPULOONGARCHState *env, uint32_t fst0, \ ++ uint32_t fst1) \ ++ { \ ++ uint64_t c; \ ++ c = cond; \ ++ update_fcsr0(env, GETPC()); \ ++ if (c) { \ ++ return -1; \ ++ } else { \ ++ return 0; \ ++ } \ ++ } ++ ++/* ++ * NOTE: the comma operator will make "cond" to eval to false, ++ * but float32_unordered_quiet() is still called. ++ */ ++FOP_CONDN_S(af, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), ++ 0)) ++FOP_CONDN_S(un, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))) ++FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(ueq, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(ult, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(ule, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++/* ++ * NOTE: the comma operator will make "cond" to eval to false, ++ * but float32_unordered() is still called. ++ */ ++FOP_CONDN_S(saf, ++ (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) ++FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status))) ++FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_eq(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_le(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(une, ++ (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_le(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt(fst0, fst1, &env->active_fpu.fp_status))) ++FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) || ++ float32_lt(fst0, fst1, &env->active_fpu.fp_status))) ++ ++uint32_t helper_float_logb_s(CPULOONGARCHState *env, uint32_t fst0) ++{ ++ uint32_t wt2; ++ ++ wt2 = float32_log2(fst0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return wt2; ++} ++ ++uint64_t helper_float_logb_d(CPULOONGARCHState *env, uint64_t fdt0) ++{ ++ uint64_t dt2; ++ ++ dt2 = float64_log2(fdt0, &env->active_fpu.fp_status); ++ update_fcsr0(env, GETPC()); ++ return dt2; ++} ++ ++target_ulong helper_fsel(CPULOONGARCHState *env, target_ulong fj, ++ target_ulong fk, uint32_t ca) ++{ ++ if (env->active_fpu.cf[ca & 0x7]) { ++ return fk; ++ } else { ++ return fj; ++ } ++} +diff --git a/target/loongarch64/fpu_helper.h b/target/loongarch64/fpu_helper.h +new file mode 100644 +index 0000000000..9efa7e30ca +--- /dev/null ++++ b/target/loongarch64/fpu_helper.h +@@ -0,0 +1,127 @@ ++/* ++ * loongarch internal definitions and helpers ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_FPU_H ++#define LOONGARCH_FPU_H ++ ++#include "cpu-csr.h" ++ ++extern const struct loongarch_def_t loongarch_defs[]; ++extern const int loongarch_defs_number; ++ ++enum CPULSXDataFormat { DF_BYTE = 0, DF_HALF, DF_WORD, DF_DOUBLE, DF_QUAD }; ++ ++void loongarch_cpu_do_interrupt(CPUState *cpu); ++bool loongarch_cpu_exec_interrupt(CPUState *cpu, int int_req); ++void loongarch_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, ++ MMUAccessType access_type, int mmu_idx, ++ uintptr_t retaddr) QEMU_NORETURN; ++ ++#if !defined(CONFIG_USER_ONLY) ++ ++typedef struct r4k_tlb_t r4k_tlb_t; ++struct r4k_tlb_t { ++ target_ulong VPN; ++ uint32_t PageMask; ++ uint16_t ASID; ++ unsigned int G:1; ++ unsigned int C0:3; ++ unsigned int C1:3; ++ unsigned int V0:1; ++ unsigned int V1:1; ++ unsigned int D0:1; ++ unsigned int D1:1; ++ unsigned int XI0:1; ++ unsigned int XI1:1; ++ unsigned int RI0:1; ++ unsigned int RI1:1; ++ unsigned int EHINV:1; ++ uint64_t PPN[2]; ++}; ++ ++int no_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, ++ target_ulong address, int rw, int access_type); ++int fixed_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, ++ target_ulong address, int rw, int access_type); ++int r4k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, ++ target_ulong address, int rw, int access_type); ++ ++/* loongarch 3a5000 tlb helper function : lisa csr */ ++int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, ++ target_ulong address, int rw, int access_type); ++void ls3a5k_helper_tlbwr(CPULOONGARCHState *env); ++void ls3a5k_helper_tlbfill(CPULOONGARCHState *env); ++void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env); ++void ls3a5k_helper_tlbrd(CPULOONGARCHState *env); ++void ls3a5k_helper_tlbclr(CPULOONGARCHState *env); ++void ls3a5k_helper_tlbflush(CPULOONGARCHState *env); ++void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx); ++void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, ++ target_ulong info, int op); ++void ls3a5k_flush_vtlb(CPULOONGARCHState *env); ++void ls3a5k_flush_ftlb(CPULOONGARCHState *env); ++hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, ++ target_ulong address, int rw); ++#endif ++ ++#define cpu_signal_handler cpu_loongarch_signal_handler ++ ++static inline bool cpu_loongarch_hw_interrupts_enabled(CPULOONGARCHState *env) ++{ ++ bool ret = 0; ++ ++ ret = env->CSR_CRMD & (1 << CSR_CRMD_IE_SHIFT); ++ ++ return ret; ++} ++ ++void loongarch_tcg_init(void); ++ ++/* helper.c */ ++bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, bool probe, ++ uintptr_t retaddr); ++ ++/* op_helper.c */ ++uint32_t float_class_s(uint32_t arg, float_status *fst); ++uint64_t float_class_d(uint64_t arg, float_status *fst); ++ ++int ieee_ex_to_loongarch(int xcpt); ++void update_pagemask(CPULOONGARCHState *env, target_ulong arg1, ++ int32_t *pagemask); ++ ++void cpu_loongarch_tlb_flush(CPULOONGARCHState *env); ++void sync_c0_status(CPULOONGARCHState *env, CPULOONGARCHState *cpu, int tc); ++ ++void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, ++ uint32_t exception, int error_code, ++ uintptr_t pc); ++int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf, ++ unsigned long offset, unsigned long len); ++int loongarch_write_qxfer(CPUState *cs, const char *annex, ++ const uint8_t *write_buf, unsigned long offset, ++ unsigned long len); ++ ++static inline void QEMU_NORETURN do_raise_exception(CPULOONGARCHState *env, ++ uint32_t exception, ++ uintptr_t pc) ++{ ++ do_raise_exception_err(env, exception, 0, pc); ++} ++#endif +diff --git a/target/loongarch64/gdbstub.c b/target/loongarch64/gdbstub.c +new file mode 100644 +index 0000000000..5ee91dc930 +--- /dev/null ++++ b/target/loongarch64/gdbstub.c +@@ -0,0 +1,164 @@ ++/* ++ * LOONGARCH gdb server stub ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "cpu.h" ++#include "internal.h" ++#include "exec/gdbstub.h" ++#ifdef CONFIG_TCG ++#include "exec/helper-proto.h" ++#endif ++ ++uint64_t read_fcc(CPULOONGARCHState *env) ++{ ++ uint64_t ret = 0; ++ ++ for (int i = 0; i < 8; ++i) { ++ ret |= (uint64_t)env->active_fpu.cf[i] << (i * 8); ++ } ++ ++ return ret; ++} ++ ++void write_fcc(CPULOONGARCHState *env, uint64_t val) ++{ ++ for (int i = 0; i < 8; ++i) { ++ env->active_fpu.cf[i] = (val >> (i * 8)) & 1; ++ } ++} ++ ++int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int size = 0; ++ ++ if (0 <= n && n < 32) { ++ return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); ++ } ++ ++ switch (n) { ++ case 32: ++ size = gdb_get_regl(mem_buf, 0); ++ break; ++ case 33: ++ size = gdb_get_regl(mem_buf, env->active_tc.PC); ++ break; ++ case 34: ++ size = gdb_get_regl(mem_buf, env->CSR_BADV); ++ break; ++ default: ++ break; ++ } ++ ++ return size; ++} ++ ++int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ target_ulong tmp = ldtul_p(mem_buf); ++ int size = 0; ++ ++ if (0 <= n && n < 32) { ++ return env->active_tc.gpr[n] = tmp, sizeof(target_ulong); ++ } ++ ++ size = sizeof(target_ulong); ++ ++ switch (n) { ++ case 33: ++ env->active_tc.PC = tmp; ++ break; ++ case 32: ++ case 34: ++ default: ++ size = 0; ++ break; ++ } ++ ++ return size; ++} ++ ++static int loongarch_gdb_get_fpu(CPULOONGARCHState *env, GByteArray *mem_buf, ++ int n) ++{ ++ if (0 <= n && n < 32) { ++ return gdb_get_reg64(mem_buf, env->active_fpu.fpr[n].d); ++ } else if (n == 32) { ++ uint64_t val = read_fcc(env); ++ return gdb_get_reg64(mem_buf, val); ++ } else if (n == 33) { ++ return gdb_get_reg32(mem_buf, env->active_fpu.fcsr0); ++ } ++ return 0; ++} ++ ++static int loongarch_gdb_set_fpu(CPULOONGARCHState *env, uint8_t *mem_buf, ++ int n) ++{ ++ int length = 0; ++ ++ if (0 <= n && n < 32) { ++ env->active_fpu.fpr[n].d = ldq_p(mem_buf); ++ length = 8; ++ } else if (n == 32) { ++ uint64_t val = ldq_p(mem_buf); ++ write_fcc(env, val); ++ length = 8; ++ } else if (n == 33) { ++ env->active_fpu.fcsr0 = ldl_p(mem_buf); ++ length = 4; ++ } ++ return length; ++} ++ ++void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) ++{ ++ gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, ++ 34, "loongarch-fpu.xml", 0); ++} ++ ++#ifdef CONFIG_TCG ++int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf, ++ unsigned long offset, unsigned long len) ++{ ++ if (strncmp(annex, "cpucfg", sizeof("cpucfg") - 1) == 0) { ++ if (offset % 4 != 0 || len % 4 != 0) { ++ return 0; ++ } ++ ++ size_t i; ++ for (i = offset; i < offset + len; i += 4) ++ ((uint32_t *)read_buf)[(i - offset) / 4] = ++ helper_cpucfg(&(LOONGARCH_CPU(cs)->env), i / 4); ++ return 32 * 4; ++ } ++ return 0; ++} ++ ++int loongarch_write_qxfer(CPUState *cs, const char *annex, ++ const uint8_t *write_buf, unsigned long offset, ++ unsigned long len) ++{ ++ return 0; ++} ++#endif +diff --git a/target/loongarch64/helper.c b/target/loongarch64/helper.c +new file mode 100644 +index 0000000000..ec25803c1c +--- /dev/null ++++ b/target/loongarch64/helper.c +@@ -0,0 +1,726 @@ ++/* ++ * LOONGARCH emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "internal.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "exec/log.h" ++#include "hw/loongarch/cpudevs.h" ++ ++#if !defined(CONFIG_USER_ONLY) ++ ++static int ls3a5k_map_address_tlb_entry(CPULOONGARCHState *env, ++ hwaddr *physical, int *prot, ++ target_ulong address, int rw, ++ int access_type, ls3a5k_tlb_t *tlb) ++{ ++ uint64_t mask = tlb->PageMask; ++ int n = !!(address & mask & ~(mask >> 1)); ++ uint32_t plv = env->CSR_CRMD & CSR_CRMD_PLV; ++ ++ /* Check access rights */ ++ if (!(n ? tlb->V1 : tlb->V0)) { ++ return TLBRET_INVALID; ++ } ++ ++ if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { ++ return TLBRET_XI; ++ } ++ ++ if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { ++ return TLBRET_RI; ++ } ++ ++ if (plv > (n ? tlb->PLV1 : tlb->PLV0)) { ++ return TLBRET_PE; ++ } ++ ++ if (rw != MMU_DATA_STORE || (n ? tlb->WE1 : tlb->WE0)) { ++ /* ++ * PPN address ++ * 4 KB: [47:13] [12;0] ++ * 16 KB: [47:15] [14:0] ++ */ ++ if (n) { ++ *physical = tlb->PPN1 | (address & (mask >> 1)); ++ } else { ++ *physical = tlb->PPN0 | (address & (mask >> 1)); ++ } ++ *prot = PAGE_READ; ++ if (n ? tlb->WE1 : tlb->WE0) { ++ *prot |= PAGE_WRITE; ++ } ++ if (!(n ? tlb->XI1 : tlb->XI0)) { ++ *prot |= PAGE_EXEC; ++ } ++ return TLBRET_MATCH; ++ } ++ ++ return TLBRET_DIRTY; ++} ++ ++/* Loongarch 3A5K -style MMU emulation */ ++int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, ++ target_ulong address, int rw, int access_type) ++{ ++ uint16_t asid = env->CSR_ASID & 0x3ff; ++ int i; ++ ls3a5k_tlb_t *tlb; ++ ++ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; ++ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; ++ ++ int ftlb_idx; ++ ++ uint64_t mask; ++ uint64_t vpn; /* address to map */ ++ uint64_t tag; /* address in TLB entry */ ++ ++ /* search VTLB */ ++ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { ++ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ mask = tlb->PageMask; ++ ++ vpn = address & 0xffffffffe000 & ~mask; ++ tag = tlb->VPN & ~mask; ++ ++ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && ++ tlb->EHINV != 1) { ++ return ls3a5k_map_address_tlb_entry(env, physical, prot, address, ++ rw, access_type, tlb); ++ } ++ } ++ ++ if (ftlb_size == 0) { ++ return TLBRET_NOMATCH; ++ } ++ ++ /* search FTLB */ ++ mask = env->tlb->mmu.ls3a5k.ftlb_mask; ++ vpn = address & 0xffffffffe000 & ~mask; ++ ++ ftlb_idx = (address & 0xffffffffc000) >> 15; /* 16 KB */ ++ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ ++ ++ for (i = 0; i < 8; ++i) { ++ /* ++ * ---------- set 0 1 2 ... 7 ++ * ftlb_idx ----------------------------------- ++ * 0 | 0 1 2 ... 7 ++ * 1 | 8 9 10 ... 15 ++ * 2 | 16 17 18 ... 23 ++ * ... | ++ * 255 | 2040 2041 2042 ... 2047 ++ */ ++ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; ++ tag = tlb->VPN & ~mask; ++ ++ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && ++ tlb->EHINV != 1) { ++ return ls3a5k_map_address_tlb_entry(env, physical, prot, address, ++ rw, access_type, tlb); ++ } ++ } ++ ++ return TLBRET_NOMATCH; ++} ++ ++static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, ++ int *prot, target_ulong real_address, int rw, ++ int access_type, int mmu_idx) ++{ ++ int user_mode = mmu_idx == LARCH_HFLAG_UM; ++ int kernel_mode = !user_mode; ++ unsigned plv, base_c, base_v, tmp; ++ ++ /* effective address (modified for KVM T&E kernel segments) */ ++ target_ulong address = real_address; ++ ++ /* Check PG */ ++ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { ++ /* DA mode */ ++ *physical = address & 0xffffffffffffUL; ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ ++ plv = kernel_mode | (user_mode << 3); ++ base_v = address >> CSR_DMW_BASE_SH; ++ /* Check direct map window 0 */ ++ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; ++ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { ++ *physical = dmwin_va2pa(address); ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ /* Check direct map window 1 */ ++ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; ++ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { ++ *physical = dmwin_va2pa(address); ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ /* Check valid extension */ ++ tmp = address >> 47; ++ if (!(tmp == 0 || tmp == 0x1ffff)) { ++ return TLBRET_BADADDR; ++ } ++ /* mapped address */ ++ return env->tlb->map_address(env, physical, prot, real_address, rw, ++ access_type); ++} ++ ++void cpu_loongarch_tlb_flush(CPULOONGARCHState *env) ++{ ++ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); ++ ++ /* Flush qemu's TLB and discard all shadowed entries. */ ++ tlb_flush(CPU(cpu)); ++ env->tlb->tlb_in_use = env->tlb->nb_tlb; ++} ++#endif ++ ++static void raise_mmu_exception(CPULOONGARCHState *env, target_ulong address, ++ int rw, int tlb_error) ++{ ++ CPUState *cs = CPU(loongarch_env_get_cpu(env)); ++ int exception = 0, error_code = 0; ++ ++ if (rw == MMU_INST_FETCH) { ++ error_code |= EXCP_INST_NOTAVAIL; ++ } ++ ++ switch (tlb_error) { ++ default: ++ case TLBRET_BADADDR: ++ /* Reference to kernel address from user mode or supervisor mode */ ++ /* Reference to supervisor address from user mode */ ++ if (rw == MMU_DATA_STORE) { ++ exception = EXCP_AdES; ++ } else { ++ exception = EXCP_AdEL; ++ } ++ break; ++ case TLBRET_NOMATCH: ++ /* No TLB match for a mapped address */ ++ if (rw == MMU_DATA_STORE) { ++ exception = EXCP_TLBS; ++ } else { ++ exception = EXCP_TLBL; ++ } ++ error_code |= EXCP_TLB_NOMATCH; ++ break; ++ case TLBRET_INVALID: ++ /* TLB match with no valid bit */ ++ if (rw == MMU_DATA_STORE) { ++ exception = EXCP_TLBS; ++ } else { ++ exception = EXCP_TLBL; ++ } ++ break; ++ case TLBRET_DIRTY: ++ /* TLB match but 'D' bit is cleared */ ++ exception = EXCP_LTLBL; ++ break; ++ case TLBRET_XI: ++ /* Execute-Inhibit Exception */ ++ exception = EXCP_TLBXI; ++ break; ++ case TLBRET_RI: ++ /* Read-Inhibit Exception */ ++ exception = EXCP_TLBRI; ++ break; ++ case TLBRET_PE: ++ /* Privileged Exception */ ++ exception = EXCP_TLBPE; ++ break; ++ } ++ ++ if (env->insn_flags & INSN_LOONGARCH) { ++ if (tlb_error == TLBRET_NOMATCH) { ++ env->CSR_TLBRBADV = address; ++ env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1); ++ cs->exception_index = exception; ++ env->error_code = error_code; ++ return; ++ } ++ } ++ ++ /* Raise exception */ ++ env->CSR_BADV = address; ++ cs->exception_index = exception; ++ env->error_code = error_code; ++ ++ if (env->insn_flags & INSN_LOONGARCH) { ++ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); ++ } ++} ++ ++bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, bool probe, ++ uintptr_t retaddr) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++#if !defined(CONFIG_USER_ONLY) ++ hwaddr physical; ++ int prot; ++ int loongarch_access_type; ++#endif ++ int ret = TLBRET_BADADDR; ++ ++ qemu_log_mask(CPU_LOG_MMU, ++ "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " mmu_idx %d\n", ++ __func__, env->active_tc.PC, address, mmu_idx); ++ ++ /* data access */ ++#if !defined(CONFIG_USER_ONLY) ++ /* XXX: put correct access by using cpu_restore_state() correctly */ ++ loongarch_access_type = ACCESS_INT; ++ ret = get_physical_address(env, &physical, &prot, address, access_type, ++ loongarch_access_type, mmu_idx); ++ switch (ret) { ++ case TLBRET_MATCH: ++ qemu_log_mask(CPU_LOG_MMU, ++ "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx ++ " prot %d asid %ld pc 0x%lx\n", ++ __func__, address, physical, prot, env->CSR_ASID, ++ env->active_tc.PC); ++ break; ++ default: ++ qemu_log_mask(CPU_LOG_MMU, ++ "%s address=%" VADDR_PRIx " ret %d asid %ld pc 0x%lx\n", ++ __func__, address, ret, env->CSR_ASID, ++ env->active_tc.PC); ++ break; ++ } ++ if (ret == TLBRET_MATCH) { ++ tlb_set_page(cs, address & TARGET_PAGE_MASK, ++ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, mmu_idx, ++ TARGET_PAGE_SIZE); ++ ret = true; ++ } ++ if (probe) { ++ return false; ++ } ++#endif ++ ++ raise_mmu_exception(env, address, access_type, ret); ++ do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); ++} ++ ++#if !defined(CONFIG_USER_ONLY) ++hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, ++ target_ulong address, int rw) ++{ ++ hwaddr physical; ++ int prot; ++ int access_type; ++ int ret = 0; ++ ++ /* data access */ ++ access_type = ACCESS_INT; ++ ret = get_physical_address(env, &physical, &prot, address, rw, access_type, ++ cpu_mmu_index(env, false)); ++ if (ret != TLBRET_MATCH) { ++ raise_mmu_exception(env, address, rw, ret); ++ return -1LL; ++ } else { ++ return physical; ++ } ++} ++ ++static const char *const excp_names[EXCP_LAST + 1] = { ++ [EXCP_RESET] = "reset", ++ [EXCP_SRESET] = "soft reset", ++ [EXCP_NMI] = "non-maskable interrupt", ++ [EXCP_EXT_INTERRUPT] = "interrupt", ++ [EXCP_AdEL] = "address error load", ++ [EXCP_AdES] = "address error store", ++ [EXCP_TLBF] = "TLB refill", ++ [EXCP_IBE] = "instruction bus error", ++ [EXCP_SYSCALL] = "syscall", ++ [EXCP_BREAK] = "break", ++ [EXCP_FPDIS] = "float unit unusable", ++ [EXCP_LSXDIS] = "vector128 unusable", ++ [EXCP_LASXDIS] = "vector256 unusable", ++ [EXCP_RI] = "reserved instruction", ++ [EXCP_OVERFLOW] = "arithmetic overflow", ++ [EXCP_TRAP] = "trap", ++ [EXCP_FPE] = "floating point", ++ [EXCP_LTLBL] = "TLB modify", ++ [EXCP_TLBL] = "TLB load", ++ [EXCP_TLBS] = "TLB store", ++ [EXCP_DBE] = "data bus error", ++ [EXCP_TLBXI] = "TLB execute-inhibit", ++ [EXCP_TLBRI] = "TLB read-inhibit", ++ [EXCP_TLBPE] = "TLB priviledged error", ++}; ++#endif ++ ++target_ulong exception_resume_pc(CPULOONGARCHState *env) ++{ ++ target_ulong bad_pc; ++ ++ bad_pc = env->active_tc.PC; ++ if (env->hflags & LARCH_HFLAG_BMASK) { ++ /* ++ * If the exception was raised from a delay slot, come back to ++ * the jump. ++ */ ++ bad_pc -= 4; ++ } ++ ++ return bad_pc; ++} ++ ++#if !defined(CONFIG_USER_ONLY) ++static void set_hflags_for_handler(CPULOONGARCHState *env) ++{ ++ /* Exception handlers are entered in 32-bit mode. */ ++} ++ ++static inline void set_badinstr_registers(CPULOONGARCHState *env) ++{ ++ if ((env->insn_flags & INSN_LOONGARCH)) { ++ env->CSR_BADI = cpu_ldl_code(env, env->active_tc.PC); ++ return; ++ } ++} ++#endif ++ ++static inline unsigned int get_vint_size(CPULOONGARCHState *env) ++{ ++ unsigned int size = 0; ++ ++ switch ((env->CSR_ECFG >> 16) & 0x7) { ++ case 0: ++ break; ++ case 1: ++ size = 2 * 4; /* #Insts * inst_size */ ++ break; ++ case 2: ++ size = 4 * 4; ++ break; ++ case 3: ++ size = 8 * 4; ++ break; ++ case 4: ++ size = 16 * 4; ++ break; ++ case 5: ++ size = 32 * 4; ++ break; ++ case 6: ++ size = 64 * 4; ++ break; ++ case 7: ++ size = 128 * 4; ++ break; ++ default: ++ printf("%s: unexpected value", __func__); ++ assert(0); ++ } ++ ++ return size; ++} ++ ++#define is_refill(cs, env) \ ++ (((cs->exception_index == EXCP_TLBL) || \ ++ (cs->exception_index == EXCP_TLBS)) && \ ++ (env->error_code & EXCP_TLB_NOMATCH)) ++ ++void loongarch_cpu_do_interrupt(CPUState *cs) ++{ ++#if !defined(CONFIG_USER_ONLY) ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ bool update_badinstr = 0; ++ int cause = -1; ++ const char *name; ++ ++ if (qemu_loglevel_mask(CPU_LOG_INT) && ++ cs->exception_index != EXCP_EXT_INTERRUPT) { ++ if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) { ++ name = "unknown"; ++ } else { ++ name = excp_names[cs->exception_index]; ++ } ++ ++ qemu_log("%s enter: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx ++ " TLBRERA 0x%016lx" ++ " %s exception\n", ++ __func__, env->active_tc.PC, env->CSR_ERA, env->CSR_TLBRERA, ++ name); ++ } ++ ++ switch (cs->exception_index) { ++ case EXCP_RESET: ++ cpu_reset(CPU(cpu)); ++ break; ++ case EXCP_NMI: ++ env->CSR_ERRERA = exception_resume_pc(env); ++ env->hflags &= ~LARCH_HFLAG_BMASK; ++ env->hflags |= LARCH_HFLAG_64; ++ env->hflags &= ~LARCH_HFLAG_AWRAP; ++ env->hflags &= ~(LARCH_HFLAG_KSU); ++ env->active_tc.PC = env->exception_base; ++ set_hflags_for_handler(env); ++ break; ++ case EXCP_EXT_INTERRUPT: ++ cause = 0; ++ goto set_ERA; ++ case EXCP_LTLBL: ++ cause = 1; ++ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); ++ goto set_ERA; ++ case EXCP_TLBL: ++ cause = 2; ++ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); ++ goto set_ERA; ++ case EXCP_TLBS: ++ cause = 3; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_AdEL: ++ cause = 4; ++ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); ++ goto set_ERA; ++ case EXCP_AdES: ++ cause = 5; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_IBE: ++ cause = 6; ++ goto set_ERA; ++ case EXCP_DBE: ++ cause = 7; ++ goto set_ERA; ++ case EXCP_SYSCALL: ++ cause = 8; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_BREAK: ++ cause = 9; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_RI: ++ cause = 10; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_FPDIS: ++ case EXCP_LSXDIS: ++ case EXCP_LASXDIS: ++ cause = 11; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_OVERFLOW: ++ cause = 12; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_TRAP: ++ cause = 13; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_FPE: ++ cause = 15; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_TLBRI: ++ cause = 19; ++ update_badinstr = 1; ++ goto set_ERA; ++ case EXCP_TLBXI: ++ case EXCP_TLBPE: ++ cause = 20; ++ goto set_ERA; ++ set_ERA: ++ if (is_refill(cs, env)) { ++ env->CSR_TLBRERA = exception_resume_pc(env); ++ env->CSR_TLBRERA |= 1; ++ } else { ++ env->CSR_ERA = exception_resume_pc(env); ++ } ++ ++ if (update_badinstr) { ++ set_badinstr_registers(env); ++ } ++ env->hflags &= ~(LARCH_HFLAG_KSU); ++ ++ env->hflags &= ~LARCH_HFLAG_BMASK; ++ if (env->insn_flags & INSN_LOONGARCH) { ++ /* save PLV and IE */ ++ if (is_refill(cs, env)) { ++ env->CSR_TLBRPRMD &= (~0x7); ++ env->CSR_TLBRPRMD |= (env->CSR_CRMD & 0x7); ++ } else { ++ env->CSR_PRMD &= (~0x7); ++ env->CSR_PRMD |= (env->CSR_CRMD & 0x7); ++ } ++ ++ env->CSR_CRMD &= ~(0x7); ++ ++ switch (cs->exception_index) { ++ case EXCP_EXT_INTERRUPT: ++ break; ++ case EXCP_TLBL: ++ if (env->error_code & EXCP_INST_NOTAVAIL) { ++ cause = EXCCODE_TLBI; ++ } else { ++ cause = EXCCODE_TLBL; ++ } ++ break; ++ case EXCP_TLBS: ++ cause = EXCCODE_TLBS; ++ break; ++ case EXCP_LTLBL: ++ cause = EXCCODE_MOD; ++ break; ++ case EXCP_TLBRI: ++ cause = EXCCODE_TLBRI; ++ break; ++ case EXCP_TLBXI: ++ cause = EXCCODE_TLBXI; ++ break; ++ case EXCP_TLBPE: ++ cause = EXCCODE_TLBPE; ++ break; ++ case EXCP_AdEL: ++ case EXCP_AdES: ++ case EXCP_IBE: ++ case EXCP_DBE: ++ cause = EXCCODE_ADE; ++ break; ++ case EXCP_SYSCALL: ++ cause = EXCCODE_SYS; ++ break; ++ case EXCP_BREAK: ++ cause = EXCCODE_BP; ++ break; ++ case EXCP_RI: ++ cause = EXCCODE_RI; ++ break; ++ case EXCP_FPDIS: ++ cause = EXCCODE_FPDIS; ++ break; ++ case EXCP_LSXDIS: ++ cause = EXCCODE_LSXDIS; ++ break; ++ case EXCP_LASXDIS: ++ cause = EXCCODE_LASXDIS; ++ break; ++ case EXCP_FPE: ++ cause = EXCCODE_FPE; ++ break; ++ default: ++ printf("Error: exception(%d) '%s' has not been supported\n", ++ cs->exception_index, excp_names[cs->exception_index]); ++ abort(); ++ } ++ ++ uint32_t vec_size = get_vint_size(env); ++ env->active_tc.PC = env->CSR_EEPN; ++ env->active_tc.PC += cause * vec_size; ++ if (is_refill(cs, env)) { ++ /* TLB Refill */ ++ env->active_tc.PC = env->CSR_TLBRENT; ++ break; /* Do not modify excode */ ++ } ++ if (cs->exception_index == EXCP_EXT_INTERRUPT) { ++ /* Interrupt */ ++ uint32_t vector = 0; ++ uint32_t pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; ++ pending &= env->CSR_ECFG & CSR_ECFG_IPMASK; ++ ++ /* Find the highest-priority interrupt. */ ++ while (pending >>= 1) { ++ vector++; ++ } ++ env->active_tc.PC = ++ env->CSR_EEPN + (EXCODE_IP + vector) * vec_size; ++ if (qemu_loglevel_mask(CPU_LOG_INT)) { ++ qemu_log("%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx ++ " cause %d\n" ++ " A " TARGET_FMT_lx " D " TARGET_FMT_lx ++ " vector = %d ExC %08lx ExS %08lx\n", ++ __func__, env->active_tc.PC, env->CSR_ERA, cause, ++ env->CSR_BADV, env->CSR_DERA, vector, ++ env->CSR_ECFG, env->CSR_ESTAT); ++ } ++ } ++ /* Excode */ ++ env->CSR_ESTAT = (env->CSR_ESTAT & ~(0x1f << CSR_ESTAT_EXC_SH)) | ++ (cause << CSR_ESTAT_EXC_SH); ++ } ++ set_hflags_for_handler(env); ++ break; ++ default: ++ abort(); ++ } ++ if (qemu_loglevel_mask(CPU_LOG_INT) && ++ cs->exception_index != EXCP_EXT_INTERRUPT) { ++ qemu_log("%s: PC " TARGET_FMT_lx " ERA 0x%08lx" ++ " cause %d%s\n" ++ " ESTAT %08lx EXCFG 0x%08lx BADVA 0x%08lx BADI 0x%08lx \ ++ SYS_NUM %lu cpu %d asid 0x%lx" ++ "\n", ++ __func__, env->active_tc.PC, ++ is_refill(cs, env) ? env->CSR_TLBRERA : env->CSR_ERA, cause, ++ is_refill(cs, env) ? "(refill)" : "", env->CSR_ESTAT, ++ env->CSR_ECFG, ++ is_refill(cs, env) ? env->CSR_TLBRBADV : env->CSR_BADV, ++ env->CSR_BADI, env->active_tc.gpr[11], cs->cpu_index, ++ env->CSR_ASID); ++ } ++#endif ++ cs->exception_index = EXCP_NONE; ++} ++ ++bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) ++{ ++ if (interrupt_request & CPU_INTERRUPT_HARD) { ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ ++ if (cpu_loongarch_hw_interrupts_enabled(env) && ++ cpu_loongarch_hw_interrupts_pending(env)) { ++ /* Raise it */ ++ cs->exception_index = EXCP_EXT_INTERRUPT; ++ env->error_code = 0; ++ loongarch_cpu_do_interrupt(cs); ++ return true; ++ } ++ } ++ return false; ++} ++ ++void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, ++ uint32_t exception, int error_code, ++ uintptr_t pc) ++{ ++ CPUState *cs = CPU(loongarch_env_get_cpu(env)); ++ ++ qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", __func__, exception, error_code); ++ cs->exception_index = exception; ++ env->error_code = error_code; ++ ++ cpu_loop_exit_restore(cs, pc); ++} +diff --git a/target/loongarch64/helper.h b/target/loongarch64/helper.h +new file mode 100644 +index 0000000000..868b16da1e +--- /dev/null ++++ b/target/loongarch64/helper.h +@@ -0,0 +1,178 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) ++DEF_HELPER_2(raise_exception, noreturn, env, i32) ++DEF_HELPER_1(raise_exception_debug, noreturn, env) ++ ++DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) ++DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) ++ ++DEF_HELPER_3(crc32, tl, tl, tl, i32) ++DEF_HELPER_3(crc32c, tl, tl, tl, i32) ++ ++#ifndef CONFIG_USER_ONLY ++/* LoongISA CSR register */ ++DEF_HELPER_2(csr_rdq, tl, env, i64) ++DEF_HELPER_3(csr_wrq, tl, env, tl, i64) ++DEF_HELPER_4(csr_xchgq, tl, env, tl, tl, i64) ++ ++#endif /* !CONFIG_USER_ONLY */ ++ ++/* CP1 functions */ ++DEF_HELPER_2(movfcsr2gr, tl, env, i32) ++DEF_HELPER_4(movgr2fcsr, void, env, tl, i32, i32) ++ ++DEF_HELPER_2(float_cvtd_s, i64, env, i32) ++DEF_HELPER_2(float_cvtd_w, i64, env, i32) ++DEF_HELPER_2(float_cvtd_l, i64, env, i64) ++DEF_HELPER_2(float_cvts_d, i32, env, i64) ++DEF_HELPER_2(float_cvts_w, i32, env, i32) ++DEF_HELPER_2(float_cvts_l, i32, env, i64) ++ ++DEF_HELPER_FLAGS_2(float_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) ++DEF_HELPER_FLAGS_2(float_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_4(float_##op##_s, i32, env, i32, i32, i32) \ ++ DEF_HELPER_4(float_##op##_d, i64, env, i64, i64, i64) ++FOP_PROTO(maddf) ++FOP_PROTO(msubf) ++FOP_PROTO(nmaddf) ++FOP_PROTO(nmsubf) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_3(float_##op##_s, i32, env, i32, i32) \ ++ DEF_HELPER_3(float_##op##_d, i64, env, i64, i64) ++FOP_PROTO(max) ++FOP_PROTO(maxa) ++FOP_PROTO(min) ++FOP_PROTO(mina) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_2(float_##op##_l_s, i64, env, i32) \ ++ DEF_HELPER_2(float_##op##_l_d, i64, env, i64) \ ++ DEF_HELPER_2(float_##op##_w_s, i32, env, i32) \ ++ DEF_HELPER_2(float_##op##_w_d, i32, env, i64) ++FOP_PROTO(cvt) ++FOP_PROTO(round) ++FOP_PROTO(trunc) ++FOP_PROTO(ceil) ++FOP_PROTO(floor) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_2(float_##op##_s, i32, env, i32) \ ++ DEF_HELPER_2(float_##op##_d, i64, env, i64) ++FOP_PROTO(sqrt) ++FOP_PROTO(rsqrt) ++FOP_PROTO(recip) ++FOP_PROTO(rint) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_1(float_##op##_s, i32, i32) \ ++ DEF_HELPER_1(float_##op##_d, i64, i64) ++FOP_PROTO(abs) ++FOP_PROTO(chs) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_3(float_##op##_s, i32, env, i32, i32) \ ++ DEF_HELPER_3(float_##op##_d, i64, env, i64, i64) ++FOP_PROTO(add) ++FOP_PROTO(sub) ++FOP_PROTO(mul) ++FOP_PROTO(div) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++ DEF_HELPER_3(cmp_d_##op, i64, env, i64, i64) \ ++ DEF_HELPER_3(cmp_s_##op, i32, env, i32, i32) ++FOP_PROTO(af) ++FOP_PROTO(un) ++FOP_PROTO(eq) ++FOP_PROTO(ueq) ++FOP_PROTO(lt) ++FOP_PROTO(ult) ++FOP_PROTO(le) ++FOP_PROTO(ule) ++FOP_PROTO(saf) ++FOP_PROTO(sun) ++FOP_PROTO(seq) ++FOP_PROTO(sueq) ++FOP_PROTO(slt) ++FOP_PROTO(sult) ++FOP_PROTO(sle) ++FOP_PROTO(sule) ++FOP_PROTO(or) ++FOP_PROTO(une) ++FOP_PROTO(ne) ++FOP_PROTO(sor) ++FOP_PROTO(sune) ++FOP_PROTO(sne) ++#undef FOP_PROTO ++ ++/* Special functions */ ++#ifndef CONFIG_USER_ONLY ++DEF_HELPER_1(tlbwr, void, env) ++DEF_HELPER_1(tlbfill, void, env) ++DEF_HELPER_1(tlbsrch, void, env) ++DEF_HELPER_1(tlbrd, void, env) ++DEF_HELPER_1(tlbclr, void, env) ++DEF_HELPER_1(tlbflush, void, env) ++DEF_HELPER_4(invtlb, void, env, tl, tl, tl) ++DEF_HELPER_1(ertn, void, env) ++DEF_HELPER_5(lddir, void, env, tl, tl, tl, i32) ++DEF_HELPER_4(ldpte, void, env, tl, tl, i32) ++DEF_HELPER_3(drdtime, void, env, tl, tl) ++DEF_HELPER_1(read_pgd, tl, env) ++#endif /* !CONFIG_USER_ONLY */ ++DEF_HELPER_2(cpucfg, tl, env, tl) ++DEF_HELPER_1(idle, void, env) ++ ++DEF_HELPER_3(float_exp2_s, i32, env, i32, i32) ++DEF_HELPER_3(float_exp2_d, i64, env, i64, i64) ++DEF_HELPER_2(float_logb_s, i32, env, i32) ++DEF_HELPER_2(float_logb_d, i64, env, i64) ++DEF_HELPER_3(movreg2cf, void, env, i32, tl) ++DEF_HELPER_2(movcf2reg, tl, env, i32) ++DEF_HELPER_3(movreg2cf_i32, void, env, i32, i32) ++DEF_HELPER_3(movreg2cf_i64, void, env, i32, i64) ++ ++DEF_HELPER_2(cto_w, tl, env, tl) ++DEF_HELPER_2(ctz_w, tl, env, tl) ++DEF_HELPER_2(cto_d, tl, env, tl) ++DEF_HELPER_2(ctz_d, tl, env, tl) ++DEF_HELPER_2(bitrev_w, tl, env, tl) ++DEF_HELPER_2(bitrev_d, tl, env, tl) ++ ++DEF_HELPER_2(load_scr, i64, env, i32) ++DEF_HELPER_3(store_scr, void, env, i32, i64) ++ ++DEF_HELPER_3(asrtle_d, void, env, tl, tl) ++DEF_HELPER_3(asrtgt_d, void, env, tl, tl) ++ ++DEF_HELPER_4(fsel, i64, env, i64, i64, i32) ++ ++#ifndef CONFIG_USER_ONLY ++DEF_HELPER_4(iocsr, void, env, tl, tl, i32) ++#endif ++DEF_HELPER_3(memtrace_addr, void, env, tl, i32) ++DEF_HELPER_2(memtrace_val, void, env, tl) +diff --git a/target/loongarch64/insn.decode b/target/loongarch64/insn.decode +new file mode 100644 +index 0000000000..2f82441ea7 +--- /dev/null ++++ b/target/loongarch64/insn.decode +@@ -0,0 +1,532 @@ ++# ++# loongarch ISA decode for 64-bit prefixed insns ++# ++# Copyright (c) 2023 Loongarch Technology ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2 or later, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program. If not, see . ++# ++ ++# Fields ++%sd 0:2 ++%rj 5:5 ++%rd 0:5 ++%sj 5:2 ++%ptr 5:3 ++%rk 10:5 ++%sa2 15:2 ++%sa3 15:3 ++%si5 10:s5 ++%code 0:15 ++%cond 10:4 ++%cond2 0:4 ++%ui5 10:5 ++%ui6 10:6 ++%ui3 10:3 ++%ui4 10:4 ++%op 5:5 ++%ui8 10:8 ++%msbw 16:5 ++%lsbw 10:5 ++%msbd 16:6 ++%lsbd 10:6 ++%fd 0:5 ++%fj 5:5 ++%fk 10:5 ++%fcsrd 0:5 ++%fcsrs 5:5 ++%cd 0:3 ++%cj 5:3 ++%si12 10:s12 ++%ui12 10:12 ++%csr 10:14 ++%cop 0:5 ++%level 10:8 ++%seq 10:8 ++%whint 0:15 ++%addr 10:5 ++%info 5:5 ++%invop 0:5 ++%fa 15:5 ++%vd 0:5 ++%vj 5:5 ++%vk 10:5 ++%va 15:5 ++%xd 0:5 ++%xj 5:5 ++%xk 10:5 ++%xa 15:5 ++%fcond 15:5 ++%ca 15:3 ++%vui5 15:5 ++%si16 10:s16 ++%si20 5:s20 ++%si14 10:s14 ++%hint 0:5 ++%si9 10:s9 ++%si10 10:s10 ++%si11 10:s11 ++%si8 10:s8 ++%idx1 18:1 ++%idx2 18:2 ++%idx3 18:3 ++%idx4 18:4 ++%idx 18:5 ++%offs21 0:s5 10:16 ++%offs16 10:s16 ++%offs 0:s10 10:16 ++%mode 5:5 ++%ui2 10:2 ++%ui1 10:1 ++%ui7 10:7 ++%i13 5:13 ++ ++# Argument sets ++&fmt_sdrj sd rj ++&fmt_rdsj rd sj ++&fmt_rdrj rd rj ++&fmt_empty ++&fmt_rjrk rj rk ++&fmt_rdrjrksa2 rd rj rk sa2 ++&fmt_rdrjrksa3 rd rj rk sa3 ++&fmt_rdrjrk rd rj rk ++&fmt_code code ++&fmt_rdrjui5 rd rj ui5 ++&fmt_rdrjui6 rd rj ui6 ++&fmt_rdrjmsbwlsbw rd rj msbw lsbw ++&fmt_rdrjmsbdlsbd rd rj msbd lsbd ++&fmt_fdfjfk fd fj fk ++&fmt_fdfj fd fj ++&fmt_fdrj fd rj ++&fmt_rdfj rd fj ++&fmt_fcsrdrj fcsrd rj ++&fmt_rdfcsrs rd fcsrs ++&fmt_cdfj cd fj ++&fmt_fdcj fd cj ++&fmt_cdrj cd rj ++&fmt_rdcj rd cj ++&fmt_rdrjsi12 rd rj si12 ++&fmt_rdrjui12 rd rj ui12 ++&fmt_rdrjcsr rd rj csr ++&fmt_coprjsi12 cop rj si12 ++&fmt_rdrjlevel rd rj level ++&fmt_rjseq rj seq ++&fmt_whint whint ++&fmt_invtlb addr info invop ++&fmt_fdfjfkfa fd fj fk fa ++&fmt_cdfjfkfcond cd fj fk fcond ++&fmt_fdfjfkca fd fj fk ca ++&fmt_rdrjsi16 rd rj si16 ++&fmt_rdsi20 rd si20 ++&fmt_rdrjsi14 rd rj si14 ++&fmt_hintrjsi12 hint rj si12 ++&fmt_fdrjsi12 fd rj si12 ++&fmt_fdrjrk fd rj rk ++&fmt_rjoffs21 rj offs21 ++&fmt_cjoffs21 cj offs21 ++&fmt_rdrjoffs16 rd rj offs16 ++&fmt_offs offs ++&fmt_rjrdoffs16 rj rd offs16 ++ ++# Formats ++@fmt_sdrj .... ........ ..... ..... ..... ... .. &fmt_sdrj %sd %rj ++@fmt_rdsj .... ........ ..... ..... ... .. ..... &fmt_rdsj %rd %sj ++@fmt_rdrj .... ........ ..... ..... ..... ..... &fmt_rdrj %rd %rj ++@fmt_empty .... ........ ..... ..... ..... ..... &fmt_empty ++@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk ++@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2 ++@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3 ++@fmt_rdrjrk .... ........ ..... ..... ..... ..... &fmt_rdrjrk %rd %rj %rk ++@fmt_code .... ........ ..... ............... &fmt_code %code ++@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5 ++@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6 ++@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw ++@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd ++@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk ++@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj ++@fmt_fdrj .... ........ ..... ..... ..... ..... &fmt_fdrj %fd %rj ++@fmt_rdfj .... ........ ..... ..... ..... ..... &fmt_rdfj %rd %fj ++@fmt_fcsrdrj .... ........ ..... ..... ..... ..... &fmt_fcsrdrj %fcsrd %rj ++@fmt_rdfcsrs .... ........ ..... ..... ..... ..... &fmt_rdfcsrs %rd %fcsrs ++@fmt_cdfj .... ........ ..... ..... ..... .. ... &fmt_cdfj %cd %fj ++@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj ++@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj ++@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj ++@fmt_rdrjsi12 .... ...... ............ ..... ..... &fmt_rdrjsi12 %rd %rj %si12 ++@fmt_rdrjui12 .... ...... ............ ..... ..... &fmt_rdrjui12 %rd %rj %ui12 ++@fmt_rdrjcsr .... .... .............. ..... ..... &fmt_rdrjcsr %rd %rj %csr ++@fmt_coprjsi12 .... ...... ............ ..... ..... &fmt_coprjsi12 %cop %rj %si12 ++@fmt_rdrjlevel .... ........ .. ........ ..... ..... &fmt_rdrjlevel %rd %rj %level ++@fmt_rjseq .... ........ .. ........ ..... ..... &fmt_rjseq %rj %seq ++@fmt_whint .... ........ ..... ............... &fmt_whint %whint ++@fmt_invtlb ...... ...... ..... ..... ..... ..... &fmt_invtlb %addr %info %invop ++@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa ++@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond ++@fmt_fdfjfkca .... ........ .. ... ..... ..... ..... &fmt_fdfjfkca %fd %fj %fk %ca ++@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16 ++@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 ++@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 ++@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12 ++@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12 ++@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk ++@fmt_rjoffs21 .... .. ................ ..... ..... &fmt_rjoffs21 %rj %offs21 ++@fmt_cjoffs21 .... .. ................ .. ... ..... &fmt_cjoffs21 %cj %offs21 ++@fmt_rdrjoffs16 .... .. ................ ..... ..... &fmt_rdrjoffs16 %rd %rj %offs16 ++@fmt_offs .... .. .......................... &fmt_offs %offs ++@fmt_rjrdoffs16 .... .. ................ ..... ..... &fmt_rjrdoffs16 %rj %rd %offs16 ++ ++# Instructions ++ ++# Fiexd point arithmetic Instructions ++gr2scr 0000 00000000 00000 00010 ..... 000 .. @fmt_sdrj ++scr2gr 0000 00000000 00000 00011 000 .. ..... @fmt_rdsj ++clo_w 0000 00000000 00000 00100 ..... ..... @fmt_rdrj ++clz_w 0000 00000000 00000 00101 ..... ..... @fmt_rdrj ++cto_w 0000 00000000 00000 00110 ..... ..... @fmt_rdrj ++ctz_w 0000 00000000 00000 00111 ..... ..... @fmt_rdrj ++clo_d 0000 00000000 00000 01000 ..... ..... @fmt_rdrj ++clz_d 0000 00000000 00000 01001 ..... ..... @fmt_rdrj ++cto_d 0000 00000000 00000 01010 ..... ..... @fmt_rdrj ++ctz_d 0000 00000000 00000 01011 ..... ..... @fmt_rdrj ++revb_2h 0000 00000000 00000 01100 ..... ..... @fmt_rdrj ++revb_4h 0000 00000000 00000 01101 ..... ..... @fmt_rdrj ++revb_2w 0000 00000000 00000 01110 ..... ..... @fmt_rdrj ++revb_d 0000 00000000 00000 01111 ..... ..... @fmt_rdrj ++revh_2w 0000 00000000 00000 10000 ..... ..... @fmt_rdrj ++revh_d 0000 00000000 00000 10001 ..... ..... @fmt_rdrj ++bitrev_4b 0000 00000000 00000 10010 ..... ..... @fmt_rdrj ++bitrev_8b 0000 00000000 00000 10011 ..... ..... @fmt_rdrj ++bitrev_w 0000 00000000 00000 10100 ..... ..... @fmt_rdrj ++bitrev_d 0000 00000000 00000 10101 ..... ..... @fmt_rdrj ++ext_w_h 0000 00000000 00000 10110 ..... ..... @fmt_rdrj ++ext_w_b 0000 00000000 00000 10111 ..... ..... @fmt_rdrj ++rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj ++cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj ++asrtle_d 0000 00000000 00010 ..... ..... 00000 @fmt_rjrk ++asrtgt_d 0000 00000000 00011 ..... ..... 00000 @fmt_rjrk ++alsl_w 0000 00000000 010 .. ..... ..... ..... @fmt_rdrjrksa2 ++alsl_wu 0000 00000000 011 .. ..... ..... ..... @fmt_rdrjrksa2 ++bytepick_w 0000 00000000 100 .. ..... ..... ..... @fmt_rdrjrksa2 ++bytepick_d 0000 00000000 11 ... ..... ..... ..... @fmt_rdrjrksa3 ++add_w 0000 00000001 00000 ..... ..... ..... @fmt_rdrjrk ++add_d 0000 00000001 00001 ..... ..... ..... @fmt_rdrjrk ++sub_w 0000 00000001 00010 ..... ..... ..... @fmt_rdrjrk ++sub_d 0000 00000001 00011 ..... ..... ..... @fmt_rdrjrk ++slt 0000 00000001 00100 ..... ..... ..... @fmt_rdrjrk ++sltu 0000 00000001 00101 ..... ..... ..... @fmt_rdrjrk ++maskeqz 0000 00000001 00110 ..... ..... ..... @fmt_rdrjrk ++masknez 0000 00000001 00111 ..... ..... ..... @fmt_rdrjrk ++nor 0000 00000001 01000 ..... ..... ..... @fmt_rdrjrk ++and 0000 00000001 01001 ..... ..... ..... @fmt_rdrjrk ++or 0000 00000001 01010 ..... ..... ..... @fmt_rdrjrk ++xor 0000 00000001 01011 ..... ..... ..... @fmt_rdrjrk ++orn 0000 00000001 01100 ..... ..... ..... @fmt_rdrjrk ++andn 0000 00000001 01101 ..... ..... ..... @fmt_rdrjrk ++sll_w 0000 00000001 01110 ..... ..... ..... @fmt_rdrjrk ++srl_w 0000 00000001 01111 ..... ..... ..... @fmt_rdrjrk ++sra_w 0000 00000001 10000 ..... ..... ..... @fmt_rdrjrk ++sll_d 0000 00000001 10001 ..... ..... ..... @fmt_rdrjrk ++srl_d 0000 00000001 10010 ..... ..... ..... @fmt_rdrjrk ++sra_d 0000 00000001 10011 ..... ..... ..... @fmt_rdrjrk ++rotr_w 0000 00000001 10110 ..... ..... ..... @fmt_rdrjrk ++rotr_d 0000 00000001 10111 ..... ..... ..... @fmt_rdrjrk ++mul_w 0000 00000001 11000 ..... ..... ..... @fmt_rdrjrk ++mulh_w 0000 00000001 11001 ..... ..... ..... @fmt_rdrjrk ++mulh_wu 0000 00000001 11010 ..... ..... ..... @fmt_rdrjrk ++mul_d 0000 00000001 11011 ..... ..... ..... @fmt_rdrjrk ++mulh_d 0000 00000001 11100 ..... ..... ..... @fmt_rdrjrk ++mulh_du 0000 00000001 11101 ..... ..... ..... @fmt_rdrjrk ++mulw_d_w 0000 00000001 11110 ..... ..... ..... @fmt_rdrjrk ++mulw_d_wu 0000 00000001 11111 ..... ..... ..... @fmt_rdrjrk ++div_w 0000 00000010 00000 ..... ..... ..... @fmt_rdrjrk ++mod_w 0000 00000010 00001 ..... ..... ..... @fmt_rdrjrk ++div_wu 0000 00000010 00010 ..... ..... ..... @fmt_rdrjrk ++mod_wu 0000 00000010 00011 ..... ..... ..... @fmt_rdrjrk ++div_d 0000 00000010 00100 ..... ..... ..... @fmt_rdrjrk ++mod_d 0000 00000010 00101 ..... ..... ..... @fmt_rdrjrk ++div_du 0000 00000010 00110 ..... ..... ..... @fmt_rdrjrk ++mod_du 0000 00000010 00111 ..... ..... ..... @fmt_rdrjrk ++crc_w_b_w 0000 00000010 01000 ..... ..... ..... @fmt_rdrjrk ++crc_w_h_w 0000 00000010 01001 ..... ..... ..... @fmt_rdrjrk ++crc_w_w_w 0000 00000010 01010 ..... ..... ..... @fmt_rdrjrk ++crc_w_d_w 0000 00000010 01011 ..... ..... ..... @fmt_rdrjrk ++crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @fmt_rdrjrk ++crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @fmt_rdrjrk ++crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @fmt_rdrjrk ++crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @fmt_rdrjrk ++break 0000 00000010 10100 ............... @fmt_code ++dbcl 0000 00000010 10101 ............... @fmt_code ++syscall 0000 00000010 10110 ............... @fmt_code ++alsl_d 0000 00000010 110 .. ..... ..... ..... @fmt_rdrjrksa2 ++slli_w 0000 00000100 00001 ..... ..... ..... @fmt_rdrjui5 ++slli_d 0000 00000100 0001 ...... ..... ..... @fmt_rdrjui6 ++srli_w 0000 00000100 01001 ..... ..... ..... @fmt_rdrjui5 ++srli_d 0000 00000100 0101 ...... ..... ..... @fmt_rdrjui6 ++srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5 ++srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6 ++rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5 ++rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6 ++bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw ++bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw ++bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd ++bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd ++ ++# float Instructions ++fadd_s 0000 00010000 00001 ..... ..... ..... @fmt_fdfjfk ++fadd_d 0000 00010000 00010 ..... ..... ..... @fmt_fdfjfk ++fsub_s 0000 00010000 00101 ..... ..... ..... @fmt_fdfjfk ++fsub_d 0000 00010000 00110 ..... ..... ..... @fmt_fdfjfk ++fmul_s 0000 00010000 01001 ..... ..... ..... @fmt_fdfjfk ++fmul_d 0000 00010000 01010 ..... ..... ..... @fmt_fdfjfk ++fdiv_s 0000 00010000 01101 ..... ..... ..... @fmt_fdfjfk ++fdiv_d 0000 00010000 01110 ..... ..... ..... @fmt_fdfjfk ++fmax_s 0000 00010000 10001 ..... ..... ..... @fmt_fdfjfk ++fmax_d 0000 00010000 10010 ..... ..... ..... @fmt_fdfjfk ++fmin_s 0000 00010000 10101 ..... ..... ..... @fmt_fdfjfk ++fmin_d 0000 00010000 10110 ..... ..... ..... @fmt_fdfjfk ++fmaxa_s 0000 00010000 11001 ..... ..... ..... @fmt_fdfjfk ++fmaxa_d 0000 00010000 11010 ..... ..... ..... @fmt_fdfjfk ++fmina_s 0000 00010000 11101 ..... ..... ..... @fmt_fdfjfk ++fmina_d 0000 00010000 11110 ..... ..... ..... @fmt_fdfjfk ++fscaleb_s 0000 00010001 00001 ..... ..... ..... @fmt_fdfjfk ++fscaleb_d 0000 00010001 00010 ..... ..... ..... @fmt_fdfjfk ++fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk ++fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk ++fabs_s 0000 00010001 01000 00001 ..... ..... @fmt_fdfj ++fabs_d 0000 00010001 01000 00010 ..... ..... @fmt_fdfj ++fneg_s 0000 00010001 01000 00101 ..... ..... @fmt_fdfj ++fneg_d 0000 00010001 01000 00110 ..... ..... @fmt_fdfj ++flogb_s 0000 00010001 01000 01001 ..... ..... @fmt_fdfj ++flogb_d 0000 00010001 01000 01010 ..... ..... @fmt_fdfj ++fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj ++fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj ++fsqrt_s 0000 00010001 01000 10001 ..... ..... @fmt_fdfj ++fsqrt_d 0000 00010001 01000 10010 ..... ..... @fmt_fdfj ++frecip_s 0000 00010001 01000 10101 ..... ..... @fmt_fdfj ++frecip_d 0000 00010001 01000 10110 ..... ..... @fmt_fdfj ++frsqrt_s 0000 00010001 01000 11001 ..... ..... @fmt_fdfj ++frsqrt_d 0000 00010001 01000 11010 ..... ..... @fmt_fdfj ++fmov_s 0000 00010001 01001 00101 ..... ..... @fmt_fdfj ++fmov_d 0000 00010001 01001 00110 ..... ..... @fmt_fdfj ++movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fmt_fdrj ++movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fmt_fdrj ++movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fmt_fdrj ++movfr2gr_s 0000 00010001 01001 01101 ..... ..... @fmt_rdfj ++movfr2gr_d 0000 00010001 01001 01110 ..... ..... @fmt_rdfj ++movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @fmt_rdfj ++movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fmt_fcsrdrj ++movfcsr2gr 0000 00010001 01001 10010 ..... ..... @fmt_rdfcsrs ++movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj ++movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj ++movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj ++movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj ++fcvt_s_d 0000 00010001 10010 00110 ..... ..... @fmt_fdfj ++fcvt_d_s 0000 00010001 10010 01001 ..... ..... @fmt_fdfj ++ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @fmt_fdfj ++ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @fmt_fdfj ++ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @fmt_fdfj ++ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @fmt_fdfj ++ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @fmt_fdfj ++ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @fmt_fdfj ++ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @fmt_fdfj ++ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @fmt_fdfj ++ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @fmt_fdfj ++ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @fmt_fdfj ++ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @fmt_fdfj ++ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @fmt_fdfj ++ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @fmt_fdfj ++ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @fmt_fdfj ++ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @fmt_fdfj ++ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @fmt_fdfj ++ftint_w_s 0000 00010001 10110 00001 ..... ..... @fmt_fdfj ++ftint_w_d 0000 00010001 10110 00010 ..... ..... @fmt_fdfj ++ftint_l_s 0000 00010001 10110 01001 ..... ..... @fmt_fdfj ++ftint_l_d 0000 00010001 10110 01010 ..... ..... @fmt_fdfj ++ffint_s_w 0000 00010001 11010 00100 ..... ..... @fmt_fdfj ++ffint_s_l 0000 00010001 11010 00110 ..... ..... @fmt_fdfj ++ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj ++ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj ++frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj ++frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj ++ ++# 12 bit immediate Instructions ++slti 0000 001000 ............ ..... ..... @fmt_rdrjsi12 ++sltui 0000 001001 ............ ..... ..... @fmt_rdrjsi12 ++addi_w 0000 001010 ............ ..... ..... @fmt_rdrjsi12 ++addi_d 0000 001011 ............ ..... ..... @fmt_rdrjsi12 ++lu52i_d 0000 001100 ............ ..... ..... @fmt_rdrjsi12 ++andi 0000 001101 ............ ..... ..... @fmt_rdrjui12 ++ori 0000 001110 ............ ..... ..... @fmt_rdrjui12 ++xori 0000 001111 ............ ..... ..... @fmt_rdrjui12 ++ ++# core Instructions ++csrxchg 0000 0100 .............. ..... ..... @fmt_rdrjcsr ++cacop 0000 011000 ............ ..... ..... @fmt_coprjsi12 ++lddir 0000 01100100 00 ........ ..... ..... @fmt_rdrjlevel ++ldpte 0000 01100100 01 ........ ..... 00000 @fmt_rjseq ++iocsrrd_b 0000 01100100 10000 00000 ..... ..... @fmt_rdrj ++iocsrrd_h 0000 01100100 10000 00001 ..... ..... @fmt_rdrj ++iocsrrd_w 0000 01100100 10000 00010 ..... ..... @fmt_rdrj ++iocsrrd_d 0000 01100100 10000 00011 ..... ..... @fmt_rdrj ++iocsrwr_b 0000 01100100 10000 00100 ..... ..... @fmt_rdrj ++iocsrwr_h 0000 01100100 10000 00101 ..... ..... @fmt_rdrj ++iocsrwr_w 0000 01100100 10000 00110 ..... ..... @fmt_rdrj ++iocsrwr_d 0000 01100100 10000 00111 ..... ..... @fmt_rdrj ++tlbclr 0000 01100100 10000 01000 00000 00000 @fmt_empty ++tlbflush 0000 01100100 10000 01001 00000 00000 @fmt_empty ++tlbsrch 0000 01100100 10000 01010 00000 00000 @fmt_empty ++tlbrd 0000 01100100 10000 01011 00000 00000 @fmt_empty ++tlbwr 0000 01100100 10000 01100 00000 00000 @fmt_empty ++tlbfill 0000 01100100 10000 01101 00000 00000 @fmt_empty ++ertn 0000 01100100 10000 01110 00000 00000 @fmt_empty ++idle 0000 01100100 10001 ............... @fmt_whint ++invtlb 0000 01100100 10011 ..... ..... ..... @fmt_invtlb ++ ++# foure Op Instructions ++fmadd_s 0000 10000001 ..... ..... ..... ..... @fmt_fdfjfkfa ++fmadd_d 0000 10000010 ..... ..... ..... ..... @fmt_fdfjfkfa ++fmsub_s 0000 10000101 ..... ..... ..... ..... @fmt_fdfjfkfa ++fmsub_d 0000 10000110 ..... ..... ..... ..... @fmt_fdfjfkfa ++fnmadd_s 0000 10001001 ..... ..... ..... ..... @fmt_fdfjfkfa ++fnmadd_d 0000 10001010 ..... ..... ..... ..... @fmt_fdfjfkfa ++fnmsub_s 0000 10001101 ..... ..... ..... ..... @fmt_fdfjfkfa ++fnmsub_d 0000 10001110 ..... ..... ..... ..... @fmt_fdfjfkfa ++fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond ++fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond ++fsel 0000 11010000 00 ... ..... ..... ..... @fmt_fdfjfkca ++ ++# loog immediate Instructions ++addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16 ++lu12i_w 0001 010 .................... ..... @fmt_rdsi20 ++lu32i_d 0001 011 .................... ..... @fmt_rdsi20 ++pcaddi 0001 100 .................... ..... @fmt_rdsi20 ++pcalau12i 0001 101 .................... ..... @fmt_rdsi20 ++pcaddu12i 0001 110 .................... ..... @fmt_rdsi20 ++pcaddu18i 0001 111 .................... ..... @fmt_rdsi20 ++ ++# load/store Instructions ++ll_w 0010 0000 .............. ..... ..... @fmt_rdrjsi14 ++sc_w 0010 0001 .............. ..... ..... @fmt_rdrjsi14 ++ll_d 0010 0010 .............. ..... ..... @fmt_rdrjsi14 ++sc_d 0010 0011 .............. ..... ..... @fmt_rdrjsi14 ++ldptr_w 0010 0100 .............. ..... ..... @fmt_rdrjsi14 ++stptr_w 0010 0101 .............. ..... ..... @fmt_rdrjsi14 ++ldptr_d 0010 0110 .............. ..... ..... @fmt_rdrjsi14 ++stptr_d 0010 0111 .............. ..... ..... @fmt_rdrjsi14 ++ld_b 0010 100000 ............ ..... ..... @fmt_rdrjsi12 ++ld_h 0010 100001 ............ ..... ..... @fmt_rdrjsi12 ++ld_w 0010 100010 ............ ..... ..... @fmt_rdrjsi12 ++ld_d 0010 100011 ............ ..... ..... @fmt_rdrjsi12 ++st_b 0010 100100 ............ ..... ..... @fmt_rdrjsi12 ++st_h 0010 100101 ............ ..... ..... @fmt_rdrjsi12 ++st_w 0010 100110 ............ ..... ..... @fmt_rdrjsi12 ++st_d 0010 100111 ............ ..... ..... @fmt_rdrjsi12 ++ld_bu 0010 101000 ............ ..... ..... @fmt_rdrjsi12 ++ld_hu 0010 101001 ............ ..... ..... @fmt_rdrjsi12 ++ld_wu 0010 101010 ............ ..... ..... @fmt_rdrjsi12 ++preld 0010 101011 ............ ..... ..... @fmt_hintrjsi12 ++fld_s 0010 101100 ............ ..... ..... @fmt_fdrjsi12 ++fst_s 0010 101101 ............ ..... ..... @fmt_fdrjsi12 ++fld_d 0010 101110 ............ ..... ..... @fmt_fdrjsi12 ++fst_d 0010 101111 ............ ..... ..... @fmt_fdrjsi12 ++ldx_b 0011 10000000 00000 ..... ..... ..... @fmt_rdrjrk ++ldx_h 0011 10000000 01000 ..... ..... ..... @fmt_rdrjrk ++ldx_w 0011 10000000 10000 ..... ..... ..... @fmt_rdrjrk ++ldx_d 0011 10000000 11000 ..... ..... ..... @fmt_rdrjrk ++stx_b 0011 10000001 00000 ..... ..... ..... @fmt_rdrjrk ++stx_h 0011 10000001 01000 ..... ..... ..... @fmt_rdrjrk ++stx_w 0011 10000001 10000 ..... ..... ..... @fmt_rdrjrk ++stx_d 0011 10000001 11000 ..... ..... ..... @fmt_rdrjrk ++ldx_bu 0011 10000010 00000 ..... ..... ..... @fmt_rdrjrk ++ldx_hu 0011 10000010 01000 ..... ..... ..... @fmt_rdrjrk ++ldx_wu 0011 10000010 10000 ..... ..... ..... @fmt_rdrjrk ++fldx_s 0011 10000011 00000 ..... ..... ..... @fmt_fdrjrk ++fldx_d 0011 10000011 01000 ..... ..... ..... @fmt_fdrjrk ++fstx_s 0011 10000011 10000 ..... ..... ..... @fmt_fdrjrk ++fstx_d 0011 10000011 11000 ..... ..... ..... @fmt_fdrjrk ++amswap_w 0011 10000110 00000 ..... ..... ..... @fmt_rdrjrk ++amswap_d 0011 10000110 00001 ..... ..... ..... @fmt_rdrjrk ++amadd_w 0011 10000110 00010 ..... ..... ..... @fmt_rdrjrk ++amadd_d 0011 10000110 00011 ..... ..... ..... @fmt_rdrjrk ++amand_w 0011 10000110 00100 ..... ..... ..... @fmt_rdrjrk ++amand_d 0011 10000110 00101 ..... ..... ..... @fmt_rdrjrk ++amor_w 0011 10000110 00110 ..... ..... ..... @fmt_rdrjrk ++amor_d 0011 10000110 00111 ..... ..... ..... @fmt_rdrjrk ++amxor_w 0011 10000110 01000 ..... ..... ..... @fmt_rdrjrk ++amxor_d 0011 10000110 01001 ..... ..... ..... @fmt_rdrjrk ++ammax_w 0011 10000110 01010 ..... ..... ..... @fmt_rdrjrk ++ammax_d 0011 10000110 01011 ..... ..... ..... @fmt_rdrjrk ++ammin_w 0011 10000110 01100 ..... ..... ..... @fmt_rdrjrk ++ammin_d 0011 10000110 01101 ..... ..... ..... @fmt_rdrjrk ++ammax_wu 0011 10000110 01110 ..... ..... ..... @fmt_rdrjrk ++ammax_du 0011 10000110 01111 ..... ..... ..... @fmt_rdrjrk ++ammin_wu 0011 10000110 10000 ..... ..... ..... @fmt_rdrjrk ++ammin_du 0011 10000110 10001 ..... ..... ..... @fmt_rdrjrk ++amswap_db_w 0011 10000110 10010 ..... ..... ..... @fmt_rdrjrk ++amswap_db_d 0011 10000110 10011 ..... ..... ..... @fmt_rdrjrk ++amadd_db_w 0011 10000110 10100 ..... ..... ..... @fmt_rdrjrk ++amadd_db_d 0011 10000110 10101 ..... ..... ..... @fmt_rdrjrk ++amand_db_w 0011 10000110 10110 ..... ..... ..... @fmt_rdrjrk ++amand_db_d 0011 10000110 10111 ..... ..... ..... @fmt_rdrjrk ++amor_db_w 0011 10000110 11000 ..... ..... ..... @fmt_rdrjrk ++amor_db_d 0011 10000110 11001 ..... ..... ..... @fmt_rdrjrk ++amxor_db_w 0011 10000110 11010 ..... ..... ..... @fmt_rdrjrk ++amxor_db_d 0011 10000110 11011 ..... ..... ..... @fmt_rdrjrk ++ammax_db_w 0011 10000110 11100 ..... ..... ..... @fmt_rdrjrk ++ammax_db_d 0011 10000110 11101 ..... ..... ..... @fmt_rdrjrk ++ammin_db_w 0011 10000110 11110 ..... ..... ..... @fmt_rdrjrk ++ammin_db_d 0011 10000110 11111 ..... ..... ..... @fmt_rdrjrk ++ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk ++ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk ++ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk ++ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk ++dbar 0011 10000111 00100 ............... @fmt_whint ++ibar 0011 10000111 00101 ............... @fmt_whint ++fldgt_s 0011 10000111 01000 ..... ..... ..... @fmt_fdrjrk ++fldgt_d 0011 10000111 01001 ..... ..... ..... @fmt_fdrjrk ++fldle_s 0011 10000111 01010 ..... ..... ..... @fmt_fdrjrk ++fldle_d 0011 10000111 01011 ..... ..... ..... @fmt_fdrjrk ++fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk ++fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk ++fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk ++fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk ++ldgt_b 0011 10000111 10000 ..... ..... ..... @fmt_rdrjrk ++ldgt_h 0011 10000111 10001 ..... ..... ..... @fmt_rdrjrk ++ldgt_w 0011 10000111 10010 ..... ..... ..... @fmt_rdrjrk ++ldgt_d 0011 10000111 10011 ..... ..... ..... @fmt_rdrjrk ++ldle_b 0011 10000111 10100 ..... ..... ..... @fmt_rdrjrk ++ldle_h 0011 10000111 10101 ..... ..... ..... @fmt_rdrjrk ++ldle_w 0011 10000111 10110 ..... ..... ..... @fmt_rdrjrk ++ldle_d 0011 10000111 10111 ..... ..... ..... @fmt_rdrjrk ++stgt_b 0011 10000111 11000 ..... ..... ..... @fmt_rdrjrk ++stgt_h 0011 10000111 11001 ..... ..... ..... @fmt_rdrjrk ++stgt_w 0011 10000111 11010 ..... ..... ..... @fmt_rdrjrk ++stgt_d 0011 10000111 11011 ..... ..... ..... @fmt_rdrjrk ++stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk ++stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk ++stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk ++stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk ++ ++# jump Instructions ++beqz 0100 00 ................ ..... ..... @fmt_rjoffs21 ++bnez 0100 01 ................ ..... ..... @fmt_rjoffs21 ++bceqz 0100 10 ................ 00 ... ..... @fmt_cjoffs21 ++bcnez 0100 10 ................ 01 ... ..... @fmt_cjoffs21 ++jirl 0100 11 ................ ..... ..... @fmt_rdrjoffs16 ++b 0101 00 .......................... @fmt_offs ++bl 0101 01 .......................... @fmt_offs ++beq 0101 10 ................ ..... ..... @fmt_rjrdoffs16 ++bne 0101 11 ................ ..... ..... @fmt_rjrdoffs16 ++blt 0110 00 ................ ..... ..... @fmt_rjrdoffs16 ++bge 0110 01 ................ ..... ..... @fmt_rjrdoffs16 ++bltu 0110 10 ................ ..... ..... @fmt_rjrdoffs16 ++bgeu 0110 11 ................ ..... ..... @fmt_rjrdoffs16 +diff --git a/target/loongarch64/instmap.h b/target/loongarch64/instmap.h +new file mode 100644 +index 0000000000..5fbb8b5d29 +--- /dev/null ++++ b/target/loongarch64/instmap.h +@@ -0,0 +1,217 @@ ++/* ++ * Loongarch emulation for qemu: instruction opcode ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef TARGET_LARCH_INSTMAP_H ++#define TARGET_LARCH_INSTMAP_H ++ ++enum { ++ /* fix opcodes */ ++ OPC_LARCH_CLO_W = (0x000004 << 10), ++ OPC_LARCH_CLZ_W = (0x000005 << 10), ++ OPC_LARCH_CLO_D = (0x000008 << 10), ++ OPC_LARCH_CLZ_D = (0x000009 << 10), ++ OPC_LARCH_REVB_2H = (0x00000C << 10), ++ OPC_LARCH_REVB_4H = (0x00000D << 10), ++ OPC_LARCH_REVH_D = (0x000011 << 10), ++ OPC_LARCH_BREV_4B = (0x000012 << 10), ++ OPC_LARCH_BREV_8B = (0x000013 << 10), ++ OPC_LARCH_EXT_WH = (0x000016 << 10), ++ OPC_LARCH_EXT_WB = (0x000017 << 10), ++ ++ OPC_LARCH_ADD_W = (0x00020 << 15), ++ OPC_LARCH_ADD_D = (0x00021 << 15), ++ OPC_LARCH_SUB_W = (0x00022 << 15), ++ OPC_LARCH_SUB_D = (0x00023 << 15), ++ OPC_LARCH_SLT = (0x00024 << 15), ++ OPC_LARCH_SLTU = (0x00025 << 15), ++ OPC_LARCH_MASKEQZ = (0x00026 << 15), ++ OPC_LARCH_MASKNEZ = (0x00027 << 15), ++ OPC_LARCH_NOR = (0x00028 << 15), ++ OPC_LARCH_AND = (0x00029 << 15), ++ OPC_LARCH_OR = (0x0002A << 15), ++ OPC_LARCH_XOR = (0x0002B << 15), ++ OPC_LARCH_SLL_W = (0x0002E << 15), ++ OPC_LARCH_SRL_W = (0x0002F << 15), ++ OPC_LARCH_SRA_W = (0x00030 << 15), ++ OPC_LARCH_SLL_D = (0x00031 << 15), ++ OPC_LARCH_SRL_D = (0x00032 << 15), ++ OPC_LARCH_SRA_D = (0x00033 << 15), ++ OPC_LARCH_ROTR_W = (0x00036 << 15), ++ OPC_LARCH_ROTR_D = (0x00037 << 15), ++ OPC_LARCH_MUL_W = (0x00038 << 15), ++ OPC_LARCH_MULH_W = (0x00039 << 15), ++ OPC_LARCH_MULH_WU = (0x0003A << 15), ++ OPC_LARCH_MUL_D = (0x0003B << 15), ++ OPC_LARCH_MULH_D = (0x0003C << 15), ++ OPC_LARCH_MULH_DU = (0x0003D << 15), ++ OPC_LARCH_DIV_W = (0x00040 << 15), ++ OPC_LARCH_MOD_W = (0x00041 << 15), ++ OPC_LARCH_DIV_WU = (0x00042 << 15), ++ OPC_LARCH_MOD_WU = (0x00043 << 15), ++ OPC_LARCH_DIV_D = (0x00044 << 15), ++ OPC_LARCH_MOD_D = (0x00045 << 15), ++ OPC_LARCH_DIV_DU = (0x00046 << 15), ++ OPC_LARCH_MOD_DU = (0x00047 << 15), ++ OPC_LARCH_SRLI_W = (0x00089 << 15), ++ OPC_LARCH_SRAI_W = (0x00091 << 15), ++ OPC_LARCH_ROTRI_W = (0x00099 << 15), ++ ++ OPC_LARCH_ALSL_W = (0x0002 << 17), ++ OPC_LARCH_ALSL_D = (0x0016 << 17), ++ ++ OPC_LARCH_TRINS_W = (0x003 << 21) | (0x0 << 15), ++ OPC_LARCH_TRPICK_W = (0x003 << 21) | (0x1 << 15), ++}; ++ ++enum { ++ /* float opcodes */ ++ OPC_LARCH_FABS_S = (0x004501 << 10), ++ OPC_LARCH_FABS_D = (0x004502 << 10), ++ OPC_LARCH_FNEG_S = (0x004505 << 10), ++ OPC_LARCH_FNEG_D = (0x004506 << 10), ++ OPC_LARCH_FCLASS_S = (0x00450D << 10), ++ OPC_LARCH_FCLASS_D = (0x00450E << 10), ++ OPC_LARCH_FSQRT_S = (0x004511 << 10), ++ OPC_LARCH_FSQRT_D = (0x004512 << 10), ++ OPC_LARCH_FRECIP_S = (0x004515 << 10), ++ OPC_LARCH_FRECIP_D = (0x004516 << 10), ++ OPC_LARCH_FRSQRT_S = (0x004519 << 10), ++ OPC_LARCH_FRSQRT_D = (0x00451A << 10), ++ OPC_LARCH_FMOV_S = (0x004525 << 10), ++ OPC_LARCH_FMOV_D = (0x004526 << 10), ++ OPC_LARCH_GR2FR_W = (0x004529 << 10), ++ OPC_LARCH_GR2FR_D = (0x00452A << 10), ++ OPC_LARCH_GR2FRH_W = (0x00452B << 10), ++ OPC_LARCH_FR2GR_S = (0x00452D << 10), ++ OPC_LARCH_FR2GR_D = (0x00452E << 10), ++ OPC_LARCH_FRH2GR_S = (0x00452F << 10), ++ ++ OPC_LARCH_FCVT_S_D = (0x004646 << 10), ++ OPC_LARCH_FCVT_D_S = (0x004649 << 10), ++ OPC_LARCH_FTINTRM_W_S = (0x004681 << 10), ++ OPC_LARCH_FTINTRM_W_D = (0x004682 << 10), ++ OPC_LARCH_FTINTRM_L_S = (0x004689 << 10), ++ OPC_LARCH_FTINTRM_L_D = (0x00468A << 10), ++ OPC_LARCH_FTINTRP_W_S = (0x004691 << 10), ++ OPC_LARCH_FTINTRP_W_D = (0x004692 << 10), ++ OPC_LARCH_FTINTRP_L_S = (0x004699 << 10), ++ OPC_LARCH_FTINTRP_L_D = (0x00469A << 10), ++ OPC_LARCH_FTINTRZ_W_S = (0x0046A1 << 10), ++ OPC_LARCH_FTINTRZ_W_D = (0x0046A2 << 10), ++ OPC_LARCH_FTINTRZ_L_S = (0x0046A9 << 10), ++ OPC_LARCH_FTINTRZ_L_D = (0x0046AA << 10), ++ OPC_LARCH_FTINTRNE_W_S = (0x0046B1 << 10), ++ OPC_LARCH_FTINTRNE_W_D = (0x0046B2 << 10), ++ OPC_LARCH_FTINTRNE_L_S = (0x0046B9 << 10), ++ OPC_LARCH_FTINTRNE_L_D = (0x0046BA << 10), ++ OPC_LARCH_FTINT_W_S = (0x0046C1 << 10), ++ OPC_LARCH_FTINT_W_D = (0x0046C2 << 10), ++ OPC_LARCH_FTINT_L_S = (0x0046C9 << 10), ++ OPC_LARCH_FTINT_L_D = (0x0046CA << 10), ++ OPC_LARCH_FFINT_S_W = (0x004744 << 10), ++ OPC_LARCH_FFINT_S_L = (0x004746 << 10), ++ OPC_LARCH_FFINT_D_W = (0x004748 << 10), ++ OPC_LARCH_FFINT_D_L = (0x00474A << 10), ++ OPC_LARCH_FRINT_S = (0x004791 << 10), ++ OPC_LARCH_FRINT_D = (0x004792 << 10), ++ ++ OPC_LARCH_FADD_S = (0x00201 << 15), ++ OPC_LARCH_FADD_D = (0x00202 << 15), ++ OPC_LARCH_FSUB_S = (0x00205 << 15), ++ OPC_LARCH_FSUB_D = (0x00206 << 15), ++ OPC_LARCH_FMUL_S = (0x00209 << 15), ++ OPC_LARCH_FMUL_D = (0x0020A << 15), ++ OPC_LARCH_FDIV_S = (0x0020D << 15), ++ OPC_LARCH_FDIV_D = (0x0020E << 15), ++ OPC_LARCH_FMAX_S = (0x00211 << 15), ++ OPC_LARCH_FMAX_D = (0x00212 << 15), ++ OPC_LARCH_FMIN_S = (0x00215 << 15), ++ OPC_LARCH_FMIN_D = (0x00216 << 15), ++ OPC_LARCH_FMAXA_S = (0x00219 << 15), ++ OPC_LARCH_FMAXA_D = (0x0021A << 15), ++ OPC_LARCH_FMINA_S = (0x0021D << 15), ++ OPC_LARCH_FMINA_D = (0x0021E << 15), ++}; ++ ++enum { ++ /* 12 bit immediate opcodes */ ++ OPC_LARCH_SLTI = (0x008 << 22), ++ OPC_LARCH_SLTIU = (0x009 << 22), ++ OPC_LARCH_ADDI_W = (0x00A << 22), ++ OPC_LARCH_ADDI_D = (0x00B << 22), ++ OPC_LARCH_ANDI = (0x00D << 22), ++ OPC_LARCH_ORI = (0x00E << 22), ++ OPC_LARCH_XORI = (0x00F << 22), ++}; ++ ++enum { ++ /* load/store opcodes */ ++ OPC_LARCH_FLDX_S = (0x07060 << 15), ++ OPC_LARCH_FLDX_D = (0x07068 << 15), ++ OPC_LARCH_FSTX_S = (0x07070 << 15), ++ OPC_LARCH_FSTX_D = (0x07078 << 15), ++ OPC_LARCH_FLDGT_S = (0x070E8 << 15), ++ OPC_LARCH_FLDGT_D = (0x070E9 << 15), ++ OPC_LARCH_FLDLE_S = (0x070EA << 15), ++ OPC_LARCH_FLDLE_D = (0x070EB << 15), ++ OPC_LARCH_FSTGT_S = (0x070EC << 15), ++ OPC_LARCH_FSTGT_D = (0x070ED << 15), ++ OPC_LARCH_FSTLE_S = (0x070EE << 15), ++ OPC_LARCH_FSTLE_D = (0x070EF << 15), ++ ++ OPC_LARCH_LD_B = (0x0A0 << 22), ++ OPC_LARCH_LD_H = (0x0A1 << 22), ++ OPC_LARCH_LD_W = (0x0A2 << 22), ++ OPC_LARCH_LD_D = (0x0A3 << 22), ++ OPC_LARCH_ST_B = (0x0A4 << 22), ++ OPC_LARCH_ST_H = (0x0A5 << 22), ++ OPC_LARCH_ST_W = (0x0A6 << 22), ++ OPC_LARCH_ST_D = (0x0A7 << 22), ++ OPC_LARCH_LD_BU = (0x0A8 << 22), ++ OPC_LARCH_LD_HU = (0x0A9 << 22), ++ OPC_LARCH_LD_WU = (0x0AA << 22), ++ OPC_LARCH_FLD_S = (0x0AC << 22), ++ OPC_LARCH_FST_S = (0x0AD << 22), ++ OPC_LARCH_FLD_D = (0x0AE << 22), ++ OPC_LARCH_FST_D = (0x0AF << 22), ++ ++ OPC_LARCH_LL_W = (0x20 << 24), ++ OPC_LARCH_SC_W = (0x21 << 24), ++ OPC_LARCH_LL_D = (0x22 << 24), ++ OPC_LARCH_SC_D = (0x23 << 24), ++ OPC_LARCH_LDPTR_W = (0x24 << 24), ++ OPC_LARCH_STPTR_W = (0x25 << 24), ++ OPC_LARCH_LDPTR_D = (0x26 << 24), ++ OPC_LARCH_STPTR_D = (0x27 << 24), ++}; ++ ++enum { ++ /* jump opcodes */ ++ OPC_LARCH_BEQZ = (0x10 << 26), ++ OPC_LARCH_BNEZ = (0x11 << 26), ++ OPC_LARCH_B = (0x14 << 26), ++ OPC_LARCH_BEQ = (0x16 << 26), ++ OPC_LARCH_BNE = (0x17 << 26), ++ OPC_LARCH_BLT = (0x18 << 26), ++ OPC_LARCH_BGE = (0x19 << 26), ++ OPC_LARCH_BLTU = (0x1A << 26), ++ OPC_LARCH_BGEU = (0x1B << 26), ++}; ++ ++#endif +diff --git a/target/loongarch64/internal.h b/target/loongarch64/internal.h +new file mode 100644 +index 0000000000..a51b7e6f56 +--- /dev/null ++++ b/target/loongarch64/internal.h +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_INTERNAL_H ++#define LOONGARCH_INTERNAL_H ++ ++#include "cpu-csr.h" ++ ++/* ++ * MMU types, the first four entries have the same layout as the ++ * CP0C0_MT field. ++ */ ++enum loongarch_mmu_types { ++ MMU_TYPE_NONE, ++ MMU_TYPE_LS3A5K, /* LISA CSR */ ++}; ++ ++struct loongarch_def_t { ++ const char *name; ++ int32_t CSR_PRid; ++ int32_t FCSR0; ++ int32_t FCSR0_rw_bitmask; ++ int32_t PABITS; ++ CPU_LOONGARCH_CSR ++ uint64_t insn_flags; ++ enum loongarch_mmu_types mmu_type; ++ int cpu_cfg[64]; ++}; ++ ++/* loongarch 3a5000 TLB entry */ ++struct ls3a5k_tlb_t { ++ target_ulong VPN; ++ uint64_t PageMask; /* CSR_TLBIDX[29:24] */ ++ uint32_t PageSize; ++ uint16_t ASID; ++ unsigned int G:1; /* CSR_TLBLO[6] */ ++ ++ unsigned int C0:3; /* CSR_TLBLO[5:4] */ ++ unsigned int C1:3; ++ ++ unsigned int V0:1; /* CSR_TLBLO[0] */ ++ unsigned int V1:1; ++ ++ unsigned int WE0:1; /* CSR_TLBLO[1] */ ++ unsigned int WE1:1; ++ ++ unsigned int XI0:1; /* CSR_TLBLO[62] */ ++ unsigned int XI1:1; ++ ++ unsigned int RI0:1; /* CSR_TLBLO[61] */ ++ unsigned int RI1:1; ++ ++ unsigned int EHINV:1;/* CSR_TLBIDX[31] */ ++ ++ unsigned int PLV0:2; /* CSR_TLBLO[3:2] */ ++ unsigned int PLV1:2; ++ ++ unsigned int RPLV0:1; ++ unsigned int RPLV1:1; /* CSR_TLBLO[63] */ ++ ++ uint64_t PPN0; /* CSR_TLBLO[47:12] */ ++ uint64_t PPN1; /* CSR_TLBLO[47:12] */ ++}; ++typedef struct ls3a5k_tlb_t ls3a5k_tlb_t; ++ ++struct CPULOONGARCHTLBContext { ++ uint32_t nb_tlb; ++ uint32_t tlb_in_use; ++ int (*map_address)(struct CPULOONGARCHState *env, hwaddr *physical, ++ int *prot, target_ulong address, int rw, ++ int access_type); ++ void (*helper_tlbwr)(struct CPULOONGARCHState *env); ++ void (*helper_tlbfill)(struct CPULOONGARCHState *env); ++ void (*helper_tlbsrch)(struct CPULOONGARCHState *env); ++ void (*helper_tlbrd)(struct CPULOONGARCHState *env); ++ void (*helper_tlbclr)(struct CPULOONGARCHState *env); ++ void (*helper_tlbflush)(struct CPULOONGARCHState *env); ++ void (*helper_invtlb)(struct CPULOONGARCHState *env, target_ulong addr, ++ target_ulong info, int op); ++ union ++ { ++ struct { ++ uint64_t ftlb_mask; ++ uint32_t ftlb_size; /* at most : 8 * 256 = 2048 */ ++ uint32_t vtlb_size; /* at most : 64 */ ++ ls3a5k_tlb_t tlb[2048 + 64]; /* at most : 2048 FTLB + 64 VTLB */ ++ } ls3a5k; ++ } mmu; ++}; ++ ++enum { ++ TLBRET_PE = -7, ++ TLBRET_XI = -6, ++ TLBRET_RI = -5, ++ TLBRET_DIRTY = -4, ++ TLBRET_INVALID = -3, ++ TLBRET_NOMATCH = -2, ++ TLBRET_BADADDR = -1, ++ TLBRET_MATCH = 0 ++}; ++ ++extern unsigned int ieee_rm[]; ++ ++static inline void restore_rounding_mode(CPULOONGARCHState *env) ++{ ++ set_float_rounding_mode(ieee_rm[(env->active_fpu.fcsr0 >> FCSR0_RM) & 0x3], ++ &env->active_fpu.fp_status); ++} ++ ++static inline void restore_flush_mode(CPULOONGARCHState *env) ++{ ++ set_flush_to_zero(0, &env->active_fpu.fp_status); ++} ++ ++static inline void restore_fp_status(CPULOONGARCHState *env) ++{ ++ restore_rounding_mode(env); ++ restore_flush_mode(env); ++} ++ ++static inline void compute_hflags(CPULOONGARCHState *env) ++{ ++ env->hflags &= ~(LARCH_HFLAG_64 | LARCH_HFLAG_FPU | LARCH_HFLAG_KSU | ++ LARCH_HFLAG_AWRAP | LARCH_HFLAG_LSX | LARCH_HFLAG_LASX); ++ ++ env->hflags |= (env->CSR_CRMD & CSR_CRMD_PLV); ++ env->hflags |= LARCH_HFLAG_64; ++ ++ if (env->CSR_EUEN & CSR_EUEN_FPEN) { ++ env->hflags |= LARCH_HFLAG_FPU; ++ } ++ if (env->CSR_EUEN & CSR_EUEN_LSXEN) { ++ env->hflags |= LARCH_HFLAG_LSX; ++ } ++ if (env->CSR_EUEN & CSR_EUEN_LASXEN) { ++ env->hflags |= LARCH_HFLAG_LASX; ++ } ++ if (env->CSR_EUEN & CSR_EUEN_LBTEN) { ++ env->hflags |= LARCH_HFLAG_LBT; ++ } ++} ++ ++/* Check if there is pending and not masked out interrupt */ ++static inline bool cpu_loongarch_hw_interrupts_pending(CPULOONGARCHState *env) ++{ ++ int32_t pending; ++ int32_t status; ++ bool r; ++ ++ pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; ++ status = env->CSR_ECFG & CSR_ECFG_IPMASK; ++ ++ /* ++ * Configured with compatibility or VInt (Vectored Interrupts) ++ * treats the pending lines as individual interrupt lines, the status ++ * lines are individual masks. ++ */ ++ r = (pending & status) != 0; ++ ++ return r; ++} ++ ++/* stabletimer.c */ ++uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high); ++uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env); ++uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env); ++void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, ++ uint64_t value); ++int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, ++ int cpuid, void *opaque); ++ ++void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); ++ ++/* TODO QOM'ify CPU reset and remove */ ++void cpu_state_reset(CPULOONGARCHState *s); ++void cpu_loongarch_realize_env(CPULOONGARCHState *env); ++ ++uint64_t read_fcc(CPULOONGARCHState *env); ++void write_fcc(CPULOONGARCHState *env, uint64_t val); ++ ++int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); ++int loongarch_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); ++ ++#ifdef CONFIG_TCG ++#include "fpu_helper.h" ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++extern const struct VMStateDescription vmstate_loongarch_cpu; ++hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); ++#endif ++ ++#endif +diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c +new file mode 100644 +index 0000000000..2b0159bb32 +--- /dev/null ++++ b/target/loongarch64/kvm.c +@@ -0,0 +1,1366 @@ ++/* ++ * KVM/LOONGARCH: LOONGARCH specific KVM APIs ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include ++ ++#include "qemu-common.h" ++#include "cpu.h" ++#include "internal.h" ++#include "qemu/error-report.h" ++#include "qemu/timer.h" ++#include "qemu/main-loop.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" ++#include "sysemu/runstate.h" ++#include "sysemu/cpus.h" ++#include "kvm_larch.h" ++#include "exec/memattrs.h" ++#include "exec/gdbstub.h" ++ ++#define DEBUG_KVM 0 ++/* ++ * A 16384-byte buffer can hold the 8-byte kvm_msrs header, plus ++ * 2047 kvm_msr_entry structs ++ */ ++#define CSR_BUF_SIZE 16384 ++ ++#define DPRINTF(fmt, ...) \ ++ do { \ ++ if (DEBUG_KVM) { \ ++ fprintf(stderr, fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++/* ++ * Define loongarch kvm version. ++ * Add version number when ++ * qemu/kvm interface changed ++ */ ++#define KVM_LOONGARCH_VERSION 1 ++ ++static struct { ++ target_ulong addr; ++ int len; ++ int type; ++} inst_breakpoint[8], data_breakpoint[8]; ++ ++int nb_data_breakpoint = 0, nb_inst_breakpoint = 0; ++static int kvm_loongarch_version_cap; ++ ++/* ++ * Hardware breakpoint control register ++ * 4:1 plv0-plv3 enable ++ * 6:5 config virtualization mode ++ * 9:8 load store ++ */ ++static const int type_code[] = { [GDB_BREAKPOINT_HW] = 0x5e, ++ [GDB_WATCHPOINT_READ] = (0x5e | 1 << 8), ++ [GDB_WATCHPOINT_WRITE] = (0x5e | 1 << 9), ++ [GDB_WATCHPOINT_ACCESS] = ++ (0x5e | 1 << 8 | 1 << 9) }; ++ ++const KVMCapabilityInfo kvm_arch_required_capabilities[] = { ++ KVM_CAP_LAST_INFO ++}; ++ ++static void kvm_loongarch_update_state(void *opaque, bool running, ++ RunState state); ++static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, ++ uint64_t *addr); ++ ++unsigned long kvm_arch_vcpu_id(CPUState *cs) ++{ ++ return cs->cpu_index; ++} ++ ++int kvm_arch_init(MachineState *ms, KVMState *s) ++{ ++ /* LOONGARCH has 128 signals */ ++ kvm_set_sigmask_len(s, 16); ++ ++ kvm_loongarch_version_cap = kvm_check_extension(s, KVM_CAP_LOONGARCH_VZ); ++ ++ if (kvm_loongarch_version_cap != KVM_LOONGARCH_VERSION) { ++ warn_report("QEMU/KVM version not match, qemu_la_version: lvz-%d,\ ++ kvm_la_version: lvz-%d \n", ++ KVM_LOONGARCH_VERSION, kvm_loongarch_version_cap); ++ } ++ return 0; ++} ++ ++int kvm_arch_irqchip_create(KVMState *s) ++{ ++ return 0; ++} ++ ++static void kvm_csr_set_addr(uint64_t **addr, uint32_t index, uint64_t *p) ++{ ++ addr[index] = p; ++} ++ ++int kvm_arch_init_vcpu(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ uint64_t **addr; ++ CPULOONGARCHState *env = &cpu->env; ++ int ret = 0; ++ ++ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_FPU, 0, 0); ++ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_LSX, 0, 0); ++ ++ cpu->cpuStateEntry = ++ qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); ++ cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE + CSR_BUF_SIZE); ++ ++ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_CRMD, &env->CSR_CRMD); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRMD, &env->CSR_PRMD); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_EUEN, &env->CSR_EUEN); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_MISC, &env->CSR_MISC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ECFG, &env->CSR_ECFG); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ESTAT, &env->CSR_ESTAT); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERA, &env->CSR_ERA); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADV, &env->CSR_BADV); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADI, &env->CSR_BADI); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_EEPN, &env->CSR_EEPN); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBIDX, &env->CSR_TLBIDX); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBEHI, &env->CSR_TLBEHI); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO0, &env->CSR_TLBELO0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO1, &env->CSR_TLBELO1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GTLBC, &env->CSR_GTLBC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TRGP, &env->CSR_TRGP); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ASID, &env->CSR_ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDL, &env->CSR_PGDL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDH, &env->CSR_PGDH); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGD, &env->CSR_PGD); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL0, &env->CSR_PWCTL0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL1, &env->CSR_PWCTL1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_STLBPGSIZE, &env->CSR_STLBPGSIZE); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_RVACFG, &env->CSR_RVACFG); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_CPUID, &env->CSR_CPUID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG1, &env->CSR_PRCFG1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG2, &env->CSR_PRCFG2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG3, &env->CSR_PRCFG3); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS0, &env->CSR_KS0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS1, &env->CSR_KS1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS2, &env->CSR_KS2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS3, &env->CSR_KS3); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS4, &env->CSR_KS4); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS5, &env->CSR_KS5); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS6, &env->CSR_KS6); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS7, &env->CSR_KS7); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TMID, &env->CSR_TMID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_CNTC, &env->CSR_CNTC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TINTCLR, &env->CSR_TINTCLR); ++ ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GSTAT, &env->CSR_GSTAT); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCFG, &env->CSR_GCFG); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GINTC, &env->CSR_GINTC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCNTC, &env->CSR_GCNTC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_LLBCTL, &env->CSR_LLBCTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL1, &env->CSR_IMPCTL1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL2, &env->CSR_IMPCTL2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_GNMI, &env->CSR_GNMI); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRENT, &env->CSR_TLBRENT); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRBADV, &env->CSR_TLBRBADV); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRERA, &env->CSR_TLBRERA); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRSAVE, &env->CSR_TLBRSAVE); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO0, &env->CSR_TLBRELO0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO1, &env->CSR_TLBRELO1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBREHI, &env->CSR_TLBREHI); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRPRMD, &env->CSR_TLBRPRMD); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRCTL, &env->CSR_ERRCTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO, &env->CSR_ERRINFO); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO1, &env->CSR_ERRINFO1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRENT, &env->CSR_ERRENT); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRERA, &env->CSR_ERRERA); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRSAVE, &env->CSR_ERRSAVE); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_CTAG, &env->CSR_CTAG); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN0, &env->CSR_DMWIN0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN1, &env->CSR_DMWIN1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN2, &env->CSR_DMWIN2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN3, &env->CSR_DMWIN3); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL0, &env->CSR_PERFCTRL0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR0, &env->CSR_PERFCNTR0); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL1, &env->CSR_PERFCTRL1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR1, &env->CSR_PERFCNTR1); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL2, &env->CSR_PERFCTRL2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR2, &env->CSR_PERFCNTR2); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL3, &env->CSR_PERFCTRL3); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR3, &env->CSR_PERFCNTR3); ++ ++ /* debug */ ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPC, &env->CSR_MWPC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPS, &env->CSR_MWPS); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ADDR, &env->CSR_DB0ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0MASK, &env->CSR_DB0MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0CTL, &env->CSR_DB0CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ASID, &env->CSR_DB0ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ADDR, &env->CSR_DB1ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1MASK, &env->CSR_DB1MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1CTL, &env->CSR_DB1CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ASID, &env->CSR_DB1ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ADDR, &env->CSR_DB2ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2MASK, &env->CSR_DB2MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2CTL, &env->CSR_DB2CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ASID, &env->CSR_DB2ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ADDR, &env->CSR_DB3ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3MASK, &env->CSR_DB3MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3CTL, &env->CSR_DB3CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ASID, &env->CSR_DB3ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPC, &env->CSR_FWPC); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPS, &env->CSR_FWPS); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ADDR, &env->CSR_IB0ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0MASK, &env->CSR_IB0MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0CTL, &env->CSR_IB0CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ASID, &env->CSR_IB0ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ADDR, &env->CSR_IB1ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1MASK, &env->CSR_IB1MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1CTL, &env->CSR_IB1CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ASID, &env->CSR_IB1ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ADDR, &env->CSR_IB2ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2MASK, &env->CSR_IB2MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2CTL, &env->CSR_IB2CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ASID, &env->CSR_IB2ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ADDR, &env->CSR_IB3ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3MASK, &env->CSR_IB3MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3CTL, &env->CSR_IB3CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ASID, &env->CSR_IB3ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ADDR, &env->CSR_IB4ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4MASK, &env->CSR_IB4MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4CTL, &env->CSR_IB4CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ASID, &env->CSR_IB4ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ADDR, &env->CSR_IB5ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5MASK, &env->CSR_IB5MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5CTL, &env->CSR_IB5CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ASID, &env->CSR_IB5ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ADDR, &env->CSR_IB6ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6MASK, &env->CSR_IB6MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6CTL, &env->CSR_IB6CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ASID, &env->CSR_IB6ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ADDR, &env->CSR_IB7ADDR); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7MASK, &env->CSR_IB7MASK); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7CTL, &env->CSR_IB7CTL); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ASID, &env->CSR_IB7ASID); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DEBUG, &env->CSR_DEBUG); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DERA, &env->CSR_DERA); ++ kvm_csr_set_addr(addr, LOONGARCH_CSR_DESAVE, &env->CSR_DESAVE); ++ ++ DPRINTF("%s\n", __func__); ++ return ret; ++} ++ ++int kvm_arch_destroy_vcpu(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ ++ g_free(cpu->kvm_csr_buf); ++ cpu->kvm_csr_buf = NULL; ++ return 0; ++} ++ ++static void kvm_csr_buf_reset(LOONGARCHCPU *cpu) ++{ ++ memset(cpu->kvm_csr_buf, 0, CSR_BUF_SIZE); ++} ++ ++static void kvm_csr_entry_add(LOONGARCHCPU *cpu, uint32_t index, ++ uint64_t value) ++{ ++ struct kvm_msrs *msrs = cpu->kvm_csr_buf; ++ void *limit = ((void *)msrs) + CSR_BUF_SIZE; ++ struct kvm_csr_entry *entry = &msrs->entries[msrs->ncsrs]; ++ ++ assert((void *)(entry + 1) <= limit); ++ ++ entry->index = index; ++ entry->reserved = 0; ++ entry->data = value; ++ msrs->ncsrs++; ++} ++ ++void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu) ++{ ++ int ret = 0; ++ uint64_t reset = 1; ++ ++ if (CPU(cpu)->kvm_fd > 0) { ++ ret = kvm_larch_putq(CPU(cpu), KVM_REG_LOONGARCH_VCPU_RESET, &reset); ++ if (ret < 0) { ++ error_report("%s reset vcpu failed:%d", __func__, ret); ++ } ++ } ++ ++ DPRINTF("%s\n", __func__); ++} ++ ++void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) ++{ ++ int n; ++ if (kvm_sw_breakpoints_active(cpu)) { ++ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; ++ } ++ if (nb_data_breakpoint > 0) { ++ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; ++ for (n = 0; n < nb_data_breakpoint; n++) { ++ dbg->arch.data_breakpoint[n].addr = data_breakpoint[n].addr; ++ dbg->arch.data_breakpoint[n].mask = 0; ++ dbg->arch.data_breakpoint[n].asid = 0; ++ dbg->arch.data_breakpoint[n].ctrl = ++ type_code[data_breakpoint[n].type]; ++ } ++ dbg->arch.data_bp_nums = nb_data_breakpoint; ++ } else { ++ dbg->arch.data_bp_nums = 0; ++ } ++ if (nb_inst_breakpoint > 0) { ++ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; ++ for (n = 0; n < nb_inst_breakpoint; n++) { ++ dbg->arch.inst_breakpoint[n].addr = inst_breakpoint[n].addr; ++ dbg->arch.inst_breakpoint[n].mask = 0; ++ dbg->arch.inst_breakpoint[n].asid = 0; ++ dbg->arch.inst_breakpoint[n].ctrl = ++ type_code[inst_breakpoint[n].type]; ++ } ++ dbg->arch.inst_bp_nums = nb_inst_breakpoint; ++ } else { ++ dbg->arch.inst_bp_nums = 0; ++ } ++} ++ ++static const unsigned int brk_insn = 0x002b8005; ++ ++int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ DPRINTF("%s\n", __func__); ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { ++ error_report("%s failed", __func__); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ static uint32_t brk; ++ ++ DPRINTF("%s\n", __func__); ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || ++ brk != brk_insn || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { ++ error_report("%s failed", __func__); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int find_hw_breakpoint(uint64_t addr, int len, int type) ++{ ++ int n; ++ switch (type) { ++ case GDB_BREAKPOINT_HW: ++ if (nb_inst_breakpoint == 0) { ++ return -1; ++ } ++ for (n = 0; n < nb_inst_breakpoint; n++) { ++ if (inst_breakpoint[n].addr == addr && ++ inst_breakpoint[n].type == type) { ++ return n; ++ } ++ } ++ break; ++ case GDB_WATCHPOINT_WRITE: ++ case GDB_WATCHPOINT_READ: ++ case GDB_WATCHPOINT_ACCESS: ++ if (nb_data_breakpoint == 0) { ++ return -1; ++ } ++ for (n = 0; n < nb_data_breakpoint; n++) { ++ if (data_breakpoint[n].addr == addr && ++ data_breakpoint[n].type == type && ++ data_breakpoint[n].len == len) { ++ return n; ++ } ++ } ++ break; ++ default: ++ return -1; ++ } ++ return -1; ++} ++ ++int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, ++ int type) ++{ ++ switch (type) { ++ case GDB_BREAKPOINT_HW: ++ len = 1; ++ if (nb_inst_breakpoint == 8) { ++ return -ENOBUFS; ++ } ++ if (find_hw_breakpoint(addr, len, type) >= 0) { ++ return -EEXIST; ++ } ++ inst_breakpoint[nb_inst_breakpoint].addr = addr; ++ inst_breakpoint[nb_inst_breakpoint].len = len; ++ inst_breakpoint[nb_inst_breakpoint].type = type; ++ nb_inst_breakpoint++; ++ break; ++ case GDB_WATCHPOINT_WRITE: ++ case GDB_WATCHPOINT_READ: ++ case GDB_WATCHPOINT_ACCESS: ++ switch (len) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ if (addr & (len - 1)) { ++ return -EINVAL; ++ } ++ if (nb_data_breakpoint == 8) { ++ return -ENOBUFS; ++ } ++ if (find_hw_breakpoint(addr, len, type) >= 0) { ++ return -EEXIST; ++ } ++ data_breakpoint[nb_data_breakpoint].addr = addr; ++ data_breakpoint[nb_data_breakpoint].len = len; ++ data_breakpoint[nb_data_breakpoint].type = type; ++ nb_data_breakpoint++; ++ break; ++ default: ++ return -EINVAL; ++ } ++ break; ++ default: ++ return -ENOSYS; ++ } ++ return 0; ++} ++ ++int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, ++ int type) ++{ ++ int n; ++ n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type); ++ if (n < 0) { ++ printf("err not find remove target\n"); ++ return -ENOENT; ++ } ++ switch (type) { ++ case GDB_BREAKPOINT_HW: ++ nb_inst_breakpoint--; ++ inst_breakpoint[n] = inst_breakpoint[nb_inst_breakpoint]; ++ break; ++ case GDB_WATCHPOINT_WRITE: ++ case GDB_WATCHPOINT_READ: ++ case GDB_WATCHPOINT_ACCESS: ++ nb_data_breakpoint--; ++ data_breakpoint[n] = data_breakpoint[nb_data_breakpoint]; ++ break; ++ default: ++ return -1; ++ } ++ return 0; ++} ++ ++void kvm_arch_remove_all_hw_breakpoints(void) ++{ ++ DPRINTF("%s\n", __func__); ++ nb_data_breakpoint = 0; ++ nb_inst_breakpoint = 0; ++} ++ ++static inline int cpu_loongarch_io_interrupts_pending(LOONGARCHCPU *cpu) ++{ ++ CPULOONGARCHState *env = &cpu->env; ++ ++ return env->CSR_ESTAT & (0x1 << 2); ++} ++ ++void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ int r; ++ struct kvm_loongarch_interrupt intr; ++ ++ qemu_mutex_lock_iothread(); ++ ++ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && ++ cpu_loongarch_io_interrupts_pending(cpu)) { ++ intr.cpu = -1; ++ intr.irq = 2; ++ r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); ++ if (r < 0) { ++ error_report("%s: cpu %d: failed to inject IRQ %x", __func__, ++ cs->cpu_index, intr.irq); ++ } ++ } ++ ++ qemu_mutex_unlock_iothread(); ++} ++ ++MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) ++{ ++ return MEMTXATTRS_UNSPECIFIED; ++} ++ ++int kvm_arch_process_async_events(CPUState *cs) ++{ ++ return cs->halted; ++} ++ ++static CPUWatchpoint hw_watchpoint; ++ ++static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int i; ++ bool ret = false; ++ kvm_cpu_synchronize_state(cs); ++ if (cs->singlestep_enabled) { ++ return true; ++ } ++ if (kvm_find_sw_breakpoint(cs, env->active_tc.PC)) { ++ return true; ++ } ++ /* hw breakpoint */ ++ if (run->debug.arch.exception == EXCCODE_WATCH) { ++ for (i = 0; i < 8; i++) { ++ if (run->debug.arch.fwps & (1 << i)) { ++ ret = true; ++ break; ++ } ++ } ++ for (i = 0; i < 8; i++) { ++ if (run->debug.arch.mwps & (1 << i)) { ++ cs->watchpoint_hit = &hw_watchpoint; ++ hw_watchpoint.vaddr = data_breakpoint[i].addr; ++ switch (data_breakpoint[i].type) { ++ case GDB_WATCHPOINT_READ: ++ ret = true; ++ hw_watchpoint.flags = BP_MEM_READ; ++ break; ++ case GDB_WATCHPOINT_WRITE: ++ ret = true; ++ hw_watchpoint.flags = BP_MEM_WRITE; ++ break; ++ case GDB_WATCHPOINT_ACCESS: ++ ret = true; ++ hw_watchpoint.flags = BP_MEM_ACCESS; ++ break; ++ } ++ } ++ } ++ run->debug.arch.exception = 0; ++ run->debug.arch.fwps = 0; ++ run->debug.arch.mwps = 0; ++ } ++ return ret; ++} ++ ++int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ++{ ++ int ret; ++ ++ DPRINTF("%s\n", __func__); ++ switch (run->exit_reason) { ++ case KVM_EXIT_HYPERCALL: ++ DPRINTF("handle LOONGARCH hypercall\n"); ++ ret = 0; ++ run->hypercall.ret = ret; ++ break; ++ ++ case KVM_EXIT_DEBUG: ++ ret = 0; ++ if (kvm_loongarch_handle_debug(cs, run)) { ++ ret = EXCP_DEBUG; ++ } ++ break; ++ default: ++ error_report("%s: unknown exit reason %d", __func__, run->exit_reason); ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++bool kvm_arch_stop_on_emulation_error(CPUState *cs) ++{ ++ DPRINTF("%s\n", __func__); ++ return true; ++} ++ ++void kvm_arch_init_irq_routing(KVMState *s) ++{ ++} ++ ++int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level) ++{ ++ CPUState *cs = CPU(cpu); ++ struct kvm_loongarch_interrupt intr; ++ ++ if (!kvm_enabled()) { ++ return 0; ++ } ++ ++ intr.cpu = -1; ++ ++ if (level) { ++ intr.irq = irq; ++ } else { ++ intr.irq = -irq; ++ } ++ ++ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); ++ ++ return 0; ++} ++ ++int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level) ++{ ++ CPUState *cs = current_cpu; ++ CPUState *dest_cs = CPU(cpu); ++ struct kvm_loongarch_interrupt intr; ++ ++ if (!kvm_enabled()) { ++ return 0; ++ } ++ ++ intr.cpu = dest_cs->cpu_index; ++ ++ if (level) { ++ intr.irq = irq; ++ } else { ++ intr.irq = -irq; ++ } ++ ++ DPRINTF("%s: IRQ: %d\n", __func__, intr.irq); ++ if (!current_cpu) { ++ cs = dest_cs; ++ } ++ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); ++ ++ return 0; ++} ++ ++static inline int kvm_loongarch_put_one_reg(CPUState *cs, uint64_t reg_id, ++ int32_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_put_one_ureg(CPUState *cs, uint64_t reg_id, ++ uint32_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_put_one_ulreg(CPUState *cs, uint64_t reg_id, ++ target_ulong *addr) ++{ ++ uint64_t val64 = *addr; ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)&val64 }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_put_one_reg64(CPUState *cs, int64_t reg_id, ++ int64_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, uint64_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_get_one_reg(CPUState *cs, uint64_t reg_id, ++ int32_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_get_one_ureg(CPUState *cs, uint64_t reg_id, ++ uint32_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_get_one_ulreg(CPUState *cs, uint64_t reg_id, ++ target_ulong *addr) ++{ ++ int ret; ++ uint64_t val64 = 0; ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)&val64 }; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); ++ if (ret >= 0) { ++ *addr = val64; ++ } ++ return ret; ++} ++ ++static inline int kvm_loongarch_get_one_reg64(CPUState *cs, int64_t reg_id, ++ int64_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_larch_getq(CPUState *cs, uint64_t reg_id, uint64_t *addr) ++{ ++ struct kvm_one_reg csrreg = { .id = reg_id, .addr = (uintptr_t)addr }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); ++} ++ ++static inline int kvm_loongarch_change_one_reg(CPUState *cs, uint64_t reg_id, ++ int32_t *addr, int32_t mask) ++{ ++ int err; ++ int32_t tmp, change; ++ ++ err = kvm_loongarch_get_one_reg(cs, reg_id, &tmp); ++ if (err < 0) { ++ return err; ++ } ++ ++ /* only change bits in mask */ ++ change = (*addr ^ tmp) & mask; ++ if (!change) { ++ return 0; ++ } ++ ++ tmp = tmp ^ change; ++ return kvm_loongarch_put_one_reg(cs, reg_id, &tmp); ++} ++ ++static inline int kvm_loongarch_change_one_reg64(CPUState *cs, uint64_t reg_id, ++ int64_t *addr, int64_t mask) ++{ ++ int err; ++ int64_t tmp, change; ++ ++ err = kvm_loongarch_get_one_reg64(cs, reg_id, &tmp); ++ if (err < 0) { ++ DPRINTF("%s: Failed to get CSR_CONFIG7 (%d)\n", __func__, err); ++ return err; ++ } ++ ++ /* only change bits in mask */ ++ change = (*addr ^ tmp) & mask; ++ if (!change) { ++ return 0; ++ } ++ ++ tmp = tmp ^ change; ++ return kvm_loongarch_put_one_reg64(cs, reg_id, &tmp); ++} ++/* ++ * Handle the VM clock being started or stopped ++ */ ++static void kvm_loongarch_update_state(void *opaque, bool running, ++ RunState state) ++{ ++ CPUState *cs = opaque; ++ int ret; ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ ++ /* ++ * If state is already dirty (synced to QEMU) then the KVM timer state is ++ * already saved and can be restored when it is synced back to KVM. ++ */ ++ if (!running) { ++ ret = ++ kvm_larch_getq(cs, KVM_REG_LOONGARCH_COUNTER, &cpu->counter_value); ++ if (ret < 0) { ++ printf("%s: Failed to get counter_value (%d)\n", __func__, ret); ++ } ++ ++ } else { ++ ret = kvm_larch_putq(cs, KVM_REG_LOONGARCH_COUNTER, ++ &(LOONGARCH_CPU(cs))->counter_value); ++ if (ret < 0) { ++ printf("%s: Failed to put counter_value (%d)\n", __func__, ret); ++ } ++ } ++} ++ ++static int kvm_loongarch_put_fpu_registers(CPUState *cs, int level) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int err, ret = 0; ++ unsigned int i; ++ struct kvm_fpu fpu; ++ ++ fpu.fcsr = env->active_fpu.fcsr0; ++ for (i = 0; i < 32; i++) { ++ memcpy(&fpu.fpr[i], &env->active_fpu.fpr[i], ++ sizeof(struct kvm_fpureg)); ++ } ++ for (i = 0; i < 8; i++) { ++ ((char *)&fpu.fcc)[i] = env->active_fpu.cf[i]; ++ } ++ fpu.vcsr = env->active_fpu.vcsr16; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); ++ if (err < 0) { ++ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); ++ ret = err; ++ } ++ ++ return ret; ++} ++ ++static int kvm_loongarch_get_fpu_registers(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int err, ret = 0; ++ unsigned int i; ++ struct kvm_fpu fpu; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); ++ if (err < 0) { ++ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); ++ ret = err; ++ } else { ++ env->active_fpu.fcsr0 = fpu.fcsr; ++ for (i = 0; i < 32; i++) { ++ memcpy(&env->active_fpu.fpr[i], &fpu.fpr[i], ++ sizeof(struct kvm_fpureg)); ++ } ++ for (i = 0; i < 8; i++) { ++ env->active_fpu.cf[i] = ((char *)&fpu.fcc)[i]; ++ } ++ env->active_fpu.vcsr16 = fpu.vcsr; ++ } ++ ++ return ret; ++} ++ ++#define KVM_PUT_ONE_UREG64(cs, regidx, addr) \ ++ ({ \ ++ int err; \ ++ uint64_t csrid = 0; \ ++ csrid = (KVM_IOC_CSRID(regidx)); \ ++ err = kvm_larch_putq(cs, csrid, addr); \ ++ if (err < 0) { \ ++ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, \ ++ regidx, err); \ ++ } \ ++ err; \ ++ }) ++ ++static int kvm_loongarch_put_csr_registers(CPUState *cs, int level) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int ret = 0; ++ ++ (void)level; ++ ++ kvm_csr_buf_reset(cpu); ++ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); ++ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); ++ ++ /* debug */ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_csr_buf); ++ if (ret < cpu->kvm_csr_buf->ncsrs) { ++ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; ++ printf("error: failed to set CSR 0x%" PRIx32 " to 0x%" PRIx64 "\n", ++ (uint32_t)e->index, (uint64_t)e->data); ++ } ++ ++ /* ++ * timer cfg must be put at last since it is used to enable ++ * guest timer ++ */ ++ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); ++ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); ++ return ret; ++} ++ ++#define KVM_GET_ONE_UREG64(cs, regidx, addr) \ ++ ({ \ ++ int err; \ ++ uint64_t csrid = 0; \ ++ csrid = (KVM_IOC_CSRID(regidx)); \ ++ err = kvm_larch_getq(cs, csrid, addr); \ ++ if (err < 0) { \ ++ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, \ ++ regidx, err); \ ++ } \ ++ err; \ ++ }) ++ ++static int kvm_loongarch_get_csr_registers(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int ret = 0, i; ++ struct kvm_csr_entry *csrs = cpu->kvm_csr_buf->entries; ++ uint64_t **addr; ++ ++ kvm_csr_buf_reset(cpu); ++ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; ++ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); ++ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); ++ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); ++ ++ /* debug */ ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); ++ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_csr_buf); ++ if (ret < cpu->kvm_csr_buf->ncsrs) { ++ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; ++ printf("error: failed to get CSR 0x%" PRIx32 "\n", (uint32_t)e->index); ++ } ++ ++ for (i = 0; i < ret; i++) { ++ uint32_t index = csrs[i].index; ++ if (addr[index]) { ++ *addr[index] = csrs[i].data; ++ } else { ++ printf("Failed to get addr CSR 0x%" PRIx32 "\n", i); ++ } ++ } ++ ++ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); ++ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); ++ return ret; ++} ++ ++int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu) ++{ ++ CPULOONGARCHState *env = &cpu->env; ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LARCH_VCPU_PVTIME_IPA, ++ .addr = (uint64_t)&env->st.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); ++ if (err != 0) { ++ /* It's ok even though kvm has not such attr */ ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr); ++ if (err != 0) { ++ error_report("PVTIME IPA: KVM_SET_DEVICE_ATTR: %s", strerror(-err)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu) ++{ ++ CPULOONGARCHState *env = &cpu->env; ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LARCH_VCPU_PVTIME_IPA, ++ .addr = (uint64_t)&env->st.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); ++ if (err != 0) { ++ /* It's ok even though kvm has not such attr */ ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr); ++ if (err != 0) { ++ error_report("PVTIME IPA: KVM_GET_DEVICE_ATTR: %s", strerror(-err)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++int kvm_arch_put_registers(CPUState *cs, int level) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ struct kvm_regs regs; ++ int ret; ++ int i; ++ ++ /* Set the registers based on QEMU's view of things */ ++ for (i = 0; i < 32; i++) { ++ regs.gpr[i] = (int64_t)(target_long)env->active_tc.gpr[i]; ++ } ++ ++ regs.pc = (int64_t)(target_long)env->active_tc.PC; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ ++ ret = kvm_loongarch_put_csr_registers(cs, level); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ ret = kvm_loongarch_put_fpu_registers(cs, level); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int kvm_arch_get_registers(CPUState *cs) ++{ ++ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); ++ CPULOONGARCHState *env = &cpu->env; ++ int ret = 0; ++ struct kvm_regs regs; ++ int i; ++ ++ /* Get the current register set as KVM seems it */ ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ ++ for (i = 0; i < 32; i++) { ++ env->active_tc.gpr[i] = regs.gpr[i]; ++ } ++ ++ env->active_tc.PC = regs.pc; ++ ++ kvm_loongarch_get_csr_registers(cs); ++ kvm_loongarch_get_fpu_registers(cs); ++ ++ return ret; ++} ++ ++int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, ++ uint64_t address, uint32_t data, PCIDevice *dev) ++{ ++ return 0; ++} ++ ++int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, ++ int vector, PCIDevice *dev) ++{ ++ return 0; ++} ++ ++bool kvm_arch_cpu_check_are_resettable(void) ++{ ++ return true; ++} ++ ++int kvm_arch_release_virq_post(int virq) ++{ ++ return 0; ++} ++ ++int kvm_arch_msi_data_to_gsi(uint32_t data) ++{ ++ abort(); ++} +diff --git a/target/loongarch64/kvm_larch.h b/target/loongarch64/kvm_larch.h +new file mode 100644 +index 0000000000..637dec8106 +--- /dev/null ++++ b/target/loongarch64/kvm_larch.h +@@ -0,0 +1,49 @@ ++/* ++ * KVM/LOONGARCH: LOONGARCH specific KVM APIs ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef KVM_LOONGARCH_H ++#define KVM_LOONGARCH_H ++ ++/** ++ * kvm_loongarch_reset_vcpu: ++ * @cpu: LOONGARCHCPU ++ * ++ * Called at reset time to set kernel registers to their initial values. ++ */ ++void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu); ++ ++int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level); ++int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level); ++ ++int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu); ++int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu); ++ ++#ifndef KVM_INTERRUPT_SET ++#define KVM_INTERRUPT_SET -1 ++#endif ++ ++#ifndef KVM_INTERRUPT_UNSET ++#define KVM_INTERRUPT_UNSET -2 ++#endif ++ ++#ifndef KVM_INTERRUPT_SET_LEVEL ++#define KVM_INTERRUPT_SET_LEVEL -3 ++#endif ++ ++#endif /* KVM_LOONGARCH_H */ +diff --git a/target/loongarch64/larch-defs.h b/target/loongarch64/larch-defs.h +new file mode 100644 +index 0000000000..e22a0dc652 +--- /dev/null ++++ b/target/loongarch64/larch-defs.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef QEMU_LOONGARCH_DEFS_H ++#define QEMU_LOONGARCH_DEFS_H ++ ++/* If we want to use host float regs... */ ++/* #define USE_HOST_FLOAT_REGS */ ++ ++/* Real pages are variable size... */ ++#define TARGET_PAGE_BITS 14 ++#define LOONGARCH_TLB_MAX 2112 ++#define TARGET_LONG_BITS 64 ++#define TARGET_PHYS_ADDR_SPACE_BITS 48 ++#define TARGET_VIRT_ADDR_SPACE_BITS 48 ++ ++/* ++ * bit definitions for insn_flags (ISAs/ASEs flags) ++ * ------------------------------------------------ ++ */ ++#define ISA_LARCH32 0x00000001ULL ++#define ISA_LARCH64 0x00000002ULL ++#define INSN_LOONGARCH 0x00010000ULL ++ ++#define CPU_LARCH32 (ISA_LARCH32) ++#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) ++ ++#endif /* QEMU_LOONGARCH_DEFS_H */ +diff --git a/target/loongarch64/machine.c b/target/loongarch64/machine.c +new file mode 100644 +index 0000000000..d91c858383 +--- /dev/null ++++ b/target/loongarch64/machine.c +@@ -0,0 +1,423 @@ ++/* ++ * Loongarch 3A5000 machine emulation ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "cpu.h" ++#include "internal.h" ++#include "hw/hw.h" ++#include "kvm_larch.h" ++#include "migration/cpu.h" ++#include "linux/kvm.h" ++#include "sysemu/kvm.h" ++#include "qemu/error-report.h" ++ ++static int cpu_post_load(void *opaque, int version_id) ++{ ++ LOONGARCHCPU *cpu = opaque; ++ CPULOONGARCHState *env = &cpu->env; ++ int r = 0; ++ ++ if (!kvm_enabled()) { ++ return 0; ++ } ++ ++#ifdef CONFIG_KVM ++ struct kvm_loongarch_vcpu_state vcpu_state; ++ int i; ++ ++ vcpu_state.online_vcpus = cpu->online_vcpus; ++ vcpu_state.is_migrate = cpu->is_migrate; ++ vcpu_state.cpu_freq = cpu->cpu_freq; ++ vcpu_state.count_ctl = cpu->count_ctl; ++ vcpu_state.pending_exceptions = cpu->pending_exceptions; ++ vcpu_state.pending_exceptions_clr = cpu->pending_exceptions_clr; ++ for (i = 0; i < 4; i++) { ++ vcpu_state.core_ext_ioisr[i] = cpu->core_ext_ioisr[i]; ++ } ++ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_SET_VCPU_STATE, &vcpu_state); ++ if (r) { ++ error_report("set vcpu state failed %d", r); ++ } ++ ++ kvm_loongarch_put_pvtime(cpu); ++#endif ++ ++ restore_fp_status(env); ++ compute_hflags(env); ++ ++ return r; ++} ++ ++static int cpu_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ LOONGARCHCPU *cpu = opaque; ++ struct kvm_loongarch_vcpu_state vcpu_state; ++ int i, r = 0; ++ if (!kvm_enabled()) { ++ return 0; ++ } ++ ++ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_GET_VCPU_STATE, &vcpu_state); ++ if (r < 0) { ++ error_report("get vcpu state failed %d", r); ++ return r; ++ } ++ ++ cpu->online_vcpus = vcpu_state.online_vcpus; ++ cpu->is_migrate = vcpu_state.is_migrate; ++ cpu->cpu_freq = vcpu_state.cpu_freq; ++ cpu->count_ctl = vcpu_state.count_ctl; ++ cpu->pending_exceptions = vcpu_state.pending_exceptions; ++ cpu->pending_exceptions_clr = vcpu_state.pending_exceptions_clr; ++ for (i = 0; i < 4; i++) { ++ cpu->core_ext_ioisr[i] = vcpu_state.core_ext_ioisr[i]; ++ } ++ ++ kvm_loongarch_get_pvtime(cpu); ++#endif ++ return 0; ++} ++ ++/* FPU state */ ++ ++static int get_fpr(QEMUFile *f, void *pv, size_t size, ++ const VMStateField *field) ++{ ++ fpr_t *v = pv; ++ qemu_get_be64s(f, &v->d); ++ return 0; ++} ++ ++static int put_fpr(QEMUFile *f, void *pv, size_t size, ++ const VMStateField *field, JSONWriter *vmdesc) ++{ ++ fpr_t *v = pv; ++ qemu_put_be64s(f, &v->d); ++ return 0; ++} ++ ++const VMStateInfo vmstate_info_fpr = { ++ .name = "fpr", ++ .get = get_fpr, ++ .put = put_fpr, ++}; ++ ++#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_fpr, fpr_t) ++ ++#define VMSTATE_FPR_ARRAY(_f, _s, _n) VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0) ++ ++static VMStateField vmstate_fpu_fields[] = { ++ VMSTATE_FPR_ARRAY(fpr, CPULOONGARCHFPUContext, 32), ++ VMSTATE_UINT32(fcsr0, CPULOONGARCHFPUContext), VMSTATE_END_OF_LIST() ++}; ++ ++const VMStateDescription vmstate_fpu = { .name = "cpu/fpu", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = vmstate_fpu_fields }; ++ ++const VMStateDescription vmstate_inactive_fpu = { .name = "cpu/inactive_fpu", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = ++ vmstate_fpu_fields }; ++ ++/* TC state */ ++ ++static VMStateField vmstate_tc_fields[] = { ++ VMSTATE_UINTTL_ARRAY(gpr, TCState, 32), VMSTATE_UINTTL(PC, TCState), ++ VMSTATE_END_OF_LIST() ++}; ++ ++const VMStateDescription vmstate_tc = { .name = "cpu/tc", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = vmstate_tc_fields }; ++ ++const VMStateDescription vmstate_inactive_tc = { .name = "cpu/inactive_tc", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = vmstate_tc_fields }; ++ ++/* TLB state */ ++ ++static int get_tlb(QEMUFile *f, void *pv, size_t size, ++ const VMStateField *field) ++{ ++ ls3a5k_tlb_t *v = pv; ++ uint32_t flags; ++ ++ qemu_get_betls(f, &v->VPN); ++ qemu_get_be64s(f, &v->PageMask); ++ qemu_get_be32s(f, &v->PageSize); ++ qemu_get_be16s(f, &v->ASID); ++ qemu_get_be32s(f, &flags); ++ v->RPLV1 = (flags >> 21) & 1; ++ v->RPLV0 = (flags >> 20) & 1; ++ v->PLV1 = (flags >> 18) & 3; ++ v->PLV0 = (flags >> 16) & 3; ++ v->EHINV = (flags >> 15) & 1; ++ v->RI1 = (flags >> 14) & 1; ++ v->RI0 = (flags >> 13) & 1; ++ v->XI1 = (flags >> 12) & 1; ++ v->XI0 = (flags >> 11) & 1; ++ v->WE1 = (flags >> 10) & 1; ++ v->WE0 = (flags >> 9) & 1; ++ v->V1 = (flags >> 8) & 1; ++ v->V0 = (flags >> 7) & 1; ++ v->C1 = (flags >> 4) & 7; ++ v->C0 = (flags >> 1) & 7; ++ v->G = (flags >> 0) & 1; ++ qemu_get_be64s(f, &v->PPN0); ++ qemu_get_be64s(f, &v->PPN1); ++ ++ return 0; ++} ++ ++static int put_tlb(QEMUFile *f, void *pv, size_t size, ++ const VMStateField *field, JSONWriter *vmdesc) ++{ ++ ls3a5k_tlb_t *v = pv; ++ ++ uint16_t asid = v->ASID; ++ uint32_t flags = ++ ((v->RPLV1 << 21) | (v->RPLV0 << 20) | (v->PLV1 << 18) | ++ (v->PLV0 << 16) | (v->EHINV << 15) | (v->RI1 << 14) | (v->RI0 << 13) | ++ (v->XI1 << 12) | (v->XI0 << 11) | (v->WE1 << 10) | (v->WE0 << 9) | ++ (v->V1 << 8) | (v->V0 << 7) | (v->C1 << 4) | (v->C0 << 1) | ++ (v->G << 0)); ++ ++ qemu_put_betls(f, &v->VPN); ++ qemu_put_be64s(f, &v->PageMask); ++ qemu_put_be32s(f, &v->PageSize); ++ qemu_put_be16s(f, &asid); ++ qemu_put_be32s(f, &flags); ++ qemu_put_be64s(f, &v->PPN0); ++ qemu_put_be64s(f, &v->PPN1); ++ ++ return 0; ++} ++ ++const VMStateInfo vmstate_info_tlb = { ++ .name = "tlb_entry", ++ .get = get_tlb, ++ .put = put_tlb, ++}; ++ ++#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, ls3a5k_tlb_t) ++ ++#define VMSTATE_TLB_ARRAY(_f, _s, _n) VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0) ++ ++const VMStateDescription vmstate_tlb = { ++ .name = "cpu/tlb", ++ .version_id = 2, ++ .minimum_version_id = 2, ++ .fields = ++ (VMStateField[]){ VMSTATE_UINT32(nb_tlb, CPULOONGARCHTLBContext), ++ VMSTATE_UINT32(tlb_in_use, CPULOONGARCHTLBContext), ++ VMSTATE_TLB_ARRAY(mmu.ls3a5k.tlb, ++ CPULOONGARCHTLBContext, ++ LOONGARCH_TLB_MAX), ++ VMSTATE_END_OF_LIST() } ++}; ++ ++/* LOONGARCH CPU state */ ++ ++const VMStateDescription vmstate_loongarch_cpu = { ++ .name = "cpu", ++ .version_id = 15, ++ .minimum_version_id = 15, ++ .post_load = cpu_post_load, ++ .pre_save = cpu_pre_save, ++ .fields = ++ (VMStateField[]){ ++ /* Active TC */ ++ VMSTATE_STRUCT(env.active_tc, LOONGARCHCPU, 1, vmstate_tc, ++ TCState), ++ ++ /* Active FPU */ ++ VMSTATE_STRUCT(env.active_fpu, LOONGARCHCPU, 1, vmstate_fpu, ++ CPULOONGARCHFPUContext), ++ ++ /* TLB */ ++ VMSTATE_STRUCT_POINTER(env.tlb, LOONGARCHCPU, vmstate_tlb, ++ CPULOONGARCHTLBContext), ++ /* CPU metastate */ ++ VMSTATE_UINT32(env.current_tc, LOONGARCHCPU), ++ VMSTATE_INT32(env.error_code, LOONGARCHCPU), ++ VMSTATE_UINTTL(env.btarget, LOONGARCHCPU), ++ VMSTATE_UINTTL(env.bcond, LOONGARCHCPU), ++ ++ VMSTATE_UINT64(env.lladdr, LOONGARCHCPU), ++ ++ /* PV time */ ++ VMSTATE_UINT64(env.st.guest_addr, LOONGARCHCPU), ++ ++ /* Remaining CSR registers */ ++ VMSTATE_UINT64(env.CSR_CRMD, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PRMD, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_EUEN, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_MISC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ECFG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ESTAT, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERA, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_BADV, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_BADI, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_EEPN, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBIDX, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBEHI, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBELO0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBELO1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBWIRED, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GTLBC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TRGP, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PGDL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PGDH, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PGD, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PWCTL0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PWCTL1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_STLBPGSIZE, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_RVACFG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_CPUID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PRCFG1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PRCFG2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PRCFG3, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS3, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS4, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS5, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS6, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_KS7, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TMID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TCFG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TVAL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_CNTC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TINTCLR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GSTAT, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GCFG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GINTC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GCNTC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_LLBCTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IMPCTL1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IMPCTL2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_GNMI, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRENT, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRBADV, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRERA, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRSAVE, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRELO0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRELO1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBREHI, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_TLBRPRMD, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRCTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRINFO, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRINFO1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRENT, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRERA, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_ERRSAVE, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_CTAG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DMWIN0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DMWIN1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DMWIN2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DMWIN3, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCTRL0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCNTR0, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCTRL1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCNTR1, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCTRL2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCNTR2, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCTRL3, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_PERFCNTR3, LOONGARCHCPU), ++ /* debug */ ++ VMSTATE_UINT64(env.CSR_MWPC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_MWPS, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB0ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB0MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB0CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB0ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB1ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB1MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB1CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB1ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB2ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB2MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB2CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB2ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB3ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB3MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB3CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DB3ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_FWPC, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_FWPS, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB0ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB0MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB0CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB0ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB1ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB1MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB1CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB1ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB2ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB2MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB2CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB2ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB3ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB3MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB3CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB3ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB4ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB4MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB4CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB4ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB5ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB5MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB5CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB5ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB6ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB6MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB6CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB6ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB7ADDR, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB7MASK, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB7CTL, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_IB7ASID, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DEBUG, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DERA, LOONGARCHCPU), ++ VMSTATE_UINT64(env.CSR_DESAVE, LOONGARCHCPU), ++ ++ VMSTATE_STRUCT_ARRAY(env.fpus, LOONGARCHCPU, LOONGARCH_FPU_MAX, 1, ++ vmstate_inactive_fpu, CPULOONGARCHFPUContext), ++ VMSTATE_UINT8(online_vcpus, LOONGARCHCPU), ++ VMSTATE_UINT8(is_migrate, LOONGARCHCPU), ++ VMSTATE_UINT64(counter_value, LOONGARCHCPU), ++ VMSTATE_UINT32(cpu_freq, LOONGARCHCPU), ++ VMSTATE_UINT32(count_ctl, LOONGARCHCPU), ++ VMSTATE_UINT64(pending_exceptions, LOONGARCHCPU), ++ VMSTATE_UINT64(pending_exceptions_clr, LOONGARCHCPU), ++ VMSTATE_UINT64_ARRAY(core_ext_ioisr, LOONGARCHCPU, 4), ++ ++ VMSTATE_END_OF_LIST() }, ++}; +diff --git a/target/loongarch64/meson.build b/target/loongarch64/meson.build +new file mode 100644 +index 0000000000..6badf4484e +--- /dev/null ++++ b/target/loongarch64/meson.build +@@ -0,0 +1,35 @@ ++loongarch_user_ss = ss.source_set() ++loongarch_softmmu_ss = ss.source_set() ++loongarch_ss = ss.source_set() ++loongarch_ss.add(files( ++ 'cpu.c', ++ 'fpu.c', ++ 'gdbstub.c', ++)) ++ ++gen = [ ++ decodetree.process('insn.decode', extra_args: [ '--decode', 'decode_insn', ++ '--insnwidth', '32' ]) ++] ++ ++loongarch_ss.add(gen) ++loongarch_ss.add(when: 'CONFIG_TCG', if_true: files( ++ 'helper.c', ++ 'translate.c', ++ 'op_helper.c', ++ 'fpu_helper.c', ++ 'tlb_helper.c', ++ 'csr_helper.c', ++)) ++ ++loongarch_softmmu_ss.add(when: 'CONFIG_SOFTMMU', if_true: files( ++ 'machine.c', ++ 'stabletimer.c', ++ 'arch_dump.c', ++)) ++ ++loongarch_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) ++ ++target_arch += {'loongarch64': loongarch_ss} ++target_softmmu_arch += {'loongarch64': loongarch_softmmu_ss} ++target_user_arch += {'loongarch64': loongarch_user_ss} +diff --git a/target/loongarch64/op_helper.c b/target/loongarch64/op_helper.c +new file mode 100644 +index 0000000000..7257e59479 +--- /dev/null ++++ b/target/loongarch64/op_helper.c +@@ -0,0 +1,485 @@ ++/* ++ * LOONGARCH emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/main-loop.h" ++#include "cpu.h" ++#include "internal.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "sysemu/kvm.h" ++#include "qemu/crc32c.h" ++#include ++#include "hw/irq.h" ++#include "hw/core/cpu.h" ++#include "instmap.h" ++ ++/* Exceptions processing helpers */ ++ ++void helper_raise_exception_err(CPULOONGARCHState *env, uint32_t exception, ++ int error_code) ++{ ++ do_raise_exception_err(env, exception, error_code, 0); ++} ++ ++void helper_raise_exception(CPULOONGARCHState *env, uint32_t exception) ++{ ++ do_raise_exception(env, exception, GETPC()); ++} ++ ++void helper_raise_exception_debug(CPULOONGARCHState *env) ++{ ++ do_raise_exception(env, EXCP_DEBUG, 0); ++} ++ ++static void raise_exception(CPULOONGARCHState *env, uint32_t exception) ++{ ++ do_raise_exception(env, exception, 0); ++} ++ ++#if defined(CONFIG_USER_ONLY) ++#define HELPER_LD(name, insn, type) \ ++ static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ ++ int mem_idx, uintptr_t retaddr) \ ++ { \ ++ return (type)cpu_##insn##_data_ra(env, addr, retaddr); \ ++ } ++#else ++ ++#define HF_SMAP_SHIFT 23 /* CR4.SMAP */ ++#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT) ++#define MMU_KNOSMAP_IDX 2 ++#define HF_CPL_SHIFT 0 ++#define HF_CPL_MASK (3 << HF_CPL_SHIFT) ++#define AC_MASK 0x00040000 ++#define MMU_KSMAP_IDX 0 ++static inline int cpu_mmu_index_kernel(CPULOONGARCHState *env) ++{ ++ return !(env->hflags & HF_SMAP_MASK) ++ ? MMU_KNOSMAP_IDX ++ : ((env->hflags & HF_CPL_MASK) < 3 && (env->hflags & AC_MASK)) ++ ? MMU_KNOSMAP_IDX ++ : MMU_KSMAP_IDX; ++} ++ ++#define cpu_ldl_kernel_ra(e, p, r) \ ++ cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) ++ ++#define HELPER_LD(name, insn, type) \ ++ static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ ++ int mem_idx, uintptr_t retaddr) \ ++ { \ ++ } ++#endif ++ ++#if defined(CONFIG_USER_ONLY) ++#define HELPER_ST(name, insn, type) \ ++ static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ ++ type val, int mem_idx, uintptr_t retaddr) \ ++ { \ ++ } ++#else ++#define HELPER_ST(name, insn, type) \ ++ static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ ++ type val, int mem_idx, uintptr_t retaddr) \ ++ { \ ++ } ++#endif ++ ++static inline target_ulong bitswap(target_ulong v) ++{ ++ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | ++ ((v & (target_ulong)0x5555555555555555ULL) << 1); ++ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | ++ ((v & (target_ulong)0x3333333333333333ULL) << 2); ++ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | ++ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); ++ return v; ++} ++ ++target_ulong helper_dbitswap(target_ulong rt) ++{ ++ return bitswap(rt); ++} ++ ++target_ulong helper_bitswap(target_ulong rt) ++{ ++ return (int32_t)bitswap(rt); ++} ++ ++/* these crc32 functions are based on target/arm/helper-a64.c */ ++target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) ++{ ++ uint8_t buf[8]; ++ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); ++ ++ m &= mask; ++ stq_le_p(buf, m); ++ return (int32_t)(crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); ++} ++ ++target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) ++{ ++ uint8_t buf[8]; ++ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); ++ m &= mask; ++ stq_le_p(buf, m); ++ return (int32_t)(crc32c(val, buf, sz) ^ 0xffffffff); ++} ++ ++#ifndef CONFIG_USER_ONLY ++ ++#define HELPER_LD_ATOMIC(name, insn, almask) \ ++ target_ulong helper_##name(CPULOONGARCHState *env, target_ulong arg, \ ++ int mem_idx) \ ++ { \ ++ } ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++void helper_drdtime(CPULOONGARCHState *env, target_ulong rd, target_ulong rs) ++{ ++ env->active_tc.gpr[rd] = cpu_loongarch_get_stable_counter(env); ++ env->active_tc.gpr[rs] = env->CSR_TMID; ++} ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++static void debug_pre_ertn(CPULOONGARCHState *env) ++{ ++ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { ++ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, ++ env->active_tc.PC, env->CSR_ERA); ++ qemu_log("\n"); ++ } ++} ++ ++static void debug_post_ertn(CPULOONGARCHState *env) ++{ ++ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { ++ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, ++ env->active_tc.PC, env->CSR_ERA); ++ } ++} ++ ++static void set_pc(CPULOONGARCHState *env, target_ulong error_pc) ++{ ++ env->active_tc.PC = error_pc & ~(target_ulong)1; ++} ++ ++static inline void exception_return(CPULOONGARCHState *env) ++{ ++ debug_pre_ertn(env); ++ ++ if (cpu_refill_state(env)) { ++ env->CSR_CRMD &= (~0x7); ++ env->CSR_CRMD |= (env->CSR_TLBRPRMD & 0x7); ++ /* Clear Refill flag and set pc */ ++ env->CSR_TLBRERA &= (~0x1); ++ set_pc(env, env->CSR_TLBRERA); ++ if (qemu_loglevel_mask(CPU_LOG_INT)) { ++ qemu_log("%s: TLBRERA 0x%lx\n", __func__, env->CSR_TLBRERA); ++ } ++ } else { ++ env->CSR_CRMD &= (~0x7); ++ env->CSR_CRMD |= (env->CSR_PRMD & 0x7); ++ /* Clear Refill flag and set pc*/ ++ set_pc(env, env->CSR_ERA); ++ if (qemu_loglevel_mask(CPU_LOG_INT)) { ++ qemu_log("%s: ERA 0x%lx\n", __func__, env->CSR_ERA); ++ } ++ } ++ ++ compute_hflags(env); ++ debug_post_ertn(env); ++} ++ ++void helper_ertn(CPULOONGARCHState *env) ++{ ++ exception_return(env); ++ env->lladdr = 1; ++} ++ ++#endif /* !CONFIG_USER_ONLY */ ++ ++void helper_idle(CPULOONGARCHState *env) ++{ ++ CPUState *cs = CPU(loongarch_env_get_cpu(env)); ++ ++ cs->halted = 1; ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); ++ /* ++ * Last instruction in the block, PC was updated before ++ * - no need to recover PC and icount ++ */ ++ raise_exception(env, EXCP_HLT); ++} ++ ++#if !defined(CONFIG_USER_ONLY) ++ ++void loongarch_cpu_do_unaligned_access(CPUState *cs, vaddr addr, ++ MMUAccessType access_type, int mmu_idx, ++ uintptr_t retaddr) ++{ ++ while (1) { ++ } ++} ++ ++#endif /* !CONFIG_USER_ONLY */ ++ ++void helper_store_scr(CPULOONGARCHState *env, uint32_t n, target_ulong val) ++{ ++ env->scr[n & 0x3] = val; ++} ++ ++target_ulong helper_load_scr(CPULOONGARCHState *env, uint32_t n) ++{ ++ return env->scr[n & 0x3]; ++} ++ ++/* loongarch assert op */ ++void helper_asrtle_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) ++{ ++ if (rs > rt) { ++ do_raise_exception(env, EXCP_AdEL, GETPC()); ++ } ++} ++ ++void helper_asrtgt_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) ++{ ++ if (rs <= rt) { ++ do_raise_exception(env, EXCP_AdEL, GETPC()); ++ } ++} ++ ++target_ulong helper_cto_w(CPULOONGARCHState *env, target_ulong a0) ++{ ++ uint32_t v = (uint32_t)a0; ++ int temp = 0; ++ ++ while ((v & 0x1) == 1) { ++ temp++; ++ v = v >> 1; ++ } ++ ++ return (target_ulong)temp; ++} ++ ++target_ulong helper_ctz_w(CPULOONGARCHState *env, target_ulong a0) ++{ ++ uint32_t v = (uint32_t)a0; ++ ++ if (v == 0) { ++ return 32; ++ } ++ ++ int temp = 0; ++ while ((v & 0x1) == 0) { ++ temp++; ++ v = v >> 1; ++ } ++ ++ return (target_ulong)temp; ++} ++ ++target_ulong helper_cto_d(CPULOONGARCHState *env, target_ulong a0) ++{ ++ uint64_t v = a0; ++ int temp = 0; ++ ++ while ((v & 0x1) == 1) { ++ temp++; ++ v = v >> 1; ++ } ++ ++ return (target_ulong)temp; ++} ++ ++target_ulong helper_ctz_d(CPULOONGARCHState *env, target_ulong a0) ++{ ++ uint64_t v = a0; ++ ++ if (v == 0) { ++ return 64; ++ } ++ ++ int temp = 0; ++ while ((v & 0x1) == 0) { ++ temp++; ++ v = v >> 1; ++ } ++ ++ return (target_ulong)temp; ++} ++ ++target_ulong helper_bitrev_w(CPULOONGARCHState *env, target_ulong a0) ++{ ++ int32_t v = (int32_t)a0; ++ const int SIZE = 32; ++ uint8_t bytes[SIZE]; ++ ++ int i; ++ for (i = 0; i < SIZE; i++) { ++ bytes[i] = v & 0x1; ++ v = v >> 1; ++ } ++ /* v == 0 */ ++ for (i = 0; i < SIZE; i++) { ++ v = v | ((uint32_t)bytes[i] << (SIZE - 1 - i)); ++ } ++ ++ return (target_ulong)(int32_t)v; ++} ++ ++target_ulong helper_bitrev_d(CPULOONGARCHState *env, target_ulong a0) ++{ ++ uint64_t v = a0; ++ const int SIZE = 64; ++ uint8_t bytes[SIZE]; ++ ++ int i; ++ for (i = 0; i < SIZE; i++) { ++ bytes[i] = v & 0x1; ++ v = v >> 1; ++ } ++ /* v == 0 */ ++ for (i = 0; i < SIZE; i++) { ++ v = v | ((uint64_t)bytes[i] << (SIZE - 1 - i)); ++ } ++ ++ return (target_ulong)v; ++} ++ ++void helper_memtrace_addr(CPULOONGARCHState *env, target_ulong address, ++ uint32_t op) ++{ ++ qemu_log("[cpu %d asid 0x%lx pc 0x%lx] addr 0x%lx op", ++ CPU(loongarch_env_get_cpu(env))->cpu_index, env->CSR_ASID, ++ env->active_tc.PC, address); ++ switch (op) { ++ case OPC_LARCH_LDPTR_D: ++ qemu_log("OPC_LARCH_LDPTR_D"); ++ break; ++ case OPC_LARCH_LD_D: ++ qemu_log("OPC_LARCH_LD_D"); ++ break; ++ case OPC_LARCH_LDPTR_W: ++ qemu_log("OPC_LARCH_LDPTR_W"); ++ break; ++ case OPC_LARCH_LD_W: ++ qemu_log("OPC_LARCH_LD_W"); ++ break; ++ case OPC_LARCH_LD_H: ++ qemu_log("OPC_LARCH_LD_H"); ++ break; ++ case OPC_LARCH_LD_B: ++ qemu_log("OPC_LARCH_LD_B"); ++ break; ++ case OPC_LARCH_LD_WU: ++ qemu_log("OPC_LARCH_LD_WU"); ++ break; ++ case OPC_LARCH_LD_HU: ++ qemu_log("OPC_LARCH_LD_HU"); ++ break; ++ case OPC_LARCH_LD_BU: ++ qemu_log("OPC_LARCH_LD_BU"); ++ break; ++ case OPC_LARCH_STPTR_D: ++ qemu_log("OPC_LARCH_STPTR_D"); ++ break; ++ case OPC_LARCH_ST_D: ++ qemu_log("OPC_LARCH_ST_D"); ++ break; ++ case OPC_LARCH_STPTR_W: ++ qemu_log("OPC_LARCH_STPTR_W"); ++ break; ++ case OPC_LARCH_ST_W: ++ qemu_log("OPC_LARCH_ST_W"); ++ break; ++ case OPC_LARCH_ST_H: ++ qemu_log("OPC_LARCH_ST_H"); ++ break; ++ case OPC_LARCH_ST_B: ++ qemu_log("OPC_LARCH_ST_B"); ++ break; ++ case OPC_LARCH_FLD_S: ++ qemu_log("OPC_LARCH_FLD_S"); ++ break; ++ case OPC_LARCH_FLD_D: ++ qemu_log("OPC_LARCH_FLD_D"); ++ break; ++ case OPC_LARCH_FST_S: ++ qemu_log("OPC_LARCH_FST_S"); ++ break; ++ case OPC_LARCH_FST_D: ++ qemu_log("OPC_LARCH_FST_D"); ++ break; ++ case OPC_LARCH_FLDX_S: ++ qemu_log("OPC_LARCH_FLDX_S"); ++ break; ++ case OPC_LARCH_FLDGT_S: ++ qemu_log("OPC_LARCH_FLDGT_S"); ++ break; ++ case OPC_LARCH_FLDLE_S: ++ qemu_log("OPC_LARCH_FLDLE_S"); ++ break; ++ case OPC_LARCH_FSTX_S: ++ qemu_log("OPC_LARCH_FSTX_S"); ++ break; ++ case OPC_LARCH_FSTGT_S: ++ qemu_log("OPC_LARCH_FSTGT_S"); ++ break; ++ case OPC_LARCH_FSTLE_S: ++ qemu_log("OPC_LARCH_FSTLE_S"); ++ break; ++ case OPC_LARCH_FLDX_D: ++ qemu_log("OPC_LARCH_FLDX_D"); ++ break; ++ case OPC_LARCH_FLDGT_D: ++ qemu_log("OPC_LARCH_FLDGT_D"); ++ break; ++ case OPC_LARCH_FLDLE_D: ++ qemu_log("OPC_LARCH_FLDLE_D"); ++ break; ++ case OPC_LARCH_FSTX_D: ++ qemu_log("OPC_LARCH_FSTX_D"); ++ break; ++ case OPC_LARCH_FSTGT_D: ++ qemu_log("OPC_LARCH_FSTGT_D"); ++ break; ++ case OPC_LARCH_FSTLE_D: ++ qemu_log("OPC_LARCH_FSTLE_D"); ++ break; ++ case OPC_LARCH_LL_W: ++ qemu_log("OPC_LARCH_LL_W"); ++ break; ++ case OPC_LARCH_LL_D: ++ qemu_log("OPC_LARCH_LL_D"); ++ break; ++ default: ++ qemu_log("0x%x", op); ++ } ++} ++ ++void helper_memtrace_val(CPULOONGARCHState *env, target_ulong val) ++{ ++ qemu_log("val 0x%lx\n", val); ++} +diff --git a/target/loongarch64/stabletimer.c b/target/loongarch64/stabletimer.c +new file mode 100644 +index 0000000000..4f4ccc5d89 +--- /dev/null ++++ b/target/loongarch64/stabletimer.c +@@ -0,0 +1,117 @@ ++/* ++ * QEMU LOONGARCH timer support ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/loongarch/cpudevs.h" ++#include "qemu/timer.h" ++#include "sysemu/kvm.h" ++#include "internal.h" ++#include "hw/irq.h" ++ ++#ifdef DEBUG_TIMER ++#define debug_timer(fmt, args...) \ ++ printf("%s(%d)-%s -> " #fmt "\n", __FILE__, __LINE__, __func__, ##args); ++#else ++#define debug_timer(fmt, args...) ++#endif ++ ++#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */ ++#define STABLETIMER_TICK_MASK 0xfffffffffffcUL ++#define STABLETIMER_ENABLE 0x1UL ++#define STABLETIMER_PERIOD 0x2UL ++ ++/* return random value in [low, high] */ ++uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high) ++{ ++ static uint32_t seed = 5; ++ static uint32_t prev_idx; ++ uint32_t idx; ++ uint32_t nb_rand_tlb = high - low + 1; ++ ++ do { ++ seed = 1103515245 * seed + 12345; ++ idx = (seed >> 16) % nb_rand_tlb + low; ++ } while (idx == prev_idx); ++ prev_idx = idx; ++ ++ return idx; ++} ++ ++/* LOONGARCH timer */ ++uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env) ++{ ++ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; ++} ++ ++uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env) ++{ ++ uint64_t now, expire; ++ ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ expire = timer_expire_time_ns(env->timer); ++ ++ return (expire - now) / TIMER_PERIOD; ++} ++ ++void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, ++ uint64_t value) ++{ ++ uint64_t now, next; ++ ++ env->CSR_TCFG = value; ++ if (value & STABLETIMER_ENABLE) { ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD; ++ timer_mod(env->timer, next); ++ } ++ debug_timer("0x%lx 0x%lx now 0x%lx, next 0x%lx", value, env->CSR_TCFG, now, ++ next); ++} ++ ++static void loongarch_stable_timer_cb(void *opaque) ++{ ++ CPULOONGARCHState *env; ++ uint64_t now, next; ++ ++ env = opaque; ++ debug_timer(); ++ if (env->CSR_TCFG & STABLETIMER_PERIOD) { ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD; ++ timer_mod(env->timer, next); ++ } else { ++ env->CSR_TCFG &= ~STABLETIMER_ENABLE; ++ } ++ ++ qemu_irq_raise(env->irq[IRQ_TIMER]); ++} ++ ++void cpu_loongarch_clock_init(LOONGARCHCPU *cpu) ++{ ++ CPULOONGARCHState *env = &cpu->env; ++ ++ /* ++ * If we're in KVM mode, don't create the periodic timer, that is handled ++ * in kernel. ++ */ ++ if (!kvm_enabled()) { ++ env->timer = ++ timer_new_ns(QEMU_CLOCK_VIRTUAL, &loongarch_stable_timer_cb, env); ++ } ++} +diff --git a/target/loongarch64/tlb_helper.c b/target/loongarch64/tlb_helper.c +new file mode 100644 +index 0000000000..b6e924fbec +--- /dev/null ++++ b/target/loongarch64/tlb_helper.c +@@ -0,0 +1,641 @@ ++/* ++ * loongarch tlb emulation helpers for qemu. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/main-loop.h" ++#include "cpu.h" ++#include "internal.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++ ++#ifndef CONFIG_USER_ONLY ++ ++#define HELPER_LD(name, insn, type) \ ++ static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ ++ int mem_idx, uintptr_t retaddr) \ ++ { \ ++ } ++ ++void helper_lddir(CPULOONGARCHState *env, target_ulong base, target_ulong rt, ++ target_ulong level, uint32_t mem_idx) ++{ ++} ++ ++void helper_ldpte(CPULOONGARCHState *env, target_ulong base, target_ulong odd, ++ uint32_t mem_idx) ++{ ++} ++ ++target_ulong helper_read_pgd(CPULOONGARCHState *env) ++{ ++ uint64_t badv; ++ ++ assert(env->CSR_TLBRERA & 0x1); ++ ++ if (env->CSR_TLBRERA & 0x1) { ++ badv = env->CSR_TLBRBADV; ++ } else { ++ badv = env->CSR_BADV; ++ } ++ ++ if ((badv >> 63) & 0x1) { ++ return env->CSR_PGDH; ++ } else { ++ return env->CSR_PGDL; ++ } ++} ++ ++/* TLB management */ ++static uint64_t ls3a5k_pagesize_to_mask(int pagesize) ++{ ++ /* 4KB - 1GB */ ++ if (pagesize < 12 && pagesize > 30) { ++ printf("[ERROR] unsupported page size %d\n", pagesize); ++ exit(-1); ++ } ++ ++ return (1 << (pagesize + 1)) - 1; ++} ++ ++static void ls3a5k_fill_tlb_entry(CPULOONGARCHState *env, ls3a5k_tlb_t *tlb, ++ int is_ftlb) ++{ ++ uint64_t page_mask; /* 0000...00001111...1111 */ ++ uint32_t page_size; ++ uint64_t entryhi; ++ uint64_t lo0, lo1; ++ ++ if (env->CSR_TLBRERA & 0x1) { ++ page_size = env->CSR_TLBREHI & 0x3f; ++ entryhi = env->CSR_TLBREHI; ++ lo0 = env->CSR_TLBRELO0; ++ lo1 = env->CSR_TLBRELO1; ++ } else { ++ page_size = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; ++ entryhi = env->CSR_TLBEHI; ++ lo0 = env->CSR_TLBELO0; ++ lo1 = env->CSR_TLBELO1; ++ } ++ ++ if (page_size == 0) { ++ printf("Warning: page_size is 0\n"); ++ } ++ ++ /* ++ * 15-12 11-8 7-4 3-0 ++ * 4KB: 0001 1111 1111 1111 // double 4KB mask [12:0] ++ * 16KB: 0111 1111 1111 1111 // double 16KB mask [14:0] ++ */ ++ if (is_ftlb) { ++ page_mask = env->tlb->mmu.ls3a5k.ftlb_mask; ++ } else { ++ page_mask = ls3a5k_pagesize_to_mask(page_size); ++ } ++ ++ tlb->VPN = entryhi & 0xffffffffe000 & ~page_mask; ++ ++ tlb->ASID = env->CSR_ASID & 0x3ff; /* CSR_ASID[9:0] */ ++ tlb->EHINV = 0; ++ tlb->G = (lo0 >> CSR_TLBLO0_GLOBAL_SHIFT) & /* CSR_TLBLO[6] */ ++ (lo1 >> CSR_TLBLO1_GLOBAL_SHIFT) & 1; ++ ++ tlb->PageMask = page_mask; ++ tlb->PageSize = page_size; ++ ++ tlb->V0 = (lo0 >> CSR_TLBLO0_V_SHIFT) & 0x1; /* [0] */ ++ tlb->WE0 = (lo0 >> CSR_TLBLO0_WE_SHIFT) & 0x1; /* [1] */ ++ tlb->PLV0 = (lo0 >> CSR_TLBLO0_PLV_SHIFT) & 0x3; /* [3:2] */ ++ tlb->C0 = (lo0 >> CSR_TLBLO0_CCA_SHIFT) & 0x3; /* [5:4] */ ++ tlb->PPN0 = (lo0 & 0xfffffffff000 & ~(page_mask >> 1)); ++ tlb->RI0 = (lo0 >> CSR_TLBLO0_RI_SHIFT) & 0x1; /* [61] */ ++ tlb->XI0 = (lo0 >> CSR_TLBLO0_XI_SHIFT) & 0x1; /* [62] */ ++ tlb->RPLV0 = (lo0 >> CSR_TLBLO0_RPLV_SHIFT) & 0x1; /* [63] */ ++ ++ tlb->V1 = (lo1 >> CSR_TLBLO1_V_SHIFT) & 0x1; /* [0] */ ++ tlb->WE1 = (lo1 >> CSR_TLBLO1_WE_SHIFT) & 0x1; /* [1] */ ++ tlb->PLV1 = (lo1 >> CSR_TLBLO1_PLV_SHIFT) & 0x3; /* [3:2] */ ++ tlb->C1 = (lo1 >> CSR_TLBLO1_CCA_SHIFT) & 0x3; /* [5:4] */ ++ tlb->PPN1 = (lo1 & 0xfffffffff000 & ~(page_mask >> 1)); ++ tlb->RI1 = (lo1 >> CSR_TLBLO1_RI_SHIFT) & 0x1; /* [61] */ ++ tlb->XI1 = (lo1 >> CSR_TLBLO1_XI_SHIFT) & 0x1; /* [62] */ ++ tlb->RPLV1 = (lo1 >> CSR_TLBLO1_RPLV_SHIFT) & 0x1; /* [63] */ ++} ++ ++static void ls3a5k_fill_tlb(CPULOONGARCHState *env, int idx, bool tlbwr) ++{ ++ ls3a5k_tlb_t *tlb; ++ ++ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; ++ if (tlbwr) { ++ if ((env->CSR_TLBIDX >> CSR_TLBIDX_EHINV_SHIFT) & 0x1) { ++ tlb->EHINV = 1; ++ return; ++ } ++ } ++ ++ if (idx < 2048) { ++ ls3a5k_fill_tlb_entry(env, tlb, 1); ++ } else { ++ ls3a5k_fill_tlb_entry(env, tlb, 0); ++ } ++} ++ ++void ls3a5k_flush_vtlb(CPULOONGARCHState *env) ++{ ++ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; ++ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; ++ int i; ++ ++ ls3a5k_tlb_t *tlb; ++ ++ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { ++ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ tlb->EHINV = 1; ++ } ++ ++ cpu_loongarch_tlb_flush(env); ++} ++ ++void ls3a5k_flush_ftlb(CPULOONGARCHState *env) ++{ ++ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; ++ int i; ++ ++ ls3a5k_tlb_t *tlb; ++ ++ for (i = 0; i < ftlb_size; ++i) { ++ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ tlb->EHINV = 1; ++ } ++ ++ cpu_loongarch_tlb_flush(env); ++} ++ ++void ls3a5k_helper_tlbclr(CPULOONGARCHState *env) ++{ ++ int i; ++ uint16_t asid; ++ int vsize, fsize, index; ++ int start = 0, end = -1; ++ ++ asid = env->CSR_ASID & 0x3ff; ++ vsize = env->tlb->mmu.ls3a5k.vtlb_size; ++ fsize = env->tlb->mmu.ls3a5k.ftlb_size; ++ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; ++ ++ if (index < fsize) { ++ /* FTLB. One line per operation */ ++ int set = index % 256; ++ start = set * 8; ++ end = start + 7; ++ } else if (index < (fsize + vsize)) { ++ /* VTLB. All entries */ ++ start = fsize; ++ end = fsize + vsize - 1; ++ } else { ++ /* Ignore */ ++ } ++ ++ for (i = start; i <= end; i++) { ++ ls3a5k_tlb_t *tlb; ++ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ if (!tlb->G && tlb->ASID == asid) { ++ tlb->EHINV = 1; ++ } ++ } ++ ++ cpu_loongarch_tlb_flush(env); ++} ++ ++void ls3a5k_helper_tlbflush(CPULOONGARCHState *env) ++{ ++ int i; ++ int vsize, fsize, index; ++ int start = 0, end = -1; ++ ++ vsize = env->tlb->mmu.ls3a5k.vtlb_size; ++ fsize = env->tlb->mmu.ls3a5k.ftlb_size; ++ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; ++ ++ if (index < fsize) { ++ /* FTLB. One line per operation */ ++ int set = index % 256; ++ start = set * 8; ++ end = start + 7; ++ } else if (index < (fsize + vsize)) { ++ /* VTLB. All entries */ ++ start = fsize; ++ end = fsize + vsize - 1; ++ } else { ++ /* Ignore */ ++ } ++ ++ for (i = start; i <= end; i++) { ++ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; ++ } ++ ++ cpu_loongarch_tlb_flush(env); ++} ++ ++void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, ++ target_ulong info, int op) ++{ ++ uint32_t asid = info & 0x3ff; ++ int i; ++ ++ switch (op) { ++ case 0: ++ case 1: ++ for (i = 0; i < env->tlb->nb_tlb; i++) { ++ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; ++ } ++ break; ++ case 4: { ++ int i; ++ for (i = 0; i < env->tlb->nb_tlb; i++) { ++ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ ++ if (!tlb->G && tlb->ASID == asid) { ++ tlb->EHINV = 1; ++ } ++ } ++ break; ++ } ++ ++ case 5: { ++ int i; ++ for (i = 0; i < env->tlb->nb_tlb; i++) { ++ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; ++ ++ if (!tlb->G && tlb->ASID == asid && vpn == tlb->VPN) { ++ tlb->EHINV = 1; ++ } ++ } ++ break; ++ } ++ case 6: { ++ int i; ++ for (i = 0; i < env->tlb->nb_tlb; i++) { ++ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; ++ ++ if ((tlb->G || tlb->ASID == asid) && vpn == tlb->VPN) { ++ tlb->EHINV = 1; ++ } ++ } ++ break; ++ } ++ default: ++ helper_raise_exception(env, EXCP_RI); ++ } ++ ++ cpu_loongarch_tlb_flush(env); ++} ++ ++static void ls3a5k_invalidate_tlb_entry(CPULOONGARCHState *env, ++ ls3a5k_tlb_t *tlb) ++{ ++ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); ++ CPUState *cs = CPU(cpu); ++ target_ulong addr; ++ target_ulong end; ++ target_ulong mask; ++ ++ mask = tlb->PageMask; /* 000...000111...111 */ ++ ++ if (tlb->V0) { ++ addr = tlb->VPN & ~mask; /* xxx...xxx[0]000..0000 */ ++ end = addr | (mask >> 1); /* xxx...xxx[0]111..1111 */ ++ while (addr < end) { ++ tlb_flush_page(cs, addr); ++ addr += TARGET_PAGE_SIZE; ++ } ++ } ++ ++ if (tlb->V1) { ++ /* xxx...xxx[1]000..0000 */ ++ addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); ++ end = addr | mask; /* xxx...xxx[1]111..1111 */ ++ while (addr - 1 < end) { ++ tlb_flush_page(cs, addr); ++ addr += TARGET_PAGE_SIZE; ++ } ++ } ++} ++ ++void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx) ++{ ++ ls3a5k_tlb_t *tlb; ++ int asid = env->CSR_ASID & 0x3ff; ++ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; ++ if (tlb->G == 0 && tlb->ASID != asid) { ++ return; ++ } ++ ls3a5k_invalidate_tlb_entry(env, tlb); ++} ++ ++void ls3a5k_helper_tlbwr(CPULOONGARCHState *env) ++{ ++ int idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; /* [11:0] */ ++ ++ /* Convert idx if in FTLB */ ++ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { ++ /* ++ * 0 3 6 0 1 2 ++ * 1 4 7 => 3 4 5 ++ * 2 5 8 6 7 8 ++ */ ++ int set = idx % 256; ++ int way = idx / 256; ++ idx = set * 8 + way; ++ } ++ ls3a5k_invalidate_tlb(env, idx); ++ ls3a5k_fill_tlb(env, idx, true); ++} ++ ++void ls3a5k_helper_tlbfill(CPULOONGARCHState *env) ++{ ++ uint64_t mask; ++ uint64_t address; ++ int idx; ++ int set, ftlb_idx; ++ ++ uint64_t entryhi; ++ uint32_t pagesize; ++ ++ if (env->CSR_TLBRERA & 0x1) { ++ entryhi = env->CSR_TLBREHI & ~0x3f; ++ pagesize = env->CSR_TLBREHI & 0x3f; ++ } else { ++ entryhi = env->CSR_TLBEHI; ++ pagesize = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; ++ } ++ ++ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; ++ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; ++ ++ mask = ls3a5k_pagesize_to_mask(pagesize); ++ ++ if (mask == env->tlb->mmu.ls3a5k.ftlb_mask && ++ env->tlb->mmu.ls3a5k.ftlb_size > 0) { ++ /* only write into FTLB */ ++ address = entryhi & 0xffffffffe000; /* [47:13] */ ++ ++ /* choose one set ramdomly */ ++ set = cpu_loongarch_get_random_ls3a5k_tlb(0, 7); ++ ++ /* index in one set */ ++ ftlb_idx = (address >> 15) & 0xff; /* [0,255] */ ++ ++ /* final idx */ ++ idx = ftlb_idx * 8 + set; /* max is 7 + 8 * 255 = 2047 */ ++ } else { ++ /* only write into VTLB */ ++ int wired_nr = env->CSR_TLBWIRED & 0x3f; ++ idx = cpu_loongarch_get_random_ls3a5k_tlb(ftlb_size + wired_nr, ++ ftlb_size + vtlb_size - 1); ++ } ++ ++ ls3a5k_invalidate_tlb(env, idx); ++ ls3a5k_fill_tlb(env, idx, false); ++} ++ ++void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env) ++{ ++ uint64_t mask; ++ uint64_t vpn; ++ uint64_t tag; ++ uint16_t asid; ++ ++ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; ++ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; ++ int i; ++ int ftlb_idx; /* [0,255] 2^8 0xff */ ++ ++ ls3a5k_tlb_t *tlb; ++ ++ asid = env->CSR_ASID & 0x3ff; ++ ++ /* search VTLB */ ++ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { ++ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; ++ mask = tlb->PageMask; ++ ++ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; ++ tag = tlb->VPN & ~mask; ++ ++ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && ++ tlb->EHINV != 1) { ++ env->CSR_TLBIDX = ++ (i & 0xfff) | ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); ++ goto _MATCH_OUT_; ++ } ++ } ++ ++ if (ftlb_size == 0) { ++ goto _NO_MATCH_OUT_; ++ } ++ ++ /* search FTLB */ ++ mask = env->tlb->mmu.ls3a5k.ftlb_mask; ++ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; ++ ++ ftlb_idx = (env->CSR_TLBEHI & 0xffffffffe000) >> 15; /* 16 KB */ ++ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ ++ ++ for (i = 0; i < 8; ++i) { ++ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; ++ tag = tlb->VPN & ~mask; ++ ++ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && ++ tlb->EHINV != 1) { ++ env->CSR_TLBIDX = ((i * 256 + ftlb_idx) & 0xfff) | ++ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); ++ goto _MATCH_OUT_; ++ } ++ } ++ ++_NO_MATCH_OUT_: ++ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; ++_MATCH_OUT_: ++ return; ++} ++ ++void ls3a5k_helper_tlbrd(CPULOONGARCHState *env) ++{ ++ ls3a5k_tlb_t *tlb; ++ int idx; ++ uint16_t asid; ++ ++ idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; ++ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { ++ int set = idx % 256; ++ int way = idx / 256; ++ idx = set * 8 + way; ++ } ++ ++ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; ++ ++ asid = env->CSR_ASID & 0x3ff; ++ ++ if (asid != tlb->ASID) { ++ cpu_loongarch_tlb_flush(env); ++ } ++ ++ if (tlb->EHINV) { ++ /* invalid TLB entry */ ++ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; ++ env->CSR_TLBEHI = 0; ++ env->CSR_TLBELO0 = 0; ++ env->CSR_TLBELO1 = 0; ++ } else { ++ /* valid TLB entry */ ++ env->CSR_TLBIDX = (env->CSR_TLBIDX & 0xfff) | ++ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); ++ env->CSR_TLBEHI = tlb->VPN; ++ env->CSR_TLBELO0 = (tlb->V0 << CSR_TLBLO0_V_SHIFT) | ++ (tlb->WE0 << CSR_TLBLO0_WE_SHIFT) | ++ (tlb->PLV0 << CSR_TLBLO0_PLV_SHIFT) | ++ (tlb->C0 << CSR_TLBLO0_CCA_SHIFT) | ++ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | ++ (tlb->PPN0 & 0xfffffffff000) | ++ ((uint64_t)tlb->RI0 << CSR_TLBLO0_RI_SHIFT) | ++ ((uint64_t)tlb->XI0 << CSR_TLBLO0_XI_SHIFT) | ++ ((uint64_t)tlb->RPLV0 << CSR_TLBLO0_RPLV_SHIFT); ++ env->CSR_TLBELO1 = (tlb->V1 << CSR_TLBLO1_V_SHIFT) | ++ (tlb->WE1 << CSR_TLBLO1_WE_SHIFT) | ++ (tlb->PLV1 << CSR_TLBLO1_PLV_SHIFT) | ++ (tlb->C1 << CSR_TLBLO1_CCA_SHIFT) | ++ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | ++ (tlb->PPN1 & 0xfffffffff000) | ++ ((uint64_t)tlb->RI1 << CSR_TLBLO1_RI_SHIFT) | ++ ((uint64_t)tlb->XI1 << CSR_TLBLO1_XI_SHIFT) | ++ ((uint64_t)tlb->RPLV1 << CSR_TLBLO1_RPLV_SHIFT); ++ env->CSR_ASID = ++ (tlb->ASID << CSR_ASID_ASID_SHIFT) | (env->CSR_ASID & 0xff0000); ++ } ++} ++ ++void helper_tlbwr(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbwr(env); ++} ++ ++void helper_tlbfill(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbfill(env); ++} ++ ++void helper_tlbsrch(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbsrch(env); ++} ++ ++void helper_tlbrd(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbrd(env); ++} ++ ++void helper_tlbclr(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbclr(env); ++} ++ ++void helper_tlbflush(CPULOONGARCHState *env) ++{ ++ env->tlb->helper_tlbflush(env); ++} ++ ++void helper_invtlb(CPULOONGARCHState *env, target_ulong addr, ++ target_ulong info, target_ulong op) ++{ ++ env->tlb->helper_invtlb(env, addr, info, op); ++} ++ ++static void ls3a5k_mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) ++{ ++ /* number of VTLB */ ++ env->tlb->nb_tlb = 64; ++ env->tlb->mmu.ls3a5k.vtlb_size = 64; ++ ++ /* number of FTLB */ ++ env->tlb->nb_tlb += 2048; ++ env->tlb->mmu.ls3a5k.ftlb_size = 2048; ++ env->tlb->mmu.ls3a5k.ftlb_mask = (1 << 15) - 1; /* 16 KB */ ++ /* ++ * page_size | ftlb_mask | party field ++ * ---------------------------------------------------------------- ++ * 4 KB = 12 | ( 1 << 13 ) - 1 = [12:0] | [12] ++ * 16 KB = 14 | ( 1 << 15 ) - 1 = [14:0] | [14] ++ * 64 KB = 16 | ( 1 << 17 ) - 1 = [16:0] | [16] ++ * 256 KB = 18 | ( 1 << 19 ) - 1 = [18:0] | [18] ++ * 1 MB = 20 | ( 1 << 21 ) - 1 = [20:0] | [20] ++ * 4 MB = 22 | ( 1 << 23 ) - 1 = [22:0] | [22] ++ * 16 MB = 24 | ( 1 << 25 ) - 1 = [24:0] | [24] ++ * 64 MB = 26 | ( 1 << 27 ) - 1 = [26:0] | [26] ++ * 256 MB = 28 | ( 1 << 29 ) - 1 = [28:0] | [28] ++ * 1 GB = 30 | ( 1 << 31 ) - 1 = [30:0] | [30] ++ * ---------------------------------------------------------------- ++ * take party field index as @n. eg. For 16 KB, n = 14 ++ * ---------------------------------------------------------------- ++ * tlb->VPN = TLBEHI & 0xffffffffe000[47:13] & ~mask = [47:n+1] ++ * tlb->PPN = TLBLO0 & 0xffffffffe000[47:13] & ~mask = [47:n+1] ++ * tlb->PPN = TLBLO1 & 0xffffffffe000[47:13] & ~mask = [47:n+1] ++ * ---------------------------------------------------------------- ++ * On mapping : ++ * > vpn = address & 0xffffffffe000[47:13] & ~mask = [47:n+1] ++ * > tag = tlb->VPN & ~mask = [47:n+1] ++ * ---------------------------------------------------------------- ++ * physical address = [47:n+1] | [n:0] ++ * physical address = tlb->PPN0 | (address & mask) ++ * physical address = tlb->PPN1 | (address & mask) ++ */ ++ ++ int i; ++ for (i = 0; i < env->tlb->nb_tlb; i++) { ++ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; ++ } ++ ++ /* TLB's helper functions */ ++ env->tlb->map_address = &ls3a5k_map_address; ++ env->tlb->helper_tlbwr = ls3a5k_helper_tlbwr; ++ env->tlb->helper_tlbfill = ls3a5k_helper_tlbfill; ++ env->tlb->helper_tlbsrch = ls3a5k_helper_tlbsrch; ++ env->tlb->helper_tlbrd = ls3a5k_helper_tlbrd; ++ env->tlb->helper_tlbclr = ls3a5k_helper_tlbclr; ++ env->tlb->helper_tlbflush = ls3a5k_helper_tlbflush; ++ env->tlb->helper_invtlb = ls3a5k_helper_invtlb; ++} ++ ++void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) ++{ ++ env->tlb = g_malloc0(sizeof(CPULOONGARCHTLBContext)); ++ ++ switch (def->mmu_type) { ++ case MMU_TYPE_LS3A5K: ++ ls3a5k_mmu_init(env, def); ++ break; ++ default: ++ cpu_abort(CPU(loongarch_env_get_cpu(env)), "MMU type not supported\n"); ++ } ++} ++#endif /* !CONFIG_USER_ONLY */ +diff --git a/target/loongarch64/trans.inc.c b/target/loongarch64/trans.inc.c +new file mode 100644 +index 0000000000..07bb0bb6e0 +--- /dev/null ++++ b/target/loongarch64/trans.inc.c +@@ -0,0 +1,3482 @@ ++/* ++ * LOONGARCH emulation for QEMU - main translation routines Extension ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++static bool trans_syscall(DisasContext *ctx, arg_syscall *a) ++{ ++ generate_exception_end(ctx, EXCP_SYSCALL); ++ return true; ++} ++ ++static bool trans_break(DisasContext *ctx, arg_break *a) ++{ ++ generate_exception_end(ctx, EXCP_BREAK); ++ return true; ++} ++ ++static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) ++{ ++ /* ++ * dbcl instruction is not support in tcg ++ */ ++ generate_exception_end(ctx, EXCP_RI); ++ return true; ++} ++ ++static bool trans_addi_w(DisasContext *ctx, arg_addi_w *a) ++{ ++ gen_arith_imm(ctx, OPC_LARCH_ADDI_W, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_addi_d(DisasContext *ctx, arg_addi_d *a) ++{ ++ gen_arith_imm(ctx, OPC_LARCH_ADDI_D, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_slli_d(DisasContext *ctx, arg_slli_d *a) ++{ ++ if (a->rd == 0) { ++ /* Nop */ ++ return true; ++ } ++ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ tcg_gen_shli_tl(cpu_gpr[a->rd], t0, a->ui6); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_andi(DisasContext *ctx, arg_andi *a) ++{ ++ gen_logic_imm(ctx, OPC_LARCH_ANDI, a->rd, a->rj, a->ui12); ++ return true; ++} ++ ++static bool trans_srli_d(DisasContext *ctx, arg_srli_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ tcg_gen_shri_tl(cpu_gpr[a->rd], t0, a->ui6); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_slli_w(DisasContext *ctx, arg_slli_w *a) ++{ ++ if (a->rd == 0) { ++ /* Nop */ ++ return true; ++ } ++ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ tcg_gen_shli_tl(t0, t0, a->ui5); ++ tcg_gen_ext32s_tl(cpu_gpr[a->rd], t0); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) ++{ ++ if (a->rj != 0) { ++ tcg_gen_addi_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], a->si16 << 16); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si16 << 16); ++ } ++ return true; ++} ++ ++static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) ++{ ++ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si20 << 12); ++ return true; ++} ++ ++static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) ++{ ++ TCGv_i64 t0, t1; ++ t0 = tcg_temp_new_i64(); ++ t1 = tcg_temp_new_i64(); ++ ++ tcg_gen_movi_tl(t0, a->si20); ++ tcg_gen_concat_tl_i64(t1, cpu_gpr[a->rd], t0); ++ gen_store_gpr(t1, a->rd); ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_pcaddi(DisasContext *ctx, arg_pcaddi *a) ++{ ++ target_ulong pc = ctx->base.pc_next; ++ target_ulong addr = pc + (a->si20 << 2); ++ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); ++ return true; ++} ++ ++static bool trans_pcalau12i(DisasContext *ctx, arg_pcalau12i *a) ++{ ++ target_ulong pc = ctx->base.pc_next; ++ target_ulong addr = (pc + (a->si20 << 12)) & ~0xfff; ++ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); ++ return true; ++} ++ ++static bool trans_pcaddu12i(DisasContext *ctx, arg_pcaddu12i *a) ++{ ++ target_ulong pc = ctx->base.pc_next; ++ target_ulong addr = pc + (a->si20 << 12); ++ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); ++ return true; ++} ++ ++static bool trans_pcaddu18i(DisasContext *ctx, arg_pcaddu18i *a) ++{ ++ target_ulong pc = ctx->base.pc_next; ++ target_ulong addr = pc + ((target_ulong)(a->si20) << 18); ++ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); ++ return true; ++} ++ ++static bool trans_slti(DisasContext *ctx, arg_slti *a) ++{ ++ gen_slt_imm(ctx, OPC_LARCH_SLTI, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_sltui(DisasContext *ctx, arg_sltui *a) ++{ ++ gen_slt_imm(ctx, OPC_LARCH_SLTIU, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ gen_load_gpr(t1, a->rj); ++ ++ tcg_gen_movi_tl(t0, a->si12); ++ tcg_gen_shli_tl(t0, t0, 52); ++ tcg_gen_andi_tl(t1, t1, 0xfffffffffffffU); ++ tcg_gen_or_tl(cpu_gpr[a->rd], t0, t1); ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ori(DisasContext *ctx, arg_ori *a) ++{ ++ gen_logic_imm(ctx, OPC_LARCH_ORI, a->rd, a->rj, a->ui12); ++ return true; ++} ++ ++static bool trans_xori(DisasContext *ctx, arg_xori *a) ++{ ++ gen_logic_imm(ctx, OPC_LARCH_XORI, a->rd, a->rj, a->ui12); ++ return true; ++} ++ ++static bool trans_bstrins_d(DisasContext *ctx, arg_bstrins_d *a) ++{ ++ int lsb = a->lsbd; ++ int msb = a->msbd; ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ if (lsb > msb) { ++ return false; ++ } ++ ++ gen_load_gpr(t1, a->rj); ++ gen_load_gpr(t0, a->rd); ++ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); ++ gen_store_gpr(t0, a->rd); ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_bstrpick_d(DisasContext *ctx, arg_bstrpick_d *a) ++{ ++ int lsb = a->lsbd; ++ int msb = a->msbd; ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ if (lsb > msb) { ++ return false; ++ } ++ ++ gen_load_gpr(t1, a->rj); ++ gen_load_gpr(t0, a->rd); ++ tcg_gen_extract_tl(t0, t1, lsb, msb - lsb + 1); ++ gen_store_gpr(t0, a->rd); ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_bstrins_w(DisasContext *ctx, arg_bstrins_w *a) ++{ ++ gen_bitops(ctx, OPC_LARCH_TRINS_W, a->rd, a->rj, a->lsbw, a->msbw); ++ return true; ++} ++ ++static bool trans_bstrpick_w(DisasContext *ctx, arg_bstrpick_w *a) ++{ ++ if (a->lsbw > a->msbw) { ++ return false; ++ } ++ gen_bitops(ctx, OPC_LARCH_TRPICK_W, a->rd, a->rj, a->lsbw, ++ a->msbw - a->lsbw); ++ return true; ++} ++ ++static bool trans_ldptr_w(DisasContext *ctx, arg_ldptr_w *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LDPTR_W, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_stptr_w(DisasContext *ctx, arg_stptr_w *a) ++{ ++ gen_st(ctx, OPC_LARCH_STPTR_W, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_ldptr_d(DisasContext *ctx, arg_ldptr_d *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LDPTR_D, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_stptr_d(DisasContext *ctx, arg_stptr_d *a) ++{ ++ gen_st(ctx, OPC_LARCH_STPTR_D, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_ld_b(DisasContext *ctx, arg_ld_b *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_B, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_h(DisasContext *ctx, arg_ld_h *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_H, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_w(DisasContext *ctx, arg_ld_w *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_W, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_d(DisasContext *ctx, arg_ld_d *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_D, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_st_b(DisasContext *ctx, arg_st_b *a) ++{ ++ gen_st(ctx, OPC_LARCH_ST_B, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_st_h(DisasContext *ctx, arg_st_h *a) ++{ ++ gen_st(ctx, OPC_LARCH_ST_H, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_st_w(DisasContext *ctx, arg_st_w *a) ++{ ++ gen_st(ctx, OPC_LARCH_ST_W, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_st_d(DisasContext *ctx, arg_st_d *a) ++{ ++ gen_st(ctx, OPC_LARCH_ST_D, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_bu(DisasContext *ctx, arg_ld_bu *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_BU, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_hu(DisasContext *ctx, arg_ld_hu *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_HU, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ld_wu(DisasContext *ctx, arg_ld_wu *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LD_WU, a->rd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_preld(DisasContext *ctx, arg_preld *a) ++{ ++ /* Treat as NOP. */ ++ return true; ++} ++ ++static bool trans_ll_w(DisasContext *ctx, arg_ll_w *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LL_W, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) ++{ ++ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TESL, false); ++ return true; ++} ++ ++static bool trans_ll_d(DisasContext *ctx, arg_ll_d *a) ++{ ++ gen_ld(ctx, OPC_LARCH_LL_D, a->rd, a->rj, a->si14 << 2); ++ return true; ++} ++ ++static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) ++{ ++ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TEQ, false); ++ return true; ++} ++ ++static bool trans_fld_s(DisasContext *ctx, arg_fld_s *a) ++{ ++ gen_fp_ldst(ctx, OPC_LARCH_FLD_S, a->fd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_fst_s(DisasContext *ctx, arg_fst_s *a) ++{ ++ gen_fp_ldst(ctx, OPC_LARCH_FST_S, a->fd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_fld_d(DisasContext *ctx, arg_fld_d *a) ++{ ++ gen_fp_ldst(ctx, OPC_LARCH_FLD_D, a->fd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_fst_d(DisasContext *ctx, arg_fst_d *a) ++{ ++ gen_fp_ldst(ctx, OPC_LARCH_FST_D, a->fd, a->rj, a->si12); ++ return true; ++} ++ ++static bool trans_ldx_b(DisasContext *ctx, arg_ldx_b *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_SB); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ldx_h(DisasContext *ctx, arg_ldx_h *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESW | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ldx_w(DisasContext *ctx, arg_ldx_w *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESL | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_ldx_d(DisasContext *ctx, arg_ldx_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEQ | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_stx_b(DisasContext *ctx, arg_stx_b *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ gen_load_gpr(t1, a->rd); ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_stx_h(DisasContext *ctx, arg_stx_h *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ gen_load_gpr(t1, a->rd); ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | ctx->default_tcg_memop_mask); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_stx_w(DisasContext *ctx, arg_stx_w *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ gen_load_gpr(t1, a->rd); ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | ctx->default_tcg_memop_mask); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_stx_d(DisasContext *ctx, arg_stx_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ gen_load_gpr(t1, a->rd); ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | ctx->default_tcg_memop_mask); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ldx_bu(DisasContext *ctx, arg_ldx_bu *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ldx_hu(DisasContext *ctx, arg_ldx_hu *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUW | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_ldx_wu(DisasContext *ctx, arg_ldx_wu *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); ++ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUL | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t1, a->rd); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_fldx_s(DisasContext *ctx, arg_fldx_s *a) ++{ ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_S, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fldx_d(DisasContext *ctx, arg_fldx_d *a) ++{ ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_D, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstx_s(DisasContext *ctx, arg_fstx_s *a) ++{ ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_S, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstx_d(DisasContext *ctx, arg_fstx_d *a) ++{ ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_D, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++#define TRANS_AM_W(name, op) \ ++ static bool trans_##name(DisasContext *ctx, arg_##name *a) \ ++ { \ ++ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ ++ printf("%s: warning, register equal\n", __func__); \ ++ return false; \ ++ } \ ++ int mem_idx = ctx->mem_idx; \ ++ TCGv addr = tcg_temp_new(); \ ++ TCGv val = tcg_temp_new(); \ ++ TCGv ret = tcg_temp_new(); \ ++ \ ++ gen_load_gpr(addr, a->rj); \ ++ gen_load_gpr(val, a->rk); \ ++ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, \ ++ MO_TESL | ctx->default_tcg_memop_mask); \ ++ gen_store_gpr(ret, a->rd); \ ++ \ ++ tcg_temp_free(addr); \ ++ tcg_temp_free(val); \ ++ tcg_temp_free(ret); \ ++ return true; \ ++ } ++#define TRANS_AM_D(name, op) \ ++ static bool trans_##name(DisasContext *ctx, arg_##name *a) \ ++ { \ ++ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ ++ printf("%s: warning, register equal\n", __func__); \ ++ return false; \ ++ } \ ++ int mem_idx = ctx->mem_idx; \ ++ TCGv addr = tcg_temp_new(); \ ++ TCGv val = tcg_temp_new(); \ ++ TCGv ret = tcg_temp_new(); \ ++ \ ++ gen_load_gpr(addr, a->rj); \ ++ gen_load_gpr(val, a->rk); \ ++ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, \ ++ MO_TEQ | ctx->default_tcg_memop_mask); \ ++ gen_store_gpr(ret, a->rd); \ ++ \ ++ tcg_temp_free(addr); \ ++ tcg_temp_free(val); \ ++ tcg_temp_free(ret); \ ++ return true; \ ++ } ++#define TRANS_AM(name, op) \ ++ TRANS_AM_W(name##_w, op) \ ++ TRANS_AM_D(name##_d, op) ++TRANS_AM(amswap, xchg) /* trans_amswap_w, trans_amswap_d */ ++TRANS_AM(amadd, fetch_add) /* trans_amadd_w, trans_amadd_d */ ++TRANS_AM(amand, fetch_and) /* trans_amand_w, trans_amand_d */ ++TRANS_AM(amor, fetch_or) /* trans_amor_w, trans_amor_d */ ++TRANS_AM(amxor, fetch_xor) /* trans_amxor_w, trans_amxor_d */ ++TRANS_AM(ammax, fetch_smax) /* trans_ammax_w, trans_ammax_d */ ++TRANS_AM(ammin, fetch_smin) /* trans_ammin_w, trans_ammin_d */ ++TRANS_AM_W(ammax_wu, fetch_umax) /* trans_ammax_wu */ ++TRANS_AM_D(ammax_du, fetch_umax) /* trans_ammax_du */ ++TRANS_AM_W(ammin_wu, fetch_umin) /* trans_ammin_wu */ ++TRANS_AM_D(ammin_du, fetch_umin) /* trans_ammin_du */ ++#undef TRANS_AM ++#undef TRANS_AM_W ++#undef TRANS_AM_D ++ ++#define TRANS_AM_DB_W(name, op) \ ++ static bool trans_##name(DisasContext *ctx, arg_##name *a) \ ++ { \ ++ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ ++ printf("%s: warning, register equal\n", __func__); \ ++ return false; \ ++ } \ ++ int mem_idx = ctx->mem_idx; \ ++ TCGv addr = tcg_temp_new(); \ ++ TCGv val = tcg_temp_new(); \ ++ TCGv ret = tcg_temp_new(); \ ++ \ ++ gen_sync(0x10); \ ++ gen_load_gpr(addr, a->rj); \ ++ gen_load_gpr(val, a->rk); \ ++ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, \ ++ MO_TESL | ctx->default_tcg_memop_mask); \ ++ gen_store_gpr(ret, a->rd); \ ++ \ ++ tcg_temp_free(addr); \ ++ tcg_temp_free(val); \ ++ tcg_temp_free(ret); \ ++ return true; \ ++ } ++#define TRANS_AM_DB_D(name, op) \ ++ static bool trans_##name(DisasContext *ctx, arg_##name *a) \ ++ { \ ++ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ ++ printf("%s: warning, register equal\n", __func__); \ ++ return false; \ ++ } \ ++ int mem_idx = ctx->mem_idx; \ ++ TCGv addr = tcg_temp_new(); \ ++ TCGv val = tcg_temp_new(); \ ++ TCGv ret = tcg_temp_new(); \ ++ \ ++ gen_sync(0x10); \ ++ gen_load_gpr(addr, a->rj); \ ++ gen_load_gpr(val, a->rk); \ ++ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, \ ++ MO_TEQ | ctx->default_tcg_memop_mask); \ ++ gen_store_gpr(ret, a->rd); \ ++ \ ++ tcg_temp_free(addr); \ ++ tcg_temp_free(val); \ ++ tcg_temp_free(ret); \ ++ return true; \ ++ } ++#define TRANS_AM_DB(name, op) \ ++ TRANS_AM_DB_W(name##_db_w, op) \ ++ TRANS_AM_DB_D(name##_db_d, op) ++TRANS_AM_DB(amswap, xchg) /* trans_amswap_db_w, trans_amswap_db_d */ ++TRANS_AM_DB(amadd, fetch_add) /* trans_amadd_db_w, trans_amadd_db_d */ ++TRANS_AM_DB(amand, fetch_and) /* trans_amand_db_w, trans_amand_db_d */ ++TRANS_AM_DB(amor, fetch_or) /* trans_amor_db_w, trans_amor_db_d */ ++TRANS_AM_DB(amxor, fetch_xor) /* trans_amxor_db_w, trans_amxor_db_d */ ++TRANS_AM_DB(ammax, fetch_smax) /* trans_ammax_db_w, trans_ammax_db_d */ ++TRANS_AM_DB(ammin, fetch_smin) /* trans_ammin_db_w, trans_ammin_db_d */ ++TRANS_AM_DB_W(ammax_db_wu, fetch_umax) /* trans_ammax_db_wu */ ++TRANS_AM_DB_D(ammax_db_du, fetch_umax) /* trans_ammax_db_du */ ++TRANS_AM_DB_W(ammin_db_wu, fetch_umin) /* trans_ammin_db_wu */ ++TRANS_AM_DB_D(ammin_db_du, fetch_umin) /* trans_ammin_db_du */ ++#undef TRANS_AM_DB ++#undef TRANS_AM_DB_W ++#undef TRANS_AM_DB_D ++ ++static bool trans_dbar(DisasContext *ctx, arg_dbar *a) ++{ ++ gen_sync(a->whint); ++ return true; ++} ++ ++static bool trans_ibar(DisasContext *ctx, arg_ibar *a) ++{ ++ /* ++ * FENCE_I is a no-op in QEMU, ++ * however we need to end the translation block ++ */ ++ ctx->base.is_jmp = DISAS_STOP; ++ return true; ++} ++ ++#define ASRTGT \ ++ do { \ ++ TCGv t1 = tcg_temp_new(); \ ++ TCGv t2 = tcg_temp_new(); \ ++ gen_load_gpr(t1, a->rj); \ ++ gen_load_gpr(t2, a->rk); \ ++ gen_helper_asrtgt_d(cpu_env, t1, t2); \ ++ tcg_temp_free(t1); \ ++ tcg_temp_free(t2); \ ++ } while (0) ++ ++#define ASRTLE \ ++ do { \ ++ TCGv t1 = tcg_temp_new(); \ ++ TCGv t2 = tcg_temp_new(); \ ++ gen_load_gpr(t1, a->rj); \ ++ gen_load_gpr(t2, a->rk); \ ++ gen_helper_asrtle_d(cpu_env, t1, t2); \ ++ tcg_temp_free(t1); \ ++ tcg_temp_free(t2); \ ++ } while (0) ++ ++static bool trans_fldgt_s(DisasContext *ctx, arg_fldgt_s *a) ++{ ++ ASRTGT; ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_S, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fldgt_d(DisasContext *ctx, arg_fldgt_d *a) ++{ ++ ASRTGT; ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_D, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fldle_s(DisasContext *ctx, arg_fldle_s *a) ++{ ++ ASRTLE; ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_S, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fldle_d(DisasContext *ctx, arg_fldle_d *a) ++{ ++ ASRTLE; ++ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_D, a->fd, 0, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstgt_s(DisasContext *ctx, arg_fstgt_s *a) ++{ ++ ASRTGT; ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_S, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstgt_d(DisasContext *ctx, arg_fstgt_d *a) ++{ ++ ASRTGT; ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_D, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstle_s(DisasContext *ctx, arg_fstle_s *a) ++{ ++ ASRTLE; ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_S, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_fstle_d(DisasContext *ctx, arg_fstle_d *a) ++{ ++ ASRTLE; ++ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_D, 0, a->fd, a->rj, a->rk); ++ return true; ++} ++ ++#define DECL_ARG(name) \ ++ arg_##name arg = { \ ++ .rd = a->rd, \ ++ .rj = a->rj, \ ++ .rk = a->rk, \ ++ }; ++ ++static bool trans_ldgt_b(DisasContext *ctx, arg_ldgt_b *a) ++{ ++ ASRTGT; ++ DECL_ARG(ldx_b) ++ trans_ldx_b(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldgt_h(DisasContext *ctx, arg_ldgt_h *a) ++{ ++ ASRTGT; ++ DECL_ARG(ldx_h) ++ trans_ldx_h(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldgt_w(DisasContext *ctx, arg_ldgt_w *a) ++{ ++ ASRTGT; ++ DECL_ARG(ldx_w) ++ trans_ldx_w(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldgt_d(DisasContext *ctx, arg_ldgt_d *a) ++{ ++ ASRTGT; ++ DECL_ARG(ldx_d) ++ trans_ldx_d(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldle_b(DisasContext *ctx, arg_ldle_b *a) ++{ ++ ASRTLE; ++ DECL_ARG(ldx_b) ++ trans_ldx_b(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldle_h(DisasContext *ctx, arg_ldle_h *a) ++{ ++ ASRTLE; ++ DECL_ARG(ldx_h) ++ trans_ldx_h(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldle_w(DisasContext *ctx, arg_ldle_w *a) ++{ ++ ASRTLE; ++ DECL_ARG(ldx_w) ++ trans_ldx_w(ctx, &arg); ++ return true; ++} ++ ++static bool trans_ldle_d(DisasContext *ctx, arg_ldle_d *a) ++{ ++ ASRTLE; ++ DECL_ARG(ldx_d) ++ trans_ldx_d(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stgt_b(DisasContext *ctx, arg_stgt_b *a) ++{ ++ ASRTGT; ++ DECL_ARG(stx_b) ++ trans_stx_b(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stgt_h(DisasContext *ctx, arg_stgt_h *a) ++{ ++ ASRTGT; ++ DECL_ARG(stx_h) ++ trans_stx_h(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stgt_w(DisasContext *ctx, arg_stgt_w *a) ++{ ++ ASRTGT; ++ DECL_ARG(stx_w) ++ trans_stx_w(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stgt_d(DisasContext *ctx, arg_stgt_d *a) ++{ ++ ASRTGT; ++ DECL_ARG(stx_d) ++ trans_stx_d(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stle_b(DisasContext *ctx, arg_stle_b *a) ++{ ++ ASRTLE; ++ DECL_ARG(stx_b) ++ trans_stx_b(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stle_h(DisasContext *ctx, arg_stle_h *a) ++{ ++ ASRTLE; ++ DECL_ARG(stx_h) ++ trans_stx_h(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stle_w(DisasContext *ctx, arg_stle_w *a) ++{ ++ ASRTLE; ++ DECL_ARG(stx_w) ++ trans_stx_w(ctx, &arg); ++ return true; ++} ++ ++static bool trans_stle_d(DisasContext *ctx, arg_stle_d *a) ++{ ++ ASRTLE; ++ DECL_ARG(stx_d) ++ trans_stx_d(ctx, &arg); ++ return true; ++} ++ ++#undef ASRTGT ++#undef ASRTLE ++#undef DECL_ARG ++ ++static bool trans_beqz(DisasContext *ctx, arg_beqz *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BEQZ, 4, a->rj, 0, a->offs21 << 2); ++ return true; ++} ++ ++static bool trans_bnez(DisasContext *ctx, arg_bnez *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BNEZ, 4, a->rj, 0, a->offs21 << 2); ++ return true; ++} ++ ++static bool trans_bceqz(DisasContext *ctx, arg_bceqz *a) ++{ ++ TCGv_i32 cj = tcg_const_i32(a->cj); ++ TCGv v0 = tcg_temp_new(); ++ TCGv v1 = tcg_const_i64(0); ++ ++ gen_helper_movcf2reg(v0, cpu_env, cj); ++ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, v0, v1); ++ ctx->hflags |= LARCH_HFLAG_BC; ++ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); ++ ++ tcg_temp_free_i32(cj); ++ tcg_temp_free(v0); ++ tcg_temp_free(v1); ++ return true; ++} ++ ++static bool trans_bcnez(DisasContext *ctx, arg_bcnez *a) ++{ ++ TCGv_i32 cj = tcg_const_i32(a->cj); ++ TCGv v0 = tcg_temp_new(); ++ TCGv v1 = tcg_const_i64(0); ++ ++ gen_helper_movcf2reg(v0, cpu_env, cj); ++ tcg_gen_setcond_tl(TCG_COND_NE, bcond, v0, v1); ++ ctx->hflags |= LARCH_HFLAG_BC; ++ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); ++ ++ tcg_temp_free_i32(cj); ++ tcg_temp_free(v0); ++ tcg_temp_free(v1); ++ return true; ++} ++ ++static bool trans_b(DisasContext *ctx, arg_b *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_B, 4, 0, 0, a->offs << 2); ++ return true; ++} ++ ++static bool trans_bl(DisasContext *ctx, arg_bl *a) ++{ ++ ctx->btarget = ctx->base.pc_next + (a->offs << 2); ++ tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); ++ ctx->hflags |= LARCH_HFLAG_B; ++ gen_branch(ctx, 4); ++ return true; ++} ++ ++static bool trans_blt(DisasContext *ctx, arg_blt *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BLT, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_bge(DisasContext *ctx, arg_bge *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BGE, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_bltu(DisasContext *ctx, arg_bltu *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BLTU, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BGEU, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_beq(DisasContext *ctx, arg_beq *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BEQ, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_bne(DisasContext *ctx, arg_bne *a) ++{ ++ gen_compute_branch(ctx, OPC_LARCH_BNE, 4, a->rj, a->rd, a->offs16 << 2); ++ return true; ++} ++ ++static bool trans_jirl(DisasContext *ctx, arg_jirl *a) ++{ ++ gen_base_offset_addr(ctx, btarget, a->rj, a->offs16 << 2); ++ if (a->rd != 0) { ++ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->base.pc_next + 4); ++ } ++ ctx->hflags |= LARCH_HFLAG_BR; ++ gen_branch(ctx, 4); ++ ++ return true; ++} ++ ++#define TRANS_F4FR(name, fmt, op, bits) \ ++ static bool trans_##name##_##fmt(DisasContext *ctx, \ ++ arg_##name##_##fmt *a) \ ++ { \ ++ check_cp1_enabled(ctx); \ ++ TCGv_i##bits fp0 = tcg_temp_new_i##bits(); \ ++ TCGv_i##bits fp1 = tcg_temp_new_i##bits(); \ ++ TCGv_i##bits fp2 = tcg_temp_new_i##bits(); \ ++ TCGv_i##bits fp3 = tcg_temp_new_i##bits(); \ ++ check_cp1_enabled(ctx); \ ++ gen_load_fpr##bits(ctx, fp0, a->fj); \ ++ gen_load_fpr##bits(ctx, fp1, a->fk); \ ++ gen_load_fpr##bits(ctx, fp2, a->fa); \ ++ gen_helper_float_##op##_##fmt(fp3, cpu_env, fp0, fp1, fp2); \ ++ gen_store_fpr##bits(ctx, fp3, a->fd); \ ++ tcg_temp_free_i##bits(fp3); \ ++ tcg_temp_free_i##bits(fp2); \ ++ tcg_temp_free_i##bits(fp1); \ ++ tcg_temp_free_i##bits(fp0); \ ++ return true; \ ++ } ++ ++TRANS_F4FR(fmadd, s, maddf, 32) /* trans_fmadd_s */ ++TRANS_F4FR(fmadd, d, maddf, 64) /* trans_fmadd_d */ ++TRANS_F4FR(fmsub, s, msubf, 32) /* trans_fmsub_s */ ++TRANS_F4FR(fmsub, d, msubf, 64) /* trans_fmsub_d */ ++TRANS_F4FR(fnmadd, s, nmaddf, 32) /* trans_fnmadd_s */ ++TRANS_F4FR(fnmadd, d, nmaddf, 64) /* trans_fnmadd_d */ ++TRANS_F4FR(fnmsub, s, nmsubf, 32) /* trans_fnmsub_s */ ++TRANS_F4FR(fnmsub, d, nmsubf, 64) /* trans_fnmsub_d */ ++#undef TRANS_F4FR ++ ++static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FADD_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FADD_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FSUB_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FSUB_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMUL_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMUL_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FDIV_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FDIV_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMAX_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMAX_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMIN_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMIN_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmaxa_s(DisasContext *ctx, arg_fmaxa_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMAXA_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmaxa_d(DisasContext *ctx, arg_fmaxa_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMAXA_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmina_s(DisasContext *ctx, arg_fmina_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMINA_S, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmina_d(DisasContext *ctx, arg_fmina_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMINA_D, a->fk, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fscaleb_s(DisasContext *ctx, arg_fscaleb_s *a) ++{ ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr32(ctx, fp0, a->fj); ++ gen_load_fpr32(ctx, fp1, a->fk); ++ gen_helper_float_exp2_s(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i32(fp1); ++ gen_store_fpr32(ctx, fp0, a->fd); ++ tcg_temp_free_i32(fp0); ++ return true; ++} ++ ++static bool trans_fscaleb_d(DisasContext *ctx, arg_fscaleb_d *a) ++{ ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr64(ctx, fp0, a->fj); ++ gen_load_fpr64(ctx, fp1, a->fk); ++ gen_helper_float_exp2_d(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i64(fp1); ++ gen_store_fpr64(ctx, fp0, a->fd); ++ tcg_temp_free_i64(fp0); ++ return true; ++} ++ ++static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) ++{ ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ TCGv_i32 fp2 = tcg_temp_new_i32(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr32(ctx, fp0, a->fj); ++ gen_load_fpr32(ctx, fp1, a->fk); ++ tcg_gen_deposit_i32(fp2, fp1, fp0, 0, 31); ++ gen_store_fpr32(ctx, fp2, a->fd); ++ ++ tcg_temp_free_i32(fp2); ++ tcg_temp_free_i32(fp1); ++ tcg_temp_free_i32(fp0); ++ return true; ++} ++ ++static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) ++{ ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ TCGv_i64 fp2 = tcg_temp_new_i64(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr64(ctx, fp0, a->fj); ++ gen_load_fpr64(ctx, fp1, a->fk); ++ tcg_gen_deposit_i64(fp2, fp1, fp0, 0, 63); ++ gen_store_fpr64(ctx, fp2, a->fd); ++ ++ tcg_temp_free_i64(fp2); ++ tcg_temp_free_i64(fp1); ++ tcg_temp_free_i64(fp0); ++ return true; ++} ++ ++static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FABS_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FABS_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FNEG_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FNEG_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_flogb_s(DisasContext *ctx, arg_flogb_s *a) ++{ ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr32(ctx, fp0, a->fj); ++ gen_helper_float_logb_s(fp1, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp1, a->fd); ++ ++ tcg_temp_free_i32(fp0); ++ tcg_temp_free_i32(fp1); ++ return true; ++} ++ ++static bool trans_flogb_d(DisasContext *ctx, arg_flogb_d *a) ++{ ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr64(ctx, fp0, a->fj); ++ gen_helper_float_logb_d(fp1, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp1, a->fd); ++ ++ tcg_temp_free_i64(fp0); ++ tcg_temp_free_i64(fp1); ++ return true; ++} ++ ++static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FCLASS_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FCLASS_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FSQRT_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FSQRT_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frecip_s(DisasContext *ctx, arg_frecip_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRECIP_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frecip_d(DisasContext *ctx, arg_frecip_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRECIP_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frsqrt_s(DisasContext *ctx, arg_frsqrt_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRSQRT_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frsqrt_d(DisasContext *ctx, arg_frsqrt_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRSQRT_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmov_s(DisasContext *ctx, arg_fmov_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMOV_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fmov_d(DisasContext *ctx, arg_fmov_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FMOV_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_movgr2fr_w(DisasContext *ctx, arg_movgr2fr_w *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_GR2FR_W, a->rj, a->fd); ++ return true; ++} ++ ++static bool trans_movgr2fr_d(DisasContext *ctx, arg_movgr2fr_d *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_GR2FR_D, a->rj, a->fd); ++ return true; ++} ++ ++static bool trans_movgr2frh_w(DisasContext *ctx, arg_movgr2frh_w *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_GR2FRH_W, a->rj, a->fd); ++ return true; ++} ++ ++static bool trans_movfr2gr_s(DisasContext *ctx, arg_movfr2gr_s *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_FR2GR_S, a->rd, a->fj); ++ return true; ++} ++ ++static bool trans_movfr2gr_d(DisasContext *ctx, arg_movfr2gr_d *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_FR2GR_D, a->rd, a->fj); ++ return true; ++} ++ ++static bool trans_movfrh2gr_s(DisasContext *ctx, arg_movfrh2gr_s *a) ++{ ++ gen_cp1(ctx, OPC_LARCH_FRH2GR_S, a->rd, a->fj); ++ return true; ++} ++ ++static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ check_cp1_enabled(ctx); ++ gen_load_gpr(t0, a->rj); ++ save_cpu_state(ctx, 0); ++ { ++ TCGv_i32 fs_tmp = tcg_const_i32(a->fcsrd); ++ gen_helper_0e2i(movgr2fcsr, t0, fs_tmp, a->rj); ++ tcg_temp_free_i32(fs_tmp); ++ } ++ /* Stop translation as we may have changed hflags */ ++ ctx->base.is_jmp = DISAS_STOP; ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ gen_helper_1e0i(movfcsr2gr, t0, a->fcsrs); ++ gen_store_gpr(t0, a->rd); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) ++{ ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i32 cd = tcg_const_i32(a->cd); ++ ++ check_cp1_enabled(ctx); ++ gen_load_fpr64(ctx, fp0, a->fj); ++ gen_helper_movreg2cf(cpu_env, cd, fp0); ++ ++ tcg_temp_free_i64(fp0); ++ tcg_temp_free_i32(cd); ++ return true; ++} ++ ++static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv_i32 cj = tcg_const_i32(a->cj); ++ ++ check_cp1_enabled(ctx); ++ gen_helper_movcf2reg(t0, cpu_env, cj); ++ gen_store_fpr64(ctx, t0, a->fd); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv_i32 cd = tcg_const_i32(a->cd); ++ ++ check_cp1_enabled(ctx); ++ gen_load_gpr(t0, a->rj); ++ gen_helper_movreg2cf(cpu_env, cd, t0); ++ ++ tcg_temp_free(t0); ++ tcg_temp_free_i32(cd); ++ return true; ++} ++ ++static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) ++{ ++ TCGv_i32 cj = tcg_const_i32(a->cj); ++ ++ check_cp1_enabled(ctx); ++ gen_helper_movcf2reg(cpu_gpr[a->rd], cpu_env, cj); ++ ++ tcg_temp_free_i32(cj); ++ return true; ++} ++ ++static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FCVT_S_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FCVT_D_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrm_w_s(DisasContext *ctx, arg_ftintrm_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRM_W_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrm_w_d(DisasContext *ctx, arg_ftintrm_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRM_W_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrm_l_s(DisasContext *ctx, arg_ftintrm_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRM_L_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrm_l_d(DisasContext *ctx, arg_ftintrm_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRM_L_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrp_w_s(DisasContext *ctx, arg_ftintrp_w_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRP_W_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrp_w_d(DisasContext *ctx, arg_ftintrp_w_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRP_W_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrp_l_s(DisasContext *ctx, arg_ftintrp_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRP_L_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrp_l_d(DisasContext *ctx, arg_ftintrp_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRP_L_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrz_w_s(DisasContext *ctx, arg_ftintrz_w_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrz_w_d(DisasContext *ctx, arg_ftintrz_w_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrz_l_s(DisasContext *ctx, arg_ftintrz_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrz_l_d(DisasContext *ctx, arg_ftintrz_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrne_w_s(DisasContext *ctx, arg_ftintrne_w_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrne_w_d(DisasContext *ctx, arg_ftintrne_w_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrne_l_s(DisasContext *ctx, arg_ftintrne_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftintrne_l_d(DisasContext *ctx, arg_ftintrne_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftint_w_s(DisasContext *ctx, arg_ftint_w_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINT_W_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftint_w_d(DisasContext *ctx, arg_ftint_w_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINT_W_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftint_l_s(DisasContext *ctx, arg_ftint_l_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINT_L_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ftint_l_d(DisasContext *ctx, arg_ftint_l_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FTINT_L_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ffint_s_w(DisasContext *ctx, arg_ffint_s_w *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FFINT_S_W, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ffint_s_l(DisasContext *ctx, arg_ffint_s_l *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FFINT_S_L, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ffint_d_w(DisasContext *ctx, arg_ffint_d_w *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FFINT_D_W, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_ffint_d_l(DisasContext *ctx, arg_ffint_d_l *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FFINT_D_L, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frint_s(DisasContext *ctx, arg_frint_s *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRINT_S, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_frint_d(DisasContext *ctx, arg_frint_d *a) ++{ ++ gen_farith(ctx, OPC_LARCH_FRINT_D, 0, a->fj, a->fd, 0); ++ return true; ++} ++ ++static bool trans_alsl_w(DisasContext *ctx, arg_alsl_w *a) ++{ ++ gen_lsa(ctx, OPC_LARCH_ALSL_W, a->rd, a->rj, a->rk, a->sa2); ++ return true; ++} ++ ++static bool trans_alsl_wu(DisasContext *ctx, arg_alsl_wu *a) ++{ ++ TCGv t0, t1; ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ gen_load_gpr(t1, a->rk); ++ tcg_gen_shli_tl(t0, t0, a->sa2 + 1); ++ tcg_gen_add_tl(t0, t0, t1); ++ tcg_gen_ext32u_tl(cpu_gpr[a->rd], t0); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ ++ return true; ++} ++ ++static bool trans_alsl_d(DisasContext *ctx, arg_alsl_d *a) ++{ ++ check_larch_64(ctx); ++ gen_lsa(ctx, OPC_LARCH_ALSL_D, a->rd, a->rj, a->rk, a->sa2); ++ return true; ++} ++ ++static bool trans_bytepick_w(DisasContext *ctx, arg_bytepick_w *a) ++{ ++ gen_align(ctx, 32, a->rd, a->rj, a->rk, a->sa2); ++ return true; ++} ++ ++static bool trans_bytepick_d(DisasContext *ctx, arg_bytepick_d *a) ++{ ++ check_larch_64(ctx); ++ gen_align(ctx, 64, a->rd, a->rj, a->rk, a->sa3); ++ return true; ++} ++ ++static bool trans_add_w(DisasContext *ctx, arg_add_w *a) ++{ ++ gen_arith(ctx, OPC_LARCH_ADD_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_sub_w(DisasContext *ctx, arg_sub_w *a) ++{ ++ gen_arith(ctx, OPC_LARCH_SUB_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_add_d(DisasContext *ctx, arg_add_d *a) ++{ ++ gen_arith(ctx, OPC_LARCH_ADD_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_sub_d(DisasContext *ctx, arg_sub_d *a) ++{ ++ check_larch_64(ctx); ++ gen_arith(ctx, OPC_LARCH_SUB_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_slt(DisasContext *ctx, arg_slt *a) ++{ ++ gen_slt(ctx, OPC_LARCH_SLT, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_sltu(DisasContext *ctx, arg_sltu *a) ++{ ++ gen_slt(ctx, OPC_LARCH_SLTU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_maskeqz(DisasContext *ctx, arg_maskeqz *a) ++{ ++ gen_cond_move(ctx, OPC_LARCH_MASKEQZ, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_masknez(DisasContext *ctx, arg_masknez *a) ++{ ++ gen_cond_move(ctx, OPC_LARCH_MASKNEZ, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_nor(DisasContext *ctx, arg_nor *a) ++{ ++ gen_logic(ctx, OPC_LARCH_NOR, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_and(DisasContext *ctx, arg_and *a) ++{ ++ gen_logic(ctx, OPC_LARCH_AND, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_or(DisasContext *ctx, arg_or *a) ++{ ++ gen_logic(ctx, OPC_LARCH_OR, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_xor(DisasContext *ctx, arg_xor *a) ++{ ++ gen_logic(ctx, OPC_LARCH_XOR, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_orn(DisasContext *ctx, arg_orn *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rk); ++ tcg_gen_not_tl(t0, t0); ++ tcg_gen_or_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], t0); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_andn(DisasContext *ctx, arg_andn *a) ++{ ++ TCGv t0, t1; ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rk); ++ gen_load_gpr(t1, a->rj); ++ tcg_gen_not_tl(t0, t0); ++ tcg_gen_and_tl(cpu_gpr[a->rd], t1, t0); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++static bool trans_sll_w(DisasContext *ctx, arg_sll_w *a) ++{ ++ gen_shift(ctx, OPC_LARCH_SLL_W, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_srl_w(DisasContext *ctx, arg_srl_w *a) ++{ ++ gen_shift(ctx, OPC_LARCH_SRL_W, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_sra_w(DisasContext *ctx, arg_sra_w *a) ++{ ++ gen_shift(ctx, OPC_LARCH_SRA_W, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_sll_d(DisasContext *ctx, arg_sll_d *a) ++{ ++ check_larch_64(ctx); ++ gen_shift(ctx, OPC_LARCH_SLL_D, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_srl_d(DisasContext *ctx, arg_srl_d *a) ++{ ++ check_larch_64(ctx); ++ gen_shift(ctx, OPC_LARCH_SRL_D, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_sra_d(DisasContext *ctx, arg_sra_d *a) ++{ ++ check_larch_64(ctx); ++ gen_shift(ctx, OPC_LARCH_SRA_D, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_rotr_w(DisasContext *ctx, arg_rotr_w *a) ++{ ++ gen_shift(ctx, OPC_LARCH_ROTR_W, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_rotr_d(DisasContext *ctx, arg_rotr_d *a) ++{ ++ check_larch_64(ctx); ++ gen_shift(ctx, OPC_LARCH_ROTR_D, a->rd, a->rk, a->rj); ++ return true; ++} ++ ++static bool trans_crc_w_b_w(DisasContext *ctx, arg_crc_w_b_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 0); ++ return true; ++} ++ ++static bool trans_crc_w_h_w(DisasContext *ctx, arg_crc_w_h_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 0); ++ return true; ++} ++ ++static bool trans_crc_w_w_w(DisasContext *ctx, arg_crc_w_w_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 0); ++ return true; ++} ++ ++static bool trans_crc_w_d_w(DisasContext *ctx, arg_crc_w_d_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 0); ++ return true; ++} ++ ++static bool trans_crcc_w_b_w(DisasContext *ctx, arg_crcc_w_b_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 1); ++ return true; ++} ++ ++static bool trans_crcc_w_h_w(DisasContext *ctx, arg_crcc_w_h_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 1); ++ return true; ++} ++ ++static bool trans_crcc_w_w_w(DisasContext *ctx, arg_crcc_w_w_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 1); ++ return true; ++} ++ ++static bool trans_crcc_w_d_w(DisasContext *ctx, arg_crcc_w_d_w *a) ++{ ++ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 1); ++ return true; ++} ++ ++static bool trans_mul_w(DisasContext *ctx, arg_mul_w *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_MUL_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mulh_w(DisasContext *ctx, arg_mulh_w *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_MULH_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mulh_wu(DisasContext *ctx, arg_mulh_wu *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_MULH_WU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mul_d(DisasContext *ctx, arg_mul_d *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_MUL_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mulh_d(DisasContext *ctx, arg_mulh_d *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_MULH_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mulh_du(DisasContext *ctx, arg_mulh_du *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_MULH_DU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mulw_d_w(DisasContext *ctx, arg_mulw_d_w *a) ++{ ++ TCGv_i64 t0 = tcg_temp_new_i64(); ++ TCGv_i64 t1 = tcg_temp_new_i64(); ++ TCGv_i64 t2 = tcg_temp_new_i64(); ++ gen_load_gpr(t0, a->rj); ++ gen_load_gpr(t1, a->rk); ++ tcg_gen_ext32s_i64(t0, t0); ++ tcg_gen_ext32s_i64(t1, t1); ++ tcg_gen_mul_i64(t2, t0, t1); ++ gen_store_gpr(t2, a->rd); ++ tcg_temp_free_i64(t0); ++ tcg_temp_free_i64(t1); ++ tcg_temp_free_i64(t2); ++ return true; ++} ++ ++static bool trans_mulw_d_wu(DisasContext *ctx, arg_mulw_d_wu *a) ++{ ++ TCGv_i64 t0 = tcg_temp_new_i64(); ++ TCGv_i64 t1 = tcg_temp_new_i64(); ++ TCGv_i64 t2 = tcg_temp_new_i64(); ++ gen_load_gpr(t0, a->rj); ++ gen_load_gpr(t1, a->rk); ++ tcg_gen_ext32u_i64(t0, t0); ++ tcg_gen_ext32u_i64(t1, t1); ++ tcg_gen_mul_i64(t2, t0, t1); ++ gen_store_gpr(t2, a->rd); ++ tcg_temp_free_i64(t0); ++ tcg_temp_free_i64(t1); ++ tcg_temp_free_i64(t2); ++ return true; ++} ++ ++static bool trans_div_w(DisasContext *ctx, arg_div_w *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_DIV_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mod_w(DisasContext *ctx, arg_mod_w *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_MOD_W, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_div_wu(DisasContext *ctx, arg_div_wu *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_DIV_WU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mod_wu(DisasContext *ctx, arg_mod_wu *a) ++{ ++ gen_r6_muldiv(ctx, OPC_LARCH_MOD_WU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_div_d(DisasContext *ctx, arg_div_d *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_DIV_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mod_d(DisasContext *ctx, arg_mod_d *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_MOD_D, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_div_du(DisasContext *ctx, arg_div_du *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_DIV_DU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++static bool trans_mod_du(DisasContext *ctx, arg_mod_du *a) ++{ ++ check_larch_64(ctx); ++ gen_r6_muldiv(ctx, OPC_LARCH_MOD_DU, a->rd, a->rj, a->rk); ++ return true; ++} ++ ++/* do not update CP0.BadVaddr */ ++static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d *a) ++{ ++ TCGv t1 = tcg_temp_new(); ++ TCGv t2 = tcg_temp_new(); ++ gen_load_gpr(t1, a->rj); ++ gen_load_gpr(t2, a->rk); ++ gen_helper_asrtle_d(cpu_env, t1, t2); ++ tcg_temp_free(t1); ++ tcg_temp_free(t2); ++ return true; ++} ++ ++/* do not update CP0.BadVaddr */ ++static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d *a) ++{ ++ TCGv t1 = tcg_temp_new(); ++ TCGv t2 = tcg_temp_new(); ++ gen_load_gpr(t1, a->rj); ++ gen_load_gpr(t2, a->rk); ++ gen_helper_asrtgt_d(cpu_env, t1, t2); ++ tcg_temp_free(t1); ++ tcg_temp_free(t2); ++ return true; ++} ++ ++#ifdef CONFIG_USER_ONLY ++static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) ++{ ++ return false; ++} ++ ++static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) ++{ ++ return false; ++} ++#else ++static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) ++{ ++ TCGv_i32 sd = tcg_const_i32(a->sd); ++ TCGv val = tcg_temp_new(); ++ check_lbt_enabled(ctx); ++ gen_load_gpr(val, a->rj); ++ gen_helper_store_scr(cpu_env, sd, val); ++ tcg_temp_free_i32(sd); ++ tcg_temp_free(val); ++ return true; ++} ++ ++static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) ++{ ++ if (a->rd == 0) { ++ /* Nop */ ++ return true; ++ } ++ ++ TCGv_i32 tsj = tcg_const_i32(a->sj); ++ check_lbt_enabled(ctx); ++ gen_helper_load_scr(cpu_gpr[a->rd], cpu_env, tsj); ++ tcg_temp_free_i32(tsj); ++ return true; ++} ++#endif ++ ++static bool trans_clo_w(DisasContext *ctx, arg_clo_w *a) ++{ ++ gen_cl(ctx, OPC_LARCH_CLO_W, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_clz_w(DisasContext *ctx, arg_clz_w *a) ++{ ++ gen_cl(ctx, OPC_LARCH_CLZ_W, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_cto_w(DisasContext *ctx, arg_cto_w *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ gen_helper_cto_w(cpu_gpr[a->rd], cpu_env, t0); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_ctz_w(DisasContext *ctx, arg_ctz_w *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ gen_helper_ctz_w(cpu_gpr[a->rd], cpu_env, t0); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_clo_d(DisasContext *ctx, arg_clo_d *a) ++{ ++ check_larch_64(ctx); ++ gen_cl(ctx, OPC_LARCH_CLO_D, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_clz_d(DisasContext *ctx, arg_clz_d *a) ++{ ++ check_larch_64(ctx); ++ gen_cl(ctx, OPC_LARCH_CLZ_D, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_cto_d(DisasContext *ctx, arg_cto_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ gen_helper_cto_d(cpu_gpr[a->rd], cpu_env, t0); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_ctz_d(DisasContext *ctx, arg_ctz_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, a->rj); ++ gen_helper_ctz_d(cpu_gpr[a->rd], cpu_env, t0); ++ ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_revb_2h(DisasContext *ctx, arg_revb_2h *a) ++{ ++ gen_bshfl(ctx, OPC_LARCH_REVB_2H, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_revb_4h(DisasContext *ctx, arg_revb_4h *a) ++{ ++ check_larch_64(ctx); ++ gen_bshfl(ctx, OPC_LARCH_REVB_4H, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_revb_2w(DisasContext *ctx, arg_revb_2w *a) ++{ ++ handle_rev32(ctx, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_revb_d(DisasContext *ctx, arg_revb_d *a) ++{ ++ handle_rev64(ctx, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_revh_2w(DisasContext *ctx, arg_revh_2w *a) ++{ ++ handle_rev16(ctx, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_revh_d(DisasContext *ctx, arg_revh_d *a) ++{ ++ check_larch_64(ctx); ++ gen_bshfl(ctx, OPC_LARCH_REVH_D, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_bitrev_4b(DisasContext *ctx, arg_bitrev_4b *a) ++{ ++ gen_bitswap(ctx, OPC_LARCH_BREV_4B, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_bitrev_8b(DisasContext *ctx, arg_bitrev_8b *a) ++{ ++ check_larch_64(ctx); ++ gen_bitswap(ctx, OPC_LARCH_BREV_8B, a->rd, a->rj); ++ return true; ++} ++ ++static bool trans_bitrev_w(DisasContext *ctx, arg_bitrev_w *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ gen_helper_bitrev_w(cpu_gpr[a->rd], cpu_env, t0); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_bitrev_d(DisasContext *ctx, arg_bitrev_d *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ gen_helper_bitrev_d(cpu_gpr[a->rd], cpu_env, t0); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_ext_w_h(DisasContext *ctx, arg_ext_w_h *a) ++{ ++ gen_bshfl(ctx, OPC_LARCH_EXT_WH, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_ext_w_b(DisasContext *ctx, arg_ext_w_b *a) ++{ ++ gen_bshfl(ctx, OPC_LARCH_EXT_WB, a->rj, a->rd); ++ return true; ++} ++ ++static bool trans_srli_w(DisasContext *ctx, arg_srli_w *a) ++{ ++ gen_shift_imm(ctx, OPC_LARCH_SRLI_W, a->rd, a->rj, a->ui5); ++ return true; ++} ++ ++static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) ++{ ++ gen_shift_imm(ctx, OPC_LARCH_SRAI_W, a->rd, a->rj, a->ui5); ++ return true; ++} ++ ++static bool trans_srai_d(DisasContext *ctx, arg_srai_d *a) ++{ ++ TCGv t0; ++ check_larch_64(ctx); ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ tcg_gen_sari_tl(cpu_gpr[a->rd], t0, a->ui6); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_rotri_w(DisasContext *ctx, arg_rotri_w *a) ++{ ++ gen_shift_imm(ctx, OPC_LARCH_ROTRI_W, a->rd, a->rj, a->ui5); ++ return true; ++} ++ ++static bool trans_rotri_d(DisasContext *ctx, arg_rotri_d *a) ++{ ++ TCGv t0; ++ check_larch_64(ctx); ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ tcg_gen_rotri_tl(cpu_gpr[a->rd], t0, a->ui6); ++ tcg_temp_free(t0); ++ return true; ++} ++ ++static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) ++{ ++ check_cp1_enabled(ctx); ++ gen_fcmp_s(ctx, a->fcond, a->fk, a->fj, a->cd); ++ return true; ++} ++ ++static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) ++{ ++ check_cp1_enabled(ctx); ++ gen_fcmp_d(ctx, a->fcond, a->fk, a->fj, a->cd); ++ return true; ++} ++ ++static bool trans_fsel(DisasContext *ctx, arg_fsel *a) ++{ ++ TCGv_i64 fj = tcg_temp_new_i64(); ++ TCGv_i64 fk = tcg_temp_new_i64(); ++ TCGv_i64 fd = tcg_temp_new_i64(); ++ TCGv_i32 ca = tcg_const_i32(a->ca); ++ check_cp1_enabled(ctx); ++ gen_load_fpr64(ctx, fj, a->fj); ++ gen_load_fpr64(ctx, fk, a->fk); ++ gen_helper_fsel(fd, cpu_env, fj, fk, ca); ++ gen_store_fpr64(ctx, fd, a->fd); ++ tcg_temp_free_i64(fj); ++ tcg_temp_free_i64(fk); ++ tcg_temp_free_i64(fd); ++ tcg_temp_free_i32(ca); ++ return true; ++} ++ ++#include "cpu-csr.h" ++ ++#ifdef CONFIG_USER_ONLY ++ ++static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) ++{ ++ return false; ++} ++ ++#else ++ ++#define GEN_CSRRQ_CASE(name) \ ++ do { \ ++ case LOONGARCH_CSR_##name: \ ++ gen_csr_rdq(ctx, cpu_gpr[rd], LOONGARCH_CSR_##name); \ ++ } while (0) ++ ++static bool trans_csrrd(DisasContext *ctx, unsigned rd, unsigned csr) ++{ ++ switch (csr) { ++ GEN_CSRRQ_CASE(CRMD); ++ break; ++ GEN_CSRRQ_CASE(PRMD); ++ break; ++ GEN_CSRRQ_CASE(EUEN); ++ break; ++ GEN_CSRRQ_CASE(MISC); ++ break; ++ GEN_CSRRQ_CASE(ECFG); ++ break; ++ GEN_CSRRQ_CASE(ESTAT); ++ break; ++ GEN_CSRRQ_CASE(ERA); ++ break; ++ GEN_CSRRQ_CASE(BADV); ++ break; ++ GEN_CSRRQ_CASE(BADI); ++ break; ++ GEN_CSRRQ_CASE(EEPN); ++ break; ++ GEN_CSRRQ_CASE(TLBIDX); ++ break; ++ GEN_CSRRQ_CASE(TLBEHI); ++ break; ++ GEN_CSRRQ_CASE(TLBELO0); ++ break; ++ GEN_CSRRQ_CASE(TLBELO1); ++ break; ++ GEN_CSRRQ_CASE(TLBWIRED); ++ break; ++ GEN_CSRRQ_CASE(GTLBC); ++ break; ++ GEN_CSRRQ_CASE(TRGP); ++ break; ++ GEN_CSRRQ_CASE(ASID); ++ break; ++ GEN_CSRRQ_CASE(PGDL); ++ break; ++ GEN_CSRRQ_CASE(PGDH); ++ break; ++ case LOONGARCH_CSR_PGD: ++ gen_helper_read_pgd(cpu_gpr[rd], cpu_env); ++ break; ++ GEN_CSRRQ_CASE(PWCTL0); ++ break; ++ GEN_CSRRQ_CASE(PWCTL1); ++ break; ++ GEN_CSRRQ_CASE(STLBPGSIZE); ++ break; ++ GEN_CSRRQ_CASE(RVACFG); ++ break; ++ GEN_CSRRQ_CASE(CPUID); ++ break; ++ GEN_CSRRQ_CASE(PRCFG1); ++ break; ++ GEN_CSRRQ_CASE(PRCFG2); ++ break; ++ GEN_CSRRQ_CASE(PRCFG3); ++ break; ++ GEN_CSRRQ_CASE(KS0); ++ break; ++ GEN_CSRRQ_CASE(KS1); ++ break; ++ GEN_CSRRQ_CASE(KS2); ++ break; ++ GEN_CSRRQ_CASE(KS3); ++ break; ++ GEN_CSRRQ_CASE(KS4); ++ break; ++ GEN_CSRRQ_CASE(KS5); ++ break; ++ GEN_CSRRQ_CASE(KS6); ++ break; ++ GEN_CSRRQ_CASE(KS7); ++ break; ++ GEN_CSRRQ_CASE(KS8); ++ break; ++ GEN_CSRRQ_CASE(TMID); ++ break; ++ GEN_CSRRQ_CASE(TCFG); ++ break; ++ GEN_CSRRQ_CASE(TVAL); ++ break; ++ GEN_CSRRQ_CASE(CNTC); ++ break; ++ GEN_CSRRQ_CASE(TINTCLR); ++ break; ++ GEN_CSRRQ_CASE(GSTAT); ++ break; ++ GEN_CSRRQ_CASE(GCFG); ++ break; ++ GEN_CSRRQ_CASE(GINTC); ++ break; ++ GEN_CSRRQ_CASE(GCNTC); ++ break; ++ GEN_CSRRQ_CASE(LLBCTL); ++ break; ++ GEN_CSRRQ_CASE(IMPCTL1); ++ break; ++ GEN_CSRRQ_CASE(IMPCTL2); ++ break; ++ GEN_CSRRQ_CASE(GNMI); ++ break; ++ GEN_CSRRQ_CASE(TLBRENT); ++ break; ++ GEN_CSRRQ_CASE(TLBRBADV); ++ break; ++ GEN_CSRRQ_CASE(TLBRERA); ++ break; ++ GEN_CSRRQ_CASE(TLBRSAVE); ++ break; ++ GEN_CSRRQ_CASE(TLBRELO0); ++ break; ++ GEN_CSRRQ_CASE(TLBRELO1); ++ break; ++ GEN_CSRRQ_CASE(TLBREHI); ++ break; ++ GEN_CSRRQ_CASE(TLBRPRMD); ++ break; ++ GEN_CSRRQ_CASE(ERRCTL); ++ break; ++ GEN_CSRRQ_CASE(ERRINFO); ++ break; ++ GEN_CSRRQ_CASE(ERRINFO1); ++ break; ++ GEN_CSRRQ_CASE(ERRENT); ++ break; ++ GEN_CSRRQ_CASE(ERRERA); ++ break; ++ GEN_CSRRQ_CASE(ERRSAVE); ++ break; ++ GEN_CSRRQ_CASE(CTAG); ++ break; ++ GEN_CSRRQ_CASE(DMWIN0); ++ break; ++ GEN_CSRRQ_CASE(DMWIN1); ++ break; ++ GEN_CSRRQ_CASE(DMWIN2); ++ break; ++ GEN_CSRRQ_CASE(DMWIN3); ++ break; ++ GEN_CSRRQ_CASE(PERFCTRL0); ++ break; ++ GEN_CSRRQ_CASE(PERFCNTR0); ++ break; ++ GEN_CSRRQ_CASE(PERFCTRL1); ++ break; ++ GEN_CSRRQ_CASE(PERFCNTR1); ++ break; ++ GEN_CSRRQ_CASE(PERFCTRL2); ++ break; ++ GEN_CSRRQ_CASE(PERFCNTR2); ++ break; ++ GEN_CSRRQ_CASE(PERFCTRL3); ++ break; ++ GEN_CSRRQ_CASE(PERFCNTR3); ++ break; ++ /* debug */ ++ GEN_CSRRQ_CASE(MWPC); ++ break; ++ GEN_CSRRQ_CASE(MWPS); ++ break; ++ GEN_CSRRQ_CASE(DB0ADDR); ++ break; ++ GEN_CSRRQ_CASE(DB0MASK); ++ break; ++ GEN_CSRRQ_CASE(DB0CTL); ++ break; ++ GEN_CSRRQ_CASE(DB0ASID); ++ break; ++ GEN_CSRRQ_CASE(DB1ADDR); ++ break; ++ GEN_CSRRQ_CASE(DB1MASK); ++ break; ++ GEN_CSRRQ_CASE(DB1CTL); ++ break; ++ GEN_CSRRQ_CASE(DB1ASID); ++ break; ++ GEN_CSRRQ_CASE(DB2ADDR); ++ break; ++ GEN_CSRRQ_CASE(DB2MASK); ++ break; ++ GEN_CSRRQ_CASE(DB2CTL); ++ break; ++ GEN_CSRRQ_CASE(DB2ASID); ++ break; ++ GEN_CSRRQ_CASE(DB3ADDR); ++ break; ++ GEN_CSRRQ_CASE(DB3MASK); ++ break; ++ GEN_CSRRQ_CASE(DB3CTL); ++ break; ++ GEN_CSRRQ_CASE(DB3ASID); ++ break; ++ GEN_CSRRQ_CASE(FWPC); ++ break; ++ GEN_CSRRQ_CASE(FWPS); ++ break; ++ GEN_CSRRQ_CASE(IB0ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB0MASK); ++ break; ++ GEN_CSRRQ_CASE(IB0CTL); ++ break; ++ GEN_CSRRQ_CASE(IB0ASID); ++ break; ++ GEN_CSRRQ_CASE(IB1ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB1MASK); ++ break; ++ GEN_CSRRQ_CASE(IB1CTL); ++ break; ++ GEN_CSRRQ_CASE(IB1ASID); ++ break; ++ GEN_CSRRQ_CASE(IB2ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB2MASK); ++ break; ++ GEN_CSRRQ_CASE(IB2CTL); ++ break; ++ GEN_CSRRQ_CASE(IB2ASID); ++ break; ++ GEN_CSRRQ_CASE(IB3ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB3MASK); ++ break; ++ GEN_CSRRQ_CASE(IB3CTL); ++ break; ++ GEN_CSRRQ_CASE(IB3ASID); ++ break; ++ GEN_CSRRQ_CASE(IB4ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB4MASK); ++ break; ++ GEN_CSRRQ_CASE(IB4CTL); ++ break; ++ GEN_CSRRQ_CASE(IB4ASID); ++ break; ++ GEN_CSRRQ_CASE(IB5ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB5MASK); ++ break; ++ GEN_CSRRQ_CASE(IB5CTL); ++ break; ++ GEN_CSRRQ_CASE(IB5ASID); ++ break; ++ GEN_CSRRQ_CASE(IB6ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB6MASK); ++ break; ++ GEN_CSRRQ_CASE(IB6CTL); ++ break; ++ GEN_CSRRQ_CASE(IB6ASID); ++ break; ++ GEN_CSRRQ_CASE(IB7ADDR); ++ break; ++ GEN_CSRRQ_CASE(IB7MASK); ++ break; ++ GEN_CSRRQ_CASE(IB7CTL); ++ break; ++ GEN_CSRRQ_CASE(IB7ASID); ++ break; ++ GEN_CSRRQ_CASE(DEBUG); ++ break; ++ GEN_CSRRQ_CASE(DERA); ++ break; ++ GEN_CSRRQ_CASE(DESAVE); ++ break; ++ default: ++ return false; ++ } ++ ++#undef GEN_CSRRQ_CASE ++ ++ return true; ++} ++ ++#define GEN_CSRWQ_CASE(name) \ ++ do { \ ++ case LOONGARCH_CSR_##name: \ ++ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_##name); \ ++ } while (0) ++ ++static bool trans_csrwr(DisasContext *ctx, unsigned rd, unsigned csr) ++{ ++ ++ switch (csr) { ++ case LOONGARCH_CSR_CRMD: ++ save_cpu_state(ctx, 1); ++ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_CRMD); ++ gen_save_pc(ctx->base.pc_next + 4); ++ ctx->base.is_jmp = DISAS_EXIT; ++ break; ++ GEN_CSRWQ_CASE(PRMD); ++ break; ++ case LOONGARCH_CSR_EUEN: ++ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_EUEN); ++ /* Stop translation */ ++ gen_save_pc(ctx->base.pc_next + 4); ++ ctx->base.is_jmp = DISAS_EXIT; ++ break; ++ GEN_CSRWQ_CASE(MISC); ++ break; ++ GEN_CSRWQ_CASE(ECFG); ++ break; ++ GEN_CSRWQ_CASE(ESTAT); ++ break; ++ GEN_CSRWQ_CASE(ERA); ++ break; ++ GEN_CSRWQ_CASE(BADV); ++ break; ++ GEN_CSRWQ_CASE(BADI); ++ break; ++ GEN_CSRWQ_CASE(EEPN); ++ break; ++ GEN_CSRWQ_CASE(TLBIDX); ++ break; ++ GEN_CSRWQ_CASE(TLBEHI); ++ break; ++ GEN_CSRWQ_CASE(TLBELO0); ++ break; ++ GEN_CSRWQ_CASE(TLBELO1); ++ break; ++ GEN_CSRWQ_CASE(TLBWIRED); ++ break; ++ GEN_CSRWQ_CASE(GTLBC); ++ break; ++ GEN_CSRWQ_CASE(TRGP); ++ break; ++ GEN_CSRWQ_CASE(ASID); ++ break; ++ GEN_CSRWQ_CASE(PGDL); ++ break; ++ GEN_CSRWQ_CASE(PGDH); ++ break; ++ GEN_CSRWQ_CASE(PGD); ++ break; ++ GEN_CSRWQ_CASE(PWCTL0); ++ break; ++ GEN_CSRWQ_CASE(PWCTL1); ++ break; ++ GEN_CSRWQ_CASE(STLBPGSIZE); ++ break; ++ GEN_CSRWQ_CASE(RVACFG); ++ break; ++ GEN_CSRWQ_CASE(CPUID); ++ break; ++ GEN_CSRWQ_CASE(PRCFG1); ++ break; ++ GEN_CSRWQ_CASE(PRCFG2); ++ break; ++ GEN_CSRWQ_CASE(PRCFG3); ++ break; ++ GEN_CSRWQ_CASE(KS0); ++ break; ++ GEN_CSRWQ_CASE(KS1); ++ break; ++ GEN_CSRWQ_CASE(KS2); ++ break; ++ GEN_CSRWQ_CASE(KS3); ++ break; ++ GEN_CSRWQ_CASE(KS4); ++ break; ++ GEN_CSRWQ_CASE(KS5); ++ break; ++ GEN_CSRWQ_CASE(KS6); ++ break; ++ GEN_CSRWQ_CASE(KS7); ++ break; ++ GEN_CSRWQ_CASE(KS8); ++ break; ++ GEN_CSRWQ_CASE(TMID); ++ break; ++ GEN_CSRWQ_CASE(TCFG); ++ break; ++ GEN_CSRWQ_CASE(TVAL); ++ break; ++ GEN_CSRWQ_CASE(CNTC); ++ break; ++ GEN_CSRWQ_CASE(TINTCLR); ++ break; ++ GEN_CSRWQ_CASE(GSTAT); ++ break; ++ GEN_CSRWQ_CASE(GCFG); ++ break; ++ GEN_CSRWQ_CASE(GINTC); ++ break; ++ GEN_CSRWQ_CASE(GCNTC); ++ break; ++ GEN_CSRWQ_CASE(LLBCTL); ++ break; ++ GEN_CSRWQ_CASE(IMPCTL1); ++ break; ++ GEN_CSRWQ_CASE(IMPCTL2); ++ break; ++ GEN_CSRWQ_CASE(GNMI); ++ break; ++ GEN_CSRWQ_CASE(TLBRENT); ++ break; ++ GEN_CSRWQ_CASE(TLBRBADV); ++ break; ++ GEN_CSRWQ_CASE(TLBRERA); ++ break; ++ GEN_CSRWQ_CASE(TLBRSAVE); ++ break; ++ GEN_CSRWQ_CASE(TLBRELO0); ++ break; ++ GEN_CSRWQ_CASE(TLBRELO1); ++ break; ++ GEN_CSRWQ_CASE(TLBREHI); ++ break; ++ GEN_CSRWQ_CASE(TLBRPRMD); ++ break; ++ GEN_CSRWQ_CASE(ERRCTL); ++ break; ++ GEN_CSRWQ_CASE(ERRINFO); ++ break; ++ GEN_CSRWQ_CASE(ERRINFO1); ++ break; ++ GEN_CSRWQ_CASE(ERRENT); ++ break; ++ GEN_CSRWQ_CASE(ERRERA); ++ break; ++ GEN_CSRWQ_CASE(ERRSAVE); ++ break; ++ GEN_CSRWQ_CASE(CTAG); ++ break; ++ GEN_CSRWQ_CASE(DMWIN0); ++ break; ++ GEN_CSRWQ_CASE(DMWIN1); ++ break; ++ GEN_CSRWQ_CASE(DMWIN2); ++ break; ++ GEN_CSRWQ_CASE(DMWIN3); ++ break; ++ GEN_CSRWQ_CASE(PERFCTRL0); ++ break; ++ GEN_CSRWQ_CASE(PERFCNTR0); ++ break; ++ GEN_CSRWQ_CASE(PERFCTRL1); ++ break; ++ GEN_CSRWQ_CASE(PERFCNTR1); ++ break; ++ GEN_CSRWQ_CASE(PERFCTRL2); ++ break; ++ GEN_CSRWQ_CASE(PERFCNTR2); ++ break; ++ GEN_CSRWQ_CASE(PERFCTRL3); ++ break; ++ GEN_CSRWQ_CASE(PERFCNTR3); ++ break; ++ /* debug */ ++ GEN_CSRWQ_CASE(MWPC); ++ break; ++ GEN_CSRWQ_CASE(MWPS); ++ break; ++ GEN_CSRWQ_CASE(DB0ADDR); ++ break; ++ GEN_CSRWQ_CASE(DB0MASK); ++ break; ++ GEN_CSRWQ_CASE(DB0CTL); ++ break; ++ GEN_CSRWQ_CASE(DB0ASID); ++ break; ++ GEN_CSRWQ_CASE(DB1ADDR); ++ break; ++ GEN_CSRWQ_CASE(DB1MASK); ++ break; ++ GEN_CSRWQ_CASE(DB1CTL); ++ break; ++ GEN_CSRWQ_CASE(DB1ASID); ++ break; ++ GEN_CSRWQ_CASE(DB2ADDR); ++ break; ++ GEN_CSRWQ_CASE(DB2MASK); ++ break; ++ GEN_CSRWQ_CASE(DB2CTL); ++ break; ++ GEN_CSRWQ_CASE(DB2ASID); ++ break; ++ GEN_CSRWQ_CASE(DB3ADDR); ++ break; ++ GEN_CSRWQ_CASE(DB3MASK); ++ break; ++ GEN_CSRWQ_CASE(DB3CTL); ++ break; ++ GEN_CSRWQ_CASE(DB3ASID); ++ break; ++ GEN_CSRWQ_CASE(FWPC); ++ break; ++ GEN_CSRWQ_CASE(FWPS); ++ break; ++ GEN_CSRWQ_CASE(IB0ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB0MASK); ++ break; ++ GEN_CSRWQ_CASE(IB0CTL); ++ break; ++ GEN_CSRWQ_CASE(IB0ASID); ++ break; ++ GEN_CSRWQ_CASE(IB1ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB1MASK); ++ break; ++ GEN_CSRWQ_CASE(IB1CTL); ++ break; ++ GEN_CSRWQ_CASE(IB1ASID); ++ break; ++ GEN_CSRWQ_CASE(IB2ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB2MASK); ++ break; ++ GEN_CSRWQ_CASE(IB2CTL); ++ break; ++ GEN_CSRWQ_CASE(IB2ASID); ++ break; ++ GEN_CSRWQ_CASE(IB3ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB3MASK); ++ break; ++ GEN_CSRWQ_CASE(IB3CTL); ++ break; ++ GEN_CSRWQ_CASE(IB3ASID); ++ break; ++ GEN_CSRWQ_CASE(IB4ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB4MASK); ++ break; ++ GEN_CSRWQ_CASE(IB4CTL); ++ break; ++ GEN_CSRWQ_CASE(IB4ASID); ++ break; ++ GEN_CSRWQ_CASE(IB5ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB5MASK); ++ break; ++ GEN_CSRWQ_CASE(IB5CTL); ++ break; ++ GEN_CSRWQ_CASE(IB5ASID); ++ break; ++ GEN_CSRWQ_CASE(IB6ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB6MASK); ++ break; ++ GEN_CSRWQ_CASE(IB6CTL); ++ break; ++ GEN_CSRWQ_CASE(IB6ASID); ++ break; ++ GEN_CSRWQ_CASE(IB7ADDR); ++ break; ++ GEN_CSRWQ_CASE(IB7MASK); ++ break; ++ GEN_CSRWQ_CASE(IB7CTL); ++ break; ++ GEN_CSRWQ_CASE(IB7ASID); ++ break; ++ GEN_CSRWQ_CASE(DEBUG); ++ break; ++ GEN_CSRWQ_CASE(DERA); ++ break; ++ GEN_CSRWQ_CASE(DESAVE); ++ break; ++ default: ++ return false; ++ } ++ ++#undef GEN_CSRWQ_CASE ++ ++ return true; ++} ++ ++#define GEN_CSRXQ_CASE(name) \ ++ do { \ ++ case LOONGARCH_CSR_##name: \ ++ if (rd == 0) { \ ++ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_##name); \ ++ } else { \ ++ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], \ ++ LOONGARCH_CSR_##name); \ ++ } \ ++ } while (0) ++ ++static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) ++{ ++ unsigned rd, rj, csr; ++ TCGv zero = tcg_const_tl(0); ++ rd = a->rd; ++ rj = a->rj; ++ csr = a->csr; ++ ++ if (rj == 0) { ++ return trans_csrrd(ctx, rd, csr); ++ } else if (rj == 1) { ++ return trans_csrwr(ctx, rd, csr); ++ } ++ ++ switch (csr) { ++ case LOONGARCH_CSR_CRMD: ++ save_cpu_state(ctx, 1); ++ if (rd == 0) { ++ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_CRMD); ++ } else { ++ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_CRMD); ++ } ++ gen_save_pc(ctx->base.pc_next + 4); ++ ctx->base.is_jmp = DISAS_EXIT; ++ break; ++ ++ GEN_CSRXQ_CASE(PRMD); ++ break; ++ case LOONGARCH_CSR_EUEN: ++ if (rd == 0) { ++ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_EUEN); ++ } else { ++ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_EUEN); ++ } ++ /* Stop translation */ ++ gen_save_pc(ctx->base.pc_next + 4); ++ ctx->base.is_jmp = DISAS_EXIT; ++ break; ++ GEN_CSRXQ_CASE(MISC); ++ break; ++ GEN_CSRXQ_CASE(ECFG); ++ break; ++ GEN_CSRXQ_CASE(ESTAT); ++ break; ++ GEN_CSRXQ_CASE(ERA); ++ break; ++ GEN_CSRXQ_CASE(BADV); ++ break; ++ GEN_CSRXQ_CASE(BADI); ++ break; ++ GEN_CSRXQ_CASE(EEPN); ++ break; ++ GEN_CSRXQ_CASE(TLBIDX); ++ break; ++ GEN_CSRXQ_CASE(TLBEHI); ++ break; ++ GEN_CSRXQ_CASE(TLBELO0); ++ break; ++ GEN_CSRXQ_CASE(TLBELO1); ++ break; ++ GEN_CSRXQ_CASE(TLBWIRED); ++ break; ++ GEN_CSRXQ_CASE(GTLBC); ++ break; ++ GEN_CSRXQ_CASE(TRGP); ++ break; ++ GEN_CSRXQ_CASE(ASID); ++ break; ++ GEN_CSRXQ_CASE(PGDL); ++ break; ++ GEN_CSRXQ_CASE(PGDH); ++ break; ++ GEN_CSRXQ_CASE(PGD); ++ break; ++ GEN_CSRXQ_CASE(PWCTL0); ++ break; ++ GEN_CSRXQ_CASE(PWCTL1); ++ break; ++ GEN_CSRXQ_CASE(STLBPGSIZE); ++ break; ++ GEN_CSRXQ_CASE(RVACFG); ++ break; ++ GEN_CSRXQ_CASE(CPUID); ++ break; ++ GEN_CSRXQ_CASE(PRCFG1); ++ break; ++ GEN_CSRXQ_CASE(PRCFG2); ++ break; ++ GEN_CSRXQ_CASE(PRCFG3); ++ break; ++ GEN_CSRXQ_CASE(KS0); ++ break; ++ GEN_CSRXQ_CASE(KS1); ++ break; ++ GEN_CSRXQ_CASE(KS2); ++ break; ++ GEN_CSRXQ_CASE(KS3); ++ break; ++ GEN_CSRXQ_CASE(KS4); ++ break; ++ GEN_CSRXQ_CASE(KS5); ++ break; ++ GEN_CSRXQ_CASE(KS6); ++ break; ++ GEN_CSRXQ_CASE(KS7); ++ break; ++ GEN_CSRXQ_CASE(KS8); ++ break; ++ GEN_CSRXQ_CASE(TMID); ++ break; ++ GEN_CSRXQ_CASE(TCFG); ++ break; ++ GEN_CSRXQ_CASE(TVAL); ++ break; ++ GEN_CSRXQ_CASE(CNTC); ++ break; ++ GEN_CSRXQ_CASE(TINTCLR); ++ break; ++ GEN_CSRXQ_CASE(GSTAT); ++ break; ++ GEN_CSRXQ_CASE(GCFG); ++ break; ++ GEN_CSRXQ_CASE(GINTC); ++ break; ++ GEN_CSRXQ_CASE(GCNTC); ++ break; ++ GEN_CSRXQ_CASE(LLBCTL); ++ break; ++ GEN_CSRXQ_CASE(IMPCTL1); ++ break; ++ GEN_CSRXQ_CASE(IMPCTL2); ++ break; ++ GEN_CSRXQ_CASE(GNMI); ++ break; ++ GEN_CSRXQ_CASE(TLBRENT); ++ break; ++ GEN_CSRXQ_CASE(TLBRBADV); ++ break; ++ GEN_CSRXQ_CASE(TLBRERA); ++ break; ++ GEN_CSRXQ_CASE(TLBRSAVE); ++ break; ++ GEN_CSRXQ_CASE(TLBRELO0); ++ break; ++ GEN_CSRXQ_CASE(TLBRELO1); ++ break; ++ GEN_CSRXQ_CASE(TLBREHI); ++ break; ++ GEN_CSRXQ_CASE(TLBRPRMD); ++ break; ++ GEN_CSRXQ_CASE(ERRCTL); ++ break; ++ GEN_CSRXQ_CASE(ERRINFO); ++ break; ++ GEN_CSRXQ_CASE(ERRINFO1); ++ break; ++ GEN_CSRXQ_CASE(ERRENT); ++ break; ++ GEN_CSRXQ_CASE(ERRERA); ++ break; ++ GEN_CSRXQ_CASE(ERRSAVE); ++ break; ++ GEN_CSRXQ_CASE(CTAG); ++ break; ++ GEN_CSRXQ_CASE(DMWIN0); ++ break; ++ GEN_CSRXQ_CASE(DMWIN1); ++ break; ++ GEN_CSRXQ_CASE(DMWIN2); ++ break; ++ GEN_CSRXQ_CASE(DMWIN3); ++ break; ++ GEN_CSRXQ_CASE(PERFCTRL0); ++ break; ++ GEN_CSRXQ_CASE(PERFCNTR0); ++ break; ++ GEN_CSRXQ_CASE(PERFCTRL1); ++ break; ++ GEN_CSRXQ_CASE(PERFCNTR1); ++ break; ++ GEN_CSRXQ_CASE(PERFCTRL2); ++ break; ++ GEN_CSRXQ_CASE(PERFCNTR2); ++ break; ++ GEN_CSRXQ_CASE(PERFCTRL3); ++ break; ++ GEN_CSRXQ_CASE(PERFCNTR3); ++ break; ++ /* debug */ ++ GEN_CSRXQ_CASE(MWPC); ++ break; ++ GEN_CSRXQ_CASE(MWPS); ++ break; ++ GEN_CSRXQ_CASE(DB0ADDR); ++ break; ++ GEN_CSRXQ_CASE(DB0MASK); ++ break; ++ GEN_CSRXQ_CASE(DB0CTL); ++ break; ++ GEN_CSRXQ_CASE(DB0ASID); ++ break; ++ GEN_CSRXQ_CASE(DB1ADDR); ++ break; ++ GEN_CSRXQ_CASE(DB1MASK); ++ break; ++ GEN_CSRXQ_CASE(DB1CTL); ++ break; ++ GEN_CSRXQ_CASE(DB1ASID); ++ break; ++ GEN_CSRXQ_CASE(DB2ADDR); ++ break; ++ GEN_CSRXQ_CASE(DB2MASK); ++ break; ++ GEN_CSRXQ_CASE(DB2CTL); ++ break; ++ GEN_CSRXQ_CASE(DB2ASID); ++ break; ++ GEN_CSRXQ_CASE(DB3ADDR); ++ break; ++ GEN_CSRXQ_CASE(DB3MASK); ++ break; ++ GEN_CSRXQ_CASE(DB3CTL); ++ break; ++ GEN_CSRXQ_CASE(DB3ASID); ++ break; ++ GEN_CSRXQ_CASE(FWPC); ++ break; ++ GEN_CSRXQ_CASE(FWPS); ++ break; ++ GEN_CSRXQ_CASE(IB0ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB0MASK); ++ break; ++ GEN_CSRXQ_CASE(IB0CTL); ++ break; ++ GEN_CSRXQ_CASE(IB0ASID); ++ break; ++ GEN_CSRXQ_CASE(IB1ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB1MASK); ++ break; ++ GEN_CSRXQ_CASE(IB1CTL); ++ break; ++ GEN_CSRXQ_CASE(IB1ASID); ++ break; ++ GEN_CSRXQ_CASE(IB2ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB2MASK); ++ break; ++ GEN_CSRXQ_CASE(IB2CTL); ++ break; ++ GEN_CSRXQ_CASE(IB2ASID); ++ break; ++ GEN_CSRXQ_CASE(IB3ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB3MASK); ++ break; ++ GEN_CSRXQ_CASE(IB3CTL); ++ break; ++ GEN_CSRXQ_CASE(IB3ASID); ++ break; ++ GEN_CSRXQ_CASE(IB4ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB4MASK); ++ break; ++ GEN_CSRXQ_CASE(IB4CTL); ++ break; ++ GEN_CSRXQ_CASE(IB4ASID); ++ break; ++ GEN_CSRXQ_CASE(IB5ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB5MASK); ++ break; ++ GEN_CSRXQ_CASE(IB5CTL); ++ break; ++ GEN_CSRXQ_CASE(IB5ASID); ++ break; ++ GEN_CSRXQ_CASE(IB6ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB6MASK); ++ break; ++ GEN_CSRXQ_CASE(IB6CTL); ++ break; ++ GEN_CSRXQ_CASE(IB6ASID); ++ break; ++ GEN_CSRXQ_CASE(IB7ADDR); ++ break; ++ GEN_CSRXQ_CASE(IB7MASK); ++ break; ++ GEN_CSRXQ_CASE(IB7CTL); ++ break; ++ GEN_CSRXQ_CASE(IB7ASID); ++ break; ++ GEN_CSRXQ_CASE(DEBUG); ++ break; ++ GEN_CSRXQ_CASE(DERA); ++ break; ++ GEN_CSRXQ_CASE(DESAVE); ++ break; ++ default: ++ return false; ++ } ++ ++#undef GEN_CSRXQ_CASE ++ tcg_temp_free(zero); ++ return true; ++} ++ ++#endif ++ ++static bool trans_cacop(DisasContext *ctx, arg_cacop *a) ++{ ++ /* Treat as NOP. */ ++ return true; ++} ++ ++#ifdef CONFIG_USER_ONLY ++ ++static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) ++{ ++ return false; ++} ++ ++static bool trans_lddir(DisasContext *ctx, arg_lddir *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) ++{ ++ return false; ++} ++#else ++ ++static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) ++{ ++ TCGv t0, t1; ++ TCGv_i32 t2; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->seq); ++ t2 = tcg_const_i32(ctx->mem_idx); ++ gen_helper_ldpte(cpu_env, t0, t1, t2); ++ ++ return true; ++} ++ ++static bool trans_lddir(DisasContext *ctx, arg_lddir *a) ++{ ++ TCGv t0, t1, t2; ++ TCGv_i32 t3; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ t2 = tcg_const_tl(a->level); ++ t3 = tcg_const_i32(ctx->mem_idx); ++ gen_helper_lddir(cpu_env, t0, t1, t2, t3); ++ ++ return true; ++} ++ ++static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) ++{ ++ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_W); ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); ++ return true; ++} ++ ++static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) ++{ ++ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_D); ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); ++ return true; ++} ++ ++static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) ++{ ++ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_B); ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); ++ return true; ++} ++ ++static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) ++{ ++ return false; ++} ++ ++static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) ++{ ++ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_W); ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); ++ return true; ++} ++ ++static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) ++{ ++ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_D); ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rj); ++ t1 = tcg_const_tl(a->rd); ++ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); ++ return true; ++} ++#endif /* !CONFIG_USER_ONLY */ ++ ++#ifdef CONFIG_USER_ONLY ++ ++#define GEN_FALSE_TRANS(name) \ ++ static bool trans_##name(DisasContext *ctx, arg_##name *a) \ ++ { \ ++ return false; \ ++ } ++ ++GEN_FALSE_TRANS(tlbclr) ++GEN_FALSE_TRANS(invtlb) ++GEN_FALSE_TRANS(tlbflush) ++GEN_FALSE_TRANS(tlbsrch) ++GEN_FALSE_TRANS(tlbrd) ++GEN_FALSE_TRANS(tlbwr) ++GEN_FALSE_TRANS(tlbfill) ++GEN_FALSE_TRANS(ertn) ++ ++#else ++ ++static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) ++{ ++ gen_helper_tlbclr(cpu_env); ++ return true; ++} ++ ++static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) ++{ ++ gen_helper_tlbflush(cpu_env); ++ return true; ++} ++ ++static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) ++{ ++ TCGv addr = tcg_temp_new(); ++ TCGv info = tcg_temp_new(); ++ TCGv op = tcg_const_tl(a->invop); ++ ++ gen_load_gpr(addr, a->addr); ++ gen_load_gpr(info, a->info); ++ gen_helper_invtlb(cpu_env, addr, info, op); ++ ++ tcg_temp_free(addr); ++ tcg_temp_free(info); ++ tcg_temp_free(op); ++ return true; ++} ++ ++static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) ++{ ++ gen_helper_tlbsrch(cpu_env); ++ return true; ++} ++ ++static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) ++{ ++ gen_helper_tlbrd(cpu_env); ++ return true; ++} ++ ++static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) ++{ ++ gen_helper_tlbwr(cpu_env); ++ return true; ++} ++ ++static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) ++{ ++ gen_helper_tlbfill(cpu_env); ++ return true; ++} ++ ++static bool trans_ertn(DisasContext *ctx, arg_ertn *a) ++{ ++ gen_helper_ertn(cpu_env); ++ ctx->base.is_jmp = DISAS_EXIT; ++ return true; ++} ++ ++#endif /* CONFIG_USER_ONLY */ ++ ++static bool trans_idle(DisasContext *ctx, arg_idle *a) ++{ ++ ctx->base.pc_next += 4; ++ save_cpu_state(ctx, 1); ++ ctx->base.pc_next -= 4; ++ gen_helper_idle(cpu_env); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ return true; ++} ++ ++#ifdef CONFIG_USER_ONLY ++ ++static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) ++{ ++ /* Nop */ ++ return true; ++} ++ ++#else ++ ++static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) ++{ ++ TCGv t0, t1; ++ t0 = tcg_const_tl(a->rd); ++ t1 = tcg_const_tl(a->rj); ++ gen_helper_drdtime(cpu_env, t0, t1); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return true; ++} ++ ++#endif ++ ++static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) ++{ ++ TCGv t0 = tcg_temp_new(); ++ gen_load_gpr(t0, a->rj); ++ gen_helper_cpucfg(cpu_gpr[a->rd], cpu_env, t0); ++ tcg_temp_free(t0); ++ return true; ++} +diff --git a/target/loongarch64/translate.c b/target/loongarch64/translate.c +new file mode 100644 +index 0000000000..2c65e4826a +--- /dev/null ++++ b/target/loongarch64/translate.c +@@ -0,0 +1,2705 @@ ++/* ++ * LOONGARCH emulation for QEMU - main translation routines ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "internal.h" ++#include "disas/disas.h" ++#include "exec/exec-all.h" ++#include "tcg/tcg-op.h" ++#include "exec/cpu_ldst.h" ++#include "hw/loongarch/cpudevs.h" ++ ++#include "exec/helper-proto.h" ++#include "exec/helper-gen.h" ++#include "semihosting/semihost.h" ++ ++#include "trace-tcg.h" ++#include "exec/translator.h" ++#include "exec/log.h" ++ ++#include "instmap.h" ++ ++#define LARCH_DEBUG_DISAS 0 ++ ++/* Values for the fmt field in FP instructions */ ++enum { ++ /* 0 - 15 are reserved */ ++ FMT_S = 16, /* single fp */ ++ FMT_D = 17, /* double fp */ ++}; ++ ++/* global register indices */ ++static TCGv cpu_gpr[32], cpu_PC; ++static TCGv btarget, bcond; ++static TCGv cpu_lladdr, cpu_llval; ++static TCGv_i32 hflags; ++static TCGv_i32 fpu_fcsr0; ++static TCGv_i64 fpu_f64[32]; ++ ++#include "exec/gen-icount.h" ++ ++#define gen_helper_0e0i(name, arg) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg); \ ++ gen_helper_##name(cpu_env, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_0e1i(name, arg1, arg2) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ ++ gen_helper_##name(cpu_env, arg1, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_1e0i(name, ret, arg1) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg1); \ ++ gen_helper_##name(ret, cpu_env, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_1e1i(name, ret, arg1, arg2) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ ++ gen_helper_##name(ret, cpu_env, arg1, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_0e2i(name, arg1, arg2, arg3) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ ++ gen_helper_##name(cpu_env, arg1, arg2, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_1e2i(name, ret, arg1, arg2, arg3) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ ++ gen_helper_##name(ret, cpu_env, arg1, arg2, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++#define gen_helper_0e3i(name, arg1, arg2, arg3, arg4) \ ++ do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ ++ gen_helper_##name(cpu_env, arg1, arg2, arg3, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while (0) ++ ++typedef struct DisasContext { ++ DisasContextBase base; ++ target_ulong saved_pc; ++ target_ulong page_start; ++ uint32_t opcode; ++ uint64_t insn_flags; ++ /* Routine used to access memory */ ++ int mem_idx; ++ MemOp default_tcg_memop_mask; ++ uint32_t hflags, saved_hflags; ++ target_ulong btarget; ++} DisasContext; ++ ++#define DISAS_STOP DISAS_TARGET_0 ++#define DISAS_EXIT DISAS_TARGET_1 ++ ++#define LOG_DISAS(...) \ ++ do { \ ++ if (LARCH_DEBUG_DISAS) { \ ++ qemu_log_mask(CPU_LOG_TB_IN_ASM, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define LARCH_INVAL(op) \ ++ do { \ ++ if (LARCH_DEBUG_DISAS) { \ ++ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ ++ TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \ ++ ctx->base.pc_next, ctx->opcode, op, \ ++ ctx->opcode >> 26, ctx->opcode & 0x3F, \ ++ ((ctx->opcode >> 16) & 0x1F)); \ ++ } \ ++ } while (0) ++ ++/* General purpose registers moves. */ ++static inline void gen_load_gpr(TCGv t, int reg) ++{ ++ if (reg == 0) { ++ tcg_gen_movi_tl(t, 0); ++ } else { ++ tcg_gen_mov_tl(t, cpu_gpr[reg]); ++ } ++} ++ ++static inline void gen_store_gpr(TCGv t, int reg) ++{ ++ if (reg != 0) { ++ tcg_gen_mov_tl(cpu_gpr[reg], t); ++ } ++} ++ ++/* Moves to/from shadow registers. */ ++/* Tests */ ++static inline void gen_save_pc(target_ulong pc) ++{ ++ tcg_gen_movi_tl(cpu_PC, pc); ++} ++ ++static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) ++{ ++ LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); ++ if (do_save_pc && ctx->base.pc_next != ctx->saved_pc) { ++ gen_save_pc(ctx->base.pc_next); ++ ctx->saved_pc = ctx->base.pc_next; ++ } ++ if (ctx->hflags != ctx->saved_hflags) { ++ tcg_gen_movi_i32(hflags, ctx->hflags); ++ ctx->saved_hflags = ctx->hflags; ++ switch (ctx->hflags & LARCH_HFLAG_BMASK) { ++ case LARCH_HFLAG_BR: ++ break; ++ case LARCH_HFLAG_BC: ++ case LARCH_HFLAG_B: ++ tcg_gen_movi_tl(btarget, ctx->btarget); ++ break; ++ } ++ } ++} ++ ++static inline void restore_cpu_state(CPULOONGARCHState *env, DisasContext *ctx) ++{ ++ ctx->saved_hflags = ctx->hflags; ++ switch (ctx->hflags & LARCH_HFLAG_BMASK) { ++ case LARCH_HFLAG_BR: ++ break; ++ case LARCH_HFLAG_BC: ++ case LARCH_HFLAG_B: ++ ctx->btarget = env->btarget; ++ break; ++ } ++} ++ ++static inline void generate_exception_err(DisasContext *ctx, int excp, int err) ++{ ++ TCGv_i32 texcp = tcg_const_i32(excp); ++ TCGv_i32 terr = tcg_const_i32(err); ++ save_cpu_state(ctx, 1); ++ gen_helper_raise_exception_err(cpu_env, texcp, terr); ++ tcg_temp_free_i32(terr); ++ tcg_temp_free_i32(texcp); ++ ctx->base.is_jmp = DISAS_NORETURN; ++} ++ ++static inline void generate_exception_end(DisasContext *ctx, int excp) ++{ ++ generate_exception_err(ctx, excp, 0); ++} ++ ++/* Floating point register moves. */ ++static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) ++{ ++ tcg_gen_extrl_i64_i32(t, fpu_f64[reg]); ++} ++ ++static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) ++{ ++ TCGv_i64 t64; ++ t64 = tcg_temp_new_i64(); ++ tcg_gen_extu_i32_i64(t64, t); ++ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); ++ tcg_temp_free_i64(t64); ++} ++ ++static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) ++{ ++ tcg_gen_extrh_i64_i32(t, fpu_f64[reg]); ++} ++ ++static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) ++{ ++ TCGv_i64 t64 = tcg_temp_new_i64(); ++ tcg_gen_extu_i32_i64(t64, t); ++ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); ++ tcg_temp_free_i64(t64); ++} ++ ++static void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) ++{ ++ tcg_gen_mov_i64(t, fpu_f64[reg]); ++} ++ ++static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) ++{ ++ tcg_gen_mov_i64(fpu_f64[reg], t); ++} ++ ++static inline int get_fp_bit(int cc) ++{ ++ if (cc) { ++ return 24 + cc; ++ } else { ++ return 23; ++ } ++} ++ ++/* Addresses computation */ ++static inline void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, ++ TCGv arg1) ++{ ++ tcg_gen_add_tl(ret, arg0, arg1); ++ ++ if (ctx->hflags & LARCH_HFLAG_AWRAP) { ++ tcg_gen_ext32s_i64(ret, ret); ++ } ++} ++ ++static inline void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, ++ target_long ofs) ++{ ++ tcg_gen_addi_tl(ret, base, ofs); ++ ++ if (ctx->hflags & LARCH_HFLAG_AWRAP) { ++ tcg_gen_ext32s_i64(ret, ret); ++ } ++} ++ ++/* Sign-extract the low 32-bits to a target_long. */ ++static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) ++{ ++ tcg_gen_ext32s_i64(ret, arg); ++} ++ ++/* Sign-extract the high 32-bits to a target_long. */ ++static inline void gen_move_high32(TCGv ret, TCGv_i64 arg) ++{ ++ tcg_gen_sari_i64(ret, arg, 32); ++} ++ ++static inline void check_cp1_enabled(DisasContext *ctx) ++{ ++#ifndef CONFIG_USER_ONLY ++ if (unlikely(!(ctx->hflags & LARCH_HFLAG_FPU))) { ++ generate_exception_err(ctx, EXCP_FPDIS, 1); ++ } ++#endif ++} ++ ++static inline void check_lsx_enabled(DisasContext *ctx) ++{ ++#ifndef CONFIG_USER_ONLY ++ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LSX))) { ++ generate_exception_err(ctx, EXCP_LSXDIS, 1); ++ } ++#endif ++} ++ ++static inline void check_lasx_enabled(DisasContext *ctx) ++{ ++#ifndef CONFIG_USER_ONLY ++ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LASX))) { ++ generate_exception_err(ctx, EXCP_LASXDIS, 1); ++ } ++#endif ++} ++ ++static inline void check_lbt_enabled(DisasContext *ctx) ++{ ++#ifndef CONFIG_USER_ONLY ++ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LBT))) { ++ generate_exception_err(ctx, EXCP_BTDIS, 1); ++ } ++#endif ++} ++ ++/* ++ * This code generates a "reserved instruction" exception if the ++ * CPU does not support the instruction set corresponding to flags. ++ */ ++static inline void check_insn(DisasContext *ctx, uint64_t flags) ++{ ++ if (unlikely(!(ctx->insn_flags & flags))) { ++ generate_exception_end(ctx, EXCP_RI); ++ } ++} ++ ++/* ++ * This code generates a "reserved instruction" exception if the ++ * CPU has corresponding flag set which indicates that the instruction ++ * has been removed. ++ */ ++static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags) ++{ ++ if (unlikely(ctx->insn_flags & flags)) { ++ generate_exception_end(ctx, EXCP_RI); ++ } ++} ++ ++/* ++ * The Linux kernel traps certain reserved instruction exceptions to ++ * emulate the corresponding instructions. QEMU is the kernel in user ++ * mode, so those traps are emulated by accepting the instructions. ++ * ++ * A reserved instruction exception is generated for flagged CPUs if ++ * QEMU runs in system mode. ++ */ ++static inline void check_insn_opc_user_only(DisasContext *ctx, uint64_t flags) ++{ ++#ifndef CONFIG_USER_ONLY ++ check_insn_opc_removed(ctx, flags); ++#endif ++} ++ ++/* ++ * This code generates a "reserved instruction" exception if 64-bit ++ * instructions are not enabled. ++ */ ++static inline void check_larch_64(DisasContext *ctx) ++{ ++ if (unlikely(!(ctx->hflags & LARCH_HFLAG_64))) { ++ generate_exception_end(ctx, EXCP_RI); ++ } ++} ++ ++/* ++ * Define small wrappers for gen_load_fpr* so that we have a uniform ++ * calling interface for 32 and 64-bit FPRs. No sense in changing ++ * all callers for gen_load_fpr32 when we need the CTX parameter for ++ * this one use. ++ */ ++#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(ctx, x, y) ++#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) ++#define FCOP_CONDNS(fmt, ifmt, bits, STORE) \ ++ static inline void gen_fcmp_##fmt(DisasContext *ctx, int n, int ft, \ ++ int fs, int cd) \ ++ { \ ++ TCGv_i##bits fp0 = tcg_temp_new_i##bits(); \ ++ TCGv_i##bits fp1 = tcg_temp_new_i##bits(); \ ++ TCGv_i32 fcc = tcg_const_i32(cd); \ ++ check_cp1_enabled(ctx); \ ++ gen_ldcmp_fpr##bits(ctx, fp0, fs); \ ++ gen_ldcmp_fpr##bits(ctx, fp1, ft); \ ++ switch (n) { \ ++ case 0: \ ++ gen_helper_cmp_##fmt##_af(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 1: \ ++ gen_helper_cmp_##fmt##_saf(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 2: \ ++ gen_helper_cmp_##fmt##_lt(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 3: \ ++ gen_helper_cmp_##fmt##_slt(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 4: \ ++ gen_helper_cmp_##fmt##_eq(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 5: \ ++ gen_helper_cmp_##fmt##_seq(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 6: \ ++ gen_helper_cmp_##fmt##_le(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 7: \ ++ gen_helper_cmp_##fmt##_sle(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 8: \ ++ gen_helper_cmp_##fmt##_un(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 9: \ ++ gen_helper_cmp_##fmt##_sun(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 10: \ ++ gen_helper_cmp_##fmt##_ult(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 11: \ ++ gen_helper_cmp_##fmt##_sult(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 12: \ ++ gen_helper_cmp_##fmt##_ueq(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 13: \ ++ gen_helper_cmp_##fmt##_sueq(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 14: \ ++ gen_helper_cmp_##fmt##_ule(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 15: \ ++ gen_helper_cmp_##fmt##_sule(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 16: \ ++ gen_helper_cmp_##fmt##_ne(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 17: \ ++ gen_helper_cmp_##fmt##_sne(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 20: \ ++ gen_helper_cmp_##fmt##_or(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 21: \ ++ gen_helper_cmp_##fmt##_sor(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 24: \ ++ gen_helper_cmp_##fmt##_une(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ case 25: \ ++ gen_helper_cmp_##fmt##_sune(fp0, cpu_env, fp0, fp1); \ ++ break; \ ++ default: \ ++ abort(); \ ++ } \ ++ STORE; \ ++ tcg_temp_free_i##bits(fp0); \ ++ tcg_temp_free_i##bits(fp1); \ ++ tcg_temp_free_i32(fcc); \ ++ } ++ ++FCOP_CONDNS(d, FMT_D, 64, gen_helper_movreg2cf_i64(cpu_env, fcc, fp0)) ++FCOP_CONDNS(s, FMT_S, 32, gen_helper_movreg2cf_i32(cpu_env, fcc, fp0)) ++#undef FCOP_CONDNS ++#undef gen_ldcmp_fpr32 ++#undef gen_ldcmp_fpr64 ++ ++/* load/store instructions. */ ++#ifdef CONFIG_USER_ONLY ++#define OP_LD_ATOMIC(insn, fname) \ ++ static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ ++ DisasContext *ctx) \ ++ { \ ++ TCGv t0 = tcg_temp_new(); \ ++ tcg_gen_mov_tl(t0, arg1); \ ++ tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ ++ tcg_gen_st_tl(t0, cpu_env, offsetof(CPULOONGARCHState, lladdr)); \ ++ tcg_gen_st_tl(ret, cpu_env, offsetof(CPULOONGARCHState, llval)); \ ++ tcg_temp_free(t0); \ ++ } ++#else ++#define OP_LD_ATOMIC(insn, fname) \ ++ static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ ++ DisasContext *ctx) \ ++ { \ ++ gen_helper_1e1i(insn, ret, arg1, mem_idx); \ ++ } ++#endif ++ ++static void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, ++ int offset) ++{ ++ if (base == 0) { ++ tcg_gen_movi_tl(addr, offset); ++ } else if (offset == 0) { ++ gen_load_gpr(addr, base); ++ } else { ++ tcg_gen_movi_tl(addr, offset); ++ gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); ++ } ++} ++ ++/* Load */ ++static void gen_ld(DisasContext *ctx, uint32_t opc, int rt, int base, ++ int offset) ++{ ++ TCGv t0; ++ int mem_idx = ctx->mem_idx; ++ ++ t0 = tcg_temp_new(); ++ gen_base_offset_addr(ctx, t0, base, offset); ++ ++ switch (opc) { ++ case OPC_LARCH_LD_WU: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, ++ MO_TEUL | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LDPTR_D: ++ case OPC_LARCH_LD_D: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, ++ MO_TEQ | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LL_D: ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LDPTR_W: ++ case OPC_LARCH_LD_W: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, ++ MO_TESL | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LD_H: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, ++ MO_TESW | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LD_HU: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, ++ MO_TEUW | ctx->default_tcg_memop_mask); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LD_B: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_SB); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LD_BU: ++ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_LL_W: ++ gen_store_gpr(t0, rt); ++ break; ++ } ++ ++ tcg_temp_free(t0); ++} ++ ++/* Store */ ++static void gen_st(DisasContext *ctx, uint32_t opc, int rt, int base, ++ int offset) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ int mem_idx = ctx->mem_idx; ++ ++ gen_base_offset_addr(ctx, t0, base, offset); ++ gen_load_gpr(t1, rt); ++ ++ switch (opc) { ++ case OPC_LARCH_STPTR_D: ++ case OPC_LARCH_ST_D: ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, ++ MO_TEQ | ctx->default_tcg_memop_mask); ++ break; ++ case OPC_LARCH_STPTR_W: ++ case OPC_LARCH_ST_W: ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, ++ MO_TEUL | ctx->default_tcg_memop_mask); ++ break; ++ case OPC_LARCH_ST_H: ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, ++ MO_TEUW | ctx->default_tcg_memop_mask); ++ break; ++ case OPC_LARCH_ST_B: ++ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); ++ break; ++ } ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++/* Store conditional */ ++static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, ++ MemOp tcg_mo, bool eva) ++{ ++ TCGv addr, t0, val; ++ TCGLabel *l1 = gen_new_label(); ++ TCGLabel *done = gen_new_label(); ++ ++ t0 = tcg_temp_new(); ++ addr = tcg_temp_new(); ++ /* compare the address against that of the preceeding LL */ ++ gen_base_offset_addr(ctx, addr, base, offset); ++ tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1); ++ tcg_temp_free(addr); ++ tcg_gen_movi_tl(t0, 0); ++ gen_store_gpr(t0, rt); ++ tcg_gen_br(done); ++ ++ gen_set_label(l1); ++ /* generate cmpxchg */ ++ val = tcg_temp_new(); ++ gen_load_gpr(val, rt); ++ tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, val, ++ eva ? LARCH_HFLAG_UM : ctx->mem_idx, tcg_mo); ++ tcg_gen_setcond_tl(TCG_COND_EQ, t0, t0, cpu_llval); ++ gen_store_gpr(t0, rt); ++ tcg_temp_free(val); ++ ++ gen_set_label(done); ++ tcg_temp_free(t0); ++} ++ ++/* Load and store */ ++static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft, TCGv t0) ++{ ++ /* ++ * Don't do NOP if destination is zero: we must perform the actual ++ * memory access. ++ */ ++ switch (opc) { ++ case OPC_LARCH_FLD_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, ++ MO_TESL | ctx->default_tcg_memop_mask); ++ gen_store_fpr32(ctx, fp0, ft); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FST_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, ft); ++ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, ++ MO_TEUL | ctx->default_tcg_memop_mask); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FLD_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, ++ MO_TEQ | ctx->default_tcg_memop_mask); ++ gen_store_fpr64(ctx, fp0, ft); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FST_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, ft); ++ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, ++ MO_TEQ | ctx->default_tcg_memop_mask); ++ tcg_temp_free_i64(fp0); ++ } break; ++ default: ++ LARCH_INVAL("flt_ldst"); ++ generate_exception_end(ctx, EXCP_RI); ++ break; ++ } ++} ++ ++static void gen_fp_ldst(DisasContext *ctx, uint32_t op, int rt, int rs, ++ int16_t imm) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ check_cp1_enabled(ctx); ++ gen_base_offset_addr(ctx, t0, rs, imm); ++ gen_flt_ldst(ctx, op, rt, t0); ++ tcg_temp_free(t0); ++} ++ ++/* Arithmetic with immediate operand */ ++static void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, ++ int imm) ++{ ++ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ ++ ++ if (rt == 0) { ++ /* ++ * If no destination, treat it as a NOP. ++ * For addi, we must generate the overflow exception when needed. ++ */ ++ return; ++ } ++ switch (opc) { ++ case OPC_LARCH_ADDI_W: ++ if (rs != 0) { ++ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); ++ tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rt], uimm); ++ } ++ break; ++ case OPC_LARCH_ADDI_D: ++ if (rs != 0) { ++ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rt], uimm); ++ } ++ break; ++ } ++} ++ ++/* Logic with immediate operand */ ++static void gen_logic_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, ++ int16_t imm) ++{ ++ target_ulong uimm; ++ ++ if (rt == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ uimm = (uint16_t)imm; ++ switch (opc) { ++ case OPC_LARCH_ANDI: ++ if (likely(rs != 0)) { ++ tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rt], 0); ++ } ++ break; ++ case OPC_LARCH_ORI: ++ if (rs != 0) { ++ tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rt], uimm); ++ } ++ break; ++ case OPC_LARCH_XORI: ++ if (likely(rs != 0)) { ++ tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rt], uimm); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++/* Set on less than with immediate operand */ ++static void gen_slt_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, ++ int16_t imm) ++{ ++ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ ++ TCGv t0; ++ ++ if (rt == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, rs); ++ switch (opc) { ++ case OPC_LARCH_SLTI: ++ tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm); ++ break; ++ case OPC_LARCH_SLTIU: ++ tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm); ++ break; ++ } ++ tcg_temp_free(t0); ++} ++ ++/* Shifts with immediate operand */ ++static void gen_shift_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, ++ int16_t imm) ++{ ++ target_ulong uimm = ((uint16_t)imm) & 0x1f; ++ TCGv t0; ++ ++ if (rt == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, rs); ++ switch (opc) { ++ case OPC_LARCH_SRAI_W: ++ tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); ++ break; ++ case OPC_LARCH_SRLI_W: ++ if (uimm != 0) { ++ tcg_gen_ext32u_tl(t0, t0); ++ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); ++ } else { ++ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); ++ } ++ break; ++ case OPC_LARCH_ROTRI_W: ++ if (uimm != 0) { ++ TCGv_i32 t1 = tcg_temp_new_i32(); ++ ++ tcg_gen_trunc_tl_i32(t1, t0); ++ tcg_gen_rotri_i32(t1, t1, uimm); ++ tcg_gen_ext_i32_tl(cpu_gpr[rt], t1); ++ tcg_temp_free_i32(t1); ++ } else { ++ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); ++ } ++ break; ++ } ++ tcg_temp_free(t0); ++} ++ ++/* Arithmetic */ ++static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) ++{ ++ if (rd == 0) { ++ /* ++ * If no destination, treat it as a NOP. ++ * For add & sub, we must generate the ++ * overflow exception when needed. ++ */ ++ return; ++ } ++ ++ switch (opc) { ++ case OPC_LARCH_ADD_W: ++ if (rs != 0 && rt != 0) { ++ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ case OPC_LARCH_SUB_W: ++ if (rs != 0 && rt != 0) { ++ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ case OPC_LARCH_ADD_D: ++ if (rs != 0 && rt != 0) { ++ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ case OPC_LARCH_SUB_D: ++ if (rs != 0 && rt != 0) { ++ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ } ++} ++ ++/* Conditional move */ ++static void gen_cond_move(DisasContext *ctx, uint32_t opc, int rd, int rs, ++ int rt) ++{ ++ TCGv t0, t1, t2; ++ ++ if (rd == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, rt); ++ t1 = tcg_const_tl(0); ++ t2 = tcg_temp_new(); ++ gen_load_gpr(t2, rs); ++ switch (opc) { ++ case OPC_LARCH_MASKEQZ: ++ tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1); ++ break; ++ case OPC_LARCH_MASKNEZ: ++ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1); ++ break; ++ } ++ tcg_temp_free(t2); ++ tcg_temp_free(t1); ++ tcg_temp_free(t0); ++} ++ ++/* Logic */ ++static void gen_logic(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) ++{ ++ if (rd == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ ++ switch (opc) { ++ case OPC_LARCH_AND: ++ if (likely(rs != 0 && rt != 0)) { ++ tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ case OPC_LARCH_NOR: ++ if (rs != 0 && rt != 0) { ++ tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); ++ } ++ break; ++ case OPC_LARCH_OR: ++ if (likely(rs != 0 && rt != 0)) { ++ tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ case OPC_LARCH_XOR: ++ if (likely(rs != 0 && rt != 0)) { ++ tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); ++ } else if (rs == 0 && rt != 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); ++ } else if (rs != 0 && rt == 0) { ++ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); ++ } else { ++ tcg_gen_movi_tl(cpu_gpr[rd], 0); ++ } ++ break; ++ } ++} ++ ++/* Set on lower than */ ++static void gen_slt(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) ++{ ++ TCGv t0, t1; ++ ++ if (rd == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ switch (opc) { ++ case OPC_LARCH_SLT: ++ tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1); ++ break; ++ case OPC_LARCH_SLTU: ++ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1); ++ break; ++ } ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++/* Shifts */ ++static void gen_shift(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) ++{ ++ TCGv t0, t1; ++ ++ if (rd == 0) { ++ /* ++ * If no destination, treat it as a NOP. ++ * For add & sub, we must generate the ++ * overflow exception when needed. ++ */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ switch (opc) { ++ case OPC_LARCH_SLL_W: ++ tcg_gen_andi_tl(t0, t0, 0x1f); ++ tcg_gen_shl_tl(t0, t1, t0); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); ++ break; ++ case OPC_LARCH_SRA_W: ++ tcg_gen_andi_tl(t0, t0, 0x1f); ++ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); ++ break; ++ case OPC_LARCH_SRL_W: ++ tcg_gen_ext32u_tl(t1, t1); ++ tcg_gen_andi_tl(t0, t0, 0x1f); ++ tcg_gen_shr_tl(t0, t1, t0); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); ++ break; ++ case OPC_LARCH_ROTR_W: { ++ TCGv_i32 t2 = tcg_temp_new_i32(); ++ TCGv_i32 t3 = tcg_temp_new_i32(); ++ ++ tcg_gen_trunc_tl_i32(t2, t0); ++ tcg_gen_trunc_tl_i32(t3, t1); ++ tcg_gen_andi_i32(t2, t2, 0x1f); ++ tcg_gen_rotr_i32(t2, t3, t2); ++ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); ++ tcg_temp_free_i32(t2); ++ tcg_temp_free_i32(t3); ++ } break; ++ case OPC_LARCH_SLL_D: ++ tcg_gen_andi_tl(t0, t0, 0x3f); ++ tcg_gen_shl_tl(cpu_gpr[rd], t1, t0); ++ break; ++ case OPC_LARCH_SRA_D: ++ tcg_gen_andi_tl(t0, t0, 0x3f); ++ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); ++ break; ++ case OPC_LARCH_SRL_D: ++ tcg_gen_andi_tl(t0, t0, 0x3f); ++ tcg_gen_shr_tl(cpu_gpr[rd], t1, t0); ++ break; ++ case OPC_LARCH_ROTR_D: ++ tcg_gen_andi_tl(t0, t0, 0x3f); ++ tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); ++ break; ++ } ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++static inline void gen_r6_ld(target_long addr, int reg, int memidx, ++ MemOp memop) ++{ ++ TCGv t0 = tcg_const_tl(addr); ++ tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); ++ gen_store_gpr(t0, reg); ++ tcg_temp_free(t0); ++} ++ ++static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) ++{ ++ TCGv t0, t1; ++ ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ ++ switch (opc) { ++ case OPC_LARCH_DIV_W: { ++ TCGv t2 = tcg_temp_new(); ++ TCGv t3 = tcg_temp_new(); ++ tcg_gen_ext32s_tl(t0, t0); ++ tcg_gen_ext32s_tl(t1, t1); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); ++ tcg_gen_and_tl(t2, t2, t3); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); ++ tcg_gen_or_tl(t2, t2, t3); ++ tcg_gen_movi_tl(t3, 0); ++ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); ++ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MOD_W: { ++ TCGv t2 = tcg_temp_new(); ++ TCGv t3 = tcg_temp_new(); ++ tcg_gen_ext32s_tl(t0, t0); ++ tcg_gen_ext32s_tl(t1, t1); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); ++ tcg_gen_and_tl(t2, t2, t3); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); ++ tcg_gen_or_tl(t2, t2, t3); ++ tcg_gen_movi_tl(t3, 0); ++ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); ++ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_DIV_WU: { ++ TCGv t2 = tcg_const_tl(0); ++ TCGv t3 = tcg_const_tl(1); ++ tcg_gen_ext32u_tl(t0, t0); ++ tcg_gen_ext32u_tl(t1, t1); ++ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); ++ tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MOD_WU: { ++ TCGv t2 = tcg_const_tl(0); ++ TCGv t3 = tcg_const_tl(1); ++ tcg_gen_ext32u_tl(t0, t0); ++ tcg_gen_ext32u_tl(t1, t1); ++ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); ++ tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MUL_W: { ++ TCGv_i32 t2 = tcg_temp_new_i32(); ++ TCGv_i32 t3 = tcg_temp_new_i32(); ++ tcg_gen_trunc_tl_i32(t2, t0); ++ tcg_gen_trunc_tl_i32(t3, t1); ++ tcg_gen_mul_i32(t2, t2, t3); ++ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); ++ tcg_temp_free_i32(t2); ++ tcg_temp_free_i32(t3); ++ } break; ++ case OPC_LARCH_MULH_W: { ++ TCGv_i32 t2 = tcg_temp_new_i32(); ++ TCGv_i32 t3 = tcg_temp_new_i32(); ++ tcg_gen_trunc_tl_i32(t2, t0); ++ tcg_gen_trunc_tl_i32(t3, t1); ++ tcg_gen_muls2_i32(t2, t3, t2, t3); ++ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); ++ tcg_temp_free_i32(t2); ++ tcg_temp_free_i32(t3); ++ } break; ++ case OPC_LARCH_MULH_WU: { ++ TCGv_i32 t2 = tcg_temp_new_i32(); ++ TCGv_i32 t3 = tcg_temp_new_i32(); ++ tcg_gen_trunc_tl_i32(t2, t0); ++ tcg_gen_trunc_tl_i32(t3, t1); ++ tcg_gen_mulu2_i32(t2, t3, t2, t3); ++ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); ++ tcg_temp_free_i32(t2); ++ tcg_temp_free_i32(t3); ++ } break; ++ case OPC_LARCH_DIV_D: { ++ TCGv t2 = tcg_temp_new(); ++ TCGv t3 = tcg_temp_new(); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); ++ tcg_gen_and_tl(t2, t2, t3); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); ++ tcg_gen_or_tl(t2, t2, t3); ++ tcg_gen_movi_tl(t3, 0); ++ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); ++ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MOD_D: { ++ TCGv t2 = tcg_temp_new(); ++ TCGv t3 = tcg_temp_new(); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); ++ tcg_gen_and_tl(t2, t2, t3); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); ++ tcg_gen_or_tl(t2, t2, t3); ++ tcg_gen_movi_tl(t3, 0); ++ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); ++ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_DIV_DU: { ++ TCGv t2 = tcg_const_tl(0); ++ TCGv t3 = tcg_const_tl(1); ++ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); ++ tcg_gen_divu_i64(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MOD_DU: { ++ TCGv t2 = tcg_const_tl(0); ++ TCGv t3 = tcg_const_tl(1); ++ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); ++ tcg_gen_remu_i64(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t3); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MUL_D: ++ tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); ++ break; ++ case OPC_LARCH_MULH_D: { ++ TCGv t2 = tcg_temp_new(); ++ tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t2); ++ } break; ++ case OPC_LARCH_MULH_DU: { ++ TCGv t2 = tcg_temp_new(); ++ tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t2); ++ } break; ++ default: ++ LARCH_INVAL("r6 mul/div"); ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++out: ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++static void gen_cl(DisasContext *ctx, uint32_t opc, int rd, int rs) ++{ ++ TCGv t0; ++ ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ t0 = cpu_gpr[rd]; ++ gen_load_gpr(t0, rs); ++ ++ switch (opc) { ++ case OPC_LARCH_CLO_W: ++ case OPC_LARCH_CLO_D: ++ tcg_gen_not_tl(t0, t0); ++ break; ++ } ++ ++ switch (opc) { ++ case OPC_LARCH_CLO_W: ++ case OPC_LARCH_CLZ_W: ++ tcg_gen_ext32u_tl(t0, t0); ++ tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS); ++ tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32); ++ break; ++ case OPC_LARCH_CLO_D: ++ case OPC_LARCH_CLZ_D: ++ tcg_gen_clzi_i64(t0, t0, 64); ++ break; ++ } ++} ++ ++static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) ++{ ++ if (unlikely(ctx->base.singlestep_enabled)) { ++ return false; ++ } ++ ++#ifndef CONFIG_USER_ONLY ++ return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); ++#else ++ return true; ++#endif ++} ++ ++static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) ++{ ++ if (use_goto_tb(ctx, dest)) { ++ tcg_gen_goto_tb(n); ++ gen_save_pc(dest); ++ tcg_gen_exit_tb(ctx->base.tb, n); ++ } else { ++ gen_save_pc(dest); ++ if (ctx->base.singlestep_enabled) { ++ save_cpu_state(ctx, 0); ++ gen_helper_raise_exception_debug(cpu_env); ++ } ++ tcg_gen_lookup_and_goto_ptr(); ++ } ++} ++ ++/* Branches */ ++static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int insn_bytes, ++ int rs, int rt, int32_t offset) ++{ ++ target_ulong btgt = -1; ++ int bcond_compute = 0; ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ if (ctx->hflags & LARCH_HFLAG_BMASK) { ++#ifdef LARCH_DEBUG_DISAS ++ LOG_DISAS("Branch at PC 0x" TARGET_FMT_lx "\n", ctx->base.pc_next); ++#endif ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++ ++ /* Load needed operands */ ++ switch (opc) { ++ case OPC_LARCH_BLT: ++ case OPC_LARCH_BGE: ++ case OPC_LARCH_BLTU: ++ case OPC_LARCH_BGEU: ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ bcond_compute = 1; ++ btgt = ctx->base.pc_next + offset; ++ break; ++ case OPC_LARCH_BEQZ: ++ case OPC_LARCH_B: ++ case OPC_LARCH_BEQ: ++ case OPC_LARCH_BNEZ: ++ case OPC_LARCH_BNE: ++ /* Compare two registers */ ++ if (rs != rt) { ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ bcond_compute = 1; ++ } ++ btgt = ctx->base.pc_next + offset; ++ break; ++ default: ++ LARCH_INVAL("branch/jump"); ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++ if (bcond_compute == 0) { ++ /* No condition to be computed */ ++ switch (opc) { ++ case OPC_LARCH_BEQZ: /* rx == rx */ ++ case OPC_LARCH_B: ++ case OPC_LARCH_BEQ: ++ /* Always take */ ++ ctx->hflags |= LARCH_HFLAG_B; ++ break; ++ case OPC_LARCH_BNEZ: ++ case OPC_LARCH_BNE: ++ /* Treat as NOP. */ ++ goto out; ++ default: ++ LARCH_INVAL("branch/jump"); ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++ } else { ++ switch (opc) { ++ case OPC_LARCH_BLT: ++ tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1); ++ goto not_likely; ++ case OPC_LARCH_BGE: ++ tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1); ++ goto not_likely; ++ case OPC_LARCH_BLTU: ++ tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1); ++ goto not_likely; ++ case OPC_LARCH_BGEU: ++ tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1); ++ goto not_likely; ++ case OPC_LARCH_BEQZ: ++ case OPC_LARCH_B: ++ case OPC_LARCH_BEQ: ++ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); ++ goto not_likely; ++ case OPC_LARCH_BNEZ: ++ case OPC_LARCH_BNE: ++ tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); ++ goto not_likely; ++ not_likely: ++ ctx->hflags |= LARCH_HFLAG_BC; ++ break; ++ default: ++ LARCH_INVAL("conditional branch/jump"); ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++ } ++ ++ ctx->btarget = btgt; ++ ++out: ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++/* special3 bitfield operations */ ++static void gen_bitops(DisasContext *ctx, uint32_t opc, int rt, int rs, ++ int lsb, int msb) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ gen_load_gpr(t1, rs); ++ switch (opc) { ++ case OPC_LARCH_TRPICK_W: ++ if (lsb + msb > 31) { ++ goto fail; ++ } ++ if (msb != 31) { ++ tcg_gen_extract_tl(t0, t1, lsb, msb + 1); ++ } else { ++ /* ++ * The two checks together imply that lsb == 0, ++ * so this is a simple sign-extension. ++ */ ++ tcg_gen_ext32s_tl(t0, t1); ++ } ++ break; ++ case OPC_LARCH_TRINS_W: ++ if (lsb > msb) { ++ goto fail; ++ } ++ gen_load_gpr(t0, rt); ++ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); ++ tcg_gen_ext32s_tl(t0, t0); ++ break; ++ default: ++ fail: ++ LARCH_INVAL("bitops"); ++ generate_exception_end(ctx, EXCP_RI); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ return; ++ } ++ gen_store_gpr(t0, rt); ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++} ++ ++static void gen_bshfl(DisasContext *ctx, uint32_t op2, int rt, int rd) ++{ ++ TCGv t0; ++ ++ if (rd == 0) { ++ /* If no destination, treat it as a NOP. */ ++ return; ++ } ++ ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, rt); ++ switch (op2) { ++ case OPC_LARCH_REVB_2H: { ++ TCGv t1 = tcg_temp_new(); ++ TCGv t2 = tcg_const_tl(0x00FF00FF); ++ ++ tcg_gen_shri_tl(t1, t0, 8); ++ tcg_gen_and_tl(t1, t1, t2); ++ tcg_gen_and_tl(t0, t0, t2); ++ tcg_gen_shli_tl(t0, t0, 8); ++ tcg_gen_or_tl(t0, t0, t1); ++ tcg_temp_free(t2); ++ tcg_temp_free(t1); ++ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); ++ } break; ++ case OPC_LARCH_EXT_WB: ++ tcg_gen_ext8s_tl(cpu_gpr[rd], t0); ++ break; ++ case OPC_LARCH_EXT_WH: ++ tcg_gen_ext16s_tl(cpu_gpr[rd], t0); ++ break; ++ case OPC_LARCH_REVB_4H: { ++ TCGv t1 = tcg_temp_new(); ++ TCGv t2 = tcg_const_tl(0x00FF00FF00FF00FFULL); ++ ++ tcg_gen_shri_tl(t1, t0, 8); ++ tcg_gen_and_tl(t1, t1, t2); ++ tcg_gen_and_tl(t0, t0, t2); ++ tcg_gen_shli_tl(t0, t0, 8); ++ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t2); ++ tcg_temp_free(t1); ++ } break; ++ case OPC_LARCH_REVH_D: { ++ TCGv t1 = tcg_temp_new(); ++ TCGv t2 = tcg_const_tl(0x0000FFFF0000FFFFULL); ++ ++ tcg_gen_shri_tl(t1, t0, 16); ++ tcg_gen_and_tl(t1, t1, t2); ++ tcg_gen_and_tl(t0, t0, t2); ++ tcg_gen_shli_tl(t0, t0, 16); ++ tcg_gen_or_tl(t0, t0, t1); ++ tcg_gen_shri_tl(t1, t0, 32); ++ tcg_gen_shli_tl(t0, t0, 32); ++ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); ++ tcg_temp_free(t2); ++ tcg_temp_free(t1); ++ } break; ++ default: ++ LARCH_INVAL("bsfhl"); ++ generate_exception_end(ctx, EXCP_RI); ++ tcg_temp_free(t0); ++ return; ++ } ++ tcg_temp_free(t0); ++} ++ ++/* REV with sf==1, opcode==3 ("REV64") */ ++static void handle_rev64(DisasContext *ctx, unsigned int rn, unsigned int rd) ++{ ++ tcg_gen_bswap64_i64(cpu_gpr[rd], cpu_gpr[rn]); ++} ++ ++/* ++ * REV with sf==0, opcode==2 ++ * REV32 (sf==1, opcode==2) ++ */ ++static void handle_rev32(DisasContext *ctx, unsigned int rn, unsigned int rd) ++{ ++ TCGv_i64 tcg_rd = tcg_temp_new_i64(); ++ gen_load_gpr(tcg_rd, rd); ++ ++ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); ++ TCGv_i64 tcg_rn = tcg_temp_new_i64(); ++ gen_load_gpr(tcg_rn, rn); ++ ++ /* bswap32_i64 requires zero high word */ ++ tcg_gen_ext32u_i64(tcg_tmp, tcg_rn); ++ tcg_gen_bswap32_i64(tcg_rd, tcg_tmp, TCG_BSWAP_OZ); ++ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32); ++ tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_OZ); ++ tcg_gen_concat32_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); ++ ++ tcg_temp_free_i64(tcg_tmp); ++ tcg_temp_free_i64(tcg_rd); ++ tcg_temp_free_i64(tcg_rn); ++} ++ ++/* REV16 */ ++static void handle_rev16(DisasContext *ctx, unsigned int rn, unsigned int rd) ++{ ++ TCGv_i64 tcg_rd = tcg_temp_new_i64(); ++ TCGv_i64 tcg_rn = tcg_temp_new_i64(); ++ gen_load_gpr(tcg_rd, rd); ++ gen_load_gpr(tcg_rn, rn); ++ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); ++ TCGv_i64 mask = tcg_const_i64(0x0000ffff0000ffffull); ++ ++ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16); ++ tcg_gen_and_i64(tcg_rd, tcg_rn, mask); ++ tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); ++ tcg_gen_shli_i64(tcg_rd, tcg_rd, 16); ++ tcg_gen_or_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); ++ ++ tcg_temp_free_i64(mask); ++ tcg_temp_free_i64(tcg_tmp); ++ tcg_temp_free_i64(tcg_rd); ++ tcg_temp_free_i64(tcg_rn); ++} ++ ++static void gen_lsa(DisasContext *ctx, int opc, int rd, int rs, int rt, ++ int imm2) ++{ ++ TCGv t0; ++ TCGv t1; ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ gen_load_gpr(t0, rs); ++ gen_load_gpr(t1, rt); ++ tcg_gen_shli_tl(t0, t0, imm2 + 1); ++ tcg_gen_add_tl(cpu_gpr[rd], t0, t1); ++ if (opc == OPC_LARCH_ALSL_W) { ++ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); ++ } ++ ++ tcg_temp_free(t1); ++ tcg_temp_free(t0); ++ ++ return; ++} ++ ++static void gen_align_bits(DisasContext *ctx, int wordsz, int rd, int rs, ++ int rt, int bits) ++{ ++ TCGv t0; ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ t0 = tcg_temp_new(); ++ if (bits == 0 || bits == wordsz) { ++ if (bits == 0) { ++ gen_load_gpr(t0, rt); ++ } else { ++ gen_load_gpr(t0, rs); ++ } ++ switch (wordsz) { ++ case 32: ++ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); ++ break; ++ case 64: ++ tcg_gen_mov_tl(cpu_gpr[rd], t0); ++ break; ++ } ++ } else { ++ TCGv t1 = tcg_temp_new(); ++ gen_load_gpr(t0, rt); ++ gen_load_gpr(t1, rs); ++ switch (wordsz) { ++ case 32: { ++ TCGv_i64 t2 = tcg_temp_new_i64(); ++ tcg_gen_concat_tl_i64(t2, t1, t0); ++ tcg_gen_shri_i64(t2, t2, 32 - bits); ++ gen_move_low32(cpu_gpr[rd], t2); ++ tcg_temp_free_i64(t2); ++ } break; ++ case 64: ++ tcg_gen_shli_tl(t0, t0, bits); ++ tcg_gen_shri_tl(t1, t1, 64 - bits); ++ tcg_gen_or_tl(cpu_gpr[rd], t1, t0); ++ break; ++ } ++ tcg_temp_free(t1); ++ } ++ ++ tcg_temp_free(t0); ++} ++ ++static void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, ++ int bp) ++{ ++ gen_align_bits(ctx, wordsz, rd, rs, rt, bp * 8); ++} ++ ++static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt) ++{ ++ TCGv t0; ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ t0 = tcg_temp_new(); ++ gen_load_gpr(t0, rt); ++ switch (opc) { ++ case OPC_LARCH_BREV_4B: ++ gen_helper_bitswap(cpu_gpr[rd], t0); ++ break; ++ case OPC_LARCH_BREV_8B: ++ gen_helper_dbitswap(cpu_gpr[rd], t0); ++ break; ++ } ++ tcg_temp_free(t0); ++} ++ ++static void gen_cp1(DisasContext *ctx, uint32_t opc, int rt, int fs) ++{ ++ TCGv t0 = tcg_temp_new(); ++ check_cp1_enabled(ctx); ++ ++ switch (opc) { ++ case OPC_LARCH_FR2GR_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ tcg_gen_ext_i32_tl(t0, fp0); ++ tcg_temp_free_i32(fp0); ++ } ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_GR2FR_W: ++ gen_load_gpr(t0, rt); ++ { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ tcg_gen_trunc_tl_i32(fp0, t0); ++ gen_store_fpr32(ctx, fp0, fs); ++ tcg_temp_free_i32(fp0); ++ } ++ break; ++ case OPC_LARCH_FR2GR_D: ++ gen_load_fpr64(ctx, t0, fs); ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_GR2FR_D: ++ gen_load_gpr(t0, rt); ++ gen_store_fpr64(ctx, t0, fs); ++ break; ++ case OPC_LARCH_FRH2GR_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32h(ctx, fp0, fs); ++ tcg_gen_ext_i32_tl(t0, fp0); ++ tcg_temp_free_i32(fp0); ++ } ++ gen_store_gpr(t0, rt); ++ break; ++ case OPC_LARCH_GR2FRH_W: ++ gen_load_gpr(t0, rt); ++ { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ tcg_gen_trunc_tl_i32(fp0, t0); ++ gen_store_fpr32h(ctx, fp0, fs); ++ tcg_temp_free_i32(fp0); ++ } ++ break; ++ default: ++ LARCH_INVAL("cp1 move"); ++ generate_exception_end(ctx, EXCP_RI); ++ goto out; ++ } ++ ++out: ++ tcg_temp_free(t0); ++} ++ ++static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, int cc, ++ int tf) ++{ ++ int cond; ++ TCGv_i32 t0 = tcg_temp_new_i32(); ++ TCGLabel *l1 = gen_new_label(); ++ TCGLabel *l2 = gen_new_label(); ++ ++ if (tf) { ++ cond = TCG_COND_EQ; ++ } else { ++ cond = TCG_COND_NE; ++ } ++ ++ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc)); ++ tcg_gen_brcondi_i32(cond, t0, 0, l1); ++ gen_load_fpr32(ctx, t0, fs); ++ gen_store_fpr32(ctx, t0, fd); ++ gen_set_label(l1); ++ ++ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc + 1)); ++ tcg_gen_brcondi_i32(cond, t0, 0, l2); ++ gen_load_fpr32h(ctx, t0, fs); ++ gen_store_fpr32h(ctx, t0, fd); ++ tcg_temp_free_i32(t0); ++ gen_set_label(l2); ++} ++ ++static void gen_farith(DisasContext *ctx, uint32_t opc, int ft, int fs, int fd, ++ int cc) ++{ ++ check_cp1_enabled(ctx); ++ switch (opc) { ++ case OPC_LARCH_FADD_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i32(fp1); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FSUB_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i32(fp1); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMUL_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i32(fp1); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FDIV_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i32(fp1); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FSQRT_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_sqrt_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FABS_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_abs_s(fp0, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMOV_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FNEG_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_chs_s(fp0, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FTINTRNE_L_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_round_l_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FTINTRZ_L_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_trunc_l_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FTINTRP_L_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_ceil_l_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FTINTRM_L_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_floor_l_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FTINTRNE_W_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_round_w_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FTINTRZ_W_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_trunc_w_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FTINTRP_W_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_ceil_w_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FTINTRM_W_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_floor_w_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FRECIP_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_recip_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FRSQRT_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FRINT_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_rint_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FCLASS_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_class_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMIN_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ TCGv_i32 fp2 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); ++ gen_store_fpr32(ctx, fp2, fd); ++ tcg_temp_free_i32(fp2); ++ tcg_temp_free_i32(fp1); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMINA_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ TCGv_i32 fp2 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); ++ gen_store_fpr32(ctx, fp2, fd); ++ tcg_temp_free_i32(fp2); ++ tcg_temp_free_i32(fp1); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMAX_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr32(ctx, fp1, fd); ++ tcg_temp_free_i32(fp1); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FMAXA_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ TCGv_i32 fp1 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_load_fpr32(ctx, fp1, ft); ++ gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr32(ctx, fp1, fd); ++ tcg_temp_free_i32(fp1); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FCVT_D_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_cvtd_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FTINT_W_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_cvt_w_s(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FTINT_L_S: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_cvt_l_s(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FADD_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_add_d(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i64(fp1); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FSUB_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_sub_d(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i64(fp1); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMUL_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_mul_d(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i64(fp1); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FDIV_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_div_d(fp0, cpu_env, fp0, fp1); ++ tcg_temp_free_i64(fp1); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FSQRT_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_sqrt_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FABS_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_abs_d(fp0, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMOV_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FNEG_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_chs_d(fp0, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FTINTRNE_L_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_round_l_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FTINTRZ_L_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_trunc_l_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FTINTRP_L_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_ceil_l_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FTINTRM_L_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_floor_l_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FTINTRNE_W_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_round_w_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FTINTRZ_W_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_trunc_w_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FTINTRP_W_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_ceil_w_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FTINTRM_W_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_floor_w_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FRECIP_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_recip_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FRSQRT_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_rsqrt_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FRINT_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_rint_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FCLASS_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_class_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMIN_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr64(ctx, fp1, fd); ++ tcg_temp_free_i64(fp1); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMINA_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr64(ctx, fp1, fd); ++ tcg_temp_free_i64(fp1); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMAX_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr64(ctx, fp1, fd); ++ tcg_temp_free_i64(fp1); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FMAXA_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ TCGv_i64 fp1 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_load_fpr64(ctx, fp1, ft); ++ gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); ++ gen_store_fpr64(ctx, fp1, fd); ++ tcg_temp_free_i64(fp1); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FCVT_S_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_cvts_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FTINT_W_D: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_cvt_w_d(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FTINT_L_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_cvt_l_d(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FFINT_S_W: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ gen_load_fpr32(ctx, fp0, fs); ++ gen_helper_float_cvts_w(fp0, cpu_env, fp0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FFINT_D_W: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr32(ctx, fp32, fs); ++ gen_helper_float_cvtd_w(fp64, cpu_env, fp32); ++ tcg_temp_free_i32(fp32); ++ gen_store_fpr64(ctx, fp64, fd); ++ tcg_temp_free_i64(fp64); ++ } break; ++ case OPC_LARCH_FFINT_S_L: { ++ TCGv_i32 fp32 = tcg_temp_new_i32(); ++ TCGv_i64 fp64 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp64, fs); ++ gen_helper_float_cvts_l(fp32, cpu_env, fp64); ++ tcg_temp_free_i64(fp64); ++ gen_store_fpr32(ctx, fp32, fd); ++ tcg_temp_free_i32(fp32); ++ } break; ++ case OPC_LARCH_FFINT_D_L: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ ++ gen_load_fpr64(ctx, fp0, fs); ++ gen_helper_float_cvtd_l(fp0, cpu_env, fp0); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ default: ++ LARCH_INVAL("farith"); ++ generate_exception_end(ctx, EXCP_RI); ++ return; ++ } ++} ++ ++/* Coprocessor 3 (FPU) */ ++static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc, int fd, int fs, ++ int base, int index) ++{ ++ TCGv t0 = tcg_temp_new(); ++ ++ check_cp1_enabled(ctx); ++ if (base == 0) { ++ gen_load_gpr(t0, index); ++ } else if (index == 0) { ++ gen_load_gpr(t0, base); ++ } else { ++ gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]); ++ } ++ ++ /* ++ * Don't do NOP if destination is zero: we must perform the actual ++ * memory access. ++ */ ++ switch (opc) { ++ case OPC_LARCH_FLDX_S: ++ case OPC_LARCH_FLDGT_S: ++ case OPC_LARCH_FLDLE_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ ++ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); ++ tcg_gen_trunc_tl_i32(fp0, t0); ++ gen_store_fpr32(ctx, fp0, fd); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FLDX_D: ++ case OPC_LARCH_FLDGT_D: ++ case OPC_LARCH_FLDLE_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ); ++ gen_store_fpr64(ctx, fp0, fd); ++ tcg_temp_free_i64(fp0); ++ } break; ++ case OPC_LARCH_FSTX_S: ++ case OPC_LARCH_FSTGT_S: ++ case OPC_LARCH_FSTLE_S: { ++ TCGv_i32 fp0 = tcg_temp_new_i32(); ++ gen_load_fpr32(ctx, fp0, fs); ++ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); ++ tcg_temp_free_i32(fp0); ++ } break; ++ case OPC_LARCH_FSTX_D: ++ case OPC_LARCH_FSTGT_D: ++ case OPC_LARCH_FSTLE_D: { ++ TCGv_i64 fp0 = tcg_temp_new_i64(); ++ gen_load_fpr64(ctx, fp0, fs); ++ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ); ++ tcg_temp_free_i64(fp0); ++ } break; ++ } ++ tcg_temp_free(t0); ++} ++ ++static inline void clear_branch_hflags(DisasContext *ctx) ++{ ++ ctx->hflags &= ~LARCH_HFLAG_BMASK; ++ if (ctx->base.is_jmp == DISAS_NEXT) { ++ save_cpu_state(ctx, 0); ++ } else { ++ /* ++ * It is not safe to save ctx->hflags as hflags may be changed ++ * in execution time. ++ */ ++ tcg_gen_andi_i32(hflags, hflags, ~LARCH_HFLAG_BMASK); ++ } ++} ++ ++static void gen_branch(DisasContext *ctx, int insn_bytes) ++{ ++ if (ctx->hflags & LARCH_HFLAG_BMASK) { ++ int proc_hflags = ctx->hflags & LARCH_HFLAG_BMASK; ++ /* Branches completion */ ++ clear_branch_hflags(ctx); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ /* FIXME: Need to clear can_do_io. */ ++ switch (proc_hflags & LARCH_HFLAG_BMASK) { ++ case LARCH_HFLAG_B: ++ /* unconditional branch */ ++ gen_goto_tb(ctx, 0, ctx->btarget); ++ break; ++ case LARCH_HFLAG_BC: ++ /* Conditional branch */ ++ { ++ TCGLabel *l1 = gen_new_label(); ++ ++ tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); ++ gen_goto_tb(ctx, 1, ctx->base.pc_next + insn_bytes); ++ gen_set_label(l1); ++ gen_goto_tb(ctx, 0, ctx->btarget); ++ } ++ break; ++ case LARCH_HFLAG_BR: ++ /* unconditional branch to register */ ++ tcg_gen_mov_tl(cpu_PC, btarget); ++ if (ctx->base.singlestep_enabled) { ++ save_cpu_state(ctx, 0); ++ gen_helper_raise_exception_debug(cpu_env); ++ } ++ tcg_gen_lookup_and_goto_ptr(); ++ break; ++ default: ++ fprintf(stderr, "unknown branch 0x%x\n", proc_hflags); ++ abort(); ++ } ++ } ++} ++ ++/* Signed immediate */ ++#define SIMM(op, start, width) \ ++ ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) << (32 - width)) >> \ ++ (32 - width)) ++/* Zero-extended immediate */ ++#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) ++ ++static void gen_sync(int stype) ++{ ++ TCGBar tcg_mo = TCG_BAR_SC; ++ ++ switch (stype) { ++ case 0x4: /* SYNC_WMB */ ++ tcg_mo |= TCG_MO_ST_ST; ++ break; ++ case 0x10: /* SYNC_MB */ ++ tcg_mo |= TCG_MO_ALL; ++ break; ++ case 0x11: /* SYNC_ACQUIRE */ ++ tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST; ++ break; ++ case 0x12: /* SYNC_RELEASE */ ++ tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST; ++ break; ++ case 0x13: /* SYNC_RMB */ ++ tcg_mo |= TCG_MO_LD_LD; ++ break; ++ default: ++ tcg_mo |= TCG_MO_ALL; ++ break; ++ } ++ ++ tcg_gen_mb(tcg_mo); ++} ++ ++static void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, ++ int crc32c) ++{ ++ TCGv t0; ++ TCGv t1; ++ TCGv_i32 tsz = tcg_const_i32(1 << sz); ++ if (rd == 0) { ++ /* Treat as NOP. */ ++ return; ++ } ++ t0 = tcg_temp_new(); ++ t1 = tcg_temp_new(); ++ ++ gen_load_gpr(t0, rt); ++ gen_load_gpr(t1, rs); ++ ++ if (crc32c) { ++ gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); ++ } else { ++ gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); ++ } ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(t1); ++ tcg_temp_free_i32(tsz); ++} ++ ++#include "cpu-csr.h" ++ ++#ifndef CONFIG_USER_ONLY ++ ++/* ++ * 64-bit CSR read ++ * ++ * @arg : GPR to store the value of CSR register ++ * @csr : CSR register number ++ */ ++static void gen_csr_rdq(DisasContext *ctx, TCGv rd, int64_t a1) ++{ ++ TCGv_i64 csr = tcg_const_i64(a1); ++ gen_helper_csr_rdq(rd, cpu_env, csr); ++} ++ ++/* ++ * 64-bit CSR write ++ * ++ * @arg : GPR that stores the new value of CSR register ++ * @csr : CSR register number ++ */ ++static void gen_csr_wrq(DisasContext *ctx, TCGv val, int64_t a1) ++{ ++ TCGv_i64 csr = tcg_const_i64(a1); ++ gen_helper_csr_wrq(val, cpu_env, val, csr); ++} ++ ++/* ++ * 64-bit CSR exchange ++ * ++ * @arg : GPR that stores the new value of CSR register ++ * @csr : CSR register number ++ */ ++static void gen_csr_xchgq(DisasContext *ctx, TCGv val, TCGv mask, int64_t a1) ++{ ++ TCGv_i64 csr = tcg_const_i64(a1); ++ gen_helper_csr_xchgq(val, cpu_env, val, mask, csr); ++} ++#endif /* !CONFIG_USER_ONLY */ ++ ++static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ++ CPUState *cs) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ CPULOONGARCHState *env = cs->env_ptr; ++ ++ ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; ++ ctx->saved_pc = -1; ++ ctx->insn_flags = env->insn_flags; ++ ctx->btarget = 0; ++ /* Restore state from the tb context. */ ++ ctx->hflags = ++ (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */ ++ restore_cpu_state(env, ctx); ++#ifdef CONFIG_USER_ONLY ++ ctx->mem_idx = LARCH_HFLAG_UM; ++#else ++ ctx->mem_idx = hflags_mmu_index(ctx->hflags); ++#endif ++ ctx->default_tcg_memop_mask = MO_ALIGN; ++ ++ LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx, ++ ctx->hflags); ++} ++ ++static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) ++{ ++} ++ ++static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ tcg_gen_insn_start(ctx->base.pc_next, ctx->hflags & LARCH_HFLAG_BMASK, ++ ctx->btarget); ++} ++ ++/* 128 and 256 lsx vector instructions are not supported yet */ ++static bool decode_vector_lsx(uint32_t opcode) ++{ ++ uint32_t value = (opcode & 0xff000000); ++ ++ if ((opcode & 0xf0000000) == 0x70000000) { ++ return true; ++ } else if ((opcode & 0xfff00000) == 0x38400000) { ++ return true; ++ } else { ++ switch (value) { ++ case 0x09000000: ++ case 0x0a000000: ++ case 0x0e000000: ++ case 0x0f000000: ++ case 0x2c000000: ++ case 0x30000000: ++ case 0x31000000: ++ case 0x32000000: ++ case 0x33000000: ++ return true; ++ } ++ } ++ return false; ++} ++ ++static bool decode_insn(DisasContext *ctx, uint32_t insn); ++#include "decode-insn.c.inc" ++#include "trans.inc.c" ++ ++static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ++{ ++ CPULOONGARCHState *env = cs->env_ptr; ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ int insn_bytes = 4; ++ ++ ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); ++ ++ if (!decode_insn(ctx, ctx->opcode)) { ++ if (decode_vector_lsx(ctx->opcode)) { ++ generate_exception_end(ctx, EXCP_RI); ++ } else { ++ fprintf(stderr, "Error: unkown opcode. 0x%lx: 0x%x\n", ++ ctx->base.pc_next, ctx->opcode); ++ generate_exception_end(ctx, EXCP_RI); ++ } ++ } ++ ++ if (ctx->hflags & LARCH_HFLAG_BMASK) { ++ gen_branch(ctx, insn_bytes); ++ } ++ ctx->base.pc_next += insn_bytes; ++} ++ ++static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) { ++ save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT); ++ gen_helper_raise_exception_debug(cpu_env); ++ } else { ++ switch (ctx->base.is_jmp) { ++ case DISAS_STOP: ++ gen_save_pc(ctx->base.pc_next); ++ tcg_gen_lookup_and_goto_ptr(); ++ break; ++ case DISAS_NEXT: ++ case DISAS_TOO_MANY: ++ save_cpu_state(ctx, 0); ++ gen_goto_tb(ctx, 0, ctx->base.pc_next); ++ break; ++ case DISAS_EXIT: ++ tcg_gen_exit_tb(NULL, 0); ++ break; ++ case DISAS_NORETURN: ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ } ++} ++ ++static void loongarch_tr_disas_log(const DisasContextBase *dcbase, ++ CPUState *cs) ++{ ++ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); ++ log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); ++} ++ ++static const TranslatorOps loongarch_tr_ops = { ++ .init_disas_context = loongarch_tr_init_disas_context, ++ .tb_start = loongarch_tr_tb_start, ++ .insn_start = loongarch_tr_insn_start, ++ .translate_insn = loongarch_tr_translate_insn, ++ .tb_stop = loongarch_tr_tb_stop, ++ .disas_log = loongarch_tr_disas_log, ++}; ++ ++void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb, ++ int max_insns) ++{ ++ DisasContext ctx; ++ ++ translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); ++} ++ ++void loongarch_tcg_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) ++ cpu_gpr[i] = tcg_global_mem_new( ++ cpu_env, offsetof(CPULOONGARCHState, active_tc.gpr[i]), ++ regnames[i]); ++ ++ for (i = 0; i < 32; i++) { ++ int off = offsetof(CPULOONGARCHState, active_fpu.fpr[i].d); ++ fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); ++ } ++ ++ cpu_PC = tcg_global_mem_new( ++ cpu_env, offsetof(CPULOONGARCHState, active_tc.PC), "PC"); ++ bcond = tcg_global_mem_new(cpu_env, offsetof(CPULOONGARCHState, bcond), ++ "bcond"); ++ btarget = tcg_global_mem_new(cpu_env, offsetof(CPULOONGARCHState, btarget), ++ "btarget"); ++ hflags = tcg_global_mem_new_i32( ++ cpu_env, offsetof(CPULOONGARCHState, hflags), "hflags"); ++ fpu_fcsr0 = tcg_global_mem_new_i32( ++ cpu_env, offsetof(CPULOONGARCHState, active_fpu.fcsr0), "fcsr0"); ++ cpu_lladdr = tcg_global_mem_new( ++ cpu_env, offsetof(CPULOONGARCHState, lladdr), "lladdr"); ++ cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPULOONGARCHState, llval), ++ "llval"); ++} ++ ++void restore_state_to_opc(CPULOONGARCHState *env, TranslationBlock *tb, ++ target_ulong *data) ++{ ++ env->active_tc.PC = data[0]; ++ env->hflags &= ~LARCH_HFLAG_BMASK; ++ env->hflags |= data[1]; ++ switch (env->hflags & LARCH_HFLAG_BMASK) { ++ case LARCH_HFLAG_BR: ++ break; ++ case LARCH_HFLAG_BC: ++ case LARCH_HFLAG_B: ++ env->btarget = data[2]; ++ break; ++ } ++} +diff --git a/target/meson.build b/target/meson.build +index ec6bc97331..a824a390f9 100644 +--- a/target/meson.build ++++ b/target/meson.build +@@ -5,6 +5,7 @@ subdir('cris') + subdir('hexagon') + subdir('hppa') + subdir('i386') ++subdir('loongarch64') + subdir('m68k') + subdir('microblaze') + subdir('mips') +-- +2.27.0 + diff --git a/Add-tcg.patch b/Add-tcg.patch new file mode 100644 index 0000000000000000000000000000000000000000..b12f7b5320498de5459356ff9ad2d50cb3668d53 --- /dev/null +++ b/Add-tcg.patch @@ -0,0 +1,3009 @@ +From 39d543dea10ff4995370e731be08017b6d3af76f Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Tue, 7 Feb 2023 07:21:51 -0500 +Subject: [PATCH] Add tcg. + +Add loongarch tcg related. + +Signed-off-by: lixianglai +--- + tcg/loongarch64/tcg-insn-defs.c.inc | 985 +++++++++++++++ + tcg/loongarch64/tcg-target-con-set.h | 39 + + tcg/loongarch64/tcg-target-con-str.h | 36 + + tcg/loongarch64/tcg-target.c.inc | 1727 ++++++++++++++++++++++++++ + tcg/loongarch64/tcg-target.h | 168 +++ + 5 files changed, 2955 insertions(+) + create mode 100644 tcg/loongarch64/tcg-insn-defs.c.inc + create mode 100644 tcg/loongarch64/tcg-target-con-set.h + create mode 100644 tcg/loongarch64/tcg-target-con-str.h + create mode 100644 tcg/loongarch64/tcg-target.c.inc + create mode 100644 tcg/loongarch64/tcg-target.h + +diff --git a/tcg/loongarch64/tcg-insn-defs.c.inc b/tcg/loongarch64/tcg-insn-defs.c.inc +new file mode 100644 +index 0000000000..2a8fdad626 +--- /dev/null ++++ b/tcg/loongarch64/tcg-insn-defs.c.inc +@@ -0,0 +1,985 @@ ++/* ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ ++ */ ++ ++typedef enum { ++ OPC_CLZ_W = 0x00001400, ++ OPC_CTZ_W = 0x00001c00, ++ OPC_CLZ_D = 0x00002400, ++ OPC_CTZ_D = 0x00002c00, ++ OPC_REVB_2H = 0x00003000, ++ OPC_REVB_2W = 0x00003800, ++ OPC_REVB_D = 0x00003c00, ++ OPC_SEXT_H = 0x00005800, ++ OPC_SEXT_B = 0x00005c00, ++ OPC_ADD_W = 0x00100000, ++ OPC_ADD_D = 0x00108000, ++ OPC_SUB_W = 0x00110000, ++ OPC_SUB_D = 0x00118000, ++ OPC_SLT = 0x00120000, ++ OPC_SLTU = 0x00128000, ++ OPC_MASKEQZ = 0x00130000, ++ OPC_MASKNEZ = 0x00138000, ++ OPC_NOR = 0x00140000, ++ OPC_AND = 0x00148000, ++ OPC_OR = 0x00150000, ++ OPC_XOR = 0x00158000, ++ OPC_ORN = 0x00160000, ++ OPC_ANDN = 0x00168000, ++ OPC_SLL_W = 0x00170000, ++ OPC_SRL_W = 0x00178000, ++ OPC_SRA_W = 0x00180000, ++ OPC_SLL_D = 0x00188000, ++ OPC_SRL_D = 0x00190000, ++ OPC_SRA_D = 0x00198000, ++ OPC_ROTR_W = 0x001b0000, ++ OPC_ROTR_D = 0x001b8000, ++ OPC_MUL_W = 0x001c0000, ++ OPC_MULH_W = 0x001c8000, ++ OPC_MULH_WU = 0x001d0000, ++ OPC_MUL_D = 0x001d8000, ++ OPC_MULH_D = 0x001e0000, ++ OPC_MULH_DU = 0x001e8000, ++ OPC_DIV_W = 0x00200000, ++ OPC_MOD_W = 0x00208000, ++ OPC_DIV_WU = 0x00210000, ++ OPC_MOD_WU = 0x00218000, ++ OPC_DIV_D = 0x00220000, ++ OPC_MOD_D = 0x00228000, ++ OPC_DIV_DU = 0x00230000, ++ OPC_MOD_DU = 0x00238000, ++ OPC_SLLI_W = 0x00408000, ++ OPC_SLLI_D = 0x00410000, ++ OPC_SRLI_W = 0x00448000, ++ OPC_SRLI_D = 0x00450000, ++ OPC_SRAI_W = 0x00488000, ++ OPC_SRAI_D = 0x00490000, ++ OPC_ROTRI_W = 0x004c8000, ++ OPC_ROTRI_D = 0x004d0000, ++ OPC_BSTRINS_W = 0x00600000, ++ OPC_BSTRPICK_W = 0x00608000, ++ OPC_BSTRINS_D = 0x00800000, ++ OPC_BSTRPICK_D = 0x00c00000, ++ OPC_SLTI = 0x02000000, ++ OPC_SLTUI = 0x02400000, ++ OPC_ADDI_W = 0x02800000, ++ OPC_ADDI_D = 0x02c00000, ++ OPC_CU52I_D = 0x03000000, ++ OPC_ANDI = 0x03400000, ++ OPC_ORI = 0x03800000, ++ OPC_XORI = 0x03c00000, ++ OPC_LU12I_W = 0x14000000, ++ OPC_CU32I_D = 0x16000000, ++ OPC_PCADDU2I = 0x18000000, ++ OPC_PCALAU12I = 0x1a000000, ++ OPC_PCADDU12I = 0x1c000000, ++ OPC_PCADDU18I = 0x1e000000, ++ OPC_LD_B = 0x28000000, ++ OPC_LD_H = 0x28400000, ++ OPC_LD_W = 0x28800000, ++ OPC_LD_D = 0x28c00000, ++ OPC_ST_B = 0x29000000, ++ OPC_ST_H = 0x29400000, ++ OPC_ST_W = 0x29800000, ++ OPC_ST_D = 0x29c00000, ++ OPC_LD_BU = 0x2a000000, ++ OPC_LD_HU = 0x2a400000, ++ OPC_LD_WU = 0x2a800000, ++ OPC_LDX_B = 0x38000000, ++ OPC_LDX_H = 0x38040000, ++ OPC_LDX_W = 0x38080000, ++ OPC_LDX_D = 0x380c0000, ++ OPC_STX_B = 0x38100000, ++ OPC_STX_H = 0x38140000, ++ OPC_STX_W = 0x38180000, ++ OPC_STX_D = 0x381c0000, ++ OPC_LDX_BU = 0x38200000, ++ OPC_LDX_HU = 0x38240000, ++ OPC_LDX_WU = 0x38280000, ++ OPC_DBAR = 0x38720000, ++ OPC_JIRL = 0x4c000000, ++ OPC_B = 0x50000000, ++ OPC_BL = 0x54000000, ++ OPC_BEQ = 0x58000000, ++ OPC_BNE = 0x5c000000, ++ OPC_BGT = 0x60000000, ++ OPC_BLE = 0x64000000, ++ OPC_BGTU = 0x68000000, ++ OPC_BLEU = 0x6c000000, ++} LoongArchInsn; ++ ++static int32_t __attribute__((unused)) ++encode_d_slot(LoongArchInsn opc, uint32_t d) ++{ ++ return opc | d; ++} ++ ++static int32_t __attribute__((unused)) ++encode_dj_slots(LoongArchInsn opc, uint32_t d, uint32_t j) ++{ ++ return opc | d | j << 5; ++} ++ ++static int32_t __attribute__((unused)) ++encode_djk_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k) ++{ ++ return opc | d | j << 5 | k << 10; ++} ++ ++static int32_t __attribute__((unused)) ++encode_djkm_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, ++ uint32_t m) ++{ ++ return opc | d | j << 5 | k << 10 | m << 16; ++} ++ ++static int32_t __attribute__((unused)) ++encode_dk_slots(LoongArchInsn opc, uint32_t d, uint32_t k) ++{ ++ return opc | d | k << 10; ++} ++ ++static int32_t __attribute__((unused)) ++encode_dj_insn(LoongArchInsn opc, TCGReg d, TCGReg j) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ return encode_dj_slots(opc, d, j); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djk_insn(LoongArchInsn opc, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(k >= 0 && k <= 0x1f); ++ return encode_djk_slots(opc, d, j, k); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djsk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(sk12 >= -0x800 && sk12 <= 0x7ff); ++ return encode_djk_slots(opc, d, j, sk12 & 0xfff); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djsk16_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(sk16 >= -0x8000 && sk16 <= 0x7fff); ++ return encode_djk_slots(opc, d, j, sk16 & 0xffff); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djuk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk12) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(uk12 <= 0xfff); ++ return encode_djk_slots(opc, d, j, uk12); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djuk5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(uk5 <= 0x1f); ++ return encode_djk_slots(opc, d, j, uk5); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djuk5um5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5, ++ uint32_t um5) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(uk5 <= 0x1f); ++ tcg_debug_assert(um5 <= 0x1f); ++ return encode_djkm_slots(opc, d, j, uk5, um5); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djuk6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(uk6 <= 0x3f); ++ return encode_djk_slots(opc, d, j, uk6); ++} ++ ++static int32_t __attribute__((unused)) ++encode_djuk6um6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6, ++ uint32_t um6) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(j >= 0 && j <= 0x1f); ++ tcg_debug_assert(uk6 <= 0x3f); ++ tcg_debug_assert(um6 <= 0x3f); ++ return encode_djkm_slots(opc, d, j, uk6, um6); ++} ++ ++static int32_t __attribute__((unused)) ++encode_dsj20_insn(LoongArchInsn opc, TCGReg d, int32_t sj20) ++{ ++ tcg_debug_assert(d >= 0 && d <= 0x1f); ++ tcg_debug_assert(sj20 >= -0x80000 && sj20 <= 0x7ffff); ++ return encode_dj_slots(opc, d, sj20 & 0xfffff); ++} ++ ++static int32_t __attribute__((unused)) ++encode_sd10k16_insn(LoongArchInsn opc, int32_t sd10k16) ++{ ++ tcg_debug_assert(sd10k16 >= -0x2000000 && sd10k16 <= 0x1ffffff); ++ return encode_dk_slots(opc, (sd10k16 >> 16) & 0x3ff, sd10k16 & 0xffff); ++} ++ ++static int32_t __attribute__((unused)) ++encode_ud15_insn(LoongArchInsn opc, uint32_t ud15) ++{ ++ tcg_debug_assert(ud15 <= 0x7fff); ++ return encode_d_slot(opc, ud15); ++} ++ ++/* Emits the `clz.w d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_clz_w(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_CLZ_W, d, j)); ++} ++ ++/* Emits the `ctz.w d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ctz_w(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_CTZ_W, d, j)); ++} ++ ++/* Emits the `clz.d d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_clz_d(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_CLZ_D, d, j)); ++} ++ ++/* Emits the `ctz.d d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ctz_d(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_CTZ_D, d, j)); ++} ++ ++/* Emits the `revb.2h d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_revb_2h(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_REVB_2H, d, j)); ++} ++ ++/* Emits the `revb.2w d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_revb_2w(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_REVB_2W, d, j)); ++} ++ ++/* Emits the `revb.d d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_revb_d(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_REVB_D, d, j)); ++} ++ ++/* Emits the `sext.h d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sext_h(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_SEXT_H, d, j)); ++} ++ ++/* Emits the `sext.b d, j` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sext_b(TCGContext *s, TCGReg d, TCGReg j) ++{ ++ tcg_out32(s, encode_dj_insn(OPC_SEXT_B, d, j)); ++} ++ ++/* Emits the `add.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_add_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ADD_W, d, j, k)); ++} ++ ++/* Emits the `add.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_add_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ADD_D, d, j, k)); ++} ++ ++/* Emits the `sub.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sub_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SUB_W, d, j, k)); ++} ++ ++/* Emits the `sub.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sub_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SUB_D, d, j, k)); ++} ++ ++/* Emits the `slt d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_slt(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SLT, d, j, k)); ++} ++ ++/* Emits the `sltu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sltu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SLTU, d, j, k)); ++} ++ ++/* Emits the `maskeqz d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_maskeqz(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MASKEQZ, d, j, k)); ++} ++ ++/* Emits the `masknez d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_masknez(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MASKNEZ, d, j, k)); ++} ++ ++/* Emits the `nor d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_nor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_NOR, d, j, k)); ++} ++ ++/* Emits the `and d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_and(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_AND, d, j, k)); ++} ++ ++/* Emits the `or d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_or(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_OR, d, j, k)); ++} ++ ++/* Emits the `xor d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_xor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_XOR, d, j, k)); ++} ++ ++/* Emits the `orn d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_orn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ORN, d, j, k)); ++} ++ ++/* Emits the `andn d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_andn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ANDN, d, j, k)); ++} ++ ++/* Emits the `sll.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sll_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SLL_W, d, j, k)); ++} ++ ++/* Emits the `srl.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srl_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SRL_W, d, j, k)); ++} ++ ++/* Emits the `sra.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sra_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SRA_W, d, j, k)); ++} ++ ++/* Emits the `sll.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sll_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SLL_D, d, j, k)); ++} ++ ++/* Emits the `srl.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srl_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SRL_D, d, j, k)); ++} ++ ++/* Emits the `sra.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sra_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_SRA_D, d, j, k)); ++} ++ ++/* Emits the `rotr.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_rotr_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ROTR_W, d, j, k)); ++} ++ ++/* Emits the `rotr.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_rotr_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_ROTR_D, d, j, k)); ++} ++ ++/* Emits the `mul.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mul_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MUL_W, d, j, k)); ++} ++ ++/* Emits the `mulh.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mulh_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MULH_W, d, j, k)); ++} ++ ++/* Emits the `mulh.wu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mulh_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MULH_WU, d, j, k)); ++} ++ ++/* Emits the `mul.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mul_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MUL_D, d, j, k)); ++} ++ ++/* Emits the `mulh.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mulh_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MULH_D, d, j, k)); ++} ++ ++/* Emits the `mulh.du d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mulh_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MULH_DU, d, j, k)); ++} ++ ++/* Emits the `div.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_div_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_DIV_W, d, j, k)); ++} ++ ++/* Emits the `mod.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mod_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MOD_W, d, j, k)); ++} ++ ++/* Emits the `div.wu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_div_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_DIV_WU, d, j, k)); ++} ++ ++/* Emits the `mod.wu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mod_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MOD_WU, d, j, k)); ++} ++ ++/* Emits the `div.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_div_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_DIV_D, d, j, k)); ++} ++ ++/* Emits the `mod.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mod_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MOD_D, d, j, k)); ++} ++ ++/* Emits the `div.du d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_div_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_DIV_DU, d, j, k)); ++} ++ ++/* Emits the `mod.du d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_mod_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_MOD_DU, d, j, k)); ++} ++ ++/* Emits the `slli.w d, j, uk5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_slli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) ++{ ++ tcg_out32(s, encode_djuk5_insn(OPC_SLLI_W, d, j, uk5)); ++} ++ ++/* Emits the `slli.d d, j, uk6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_slli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) ++{ ++ tcg_out32(s, encode_djuk6_insn(OPC_SLLI_D, d, j, uk6)); ++} ++ ++/* Emits the `srli.w d, j, uk5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) ++{ ++ tcg_out32(s, encode_djuk5_insn(OPC_SRLI_W, d, j, uk5)); ++} ++ ++/* Emits the `srli.d d, j, uk6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) ++{ ++ tcg_out32(s, encode_djuk6_insn(OPC_SRLI_D, d, j, uk6)); ++} ++ ++/* Emits the `srai.w d, j, uk5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srai_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) ++{ ++ tcg_out32(s, encode_djuk5_insn(OPC_SRAI_W, d, j, uk5)); ++} ++ ++/* Emits the `srai.d d, j, uk6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_srai_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) ++{ ++ tcg_out32(s, encode_djuk6_insn(OPC_SRAI_D, d, j, uk6)); ++} ++ ++/* Emits the `rotri.w d, j, uk5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_rotri_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) ++{ ++ tcg_out32(s, encode_djuk5_insn(OPC_ROTRI_W, d, j, uk5)); ++} ++ ++/* Emits the `rotri.d d, j, uk6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_rotri_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) ++{ ++ tcg_out32(s, encode_djuk6_insn(OPC_ROTRI_D, d, j, uk6)); ++} ++ ++/* Emits the `bstrins.w d, j, uk5, um5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bstrins_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, ++ uint32_t um5) ++{ ++ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRINS_W, d, j, uk5, um5)); ++} ++ ++/* Emits the `bstrpick.w d, j, uk5, um5` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bstrpick_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, ++ uint32_t um5) ++{ ++ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRPICK_W, d, j, uk5, um5)); ++} ++ ++/* Emits the `bstrins.d d, j, uk6, um6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bstrins_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, ++ uint32_t um6) ++{ ++ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRINS_D, d, j, uk6, um6)); ++} ++ ++/* Emits the `bstrpick.d d, j, uk6, um6` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bstrpick_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, ++ uint32_t um6) ++{ ++ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRPICK_D, d, j, uk6, um6)); ++} ++ ++/* Emits the `slti d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_slti(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_SLTI, d, j, sk12)); ++} ++ ++/* Emits the `sltui d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_sltui(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_SLTUI, d, j, sk12)); ++} ++ ++/* Emits the `addi.w d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_addi_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_W, d, j, sk12)); ++} ++ ++/* Emits the `addi.d d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_addi_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_D, d, j, sk12)); ++} ++ ++/* Emits the `cu52i.d d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_cu52i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_CU52I_D, d, j, sk12)); ++} ++ ++/* Emits the `andi d, j, uk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_andi(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) ++{ ++ tcg_out32(s, encode_djuk12_insn(OPC_ANDI, d, j, uk12)); ++} ++ ++/* Emits the `ori d, j, uk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) ++{ ++ tcg_out32(s, encode_djuk12_insn(OPC_ORI, d, j, uk12)); ++} ++ ++/* Emits the `xori d, j, uk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_xori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) ++{ ++ tcg_out32(s, encode_djuk12_insn(OPC_XORI, d, j, uk12)); ++} ++ ++/* Emits the `lu12i.w d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_LU12I_W, d, sj20)); ++} ++ ++/* Emits the `cu32i.d d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_cu32i_d(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_CU32I_D, d, sj20)); ++} ++ ++/* Emits the `pcaddu2i d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_pcaddu2i(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU2I, d, sj20)); ++} ++ ++/* Emits the `pcalau12i d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_pcalau12i(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_PCALAU12I, d, sj20)); ++} ++ ++/* Emits the `pcaddu12i d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_pcaddu12i(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU12I, d, sj20)); ++} ++ ++/* Emits the `pcaddu18i d, sj20` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_pcaddu18i(TCGContext *s, TCGReg d, int32_t sj20) ++{ ++ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU18I, d, sj20)); ++} ++ ++/* Emits the `ld.b d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_B, d, j, sk12)); ++} ++ ++/* Emits the `ld.h d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_H, d, j, sk12)); ++} ++ ++/* Emits the `ld.w d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_W, d, j, sk12)); ++} ++ ++/* Emits the `ld.d d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_D, d, j, sk12)); ++} ++ ++/* Emits the `st.b d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_st_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ST_B, d, j, sk12)); ++} ++ ++/* Emits the `st.h d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_st_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ST_H, d, j, sk12)); ++} ++ ++/* Emits the `st.w d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_st_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ST_W, d, j, sk12)); ++} ++ ++/* Emits the `st.d d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_st_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_ST_D, d, j, sk12)); ++} ++ ++/* Emits the `ld.bu d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_bu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_BU, d, j, sk12)); ++} ++ ++/* Emits the `ld.hu d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_hu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_HU, d, j, sk12)); ++} ++ ++/* Emits the `ld.wu d, j, sk12` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ld_wu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) ++{ ++ tcg_out32(s, encode_djsk12_insn(OPC_LD_WU, d, j, sk12)); ++} ++ ++/* Emits the `ldx.b d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_B, d, j, k)); ++} ++ ++/* Emits the `ldx.h d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_H, d, j, k)); ++} ++ ++/* Emits the `ldx.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_W, d, j, k)); ++} ++ ++/* Emits the `ldx.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_D, d, j, k)); ++} ++ ++/* Emits the `stx.b d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_stx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_STX_B, d, j, k)); ++} ++ ++/* Emits the `stx.h d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_stx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_STX_H, d, j, k)); ++} ++ ++/* Emits the `stx.w d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_stx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_STX_W, d, j, k)); ++} ++ ++/* Emits the `stx.d d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_stx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_STX_D, d, j, k)); ++} ++ ++/* Emits the `ldx.bu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_bu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_BU, d, j, k)); ++} ++ ++/* Emits the `ldx.hu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_hu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_HU, d, j, k)); ++} ++ ++/* Emits the `ldx.wu d, j, k` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ldx_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) ++{ ++ tcg_out32(s, encode_djk_insn(OPC_LDX_WU, d, j, k)); ++} ++ ++/* Emits the `dbar ud15` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_dbar(TCGContext *s, uint32_t ud15) ++{ ++ tcg_out32(s, encode_ud15_insn(OPC_DBAR, ud15)); ++} ++ ++/* Emits the `jirl d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_jirl(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_JIRL, d, j, sk16)); ++} ++ ++/* Emits the `b sd10k16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_b(TCGContext *s, int32_t sd10k16) ++{ ++ tcg_out32(s, encode_sd10k16_insn(OPC_B, sd10k16)); ++} ++ ++/* Emits the `bl sd10k16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bl(TCGContext *s, int32_t sd10k16) ++{ ++ tcg_out32(s, encode_sd10k16_insn(OPC_BL, sd10k16)); ++} ++ ++/* Emits the `beq d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_beq(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BEQ, d, j, sk16)); ++} ++ ++/* Emits the `bne d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bne(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BNE, d, j, sk16)); ++} ++ ++/* Emits the `bgt d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bgt(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BGT, d, j, sk16)); ++} ++ ++/* Emits the `ble d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_ble(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BLE, d, j, sk16)); ++} ++ ++/* Emits the `bgtu d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bgtu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BGTU, d, j, sk16)); ++} ++ ++/* Emits the `bleu d, j, sk16` instruction. */ ++static void __attribute__((unused)) ++tcg_out_opc_bleu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) ++{ ++ tcg_out32(s, encode_djsk16_insn(OPC_BLEU, d, j, sk16)); ++} ++/* End of generated code. */ +diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h +new file mode 100644 +index 0000000000..7b0297034f +--- /dev/null ++++ b/tcg/loongarch64/tcg-target-con-set.h +@@ -0,0 +1,39 @@ ++/* ++ * Define LoongArch target-specific constraint sets. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++/* ++ * C_On_Im(...) defines a constraint set with outputs and inputs. ++ * Each operand should be a sequence of constraint letters as defined by ++ * tcg-target-con-str.h; the constraint combination is inclusive or. ++ */ ++C_O0_I1(r) ++C_O0_I2(rZ, r) ++C_O0_I2(rZ, rZ) ++C_O0_I2(LZ, L) ++C_O1_I1(r, r) ++C_O1_I1(r, L) ++C_O1_I2(r, r, rC) ++C_O1_I2(r, r, ri) ++C_O1_I2(r, r, rI) ++C_O1_I2(r, r, rU) ++C_O1_I2(r, r, rW) ++C_O1_I2(r, r, rZ) ++C_O1_I2(r, 0, rZ) ++C_O1_I2(r, rZ, rN) ++C_O1_I2(r, rZ, rZ) +diff --git a/tcg/loongarch64/tcg-target-con-str.h b/tcg/loongarch64/tcg-target-con-str.h +new file mode 100644 +index 0000000000..b105f5ebd8 +--- /dev/null ++++ b/tcg/loongarch64/tcg-target-con-str.h +@@ -0,0 +1,36 @@ ++/* ++ * Define LoongArch target-specific operand constraints. ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++/* ++ * Define constraint letters for register sets: ++ * REGS(letter, register_mask) ++ */ ++REGS('r', ALL_GENERAL_REGS) ++REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) ++ ++/* ++ * Define constraint letters for constants: ++ * CONST(letter, TCG_CT_CONST_* bit set) ++ */ ++CONST('I', TCG_CT_CONST_S12) ++CONST('N', TCG_CT_CONST_N12) ++CONST('U', TCG_CT_CONST_U12) ++CONST('Z', TCG_CT_CONST_ZERO) ++CONST('C', TCG_CT_CONST_C12) ++CONST('W', TCG_CT_CONST_WSZ) +diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc +new file mode 100644 +index 0000000000..0b28b30002 +--- /dev/null ++++ b/tcg/loongarch64/tcg-target.c.inc +@@ -0,0 +1,1727 @@ ++/* ++ * Tiny Code Generator for QEMU ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "../tcg-ldst.c.inc" ++ ++#ifdef CONFIG_DEBUG_TCG ++static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ++ "zero", ++ "ra", ++ "tp", ++ "sp", ++ "a0", ++ "a1", ++ "a2", ++ "a3", ++ "a4", ++ "a5", ++ "a6", ++ "a7", ++ "t0", ++ "t1", ++ "t2", ++ "t3", ++ "t4", ++ "t5", ++ "t6", ++ "t7", ++ "t8", ++ "r21", /* reserved in the LP64* ABI, hence no ABI name */ ++ "s9", ++ "s0", ++ "s1", ++ "s2", ++ "s3", ++ "s4", ++ "s5", ++ "s6", ++ "s7", ++ "s8" ++}; ++#endif ++ ++static const int tcg_target_reg_alloc_order[] = { ++ /* Registers preserved across calls */ ++ /* TCG_REG_S0 reserved for TCG_AREG0 */ ++ TCG_REG_S1, ++ TCG_REG_S2, ++ TCG_REG_S3, ++ TCG_REG_S4, ++ TCG_REG_S5, ++ TCG_REG_S6, ++ TCG_REG_S7, ++ TCG_REG_S8, ++ TCG_REG_S9, ++ ++ /* Registers (potentially) clobbered across calls */ ++ TCG_REG_T0, ++ TCG_REG_T1, ++ TCG_REG_T2, ++ TCG_REG_T3, ++ TCG_REG_T4, ++ TCG_REG_T5, ++ TCG_REG_T6, ++ TCG_REG_T7, ++ TCG_REG_T8, ++ ++ /* Argument registers, opposite order of allocation. */ ++ TCG_REG_A7, ++ TCG_REG_A6, ++ TCG_REG_A5, ++ TCG_REG_A4, ++ TCG_REG_A3, ++ TCG_REG_A2, ++ TCG_REG_A1, ++ TCG_REG_A0, ++}; ++ ++static const int tcg_target_call_iarg_regs[] = { ++ TCG_REG_A0, ++ TCG_REG_A1, ++ TCG_REG_A2, ++ TCG_REG_A3, ++ TCG_REG_A4, ++ TCG_REG_A5, ++ TCG_REG_A6, ++ TCG_REG_A7, ++}; ++ ++static const int tcg_target_call_oarg_regs[] = { ++ TCG_REG_A0, ++ TCG_REG_A1, ++}; ++ ++#ifndef CONFIG_SOFTMMU ++#define USE_GUEST_BASE (guest_base != 0) ++#define TCG_GUEST_BASE_REG TCG_REG_S1 ++#endif ++ ++#define TCG_CT_CONST_ZERO 0x100 ++#define TCG_CT_CONST_S12 0x200 ++#define TCG_CT_CONST_N12 0x400 ++#define TCG_CT_CONST_U12 0x800 ++#define TCG_CT_CONST_C12 0x1000 ++#define TCG_CT_CONST_WSZ 0x2000 ++ ++#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) ++/* ++ * For softmmu, we need to avoid conflicts with the first 5 ++ * argument registers to call the helper. Some of these are ++ * also used for the tlb lookup. ++ */ ++#ifdef CONFIG_SOFTMMU ++#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_A0, 5) ++#else ++#define SOFTMMU_RESERVE_REGS 0 ++#endif ++ ++static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) ++{ ++ return sextract64(val, pos, len); ++} ++ ++/* test if a constant matches the constraint */ ++static bool tcg_target_const_match(int64_t val, TCGType type, int ct) ++{ ++ if (ct & TCG_CT_CONST) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_U12) && val >= 0 && val <= 0xfff) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_C12) && ~val >= 0 && ~val <= 0xfff) { ++ return true; ++ } ++ if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * Relocations ++ */ ++ ++/* ++ * Relocation records defined in LoongArch ELF psABI v1.00 is way too ++ * complicated; a whopping stack machine is needed to stuff the fields, at ++ * the very least one SOP_PUSH and one SOP_POP (of the correct format) are ++ * needed. ++ * ++ * Hence, define our own simpler relocation types. Numbers are chosen as to ++ * not collide with potential future additions to the true ELF relocation ++ * type enum. ++ */ ++ ++/* Field Sk16, shifted right by 2; suitable for conditional jumps */ ++#define R_LOONGARCH_BR_SK16 256 ++/* Field Sd10k16, shifted right by 2; suitable for B and BL */ ++#define R_LOONGARCH_BR_SD10K16 257 ++ ++static bool reloc_br_sk16(tcg_insn_unit *src_rw, const tcg_insn_unit *target) ++{ ++ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); ++ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; ++ ++ tcg_debug_assert((offset & 3) == 0); ++ offset >>= 2; ++ if (offset == sextreg(offset, 0, 16)) { ++ *src_rw = deposit64(*src_rw, 10, 16, offset); ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool reloc_br_sd10k16(tcg_insn_unit *src_rw, ++ const tcg_insn_unit *target) ++{ ++ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); ++ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; ++ ++ tcg_debug_assert((offset & 3) == 0); ++ offset >>= 2; ++ if (offset == sextreg(offset, 0, 26)) { ++ *src_rw = deposit64(*src_rw, 0, 10, offset >> 16); /* slot d10 */ ++ *src_rw = deposit64(*src_rw, 10, 16, offset); /* slot k16 */ ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, ++ intptr_t addend) ++{ ++ tcg_debug_assert(addend == 0); ++ switch (type) { ++ case R_LOONGARCH_BR_SK16: ++ return reloc_br_sk16(code_ptr, (tcg_insn_unit *)value); ++ case R_LOONGARCH_BR_SD10K16: ++ return reloc_br_sd10k16(code_ptr, (tcg_insn_unit *)value); ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++#include "tcg-insn-defs.c.inc" ++ ++/* ++ * TCG intrinsics ++ */ ++ ++static void tcg_out_mb(TCGContext *s, TCGArg a0) ++{ ++ /* Baseline LoongArch only has the full barrier, unfortunately. */ ++ tcg_out_opc_dbar(s, 0); ++} ++ ++static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) ++{ ++ if (ret == arg) { ++ return true; ++ } ++ switch (type) { ++ case TCG_TYPE_I32: ++ case TCG_TYPE_I64: ++ /* ++ * Conventional register-register move used in LoongArch is ++ * `or dst, src, zero`. ++ */ ++ tcg_out_opc_or(s, ret, arg, TCG_REG_ZERO); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ return true; ++} ++ ++static bool imm_part_needs_loading(bool high_bits_are_ones, ++ tcg_target_long part) ++{ ++ if (high_bits_are_ones) { ++ return part != -1; ++ } else { ++ return part != 0; ++ } ++} ++ ++/* Loads a 32-bit immediate into rd, sign-extended. */ ++static void tcg_out_movi_i32(TCGContext *s, TCGReg rd, int32_t val) ++{ ++ tcg_target_long lo = sextreg(val, 0, 12); ++ tcg_target_long hi12 = sextreg(val, 12, 20); ++ ++ /* Single-instruction cases. */ ++ if (lo == val) { ++ /* val fits in simm12: addi.w rd, zero, val */ ++ tcg_out_opc_addi_w(s, rd, TCG_REG_ZERO, val); ++ return; ++ } ++ if (0x800 <= val && val <= 0xfff) { ++ /* val fits in uimm12: ori rd, zero, val */ ++ tcg_out_opc_ori(s, rd, TCG_REG_ZERO, val); ++ return; ++ } ++ ++ /* High bits must be set; load with lu12i.w + optional ori. */ ++ tcg_out_opc_lu12i_w(s, rd, hi12); ++ if (lo != 0) { ++ tcg_out_opc_ori(s, rd, rd, lo & 0xfff); ++ } ++} ++ ++static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, ++ tcg_target_long val) ++{ ++ /* ++ * LoongArch conventionally loads 64-bit immediates in at most 4 steps, ++ * with dedicated instructions for filling the respective bitfields ++ * below: ++ * ++ * 6 5 4 3 ++ * 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 ++ * +-----------------------+---------------------------------------+... ++ * | hi52 | hi32 | ++ * +-----------------------+---------------------------------------+... ++ * 3 2 1 ++ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 ++ * ...+-------------------------------------+-------------------------+ ++ * | hi12 | lo | ++ * ...+-------------------------------------+-------------------------+ ++ * ++ * Check if val belong to one of the several fast cases, before falling ++ * back to the slow path. ++ */ ++ ++ intptr_t pc_offset; ++ tcg_target_long val_lo, val_hi, pc_hi, offset_hi; ++ tcg_target_long hi32, hi52; ++ bool rd_high_bits_are_ones; ++ ++ /* Value fits in signed i32. */ ++ if (type == TCG_TYPE_I32 || val == (int32_t)val) { ++ tcg_out_movi_i32(s, rd, val); ++ return; ++ } ++ ++ /* PC-relative cases. */ ++ pc_offset = tcg_pcrel_diff(s, (void *)val); ++ if (pc_offset == sextreg(pc_offset, 0, 22) && (pc_offset & 3) == 0) { ++ /* Single pcaddu2i. */ ++ tcg_out_opc_pcaddu2i(s, rd, pc_offset >> 2); ++ return; ++ } ++ ++ if (pc_offset == (int32_t)pc_offset) { ++ /* Offset within 32 bits; load with pcalau12i + ori. */ ++ val_lo = sextreg(val, 0, 12); ++ val_hi = val >> 12; ++ pc_hi = (val - pc_offset) >> 12; ++ offset_hi = val_hi - pc_hi; ++ ++ tcg_debug_assert(offset_hi == sextreg(offset_hi, 0, 20)); ++ tcg_out_opc_pcalau12i(s, rd, offset_hi); ++ if (val_lo != 0) { ++ tcg_out_opc_ori(s, rd, rd, val_lo & 0xfff); ++ } ++ return; ++ } ++ ++ hi32 = sextreg(val, 32, 20); ++ hi52 = sextreg(val, 52, 12); ++ ++ /* Single cu52i.d case. */ ++ if (ctz64(val) >= 52) { ++ tcg_out_opc_cu52i_d(s, rd, TCG_REG_ZERO, hi52); ++ return; ++ } ++ ++ /* Slow path. Initialize the low 32 bits, then concat high bits. */ ++ tcg_out_movi_i32(s, rd, val); ++ rd_high_bits_are_ones = (int32_t)val < 0; ++ ++ if (imm_part_needs_loading(rd_high_bits_are_ones, hi32)) { ++ tcg_out_opc_cu32i_d(s, rd, hi32); ++ rd_high_bits_are_ones = hi32 < 0; ++ } ++ ++ if (imm_part_needs_loading(rd_high_bits_are_ones, hi52)) { ++ tcg_out_opc_cu52i_d(s, rd, rd, hi52); ++ } ++} ++ ++static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_andi(s, ret, arg, 0xff); ++} ++ ++static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_bstrpick_w(s, ret, arg, 0, 15); ++} ++ ++static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_bstrpick_d(s, ret, arg, 0, 31); ++} ++ ++static void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_sext_b(s, ret, arg); ++} ++ ++static void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_sext_h(s, ret, arg); ++} ++ ++static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg) ++{ ++ tcg_out_opc_addi_w(s, ret, arg, 0); ++} ++ ++static void tcg_out_clzctz(TCGContext *s, LoongArchInsn opc, TCGReg a0, ++ TCGReg a1, TCGReg a2, bool c2, bool is_32bit) ++{ ++ if (c2) { ++ /* ++ * Fast path: semantics already satisfied due to constraint and ++ * insn behavior, single instruction is enough. ++ */ ++ tcg_debug_assert(a2 == (is_32bit ? 32 : 64)); ++ /* all clz/ctz insns belong to DJ-format */ ++ tcg_out32(s, encode_dj_insn(opc, a0, a1)); ++ return; ++ } ++ ++ tcg_out32(s, encode_dj_insn(opc, TCG_REG_TMP0, a1)); ++ /* a0 = a1 ? REG_TMP0 : a2 */ ++ tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); ++ tcg_out_opc_masknez(s, a0, a2, a1); ++ tcg_out_opc_or(s, a0, TCG_REG_TMP0, a0); ++} ++ ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGReg arg1, TCGReg arg2, bool c2) ++{ ++ TCGReg tmp; ++ ++ if (c2) { ++ tcg_debug_assert(arg2 == 0); ++ } ++ ++ switch (cond) { ++ case TCG_COND_EQ: ++ if (c2) { ++ tmp = arg1; ++ } else { ++ tcg_out_opc_sub_d(s, ret, arg1, arg2); ++ tmp = ret; ++ } ++ tcg_out_opc_sltui(s, ret, tmp, 1); ++ break; ++ case TCG_COND_NE: ++ if (c2) { ++ tmp = arg1; ++ } else { ++ tcg_out_opc_sub_d(s, ret, arg1, arg2); ++ tmp = ret; ++ } ++ tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); ++ break; ++ case TCG_COND_LT: ++ tcg_out_opc_slt(s, ret, arg1, arg2); ++ break; ++ case TCG_COND_GE: ++ tcg_out_opc_slt(s, ret, arg1, arg2); ++ tcg_out_opc_xori(s, ret, ret, 1); ++ break; ++ case TCG_COND_LE: ++ tcg_out_setcond(s, TCG_COND_GE, ret, arg2, arg1, false); ++ break; ++ case TCG_COND_GT: ++ tcg_out_setcond(s, TCG_COND_LT, ret, arg2, arg1, false); ++ break; ++ case TCG_COND_LTU: ++ tcg_out_opc_sltu(s, ret, arg1, arg2); ++ break; ++ case TCG_COND_GEU: ++ tcg_out_opc_sltu(s, ret, arg1, arg2); ++ tcg_out_opc_xori(s, ret, ret, 1); ++ break; ++ case TCG_COND_LEU: ++ tcg_out_setcond(s, TCG_COND_GEU, ret, arg2, arg1, false); ++ break; ++ case TCG_COND_GTU: ++ tcg_out_setcond(s, TCG_COND_LTU, ret, arg2, arg1, false); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } ++} ++ ++/* ++ * Branch helpers ++ */ ++ ++static const struct { ++ LoongArchInsn op; ++ bool swap; ++} tcg_brcond_to_loongarch[] = { ++ [TCG_COND_EQ] = { OPC_BEQ, false }, [TCG_COND_NE] = { OPC_BNE, false }, ++ [TCG_COND_LT] = { OPC_BGT, true }, [TCG_COND_GE] = { OPC_BLE, true }, ++ [TCG_COND_LE] = { OPC_BLE, false }, [TCG_COND_GT] = { OPC_BGT, false }, ++ [TCG_COND_LTU] = { OPC_BGTU, true }, [TCG_COND_GEU] = { OPC_BLEU, true }, ++ [TCG_COND_LEU] = { OPC_BLEU, false }, [TCG_COND_GTU] = { OPC_BGTU, false } ++}; ++ ++static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, ++ TCGReg arg2, TCGLabel *l) ++{ ++ LoongArchInsn op = tcg_brcond_to_loongarch[cond].op; ++ ++ tcg_debug_assert(op != 0); ++ ++ if (tcg_brcond_to_loongarch[cond].swap) { ++ TCGReg t = arg1; ++ arg1 = arg2; ++ arg2 = t; ++ } ++ ++ /* all conditional branch insns belong to DJSk16-format */ ++ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SK16, l, 0); ++ tcg_out32(s, encode_djsk16_insn(op, arg1, arg2, 0)); ++} ++ ++static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, ++ bool tail) ++{ ++ TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA; ++ ptrdiff_t offset = tcg_pcrel_diff(s, arg); ++ ++ tcg_debug_assert((offset & 3) == 0); ++ if (offset == sextreg(offset, 0, 28)) { ++ /* short jump: +/- 256MiB */ ++ if (tail) { ++ tcg_out_opc_b(s, offset >> 2); ++ } else { ++ tcg_out_opc_bl(s, offset >> 2); ++ } ++ } else if (offset == sextreg(offset, 0, 38)) { ++ /* long jump: +/- 256GiB */ ++ tcg_target_long lo = sextreg(offset, 0, 18); ++ tcg_target_long hi = offset - lo; ++ tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, hi >> 18); ++ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); ++ } else { ++ /* far jump: 64-bit */ ++ tcg_target_long lo = sextreg((tcg_target_long)arg, 0, 18); ++ tcg_target_long hi = (tcg_target_long)arg - lo; ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, hi); ++ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); ++ } ++} ++ ++static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) ++{ ++ tcg_out_call_int(s, arg, false); ++} ++ ++/* ++ * Load/store helpers ++ */ ++ ++static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data, ++ TCGReg addr, intptr_t offset) ++{ ++ intptr_t imm12 = sextreg(offset, 0, 12); ++ ++ if (offset != imm12) { ++ intptr_t diff = offset - (uintptr_t)s->code_ptr; ++ ++ if (addr == TCG_REG_ZERO && diff == (int32_t)diff) { ++ imm12 = sextreg(diff, 0, 12); ++ tcg_out_opc_pcaddu12i(s, TCG_REG_TMP2, (diff - imm12) >> 12); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - imm12); ++ if (addr != TCG_REG_ZERO) { ++ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, addr); ++ } ++ } ++ addr = TCG_REG_TMP2; ++ } ++ ++ switch (opc) { ++ case OPC_LD_B: ++ case OPC_LD_BU: ++ case OPC_LD_H: ++ case OPC_LD_HU: ++ case OPC_LD_W: ++ case OPC_LD_WU: ++ case OPC_LD_D: ++ case OPC_ST_B: ++ case OPC_ST_H: ++ case OPC_ST_W: ++ case OPC_ST_D: ++ tcg_out32(s, encode_djsk12_insn(opc, data, addr, imm12)); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, ++ intptr_t arg2) ++{ ++ bool is_32bit = type == TCG_TYPE_I32; ++ tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2); ++} ++ ++static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, ++ intptr_t arg2) ++{ ++ bool is_32bit = type == TCG_TYPE_I32; ++ tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2); ++} ++ ++static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, ++ intptr_t ofs) ++{ ++ if (val == 0) { ++ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * Load/store helpers for SoftMMU, and qemu_ld/st implementations ++ */ ++ ++#if defined(CONFIG_SOFTMMU) ++/* ++ * helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, ++ * MemOpIdx oi, uintptr_t ra) ++ */ ++static void *const qemu_ld_helpers[4] = { ++ [MO_8] = helper_ret_ldub_mmu, ++ [MO_16] = helper_le_lduw_mmu, ++ [MO_32] = helper_le_ldul_mmu, ++ [MO_64] = helper_le_ldq_mmu, ++}; ++ ++/* ++ * helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, ++ * uintxx_t val, MemOpIdx oi, ++ * uintptr_t ra) ++ */ ++static void *const qemu_st_helpers[4] = { ++ [MO_8] = helper_ret_stb_mmu, ++ [MO_16] = helper_le_stw_mmu, ++ [MO_32] = helper_le_stl_mmu, ++ [MO_64] = helper_le_stq_mmu, ++}; ++ ++/* We expect to use a 12-bit negative offset from ENV. */ ++QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0); ++QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 11)); ++ ++static bool tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) ++{ ++ tcg_out_opc_b(s, 0); ++ return reloc_br_sd10k16(s->code_ptr - 1, target); ++} ++ ++/* ++ * Emits common code for TLB addend lookup, that eventually loads the ++ * addend in TCG_REG_TMP2. ++ */ ++static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, MemOpIdx oi, ++ tcg_insn_unit **label_ptr, bool is_load) ++{ ++ MemOp opc = get_memop(oi); ++ unsigned s_bits = opc & MO_SIZE; ++ unsigned a_bits = get_alignment_bits(opc); ++ tcg_target_long compare_mask; ++ int mem_index = get_mmuidx(oi); ++ int fast_ofs = TLB_MASK_TABLE_OFS(mem_index); ++ int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); ++ int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); ++ ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); ++ ++ tcg_out_opc_srli_d(s, TCG_REG_TMP2, addrl, ++ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ++ tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); ++ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); ++ ++ /* Load the tlb comparator and the addend. */ ++ tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_TMP0, TCG_REG_TMP2, ++ is_load ? offsetof(CPUTLBEntry, addr_read) ++ : offsetof(CPUTLBEntry, addr_write)); ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, ++ offsetof(CPUTLBEntry, addend)); ++ ++ /* We don't support unaligned accesses. */ ++ if (a_bits < s_bits) { ++ a_bits = s_bits; ++ } ++ /* Clear the non-page, non-alignment bits from the address. */ ++ compare_mask = (tcg_target_long)TARGET_PAGE_MASK | ((1 << a_bits) - 1); ++ tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, compare_mask); ++ tcg_out_opc_and(s, TCG_REG_TMP1, TCG_REG_TMP1, addrl); ++ ++ /* Compare masked address with the TLB entry. */ ++ label_ptr[0] = s->code_ptr; ++ tcg_out_opc_bne(s, TCG_REG_TMP0, TCG_REG_TMP1, 0); ++ ++ /* TLB Hit - addend in TCG_REG_TMP2, ready for use. */ ++} ++ ++static void add_qemu_ldst_label(TCGContext *s, int is_ld, MemOpIdx oi, ++ TCGType type, TCGReg datalo, TCGReg addrlo, ++ void *raddr, tcg_insn_unit **label_ptr) ++{ ++ TCGLabelQemuLdst *label = new_ldst_label(s); ++ ++ label->is_ld = is_ld; ++ label->oi = oi; ++ label->type = type; ++ label->datalo_reg = datalo; ++ label->datahi_reg = 0; /* unused */ ++ label->addrlo_reg = addrlo; ++ label->addrhi_reg = 0; /* unused */ ++ label->raddr = tcg_splitwx_to_rx(raddr); ++ label->label_ptr[0] = label_ptr[0]; ++} ++ ++static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) ++{ ++ MemOpIdx oi = l->oi; ++ MemOp opc = get_memop(oi); ++ MemOp size = opc & MO_SIZE; ++ TCGType type = l->type; ++ ++ /* resolve label address */ ++ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { ++ return false; ++ } ++ ++ /* call load helper */ ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A2, oi); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, (tcg_target_long)l->raddr); ++ ++ tcg_out_call(s, qemu_ld_helpers[size]); ++ ++ switch (opc & MO_SSIZE) { ++ case MO_SB: ++ tcg_out_ext8s(s, l->datalo_reg, TCG_REG_A0); ++ break; ++ case MO_SW: ++ tcg_out_ext16s(s, l->datalo_reg, TCG_REG_A0); ++ break; ++ case MO_SL: ++ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); ++ break; ++ case MO_UL: ++ if (type == TCG_TYPE_I32) { ++ /* MO_UL loads of i32 should be sign-extended too */ ++ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); ++ break; ++ } ++ /* fallthrough */ ++ default: ++ tcg_out_mov(s, type, l->datalo_reg, TCG_REG_A0); ++ break; ++ } ++ ++ return tcg_out_goto(s, l->raddr); ++} ++ ++static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) ++{ ++ MemOpIdx oi = l->oi; ++ MemOp opc = get_memop(oi); ++ MemOp size = opc & MO_SIZE; ++ ++ /* resolve label address */ ++ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { ++ return false; ++ } ++ ++ /* call store helper */ ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); ++ switch (size) { ++ case MO_8: ++ tcg_out_ext8u(s, TCG_REG_A2, l->datalo_reg); ++ break; ++ case MO_16: ++ tcg_out_ext16u(s, TCG_REG_A2, l->datalo_reg); ++ break; ++ case MO_32: ++ tcg_out_ext32u(s, TCG_REG_A2, l->datalo_reg); ++ break; ++ case MO_64: ++ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_A2, l->datalo_reg); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, oi); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A4, (tcg_target_long)l->raddr); ++ ++ tcg_out_call(s, qemu_st_helpers[size]); ++ ++ return tcg_out_goto(s, l->raddr); ++} ++#else ++ ++/* ++ * Alignment helpers for user-mode emulation ++ */ ++ ++static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg, ++ unsigned a_bits) ++{ ++ TCGLabelQemuLdst *l = new_ldst_label(s); ++ ++ l->is_ld = is_ld; ++ l->addrlo_reg = addr_reg; ++ ++ /* ++ * Without micro-architecture details, we don't know which of bstrpick or ++ * andi is faster, so use bstrpick as it's not constrained by imm field ++ * width. (Not to say alignments >= 2^12 are going to happen any time ++ * soon, though) ++ */ ++ tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1); ++ ++ l->label_ptr[0] = s->code_ptr; ++ tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0); ++ ++ l->raddr = tcg_splitwx_to_rx(s->code_ptr); ++} ++ ++static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l) ++{ ++ /* resolve label address */ ++ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { ++ return false; ++ } ++ ++ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg); ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); ++ ++ /* tail call, with the return address back inline. */ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr); ++ tcg_out_call_int( ++ s, ++ (const void *)(l->is_ld ? helper_unaligned_ld : helper_unaligned_st), ++ true); ++ return true; ++} ++ ++static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) ++{ ++ return tcg_out_fail_alignment(s, l); ++} ++ ++static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) ++{ ++ return tcg_out_fail_alignment(s, l); ++} ++ ++#endif /* CONFIG_SOFTMMU */ ++ ++/* ++ * `ext32u` the address register into the temp register given, ++ * if target is 32-bit, no-op otherwise. ++ * ++ * Returns the address register ready for use with TLB addend. ++ */ ++static TCGReg tcg_out_zext_addr_if_32_bit(TCGContext *s, TCGReg addr, ++ TCGReg tmp) ++{ ++ if (TARGET_LONG_BITS == 32) { ++ tcg_out_ext32u(s, tmp, addr); ++ return tmp; ++ } ++ return addr; ++} ++ ++static void tcg_out_qemu_ld_indexed(TCGContext *s, TCGReg rd, TCGReg rj, ++ TCGReg rk, MemOp opc, TCGType type) ++{ ++ /* Byte swapping is left to middle-end expansion. */ ++ tcg_debug_assert((opc & MO_BSWAP) == 0); ++ ++ switch (opc & MO_SSIZE) { ++ case MO_UB: ++ tcg_out_opc_ldx_bu(s, rd, rj, rk); ++ break; ++ case MO_SB: ++ tcg_out_opc_ldx_b(s, rd, rj, rk); ++ break; ++ case MO_UW: ++ tcg_out_opc_ldx_hu(s, rd, rj, rk); ++ break; ++ case MO_SW: ++ tcg_out_opc_ldx_h(s, rd, rj, rk); ++ break; ++ case MO_UL: ++ if (type == TCG_TYPE_I64) { ++ tcg_out_opc_ldx_wu(s, rd, rj, rk); ++ break; ++ } ++ /* fallthrough */ ++ case MO_SL: ++ tcg_out_opc_ldx_w(s, rd, rj, rk); ++ break; ++ case MO_Q: ++ tcg_out_opc_ldx_d(s, rd, rj, rk); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, TCGType type) ++{ ++ TCGReg addr_regl; ++ TCGReg data_regl; ++ MemOpIdx oi; ++ MemOp opc; ++#if defined(CONFIG_SOFTMMU) ++ tcg_insn_unit *label_ptr[1]; ++#else ++ unsigned a_bits; ++#endif ++ TCGReg base; ++ ++ data_regl = *args++; ++ addr_regl = *args++; ++ oi = *args++; ++ opc = get_memop(oi); ++ ++#if defined(CONFIG_SOFTMMU) ++ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 1); ++ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); ++ tcg_out_qemu_ld_indexed(s, data_regl, base, TCG_REG_TMP2, opc, type); ++ add_qemu_ldst_label(s, 1, oi, type, data_regl, addr_regl, s->code_ptr, ++ label_ptr); ++#else ++ a_bits = get_alignment_bits(opc); ++ if (a_bits) { ++ tcg_out_test_alignment(s, true, addr_regl, a_bits); ++ } ++ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); ++ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; ++ tcg_out_qemu_ld_indexed(s, data_regl, base, guest_base_reg, opc, type); ++#endif ++} ++ ++static void tcg_out_qemu_st_indexed(TCGContext *s, TCGReg data, TCGReg rj, ++ TCGReg rk, MemOp opc) ++{ ++ /* Byte swapping is left to middle-end expansion. */ ++ tcg_debug_assert((opc & MO_BSWAP) == 0); ++ ++ switch (opc & MO_SIZE) { ++ case MO_8: ++ tcg_out_opc_stx_b(s, data, rj, rk); ++ break; ++ case MO_16: ++ tcg_out_opc_stx_h(s, data, rj, rk); ++ break; ++ case MO_32: ++ tcg_out_opc_stx_w(s, data, rj, rk); ++ break; ++ case MO_64: ++ tcg_out_opc_stx_d(s, data, rj, rk); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) ++{ ++ TCGReg addr_regl; ++ TCGReg data_regl; ++ MemOpIdx oi; ++ MemOp opc; ++#if defined(CONFIG_SOFTMMU) ++ tcg_insn_unit *label_ptr[1]; ++#else ++ unsigned a_bits; ++#endif ++ TCGReg base; ++ ++ data_regl = *args++; ++ addr_regl = *args++; ++ oi = *args++; ++ opc = get_memop(oi); ++ ++#if defined(CONFIG_SOFTMMU) ++ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 0); ++ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); ++ tcg_out_qemu_st_indexed(s, data_regl, base, TCG_REG_TMP2, opc); ++ add_qemu_ldst_label(s, 0, oi, 0, /* type param is unused for stores */ ++ data_regl, addr_regl, s->code_ptr, label_ptr); ++#else ++ a_bits = get_alignment_bits(opc); ++ if (a_bits) { ++ tcg_out_test_alignment(s, false, addr_regl, a_bits); ++ } ++ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); ++ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; ++ tcg_out_qemu_st_indexed(s, data_regl, base, guest_base_reg, opc); ++#endif ++} ++ ++/* ++ * Entry-points ++ */ ++ ++static const tcg_insn_unit *tb_ret_addr; ++ ++static void tcg_out_op(TCGContext *s, TCGOpcode opc, ++ const TCGArg args[TCG_MAX_OP_ARGS], ++ const int const_args[TCG_MAX_OP_ARGS]) ++{ ++ TCGArg a0 = args[0]; ++ TCGArg a1 = args[1]; ++ TCGArg a2 = args[2]; ++ int c2 = const_args[2]; ++ ++ switch (opc) { ++ case INDEX_op_exit_tb: ++ /* Reuse the zeroing that exists for goto_ptr. */ ++ if (a0 == 0) { ++ tcg_out_call_int(s, tcg_code_gen_epilogue, true); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); ++ tcg_out_call_int(s, tb_ret_addr, true); ++ } ++ break; ++ ++ case INDEX_op_goto_tb: ++ assert(s->tb_jmp_insn_offset == 0); ++ /* indirect jump method */ ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, ++ (uintptr_t)(s->tb_jmp_target_addr + a0)); ++ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); ++ set_jmp_reset_offset(s, a0); ++ break; ++ ++ case INDEX_op_mb: ++ tcg_out_mb(s, a0); ++ break; ++ ++ case INDEX_op_goto_ptr: ++ tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); ++ break; ++ ++ case INDEX_op_br: ++ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SD10K16, arg_label(a0), ++ 0); ++ tcg_out_opc_b(s, 0); ++ break; ++ ++ case INDEX_op_brcond_i32: ++ case INDEX_op_brcond_i64: ++ tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); ++ break; ++ ++ case INDEX_op_ext8s_i32: ++ case INDEX_op_ext8s_i64: ++ tcg_out_ext8s(s, a0, a1); ++ break; ++ ++ case INDEX_op_ext8u_i32: ++ case INDEX_op_ext8u_i64: ++ tcg_out_ext8u(s, a0, a1); ++ break; ++ ++ case INDEX_op_ext16s_i32: ++ case INDEX_op_ext16s_i64: ++ tcg_out_ext16s(s, a0, a1); ++ break; ++ ++ case INDEX_op_ext16u_i32: ++ case INDEX_op_ext16u_i64: ++ tcg_out_ext16u(s, a0, a1); ++ break; ++ ++ case INDEX_op_ext32u_i64: ++ case INDEX_op_extu_i32_i64: ++ tcg_out_ext32u(s, a0, a1); ++ break; ++ ++ case INDEX_op_ext32s_i64: ++ case INDEX_op_extrl_i64_i32: ++ case INDEX_op_ext_i32_i64: ++ tcg_out_ext32s(s, a0, a1); ++ break; ++ ++ case INDEX_op_extrh_i64_i32: ++ tcg_out_opc_srai_d(s, a0, a1, 32); ++ break; ++ ++ case INDEX_op_not_i32: ++ case INDEX_op_not_i64: ++ tcg_out_opc_nor(s, a0, a1, TCG_REG_ZERO); ++ break; ++ ++ case INDEX_op_nor_i32: ++ case INDEX_op_nor_i64: ++ if (c2) { ++ tcg_out_opc_ori(s, a0, a1, a2); ++ tcg_out_opc_nor(s, a0, a0, TCG_REG_ZERO); ++ } else { ++ tcg_out_opc_nor(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_andc_i32: ++ case INDEX_op_andc_i64: ++ if (c2) { ++ /* guaranteed to fit due to constraint */ ++ tcg_out_opc_andi(s, a0, a1, ~a2); ++ } else { ++ tcg_out_opc_andn(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_orc_i32: ++ case INDEX_op_orc_i64: ++ if (c2) { ++ /* guaranteed to fit due to constraint */ ++ tcg_out_opc_ori(s, a0, a1, ~a2); ++ } else { ++ tcg_out_opc_orn(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_and_i32: ++ case INDEX_op_and_i64: ++ if (c2) { ++ tcg_out_opc_andi(s, a0, a1, a2); ++ } else { ++ tcg_out_opc_and(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_or_i32: ++ case INDEX_op_or_i64: ++ if (c2) { ++ tcg_out_opc_ori(s, a0, a1, a2); ++ } else { ++ tcg_out_opc_or(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_xor_i32: ++ case INDEX_op_xor_i64: ++ if (c2) { ++ tcg_out_opc_xori(s, a0, a1, a2); ++ } else { ++ tcg_out_opc_xor(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_extract_i32: ++ tcg_out_opc_bstrpick_w(s, a0, a1, a2, a2 + args[3] - 1); ++ break; ++ case INDEX_op_extract_i64: ++ tcg_out_opc_bstrpick_d(s, a0, a1, a2, a2 + args[3] - 1); ++ break; ++ ++ case INDEX_op_deposit_i32: ++ tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); ++ break; ++ case INDEX_op_deposit_i64: ++ tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); ++ break; ++ ++ case INDEX_op_bswap16_i32: ++ case INDEX_op_bswap16_i64: ++ tcg_out_opc_revb_2h(s, a0, a1); ++ if (a2 & TCG_BSWAP_OS) { ++ tcg_out_ext16s(s, a0, a0); ++ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { ++ tcg_out_ext16u(s, a0, a0); ++ } ++ break; ++ ++ case INDEX_op_bswap32_i32: ++ /* All 32-bit values are computed sign-extended in the register. */ ++ a2 = TCG_BSWAP_OS; ++ /* fallthrough */ ++ case INDEX_op_bswap32_i64: ++ tcg_out_opc_revb_2w(s, a0, a1); ++ if (a2 & TCG_BSWAP_OS) { ++ tcg_out_ext32s(s, a0, a0); ++ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { ++ tcg_out_ext32u(s, a0, a0); ++ } ++ break; ++ ++ case INDEX_op_bswap64_i64: ++ tcg_out_opc_revb_d(s, a0, a1); ++ break; ++ ++ case INDEX_op_clz_i32: ++ tcg_out_clzctz(s, OPC_CLZ_W, a0, a1, a2, c2, true); ++ break; ++ case INDEX_op_clz_i64: ++ tcg_out_clzctz(s, OPC_CLZ_D, a0, a1, a2, c2, false); ++ break; ++ ++ case INDEX_op_ctz_i32: ++ tcg_out_clzctz(s, OPC_CTZ_W, a0, a1, a2, c2, true); ++ break; ++ case INDEX_op_ctz_i64: ++ tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); ++ break; ++ ++ case INDEX_op_shl_i32: ++ if (c2) { ++ tcg_out_opc_slli_w(s, a0, a1, a2 & 0x1f); ++ } else { ++ tcg_out_opc_sll_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_shl_i64: ++ if (c2) { ++ tcg_out_opc_slli_d(s, a0, a1, a2 & 0x3f); ++ } else { ++ tcg_out_opc_sll_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_shr_i32: ++ if (c2) { ++ tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); ++ } else { ++ tcg_out_opc_srl_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_shr_i64: ++ if (c2) { ++ tcg_out_opc_srli_d(s, a0, a1, a2 & 0x3f); ++ } else { ++ tcg_out_opc_srl_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sar_i32: ++ if (c2) { ++ tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); ++ } else { ++ tcg_out_opc_sra_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_sar_i64: ++ if (c2) { ++ tcg_out_opc_srai_d(s, a0, a1, a2 & 0x3f); ++ } else { ++ tcg_out_opc_sra_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_rotl_i32: ++ /* transform into equivalent rotr/rotri */ ++ if (c2) { ++ tcg_out_opc_rotri_w(s, a0, a1, (32 - a2) & 0x1f); ++ } else { ++ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); ++ tcg_out_opc_rotr_w(s, a0, a1, TCG_REG_TMP0); ++ } ++ break; ++ case INDEX_op_rotl_i64: ++ /* transform into equivalent rotr/rotri */ ++ if (c2) { ++ tcg_out_opc_rotri_d(s, a0, a1, (64 - a2) & 0x3f); ++ } else { ++ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); ++ tcg_out_opc_rotr_d(s, a0, a1, TCG_REG_TMP0); ++ } ++ break; ++ ++ case INDEX_op_rotr_i32: ++ if (c2) { ++ tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f); ++ } else { ++ tcg_out_opc_rotr_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_rotr_i64: ++ if (c2) { ++ tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f); ++ } else { ++ tcg_out_opc_rotr_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_add_i32: ++ if (c2) { ++ tcg_out_opc_addi_w(s, a0, a1, a2); ++ } else { ++ tcg_out_opc_add_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_add_i64: ++ if (c2) { ++ tcg_out_opc_addi_d(s, a0, a1, a2); ++ } else { ++ tcg_out_opc_add_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sub_i32: ++ if (c2) { ++ tcg_out_opc_addi_w(s, a0, a1, -a2); ++ } else { ++ tcg_out_opc_sub_w(s, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_sub_i64: ++ if (c2) { ++ tcg_out_opc_addi_d(s, a0, a1, -a2); ++ } else { ++ tcg_out_opc_sub_d(s, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_mul_i32: ++ tcg_out_opc_mul_w(s, a0, a1, a2); ++ break; ++ case INDEX_op_mul_i64: ++ tcg_out_opc_mul_d(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_mulsh_i32: ++ tcg_out_opc_mulh_w(s, a0, a1, a2); ++ break; ++ case INDEX_op_mulsh_i64: ++ tcg_out_opc_mulh_d(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_muluh_i32: ++ tcg_out_opc_mulh_wu(s, a0, a1, a2); ++ break; ++ case INDEX_op_muluh_i64: ++ tcg_out_opc_mulh_du(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_div_i32: ++ tcg_out_opc_div_w(s, a0, a1, a2); ++ break; ++ case INDEX_op_div_i64: ++ tcg_out_opc_div_d(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_divu_i32: ++ tcg_out_opc_div_wu(s, a0, a1, a2); ++ break; ++ case INDEX_op_divu_i64: ++ tcg_out_opc_div_du(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_rem_i32: ++ tcg_out_opc_mod_w(s, a0, a1, a2); ++ break; ++ case INDEX_op_rem_i64: ++ tcg_out_opc_mod_d(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_remu_i32: ++ tcg_out_opc_mod_wu(s, a0, a1, a2); ++ break; ++ case INDEX_op_remu_i64: ++ tcg_out_opc_mod_du(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_setcond_i32: ++ case INDEX_op_setcond_i64: ++ tcg_out_setcond(s, args[3], a0, a1, a2, c2); ++ break; ++ ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld8s_i64: ++ tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); ++ break; ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8u_i64: ++ tcg_out_ldst(s, OPC_LD_BU, a0, a1, a2); ++ break; ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld16s_i64: ++ tcg_out_ldst(s, OPC_LD_H, a0, a1, a2); ++ break; ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16u_i64: ++ tcg_out_ldst(s, OPC_LD_HU, a0, a1, a2); ++ break; ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld32s_i64: ++ tcg_out_ldst(s, OPC_LD_W, a0, a1, a2); ++ break; ++ case INDEX_op_ld32u_i64: ++ tcg_out_ldst(s, OPC_LD_WU, a0, a1, a2); ++ break; ++ case INDEX_op_ld_i64: ++ tcg_out_ldst(s, OPC_LD_D, a0, a1, a2); ++ break; ++ ++ case INDEX_op_st8_i32: ++ case INDEX_op_st8_i64: ++ tcg_out_ldst(s, OPC_ST_B, a0, a1, a2); ++ break; ++ case INDEX_op_st16_i32: ++ case INDEX_op_st16_i64: ++ tcg_out_ldst(s, OPC_ST_H, a0, a1, a2); ++ break; ++ case INDEX_op_st_i32: ++ case INDEX_op_st32_i64: ++ tcg_out_ldst(s, OPC_ST_W, a0, a1, a2); ++ break; ++ case INDEX_op_st_i64: ++ tcg_out_ldst(s, OPC_ST_D, a0, a1, a2); ++ break; ++ ++ case INDEX_op_qemu_ld_i32: ++ tcg_out_qemu_ld(s, args, TCG_TYPE_I32); ++ break; ++ case INDEX_op_qemu_ld_i64: ++ tcg_out_qemu_ld(s, args, TCG_TYPE_I64); ++ break; ++ case INDEX_op_qemu_st_i32: ++ tcg_out_qemu_st(s, args); ++ break; ++ case INDEX_op_qemu_st_i64: ++ tcg_out_qemu_st(s, args); ++ break; ++ ++ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ ++ case INDEX_op_mov_i64: ++ case INDEX_op_call: /* Always emitted via tcg_out_call. */ ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) ++{ ++ switch (op) { ++ case INDEX_op_goto_ptr: ++ return C_O0_I1(r); ++ ++ case INDEX_op_st8_i32: ++ case INDEX_op_st8_i64: ++ case INDEX_op_st16_i32: ++ case INDEX_op_st16_i64: ++ case INDEX_op_st32_i64: ++ case INDEX_op_st_i32: ++ case INDEX_op_st_i64: ++ return C_O0_I2(rZ, r); ++ ++ case INDEX_op_brcond_i32: ++ case INDEX_op_brcond_i64: ++ return C_O0_I2(rZ, rZ); ++ ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ return C_O0_I2(LZ, L); ++ ++ case INDEX_op_ext8s_i32: ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext8u_i32: ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext16s_i32: ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext16u_i32: ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext32s_i64: ++ case INDEX_op_ext32u_i64: ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_extrl_i64_i32: ++ case INDEX_op_extrh_i64_i32: ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_not_i32: ++ case INDEX_op_not_i64: ++ case INDEX_op_extract_i32: ++ case INDEX_op_extract_i64: ++ case INDEX_op_bswap16_i32: ++ case INDEX_op_bswap16_i64: ++ case INDEX_op_bswap32_i32: ++ case INDEX_op_bswap32_i64: ++ case INDEX_op_bswap64_i64: ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld8s_i64: ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8u_i64: ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld16s_i64: ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16u_i64: ++ case INDEX_op_ld32s_i64: ++ case INDEX_op_ld32u_i64: ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld_i64: ++ return C_O1_I1(r, r); ++ ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ return C_O1_I1(r, L); ++ ++ case INDEX_op_andc_i32: ++ case INDEX_op_andc_i64: ++ case INDEX_op_orc_i32: ++ case INDEX_op_orc_i64: ++ /* ++ * LoongArch insns for these ops don't have reg-imm forms, but we ++ * can express using andi/ori if ~constant satisfies ++ * TCG_CT_CONST_U12. ++ */ ++ return C_O1_I2(r, r, rC); ++ ++ case INDEX_op_shl_i32: ++ case INDEX_op_shl_i64: ++ case INDEX_op_shr_i32: ++ case INDEX_op_shr_i64: ++ case INDEX_op_sar_i32: ++ case INDEX_op_sar_i64: ++ case INDEX_op_rotl_i32: ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotr_i32: ++ case INDEX_op_rotr_i64: ++ return C_O1_I2(r, r, ri); ++ ++ case INDEX_op_add_i32: ++ case INDEX_op_add_i64: ++ return C_O1_I2(r, r, rI); ++ ++ case INDEX_op_and_i32: ++ case INDEX_op_and_i64: ++ case INDEX_op_nor_i32: ++ case INDEX_op_nor_i64: ++ case INDEX_op_or_i32: ++ case INDEX_op_or_i64: ++ case INDEX_op_xor_i32: ++ case INDEX_op_xor_i64: ++ /* LoongArch reg-imm bitops have their imms ZERO-extended */ ++ return C_O1_I2(r, r, rU); ++ ++ case INDEX_op_clz_i32: ++ case INDEX_op_clz_i64: ++ case INDEX_op_ctz_i32: ++ case INDEX_op_ctz_i64: ++ return C_O1_I2(r, r, rW); ++ ++ case INDEX_op_setcond_i32: ++ case INDEX_op_setcond_i64: ++ return C_O1_I2(r, r, rZ); ++ ++ case INDEX_op_deposit_i32: ++ case INDEX_op_deposit_i64: ++ /* Must deposit into the same register as input */ ++ return C_O1_I2(r, 0, rZ); ++ ++ case INDEX_op_sub_i32: ++ case INDEX_op_sub_i64: ++ return C_O1_I2(r, rZ, rN); ++ ++ case INDEX_op_mul_i32: ++ case INDEX_op_mul_i64: ++ case INDEX_op_mulsh_i32: ++ case INDEX_op_mulsh_i64: ++ case INDEX_op_muluh_i32: ++ case INDEX_op_muluh_i64: ++ case INDEX_op_div_i32: ++ case INDEX_op_div_i64: ++ case INDEX_op_divu_i32: ++ case INDEX_op_divu_i64: ++ case INDEX_op_rem_i32: ++ case INDEX_op_rem_i64: ++ case INDEX_op_remu_i32: ++ case INDEX_op_remu_i64: ++ return C_O1_I2(r, rZ, rZ); ++ ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static const int tcg_target_callee_save_regs[] = { ++ TCG_REG_S0, /* used for the global env (TCG_AREG0) */ ++ TCG_REG_S1, ++ TCG_REG_S2, ++ TCG_REG_S3, ++ TCG_REG_S4, ++ TCG_REG_S5, ++ TCG_REG_S6, ++ TCG_REG_S7, ++ TCG_REG_S8, ++ TCG_REG_S9, ++ TCG_REG_RA, /* should be last for ABI compliance */ ++}; ++ ++/* Stack frame parameters. */ ++#define REG_SIZE (TCG_TARGET_REG_BITS / 8) ++#define SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * REG_SIZE) ++#define TEMP_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long)) ++#define FRAME_SIZE \ ++ ((TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE + SAVE_SIZE + \ ++ TCG_TARGET_STACK_ALIGN - 1) & \ ++ -TCG_TARGET_STACK_ALIGN) ++#define SAVE_OFS (TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE) ++ ++/* We're expecting to be able to use an immediate for frame allocation. */ ++QEMU_BUILD_BUG_ON(FRAME_SIZE > 0x7ff); ++ ++/* Generate global QEMU prologue and epilogue code */ ++static void tcg_target_qemu_prologue(TCGContext *s) ++{ ++ int i; ++ ++ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, TEMP_SIZE); ++ ++ /* TB prologue */ ++ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, -FRAME_SIZE); ++ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { ++ tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], TCG_REG_SP, ++ SAVE_OFS + i * REG_SIZE); ++ } ++ ++#if !defined(CONFIG_SOFTMMU) ++ if (USE_GUEST_BASE) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); ++ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); ++ } ++#endif ++ ++ /* Call generated code */ ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); ++ tcg_out_opc_jirl(s, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); ++ ++ /* Return path for goto_ptr. Set return value to 0 */ ++ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); ++ tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_A0, TCG_REG_ZERO); ++ ++ /* TB epilogue */ ++ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); ++ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { ++ tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], TCG_REG_SP, ++ SAVE_OFS + i * REG_SIZE); ++ } ++ ++ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE); ++ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_RA, 0); ++} ++ ++static void tcg_target_init(TCGContext *s) ++{ ++ tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; ++ tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS; ++ ++ tcg_target_call_clobber_regs = ALL_GENERAL_REGS; ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S3); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S4); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S5); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S6); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S7); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S8); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S9); ++ ++ s->reserved_regs = 0; ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP0); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RESERVED); ++} ++ ++typedef struct { ++ DebugFrameHeader h; ++ uint8_t fde_def_cfa[4]; ++ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; ++} DebugFrame; ++ ++#define ELF_HOST_MACHINE EM_LOONGARCH ++ ++static const DebugFrame ++ debug_frame = { .h.cie.len = sizeof(DebugFrameCIE) - ++ 4, /* length after .len member */ ++ .h.cie.id = -1, ++ .h.cie.version = 1, ++ .h.cie.code_align = 1, ++ .h.cie.data_align = ++ -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ ++ .h.cie.return_column = TCG_REG_RA, ++ ++ /* Total FDE size does not include the "len" member. */ ++ .h.fde.len = sizeof(DebugFrame) - ++ offsetof(DebugFrame, h.fde.cie_offset), ++ ++ .fde_def_cfa = { 12, ++ TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ ++ (FRAME_SIZE & 0x7f) | ++ 0x80, /* ... uleb128 FRAME_SIZE */ ++ (FRAME_SIZE >> 7) }, ++ .fde_reg_ofs = { ++ 0x80 + 23, 11, /* DW_CFA_offset, s0, -88 */ ++ 0x80 + 24, 10, /* DW_CFA_offset, s1, -80 */ ++ 0x80 + 25, 9, /* DW_CFA_offset, s2, -72 */ ++ 0x80 + 26, 8, /* DW_CFA_offset, s3, -64 */ ++ 0x80 + 27, 7, /* DW_CFA_offset, s4, -56 */ ++ 0x80 + 28, 6, /* DW_CFA_offset, s5, -48 */ ++ 0x80 + 29, 5, /* DW_CFA_offset, s6, -40 */ ++ 0x80 + 30, 4, /* DW_CFA_offset, s7, -32 */ ++ 0x80 + 31, 3, /* DW_CFA_offset, s8, -24 */ ++ 0x80 + 22, 2, /* DW_CFA_offset, s9, -16 */ ++ 0x80 + 1, 1, /* DW_CFA_offset, ra, -8 */ ++ } }; ++ ++void tcg_register_jit(const void *buf, size_t buf_size) ++{ ++ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); ++} +diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h +new file mode 100644 +index 0000000000..20f77b707d +--- /dev/null ++++ b/tcg/loongarch64/tcg-target.h +@@ -0,0 +1,168 @@ ++/* ++ * Tiny Code Generator for QEMU ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#ifndef LOONGARCH_TCG_TARGET_H ++#define LOONGARCH_TCG_TARGET_H ++ ++/* ++ * Loongson removed the (incomplete) 32-bit support from kernel and toolchain ++ * for the initial upstreaming of this architecture, so don't bother and just ++ * support the LP64* ABI for now. ++ */ ++ ++#if defined(__loongarch64) ++#define TCG_TARGET_REG_BITS 64 ++#else ++#error unsupported LoongArch register size ++#endif ++ ++#define TCG_TARGET_INSN_UNIT_SIZE 4 ++#define TCG_TARGET_NB_REGS 32 ++#define MAX_CODE_GEN_BUFFER_SIZE SIZE_MAX ++ ++typedef enum { ++ TCG_REG_ZERO, ++ TCG_REG_RA, ++ TCG_REG_TP, ++ TCG_REG_SP, ++ TCG_REG_A0, ++ TCG_REG_A1, ++ TCG_REG_A2, ++ TCG_REG_A3, ++ TCG_REG_A4, ++ TCG_REG_A5, ++ TCG_REG_A6, ++ TCG_REG_A7, ++ TCG_REG_T0, ++ TCG_REG_T1, ++ TCG_REG_T2, ++ TCG_REG_T3, ++ TCG_REG_T4, ++ TCG_REG_T5, ++ TCG_REG_T6, ++ TCG_REG_T7, ++ TCG_REG_T8, ++ TCG_REG_RESERVED, ++ TCG_REG_S9, ++ TCG_REG_S0, ++ TCG_REG_S1, ++ TCG_REG_S2, ++ TCG_REG_S3, ++ TCG_REG_S4, ++ TCG_REG_S5, ++ TCG_REG_S6, ++ TCG_REG_S7, ++ TCG_REG_S8, ++ ++ /* aliases */ ++ TCG_AREG0 = TCG_REG_S0, ++ TCG_REG_TMP0 = TCG_REG_T8, ++ TCG_REG_TMP1 = TCG_REG_T7, ++ TCG_REG_TMP2 = TCG_REG_T6, ++} TCGReg; ++ ++/* used for function call generation */ ++#define TCG_REG_CALL_STACK TCG_REG_SP ++#define TCG_TARGET_STACK_ALIGN 16 ++#define TCG_TARGET_CALL_ALIGN_ARGS 1 ++#define TCG_TARGET_CALL_STACK_OFFSET 0 ++ ++/* optional instructions */ ++#define TCG_TARGET_HAS_movcond_i32 0 ++#define TCG_TARGET_HAS_div_i32 1 ++#define TCG_TARGET_HAS_rem_i32 1 ++#define TCG_TARGET_HAS_div2_i32 0 ++#define TCG_TARGET_HAS_rot_i32 1 ++#define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_extract_i32 1 ++#define TCG_TARGET_HAS_sextract_i32 0 ++#define TCG_TARGET_HAS_extract2_i32 0 ++#define TCG_TARGET_HAS_add2_i32 0 ++#define TCG_TARGET_HAS_sub2_i32 0 ++#define TCG_TARGET_HAS_mulu2_i32 0 ++#define TCG_TARGET_HAS_muls2_i32 0 ++#define TCG_TARGET_HAS_muluh_i32 1 ++#define TCG_TARGET_HAS_mulsh_i32 1 ++#define TCG_TARGET_HAS_ext8s_i32 1 ++#define TCG_TARGET_HAS_ext16s_i32 1 ++#define TCG_TARGET_HAS_ext8u_i32 1 ++#define TCG_TARGET_HAS_ext16u_i32 1 ++#define TCG_TARGET_HAS_bswap16_i32 1 ++#define TCG_TARGET_HAS_bswap32_i32 1 ++#define TCG_TARGET_HAS_not_i32 1 ++#define TCG_TARGET_HAS_neg_i32 0 ++#define TCG_TARGET_HAS_andc_i32 1 ++#define TCG_TARGET_HAS_orc_i32 1 ++#define TCG_TARGET_HAS_eqv_i32 0 ++#define TCG_TARGET_HAS_nand_i32 0 ++#define TCG_TARGET_HAS_nor_i32 1 ++#define TCG_TARGET_HAS_clz_i32 1 ++#define TCG_TARGET_HAS_ctz_i32 1 ++#define TCG_TARGET_HAS_ctpop_i32 0 ++#define TCG_TARGET_HAS_direct_jump 0 ++#define TCG_TARGET_HAS_brcond2 0 ++#define TCG_TARGET_HAS_setcond2 0 ++#define TCG_TARGET_HAS_qemu_st8_i32 0 ++ ++/* 64-bit operations */ ++#define TCG_TARGET_HAS_movcond_i64 0 ++#define TCG_TARGET_HAS_div_i64 1 ++#define TCG_TARGET_HAS_rem_i64 1 ++#define TCG_TARGET_HAS_div2_i64 0 ++#define TCG_TARGET_HAS_rot_i64 1 ++#define TCG_TARGET_HAS_deposit_i64 1 ++#define TCG_TARGET_HAS_extract_i64 1 ++#define TCG_TARGET_HAS_sextract_i64 0 ++#define TCG_TARGET_HAS_extract2_i64 0 ++#define TCG_TARGET_HAS_extrl_i64_i32 1 ++#define TCG_TARGET_HAS_extrh_i64_i32 1 ++#define TCG_TARGET_HAS_ext8s_i64 1 ++#define TCG_TARGET_HAS_ext16s_i64 1 ++#define TCG_TARGET_HAS_ext32s_i64 1 ++#define TCG_TARGET_HAS_ext8u_i64 1 ++#define TCG_TARGET_HAS_ext16u_i64 1 ++#define TCG_TARGET_HAS_ext32u_i64 1 ++#define TCG_TARGET_HAS_bswap16_i64 1 ++#define TCG_TARGET_HAS_bswap32_i64 1 ++#define TCG_TARGET_HAS_bswap64_i64 1 ++#define TCG_TARGET_HAS_not_i64 1 ++#define TCG_TARGET_HAS_neg_i64 0 ++#define TCG_TARGET_HAS_andc_i64 1 ++#define TCG_TARGET_HAS_orc_i64 1 ++#define TCG_TARGET_HAS_eqv_i64 0 ++#define TCG_TARGET_HAS_nand_i64 0 ++#define TCG_TARGET_HAS_nor_i64 1 ++#define TCG_TARGET_HAS_clz_i64 1 ++#define TCG_TARGET_HAS_ctz_i64 1 ++#define TCG_TARGET_HAS_ctpop_i64 0 ++#define TCG_TARGET_HAS_add2_i64 0 ++#define TCG_TARGET_HAS_sub2_i64 0 ++#define TCG_TARGET_HAS_mulu2_i64 0 ++#define TCG_TARGET_HAS_muls2_i64 0 ++#define TCG_TARGET_HAS_muluh_i64 1 ++#define TCG_TARGET_HAS_mulsh_i64 1 ++ ++/* not defined -- call should be eliminated at compile time */ ++void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); ++ ++#define TCG_TARGET_DEFAULT_MO (0) ++#define TCG_TARGET_HAS_MEMORY_BSWAP 0 ++#define TCG_TARGET_NEED_LDST_LABELS ++ ++#endif /* LOONGARCH_TCG_TARGET_H */ +-- +2.27.0 + diff --git a/Allow-setting-up-to-8-bytes-with-the-generic-loader.patch b/Allow-setting-up-to-8-bytes-with-the-generic-loader.patch new file mode 100644 index 0000000000000000000000000000000000000000..a33522abcba10a94f2fc6dd70a5023e4ab8cb56f --- /dev/null +++ b/Allow-setting-up-to-8-bytes-with-the-generic-loader.patch @@ -0,0 +1,48 @@ +From baf464ea0c35f9b235e8385b0771392ce362a6ec Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 21 Jul 2023 06:14:37 +0000 +Subject: [PATCH] Allow setting up to 8 bytes with the generic loader mainline + inclusion commit f42483d776bce29a9925ed61cc10eb27a5b2446c category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +The documentation for the generic loader says that "the maximum size of +the data is 8 bytes". However, attempts to set data-len=8 trigger the +following assertion failure: + +../hw/core/generic-loader.c:59: generic_loader_reset: Assertion `s->data_len < sizeof(s->data)' failed. + +The type of s->data is uint64_t (i.e. 8 bytes long), so I believe this +assert should use <= instead of <. + +Fixes: e481a1f63c93 ("generic-loader: Add a generic loader") +Signed-off-by: Petr Tesarik +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Message-id: 20220120092715.7805-1-ptesarik@suse.com +Signed-off-by: Alistair Francis + +Signed-off-by: tangbinzy +--- + hw/core/generic-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c +index 9a24ffb880..504ed7ca72 100644 +--- a/hw/core/generic-loader.c ++++ b/hw/core/generic-loader.c +@@ -56,7 +56,7 @@ static void generic_loader_reset(void *opaque) + } + + if (s->data_len) { +- assert(s->data_len < sizeof(s->data)); ++ assert(s->data_len <= sizeof(s->data)); + dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len, + MEMTXATTRS_UNSPECIFIED); + } +-- +2.41.0.windows.1 + diff --git a/BinDir.tar.gz b/BinDir.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ed70f867ea227e3db214cdc9ed06d36cdcf2553 Binary files /dev/null and b/BinDir.tar.gz differ diff --git a/Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch b/Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch deleted file mode 100644 index 8d492058d77ba70d51c88bffcbef7a1ae7b28adb..0000000000000000000000000000000000000000 --- a/Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 38734e26ce3840d459da13607a9d46de24a15388 Mon Sep 17 00:00:00 2001 -From: kevinZhu -Date: Thu, 29 Oct 2020 19:24:48 +0800 -Subject: [PATCH] Bugfix: hw/acpi: Use max_cpus instead of cpus when build PPTT - table - -The field "cpus" is the initial number of CPU for guest, and the field "max_cpus" -is the max number of CPU after CPU hotplug. When building PPTT for guest, we -should take all CPUs into account, otherwise the "smp_sockets" is wrong. - -Fixes: 7cfcd8c8a2fe ("build smt processor structure to support smt topology") -Signed-off-by: Keqian Zhu ---- - hw/acpi/aml-build.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 8a3b51c835..f01669df57 100644 ---- a/hw/acpi/aml-build.c -+++ b/hw/acpi/aml-build.c -@@ -167,7 +167,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) - struct offset_status offset; - const MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cores = ms->smp.cores; -- unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads); -+ unsigned int smp_sockets = ms->smp.max_cpus / (smp_cores * ms->smp.threads); - - acpi_data_push(table_data, sizeof(AcpiTableHeader)); - --- -2.27.0 - diff --git a/COLO-compare-Fix-incorrect-if-logic.patch b/COLO-compare-Fix-incorrect-if-logic.patch deleted file mode 100644 index 8deb1b31bb0f1f801ec552f6695503809f148acb..0000000000000000000000000000000000000000 --- a/COLO-compare-Fix-incorrect-if-logic.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 124032e79e354f5e7cc28958f2ca6b9f898da719 Mon Sep 17 00:00:00 2001 -From: Fan Yang -Date: Tue, 24 Sep 2019 22:08:29 +0800 -Subject: [PATCH] COLO-compare: Fix incorrect `if` logic -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -'colo_mark_tcp_pkt' should return 'true' when packets are the same, and -'false' otherwise. However, it returns 'true' when -'colo_compare_packet_payload' returns non-zero while -'colo_compare_packet_payload' is just a 'memcmp'. The result is that -COLO-compare reports inconsistent TCP packets when they are actually -the same. - -Fixes: f449c9e549c ("colo: compare the packet based on the tcp sequence number") -Cc: qemu-stable@nongnu.org -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Fan Yang -Signed-off-by: Jason Wang -(cherry picked from commit 1e907a32b77e5d418538453df5945242e43224fa) -Signed-off-by: Michael Roth ---- - net/colo-compare.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/net/colo-compare.c b/net/colo-compare.c -index bf10526..9827c0e 100644 ---- a/net/colo-compare.c -+++ b/net/colo-compare.c -@@ -287,7 +287,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt, - *mark = 0; - - if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) { -- if (colo_compare_packet_payload(ppkt, spkt, -+ if (!colo_compare_packet_payload(ppkt, spkt, - ppkt->header_size, spkt->header_size, - ppkt->payload_size)) { - *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY; -@@ -297,7 +297,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt, - - /* one part of secondary packet payload still need to be compared */ - if (!after(ppkt->seq_end, spkt->seq_end)) { -- if (colo_compare_packet_payload(ppkt, spkt, -+ if (!colo_compare_packet_payload(ppkt, spkt, - ppkt->header_size + ppkt->offset, - spkt->header_size + spkt->offset, - ppkt->payload_size - ppkt->offset)) { -@@ -316,7 +316,7 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt, - /* primary packet is longer than secondary packet, compare - * the same part and mark the primary packet offset - */ -- if (colo_compare_packet_payload(ppkt, spkt, -+ if (!colo_compare_packet_payload(ppkt, spkt, - ppkt->header_size + ppkt->offset, - spkt->header_size + spkt->offset, - spkt->payload_size - spkt->offset)) { --- -1.8.3.1 - diff --git a/Check-and-report-for-incomplete-global-option-format.patch b/Check-and-report-for-incomplete-global-option-format.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ca33d727e550e0f71feab9f47c7c5abc9b66cb1 --- /dev/null +++ b/Check-and-report-for-incomplete-global-option-format.patch @@ -0,0 +1,49 @@ +From c24b649580f7eeb656124fabe255760829d01408 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 26 Jul 2023 13:37:41 +0000 +Subject: [PATCH] Check and report for incomplete 'global' option format + mainline inclusion commit 818e1636080768749dc826acd4825e71828ec7e6 category: + bugfix + +--------------------------------------------------------------- + +Qemu might crash when provided incomplete '-global' option. +For example: + qemu-system-x86_64 -global driver=isa-fdc + qemu-system-x86_64: ../../devel/qemu/qapi/string-input-visitor.c:394: + string_input_visitor_new: Assertion `str' failed. + Aborted (core dumped) + +Fixes: 3751d7c43f795b ("vl: allow full-blown QemuOpts syntax for -global") +Signed-off-by: Rohit Kumar +Reviewed-by: Markus Armbruster +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/604 +Message-Id: <20220216071508.412974-1-rohit.kumar3@nutanix.com> +Signed-off-by: Thomas Huth + +Signed-off-by: tangbinzy +--- + softmmu/qdev-monitor.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 4ca4e92ce2..14efb37014 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -1041,6 +1041,13 @@ int qemu_global_option(const char *str) + if (!opts) { + return -1; + } ++ if (!qemu_opt_get(opts, "driver") ++ || !qemu_opt_get(opts, "property") ++ || !qemu_opt_get(opts, "value")) { ++ error_report("options 'driver', 'property', and 'value'" ++ " are required"); ++ return -1; ++ } + + return 0; + } +-- +2.41.0.windows.1 + diff --git a/Currently-while-kvm-and-qemu-can-not-handle-some-kvm.patch b/Currently-while-kvm-and-qemu-can-not-handle-some-kvm.patch new file mode 100644 index 0000000000000000000000000000000000000000..b0071b50932b38fd7736dad548a083f356980f7f --- /dev/null +++ b/Currently-while-kvm-and-qemu-can-not-handle-some-kvm.patch @@ -0,0 +1,27 @@ +From 9e2158495059b485f2c28bb649c8b4a87fb3105c Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 11:24:32 +0800 +Subject: [PATCH 12/15] Currently, while kvm and qemu can not handle some kvm + exit, qemu will do vm_stop, which will make vm in pause state. This action + make vm unrecoverable, so send guest panic to libvirt instead. + +--- + accel/kvm/kvm-all.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index eecd8031cf..b128d311c2 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2970,7 +2970,7 @@ int kvm_cpu_exec(CPUState *cpu) + + if (ret < 0) { + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); +- vm_stop(RUN_STATE_INTERNAL_ERROR); ++ qemu_system_guest_panicked(cpu_get_crash_info(cpu)); + } + + qatomic_set(&cpu->exit_request, 0); +-- +2.27.0 + diff --git a/Drop-bogus-IPv6-messages.patch b/Drop-bogus-IPv6-messages.patch deleted file mode 100644 index 2fc1e0e780e34b1570fbcfcc4581138c79e7fa46..0000000000000000000000000000000000000000 --- a/Drop-bogus-IPv6-messages.patch +++ /dev/null @@ -1,30 +0,0 @@ -From e8b555c08061ad78920611a5e98ee14fcd967692 Mon Sep 17 00:00:00 2001 -From: Ralf Haferkamp -Date: Fri, 11 Sep 2020 10:55:49 +0800 -Subject: [PATCH] Drop bogus IPv6 messages - -Drop IPv6 message shorter than what's mentioned in the playload -length header (+the size of IPv6 header). They're invalid and could -lead to data leakage in icmp6_send_echoreply(). - -diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c -index d9d2b7e..c2dce52 100644 ---- a/slirp/src/ip6_input.c -+++ b/slirp/src/ip6_input.c -@@ -49,6 +49,13 @@ void ip6_input(struct mbuf *m) - goto bad; - } - -+ // Check if the message size is big enough to hold what's -+ // set in the payload length header. If not this is an invalid -+ // packet -+ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { -+ goto bad; -+ } -+ - /* check ip_ttl for a correct ICMP reply */ - if (ip6->ip_hl == 0) { - icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); --- -1.8.3.1 - diff --git a/Fix-STM32F2XX-USART-data-register-readout.patch b/Fix-STM32F2XX-USART-data-register-readout.patch new file mode 100644 index 0000000000000000000000000000000000000000..3244c318eea71f252674abbb455bf16e563412b0 --- /dev/null +++ b/Fix-STM32F2XX-USART-data-register-readout.patch @@ -0,0 +1,43 @@ +From 8733b8a26407177b867d3293283c257efeb784a0 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Fri, 1 Dec 2023 12:51:56 +0800 +Subject: [PATCH] Fix STM32F2XX USART data register readout +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit ab08c3467605365b44fab1b66bb6254db86814f6 + +Fix issue where the data register may be overwritten by next character +reception before being read and returned. + +Signed-off-by: Olivier Hériveaux +Reviewed-by: Peter Maydell +Reviewed-by: Alistair Francis +Message-id: 20211128120723.4053-1-olivier.heriveaux@ledger.fr +Signed-off-by: Peter Maydell +Signed-off-by: Luo Yifan +--- + hw/char/stm32f2xx_usart.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c +index 8df0832424..fde67f4f03 100644 +--- a/hw/char/stm32f2xx_usart.c ++++ b/hw/char/stm32f2xx_usart.c +@@ -103,10 +103,11 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr, + return retvalue; + case USART_DR: + DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr); ++ retvalue = s->usart_dr & 0x3FF; + s->usart_sr &= ~USART_SR_RXNE; + qemu_chr_fe_accept_input(&s->chr); + qemu_set_irq(s->irq, 0); +- return s->usart_dr & 0x3FF; ++ return retvalue; + case USART_BRR: + return s->usart_brr; + case USART_CR1: +-- +2.27.0 + diff --git a/Fix-several-typos-in-documentation-found-by-codespel.patch b/Fix-several-typos-in-documentation-found-by-codespel.patch new file mode 100644 index 0000000000000000000000000000000000000000..4140f2d601e7264925cbbec248e839fae9de1284 --- /dev/null +++ b/Fix-several-typos-in-documentation-found-by-codespel.patch @@ -0,0 +1,140 @@ +From 961450f0cf1e2e3a092dd723d7c63a310a881e93 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Wed, 23 Nov 2022 14:37:06 +0800 +Subject: [PATCH 10/29] Fix several typos in documentation (found by codespell) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Those typos are in files which are used to generate the QEMU manual. + +Signed-off-by: Stefan Weil +Message-Id: <20221110190825.879620-1-sw@weilnetz.de> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Ani Sinha +Reviewed-by: Peter Maydell +Acked-by: Michael S. Tsirkin +[thuth: update sentence in can.rst as suggested by Peter] +Signed-off-by: Thomas Huth +Signed-off-by: wangjinlei +--- + hw/scsi/esp.c | 6 +++--- + include/exec/memory.h | 6 +++--- + qemu-options.hx | 4 ++-- + tests/qtest/libqos/qgraph.h | 2 +- + tests/qtest/libqos/virtio-9p.c | 2 +- + 5 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index 58d0edbd56..f38231f8cd 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -510,7 +510,7 @@ static void do_dma_pdma_cb(ESPState *s) + } else { + /* + * Extra message out bytes received: update cmdfifo_cdb_offset +- * and then switch to commmand phase ++ * and then switch to command phase + */ + s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; +@@ -622,7 +622,7 @@ static void esp_do_dma(ESPState *s) + } else { + /* + * Extra message out bytes received: update cmdfifo_cdb_offset +- * and then switch to commmand phase ++ * and then switch to command phase + */ + s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; +@@ -733,7 +733,7 @@ static void esp_do_nodma(ESPState *s) + } else { + /* + * Extra message out bytes received: update cmdfifo_cdb_offset +- * and then switch to commmand phase ++ * and then switch to command phase + */ + s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 4b5b431e45..abb838f194 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -561,7 +561,7 @@ typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); + * A #RamDiscardManager coordinates which parts of specific RAM #MemoryRegion + * regions are currently populated to be used/accessed by the VM, notifying + * after parts were discarded (freeing up memory) and before parts will be +- * populated (consuming memory), to be used/acessed by the VM. ++ * populated (consuming memory), to be used/accessed by the VM. + * + * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the + * #MemoryRegion isn't mapped yet; it cannot change while the #MemoryRegion is +@@ -585,7 +585,7 @@ typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); + * Listeners are called in multiples of the minimum granularity (unless it + * would exceed the registered range) and changes are aligned to the minimum + * granularity within the #MemoryRegion. Listeners have to prepare for memory +- * becomming discarded in a different granularity than it was populated and the ++ * becoming discarded in a different granularity than it was populated and the + * other way around. + */ + struct RamDiscardManagerClass { +@@ -1242,7 +1242,7 @@ void memory_region_init_ram_flags_nomigrate(MemoryRegion *mr, + Error **errp); + + /** +- * memory_region_init_resizeable_ram: Initialize memory region with resizeable ++ * memory_region_init_resizeable_ram: Initialize memory region with resizable + * RAM. Accesses into the region will + * modify memory directly. Only an initial + * portion of this RAM is actually used. +diff --git a/qemu-options.hx b/qemu-options.hx +index 1aaf38c613..047d28a357 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -318,7 +318,7 @@ SRST + \ + ``-numa cpu,node-id=node[,socket-id=x][,core-id=y][,thread-id=z]`` + \ +-``-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=tpye[,latency=lat][,bandwidth=bw]`` ++``-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=type[,latency=lat][,bandwidth=bw]`` + \ + ``-numa hmat-cache,node-id=node,size=size,level=level[,associativity=str][,policy=str][,line=size]`` + Define a NUMA node and assign RAM and VCPUs to it. Set the NUMA +@@ -1717,7 +1717,7 @@ SRST + directory on host is made directly accessible by guest as a pass-through + file system by using the 9P network protocol for communication between + host and guests, if desired even accessible, shared by several guests +- simultaniously. ++ simultaneously. + + Note that ``-virtfs`` is actually just a convenience shortcut for its + generalized form ``-fsdev -device virtio-9p-pci``. +diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h +index 871740c0dc..33d609a06a 100644 +--- a/tests/qtest/libqos/qgraph.h ++++ b/tests/qtest/libqos/qgraph.h +@@ -381,7 +381,7 @@ QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent, + * mind: only tests with a path down from the actual test case node (leaf) up + * to the graph's root node are actually executed by the qtest framework. And + * the qtest framework uses QMP to automatically check which QEMU drivers are +- * actually currently available, and accordingly qos marks certain pathes as ++ * actually currently available, and accordingly qos marks certain paths as + * 'unavailable' in such cases (e.g. when QEMU was compiled without support for + * a certain feature). + */ +diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c +index b4e1143288..2941d3cdc6 100644 +--- a/tests/qtest/libqos/virtio-9p.c ++++ b/tests/qtest/libqos/virtio-9p.c +@@ -31,7 +31,7 @@ + static QGuestAllocator *alloc; + static char *local_test_path; + +-/* Concatenates the passed 2 pathes. Returned result must be freed. */ ++/* Concatenates the passed 2 paths. Returned result must be freed. */ + static char *concat_path(const char* a, const char* b) + { + return g_build_filename(a, b, NULL); +-- +2.27.0 + diff --git a/Fix-several-typos-in-documentation.patch b/Fix-several-typos-in-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fb38afd8a5ca19a0d0efae71c6d8c48bdc42b7b --- /dev/null +++ b/Fix-several-typos-in-documentation.patch @@ -0,0 +1,40 @@ +From 4dd2cdf016e40c88b57480d9c296d6c7c2cb6600 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 1 Dec 2022 20:24:53 +0800 +Subject: [PATCH 06/17] Fix several typos in documentation + +Signed-off-by: tangzhongrui tangzhongrui@cmss.chinamobile.com +--- + docs/can.txt | 2 +- + hw/virtio/virtio-mem.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/docs/can.txt b/docs/can.txt +index 0d310237df..873c95a35d 100644 +--- a/docs/can.txt ++++ b/docs/can.txt +@@ -166,7 +166,7 @@ and with bitrate switch + + cangen can0 -b + +-The test can be run viceversa, generate messages in the guest system and capture them ++The test can be run vice-versa, generate messages in the guest system and capture them + in the host one and much more combinations. + + Links to other resources +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 341c3fa2c1..becac0d93b 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -877,7 +877,7 @@ static int virtio_mem_mig_sanity_checks_post_load(void *opaque, int version_id) + return -EINVAL; + } + /* +- * Note: Preparation for resizeable memory regions. The maximum size ++ * Note: Preparation for resizable memory regions. The maximum size + * of the memory region must not change during migration. + */ + if (tmp->region_size != new_region_size) { +-- +2.27.0 + diff --git a/Fix-smp.cores-value-and-Fix-divide-0-error.patch b/Fix-smp.cores-value-and-Fix-divide-0-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d8dd6efa79ea22f78e78e27f0fb957c54e0909f --- /dev/null +++ b/Fix-smp.cores-value-and-Fix-divide-0-error.patch @@ -0,0 +1,43 @@ +From 08d0374d80ef321a421d4d9716c05006b469c78f Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Wed, 24 May 2023 23:06:51 -0400 +Subject: [PATCH] Fix smp.cores value and Fix divide 0 error + +The smp.cores should use the default value passed from +qemu start command, and the argument is cores_per_socket. + +The variable nb_numa_nodes may be 0, and a division by 0 +error will occur later, and special treatment is done for +nb_numa_nodes here. + +Signed-off-by: lixianglai +--- + hw/loongarch/larch_3a.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c +index fe786008ac..cef1a6f3d2 100644 +--- a/hw/loongarch/larch_3a.c ++++ b/hw/loongarch/larch_3a.c +@@ -1221,7 +1221,6 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; +- ms->smp.cores = 4; + + if (!lsms->fw_cfg) { + return; +@@ -2005,6 +2004,10 @@ static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) + { + int nb_numa_nodes = ms->numa_state->num_nodes; + int smp_cores = ms->smp.cores; ++ ++ if (nb_numa_nodes == 0) { ++ nb_numa_nodes = 1; ++ } + return idx / smp_cores % nb_numa_nodes; + } + +-- +2.41.0.windows.1 + diff --git a/Fix-use-after-free-in-vfio_migration_probe.patch b/Fix-use-after-free-in-vfio_migration_probe.patch deleted file mode 100644 index f0a94e60054da414102dbda43f9d111c4bc2e6d9..0000000000000000000000000000000000000000 --- a/Fix-use-after-free-in-vfio_migration_probe.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 126fc13ebe9c5e58a5b1daeb4e102e6fa5845779 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Fri, 6 Nov 2020 23:32:24 +0530 -Subject: [PATCH] Fix use after free in vfio_migration_probe -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fixes Coverity issue: -CID 1436126: Memory - illegal accesses (USE_AFTER_FREE) - -Fixes: a9e271ec9b36 ("vfio: Add migration region initialization and finalize function") -Signed-off-by: Kirti Wankhede -Reviewed-by: David Edmondson -Reviewed-by: Alex Bennée -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Alex Williamson -Signed-off-by: Kunkun Jiang ---- - hw/vfio/migration.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 1a97784486..8546075706 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -903,8 +903,8 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) - goto add_blocker; - } - -- g_free(info); - trace_vfio_migration_probe(vbasedev->name, info->index); -+ g_free(info); - return 0; - - add_blocker: --- -2.27.0 - diff --git a/Fixed-a-QEMU-hang-when-guest-poweroff-in-COLO-mode.patch b/Fixed-a-QEMU-hang-when-guest-poweroff-in-COLO-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..10e21c23b6636fdda91ab26b467c0c3f781722b2 --- /dev/null +++ b/Fixed-a-QEMU-hang-when-guest-poweroff-in-COLO-mode.patch @@ -0,0 +1,83 @@ +From 6de250962994520ba8daca709cd4b3b54d5e3afb Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Fri, 1 Dec 2023 10:47:48 +0800 +Subject: [PATCH] Fixed a QEMU hang when guest poweroff in COLO mode + +cherry picked from commit 795969ab1fe6d5a0f524be92e2e1ecd13f1873eb + +When the PVM guest poweroff, the COLO thread may wait a semaphore +in colo_process_checkpoint().So, we should wake up the COLO thread +before migration shutdown. + +Signed-off-by: Lei Rao +Reviewed-by: Zhang Chen +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Luo Yifan +--- + include/migration/colo.h | 1 + + migration/colo.c | 20 ++++++++++++++++++++ + migration/migration.c | 6 ++++++ + 3 files changed, 27 insertions(+) + +diff --git a/include/migration/colo.h b/include/migration/colo.h +index 768e1f04c3..5fbe1a6d5d 100644 +--- a/include/migration/colo.h ++++ b/include/migration/colo.h +@@ -37,4 +37,5 @@ COLOMode get_colo_mode(void); + void colo_do_failover(void); + + void colo_checkpoint_notify(void *opaque); ++void colo_shutdown(void); + #endif +diff --git a/migration/colo.c b/migration/colo.c +index 2415325262..0d3d98f707 100644 +--- a/migration/colo.c ++++ b/migration/colo.c +@@ -820,6 +820,26 @@ static void colo_wait_handle_message(MigrationIncomingState *mis, + } + } + ++void colo_shutdown(void) ++{ ++ MigrationIncomingState *mis = NULL; ++ MigrationState *s = NULL; ++ ++ switch (get_colo_mode()) { ++ case COLO_MODE_PRIMARY: ++ s = migrate_get_current(); ++ qemu_event_set(&s->colo_checkpoint_event); ++ qemu_sem_post(&s->colo_exit_sem); ++ break; ++ case COLO_MODE_SECONDARY: ++ mis = migration_incoming_get_current(); ++ qemu_sem_post(&mis->colo_incoming_sem); ++ break; ++ default: ++ break; ++ } ++} ++ + void *colo_process_incoming_thread(void *opaque) + { + MigrationIncomingState *mis = opaque; +diff --git a/migration/migration.c b/migration/migration.c +index 2ec116f901..cceaacc7f7 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -226,6 +226,12 @@ void migration_cancel(const Error *error) + + void migration_shutdown(void) + { ++ /* ++ * When the QEMU main thread exit, the COLO thread ++ * may wait a semaphore. So, we should wakeup the ++ * COLO thread before migration shutdown. ++ */ ++ colo_shutdown(); + /* + * Cancel the current migration - that will (eventually) + * stop the migration using this structure +-- +2.27.0 + diff --git a/Fixed-integer-overflow-in-e1000e.patch b/Fixed-integer-overflow-in-e1000e.patch deleted file mode 100644 index 004390fc5a3d60d2aaf4912d0679c4fa471d28a2..0000000000000000000000000000000000000000 --- a/Fixed-integer-overflow-in-e1000e.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 41077af2c4283c15c0a822017ea51612d15b68f8 Mon Sep 17 00:00:00 2001 -From: Andrew Melnychenko -Date: Wed, 4 Mar 2020 16:20:58 +0200 -Subject: [PATCH 1/5] Fixed integer overflow in e1000e -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1737400 -Fixed setting max_queue_num if there are no peers in -NICConf. qemu_new_nic() creates NICState with 1 NetClientState(index -0) without peers, set max_queue_num to 0 - It prevents undefined -behavior and possible crashes, especially during pcie hotplug. - -Fixes: 6f3fbe4ed06 ("net: Introduce e1000e device emulation") -Signed-off-by: Andrew Melnychenko -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Dmitry Fleytman -Signed-off-by: Jason Wang -Signed-off-by: Zhenyu Ye ---- - hw/net/e1000e.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c -index 581f7d03..1e827c4f 100644 ---- a/hw/net/e1000e.c -+++ b/hw/net/e1000e.c -@@ -325,7 +325,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr) - s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, - object_get_typename(OBJECT(s)), dev->id, s); - -- s->core.max_queue_num = s->conf.peers.queues - 1; -+ s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0; - - trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); - memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); --- -2.22.0.windows.1 - diff --git a/IPv6-add-support-for-IPv6-protocol.patch b/IPv6-add-support-for-IPv6-protocol.patch new file mode 100644 index 0000000000000000000000000000000000000000..23ed9a27cb5c99375ccadda8c94cefa17496fd72 --- /dev/null +++ b/IPv6-add-support-for-IPv6-protocol.patch @@ -0,0 +1,28 @@ +From 039e70e84d966ee28267f3fe76c8558ef65619f9 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Sat, 12 Feb 2022 14:31:00 +0800 +Subject: [PATCH] IPv6: add support for IPv6 protocol + +Add support for IPv6 protocol. + +Signed-off-by: Yan Wang +--- + roms/ipxe/src/config/general.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/roms/ipxe/src/config/general.h b/roms/ipxe/src/config/general.h +index 3c14a2c..e7ce2b9 100644 +--- a/roms/ipxe/src/config/general.h ++++ b/roms/ipxe/src/config/general.h +@@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + */ + + #define NET_PROTO_IPV4 /* IPv4 protocol */ +-#undef NET_PROTO_IPV6 /* IPv6 protocol */ ++#define NET_PROTO_IPV6 /* IPv6 protocol */ + #undef NET_PROTO_FCOE /* Fibre Channel over Ethernet protocol */ + #define NET_PROTO_STP /* Spanning Tree protocol */ + #define NET_PROTO_LACP /* Link Aggregation control protocol */ +-- +1.9.1 + diff --git a/KVM-x86-workaround-invalid-CPUID-0xD-9-info-on-some-.patch b/KVM-x86-workaround-invalid-CPUID-0xD-9-info-on-some-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf01f17d663941e229ab4ecbe08cab3c30e7d522 --- /dev/null +++ b/KVM-x86-workaround-invalid-CPUID-0xD-9-info-on-some-.patch @@ -0,0 +1,113 @@ +From 49cb3c9f3cc3a567ce2e6159bf27328c64b6601d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 23 Mar 2022 12:33:25 +0100 +Subject: [PATCH 10/10] KVM: x86: workaround invalid CPUID[0xD,9] info on some + AMD processors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +from mainline-v7.0.0-rc2 +commit 58f7db26f21c690cf9a669c314cfd7371506084a +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 58f7db26f21c ("KVM: x86: workaround invalid CPUID[0xD,9] info +on some AMD processors") + +---------------------------------------------------------------- + +KVM: x86: workaround invalid CPUID[0xD,9] info on some AMD processors + +Some AMD processors expose the PKRU extended save state even if they do not have +the related PKU feature in CPUID. Worse, when they do they report a size of +64, whereas the expected size of the PKRU extended save state is 8, therefore +the esa->size == eax assertion does not hold. + +The state is already ignored by KVM_GET_SUPPORTED_CPUID because it +was not enabled in the host XCR0. However, QEMU kvm_cpu_xsave_init() +runs before QEMU invokes arch_prctl() to enable dynamically-enabled +save states such as XTILEDATA, and KVM_GET_SUPPORTED_CPUID hides save +states that have yet to be enabled. Therefore, kvm_cpu_xsave_init() +needs to consult the host CPUID instead of KVM_GET_SUPPORTED_CPUID, +and dies with an assertion failure. + +When setting up the ExtSaveArea array to match the host, ignore features that +KVM does not report as supported. This will cause QEMU to skip the incorrect +CPUID leaf instead of tripping the assertion. + +Closes: https://gitlab.com/qemu-project/qemu/-/issues/916 +Reported-by: Daniel P. Berrangé +Analyzed-by: Yang Zhong +Reported-by: Peter Krempa +Tested-by: Daniel P. Berrangé +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 4 ++-- + target/i386/cpu.h | 2 ++ + target/i386/kvm/kvm-cpu.c | 19 ++++++++++++------- + 3 files changed, 16 insertions(+), 9 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 1bc03d3eef..551b47ab1e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4973,8 +4973,8 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + return cpu_list; + } + +-static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, +- bool migratable_only) ++uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, ++ bool migratable_only) + { + FeatureWordInfo *wi = &feature_word_info[w]; + uint64_t r = 0; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index eaa99c302f..290f1beaea 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -605,6 +605,8 @@ typedef enum FeatureWord { + } FeatureWord; + + typedef uint64_t FeatureWordArray[FEATURE_WORDS]; ++uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, ++ bool migratable_only); + + /* cpuid_features bits */ + #define CPUID_FP87 (1U << 0) +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index a35a1bf9fe..5eb955ce9a 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -99,13 +99,18 @@ static void kvm_cpu_xsave_init(void) + for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) { + ExtSaveArea *esa = &x86_ext_save_areas[i]; + +- if (esa->size) { +- host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); +- if (eax != 0) { +- assert(esa->size == eax); +- esa->offset = ebx; +- esa->ecx = ecx; +- } ++ if (!esa->size) { ++ continue; ++ } ++ if ((x86_cpu_get_supported_feature_word(esa->feature, false) & esa->bits) ++ != esa->bits) { ++ continue; ++ } ++ host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); ++ if (eax != 0) { ++ assert(esa->size == eax); ++ esa->offset = ebx; ++ esa->ecx = ecx; + } + } + } +-- +2.27.0 + diff --git a/QGA-VSS-Add-wrapper-to-send-log-to-debugger-and-stde.patch b/QGA-VSS-Add-wrapper-to-send-log-to-debugger-and-stde.patch new file mode 100644 index 0000000000000000000000000000000000000000..38aecce8b19120acdd95fd6baeaca3af0158fe50 --- /dev/null +++ b/QGA-VSS-Add-wrapper-to-send-log-to-debugger-and-stde.patch @@ -0,0 +1,110 @@ +From a7d32227e6a7b3eff114135f68f980ac686f6b80 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Sun, 30 Jul 2023 23:14:18 -0700 +Subject: [PATCH] QGA VSS: Add wrapper to send log to debugger and stderr + mainline inclusion commit 925d05d38a2bc76b5a49359370650a820bc891da category: + bugfix + +Reviewed-by: Thomas Huth +Signed-off-by: Konstantin Kostiuk +Signed-off-by: zhujun2 +--- + qga/vss-win32/meson.build | 2 +- + qga/vss-win32/vss-debug.cpp | 39 +++++++++++++++++++++++++++++++++++++ + qga/vss-win32/vss-debug.h | 25 ++++++++++++++++++++++++ + 3 files changed, 65 insertions(+), 1 deletion(-) + create mode 100644 qga/vss-win32/vss-debug.cpp + create mode 100644 qga/vss-win32/vss-debug.h + +diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build +index 90825edef3..290796556c 100644 +--- a/qga/vss-win32/meson.build ++++ b/qga/vss-win32/meson.build +@@ -3,7 +3,7 @@ if add_languages('cpp', required: false) + link_args = cc.get_supported_link_arguments(['-fstack-protector-all', '-fstack-protector-strong', + '-Wl,--add-stdcall-alias', '-Wl,--enable-stdcall-fixup']) + +- qga_vss = shared_module('qga-vss', ['requester.cpp', 'provider.cpp', 'install.cpp'], ++ qga_vss = shared_module('qga-vss', ['requester.cpp', 'provider.cpp', 'install.cpp', 'vss-debug.cpp'], + name_prefix: '', + cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], + link_args: link_args, +diff --git a/qga/vss-win32/vss-debug.cpp b/qga/vss-win32/vss-debug.cpp +new file mode 100644 +index 0000000000..820b1c6667 +--- /dev/null ++++ b/qga/vss-win32/vss-debug.cpp +@@ -0,0 +1,39 @@ ++/* ++ * QEMU Guest Agent VSS debug declarations ++ * ++ * Copyright (C) 2023 Red Hat Inc ++ * ++ * Authors: ++ * Konstantin Kostiuk ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "vss-debug.h" ++#include "vss-common.h" ++ ++void qga_debug_internal(const char *funcname, const char *fmt, ...) ++{ ++ char user_string[512] = {0}; ++ char full_string[640] = {0}; ++ ++ va_list args; ++ va_start(args, fmt); ++ if (vsnprintf(user_string, _countof(user_string), fmt, args) <= 0) { ++ va_end(args); ++ return; ++ } ++ ++ va_end(args); ++ ++ if (snprintf(full_string, _countof(full_string), ++ QGA_PROVIDER_NAME "[%lu]: %s %s\n", ++ GetCurrentThreadId(), funcname, user_string) <= 0) { ++ return; ++ } ++ ++ OutputDebugString(full_string); ++ fputs(full_string, stderr); ++} +diff --git a/qga/vss-win32/vss-debug.h b/qga/vss-win32/vss-debug.h +new file mode 100644 +index 0000000000..7800457392 +--- /dev/null ++++ b/qga/vss-win32/vss-debug.h +@@ -0,0 +1,25 @@ ++/* ++ * QEMU Guest Agent VSS debug declarations ++ * ++ * Copyright (C) 2023 Red Hat Inc ++ * ++ * Authors: ++ * Konstantin Kostiuk ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#ifndef VSS_DEBUG_H ++#define VSS_DEBUG_H ++ ++void qga_debug_internal(const char *funcname, const char *fmt, ...) G_GNUC_PRINTF(2, 3); ++ ++#define qga_debug(fmt, ...) qga_debug_internal(__func__, fmt, ## __VA_ARGS__) ++#define qga_debug_begin qga_debug("begin") ++#define qga_debug_end qga_debug("end") ++ ++#endif +-- +2.41.0.windows.1 + diff --git a/Remove-the-unused-local-variable-records.patch b/Remove-the-unused-local-variable-records.patch new file mode 100644 index 0000000000000000000000000000000000000000..d41ab54c9765dac7d5a8055e5b3a6fcf1e9f400d --- /dev/null +++ b/Remove-the-unused-local-variable-records.patch @@ -0,0 +1,25 @@ +From 7b859a86cbdde8bf17619c43a6d4ae687a20f003 Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Wed, 29 Jun 2022 16:26:17 +0800 +Subject: [PATCH] Remove the unused local variable "records". + +Signed-off-by: dinglimin +--- + tests/migration/guestperf/engine.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py +index 87a6ab2009..59fca2c70b 100644 +--- a/tests/migration/guestperf/engine.py ++++ b/tests/migration/guestperf/engine.py +@@ -65,7 +65,6 @@ def _vcpu_timing(self, pid, tid_list): + return records + + def _cpu_timing(self, pid): +- records = [] + now = time.time() + + jiffies_per_sec = os.sysconf(os.sysconf_names['SC_CLK_TCK']) +-- +2.27.0 + diff --git a/Remove-this-redundant-return.patch b/Remove-this-redundant-return.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d028bde780249cedd3ea87289cb69286247fcf7 --- /dev/null +++ b/Remove-this-redundant-return.patch @@ -0,0 +1,25 @@ +From e7ef56975af8553690afb16f32fe74d62762b853 Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Wed, 29 Jun 2022 14:02:59 +0800 +Subject: [PATCH] Remove this redundant return. + +Signed-off-by: dinglimin +--- + scripts/vmstate-static-checker.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py +index 539ead62b4..6838bf7e7c 100755 +--- a/scripts/vmstate-static-checker.py ++++ b/scripts/vmstate-static-checker.py +@@ -367,7 +367,6 @@ def check_machine_type(s, d): + if s["Name"] != d["Name"]: + print("Warning: checking incompatible machine types:", end=' ') + print("\"" + s["Name"] + "\", \"" + d["Name"] + "\"") +- return + + + def main(): +-- +2.27.0 + diff --git a/Revert-cpu-add-Cortex-A72-processor-kvm-target-suppo.patch b/Revert-cpu-add-Cortex-A72-processor-kvm-target-suppo.patch new file mode 100644 index 0000000000000000000000000000000000000000..684893c93f9c04880af0d0177503b8b0afaf9ffd --- /dev/null +++ b/Revert-cpu-add-Cortex-A72-processor-kvm-target-suppo.patch @@ -0,0 +1,49 @@ +From 7474971c6fd6c6f77e66ded125e5f2521c7e12a2 Mon Sep 17 00:00:00 2001 +From: Mingwang Li +Date: Wed, 9 Feb 2022 17:35:52 +0800 +Subject: [PATCH 2/3] Revert "cpu: add Cortex-A72 processor kvm target support" + +This reverts commit f0da7fa5230b5f771570b2c12288e4a56a20dd97. + +Signed-off-by: Mingwang Li +--- + target/arm/cpu64.c | 1 - + target/arm/kvm-consts.h | 3 --- + 2 files changed, 4 deletions(-) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index bd8e5b5676..26419fe994 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -202,7 +202,6 @@ static void aarch64_a72_initfn(Object *obj) + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a72"; +- cpu->kvm_target = QEMU_KVM_ARM_TARGET_GENERIC_V8; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); +diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h +index 5f1311ade7..580f1c1fee 100644 +--- a/target/arm/kvm-consts.h ++++ b/target/arm/kvm-consts.h +@@ -130,8 +130,6 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED); + #define QEMU_KVM_ARM_TARGET_CORTEX_A57 2 + #define QEMU_KVM_ARM_TARGET_XGENE_POTENZA 3 + #define QEMU_KVM_ARM_TARGET_CORTEX_A53 4 +-/* Generic ARM v8 target */ +-#define QEMU_KVM_ARM_TARGET_GENERIC_V8 5 + + /* There's no kernel define for this: sentinel value which + * matches no KVM target value for either 64 or 32 bit +@@ -143,7 +141,6 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53); +-MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_GENERIC_V8, KVM_ARM_TARGET_GENERIC_V8); + + #define CP_REG_ARM64 0x6000000000000000ULL + #define CP_REG_ARM_COPROC_MASK 0x000000000FFF0000 +-- +2.27.0 + diff --git a/Revert-cpu-parse-feature-to-avoid-failure.patch b/Revert-cpu-parse-feature-to-avoid-failure.patch new file mode 100644 index 0000000000000000000000000000000000000000..038edb892f46cd97b3a0b59dd6f6f1436a7e5442 --- /dev/null +++ b/Revert-cpu-parse-feature-to-avoid-failure.patch @@ -0,0 +1,67 @@ +From cae52ca5b1dd4a295eaabc9649481f3d6a684f06 Mon Sep 17 00:00:00 2001 +From: Mingwang Li +Date: Wed, 9 Feb 2022 17:33:26 +0800 +Subject: [PATCH 1/3] Revert "cpu: parse +/- feature to avoid failure" + +This reverts commit ef83cde8dd2c9b404527354489b14d2bd238733d. + +Signed-off-by: Mingwang Li +--- + target/arm/cpu64.c | 37 ------------------------------------- + 1 file changed, 37 deletions(-) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 08d886de7b..bd8e5b5676 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -983,47 +983,10 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) + return g_strdup("aarch64"); + } + +-/* Parse "+feature,-feature,feature=foo" CPU feature string +- */ +-static void arm_cpu_parse_featurestr(const char *typename, char *features, +- Error **errp ) +-{ +- char *featurestr; +- char *val; +- static bool cpu_globals_initialized; +- +- if (cpu_globals_initialized) { +- return; +- } +- cpu_globals_initialized = true; +- +- featurestr = features ? strtok(features, ",") : NULL; +- while (featurestr) { +- val = strchr(featurestr, '='); +- if (val) { +- GlobalProperty *prop = g_new0(typeof(*prop), 1); +- *val = 0; +- val++; +- prop->driver = typename; +- prop->property = g_strdup(featurestr); +- prop->value = g_strdup(val); +- qdev_prop_register_global(prop); +- } else if (featurestr[0] == '+' || featurestr[0] == '-') { +- warn_report("Ignore %s feature\n", featurestr); +- } else { +- error_setg(errp, "Expected key=value format, found %s.", +- featurestr); +- return; +- } +- featurestr = strtok(NULL, ","); +- } +-} +- + static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + { + CPUClass *cc = CPU_CLASS(oc); + +- cc->parse_features = arm_cpu_parse_featurestr; + cc->gdb_read_register = aarch64_cpu_gdb_read_register; + cc->gdb_write_register = aarch64_cpu_gdb_write_register; + cc->gdb_num_core_regs = 34; +-- +2.27.0 + diff --git a/Revert-hw-arm-smmu-common-Allow-domain-invalidation-.patch b/Revert-hw-arm-smmu-common-Allow-domain-invalidation-.patch new file mode 100644 index 0000000000000000000000000000000000000000..3029daa2cff8522c7c970a86d8ff95750ef9905b --- /dev/null +++ b/Revert-hw-arm-smmu-common-Allow-domain-invalidation-.patch @@ -0,0 +1,28 @@ +From c57d05a6ba11075b6998b98a204017c44f81759f Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:55 +0800 +Subject: [PATCH 32/36] Revert "hw/arm/smmu-common: Allow domain invalidation + for NH_ALL/NSNH_ALL" + +This reverts commit 876d18c962f0ead31d8458cd7ac19178be78455c. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmu-common.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c +index f253a27e1a..730dd20db1 100644 +--- a/hw/arm/smmu-common.c ++++ b/hw/arm/smmu-common.c +@@ -478,7 +478,6 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) + event.entry.iova = n->start; + event.entry.perm = IOMMU_NONE; + event.entry.addr_mask = n->end - n->start; +- event.entry.granularity = IOMMU_INV_GRAN_DOMAIN; + + memory_region_notify_iommu_one(n, &event); + } +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribu.patch b/Revert-hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribu.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a8ffa8598b1aaa8c4e91a87cd7c290b75bf8f0b --- /dev/null +++ b/Revert-hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribu.patch @@ -0,0 +1,30 @@ +From 6ce1e1161c833d59b659a9f50062439a24ce6995 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:36 +0800 +Subject: [PATCH 17/36] Revert "hw/arm/smmuv3: Advertise MSI_TRANSLATE + attribute" + +This reverts commit 5a759ab19d508361053e388694546216705d173b. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 275f1db430..5a092506d3 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -1600,9 +1600,6 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, + if (attr == IOMMU_ATTR_VFIO_NESTED) { + *(bool *) data = true; + return 0; +- } else if (attr == IOMMU_ATTR_MSI_TRANSLATE) { +- *(bool *) data = true; +- return 0; + } + return -EINVAL; + } +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Allow-MAP-notifiers.patch b/Revert-hw-arm-smmuv3-Allow-MAP-notifiers.patch new file mode 100644 index 0000000000000000000000000000000000000000..def7e72f24922400bd460cacf4a59f59f9564b47 --- /dev/null +++ b/Revert-hw-arm-smmuv3-Allow-MAP-notifiers.patch @@ -0,0 +1,34 @@ +From 27fb5c981f920fe6ee1345d35d5c3b6cff1b1ce6 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:29 +0800 +Subject: [PATCH 11/36] Revert "hw/arm/smmuv3: Allow MAP notifiers" + +This reverts commit dc126664134989975ce9ab9e7d5d2c8916628bf6. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 55e78db65d..ed932d3340 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -1632,6 +1632,14 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + return -EINVAL; + } + ++ if (new & IOMMU_NOTIFIER_MAP) { ++ error_setg(errp, ++ "device %02x.%02x.%x requires iommu MAP notifier which is " ++ "not currently supported", pci_bus_num(sdev->bus), ++ PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn)); ++ return -EINVAL; ++ } ++ + if (old == IOMMU_NOTIFIER_NONE) { + trace_smmuv3_notify_flag_add(iommu->parent_obj.name); + QLIST_INSERT_HEAD(&s->devices_with_notifiers, sdev, next); +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-.patch b/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f6885fe5049e4bbc1d9508f2bf947a271017da2 --- /dev/null +++ b/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-.patch @@ -0,0 +1,29 @@ +From 868d85814a59b1b710b3edf34a0916f6849b72c0 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:33 +0800 +Subject: [PATCH 15/36] Revert "hw/arm/smmuv3: Fill the IOTLBEntry arch_id on + NH_VA invalidation" + +This reverts commit dcda615b3d9b1acffee3d31d57974cc9e4bd0dee. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 3751fb3ea8..e09e54a9aa 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -837,8 +837,6 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + event.entry.iova = iova; + event.entry.addr_mask = num_pages * (1 << granule) - 1; + event.entry.perm = IOMMU_NONE; +- event.entry.flags = IOMMU_INV_FLAGS_ARCHID; +- event.entry.arch_id = asid; + + memory_region_notify_iommu_one(n, &event); + } +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-.patch b/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9137bbe328b540f9da509c83cc606f8b0abbd589 --- /dev/null +++ b/Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-.patch @@ -0,0 +1,73 @@ +From 62e581d9c6adfa3aebcefa8c5270aa6fc38ed541 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:32 +0800 +Subject: [PATCH 14/36] Revert "hw/arm/smmuv3: Fill the IOTLBEntry leaf field + on NH_VA invalidation" + +This reverts commit c219274b7b6a472d7340a4f72a052ba33ed19659. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index cceb3794d4..3751fb3ea8 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -804,7 +804,7 @@ epilogue: + static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + IOMMUNotifier *n, + int asid, dma_addr_t iova, +- uint8_t tg, uint64_t num_pages, bool leaf) ++ uint8_t tg, uint64_t num_pages) + { + SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); + IOMMUTLBEvent event = {}; +@@ -839,7 +839,6 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + event.entry.perm = IOMMU_NONE; + event.entry.flags = IOMMU_INV_FLAGS_ARCHID; + event.entry.arch_id = asid; +- event.entry.leaf = leaf; + + memory_region_notify_iommu_one(n, &event); + } +@@ -871,7 +870,7 @@ static void smmuv3_notify_asid(IOMMUMemoryRegion *mr, + + /* invalidate an asid/iova range tuple in all mr's */ + static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, +- uint8_t tg, uint64_t num_pages, bool leaf) ++ uint8_t tg, uint64_t num_pages) + { + SMMUDevice *sdev; + +@@ -883,7 +882,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, + tg, num_pages); + + IOMMU_NOTIFIER_FOREACH(n, mr) { +- smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages, leaf); ++ smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages); + } + } + } +@@ -908,7 +907,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) + + if (!tg) { + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, 1, ttl, leaf); +- smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1, leaf); ++ smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1); + smmu_iotlb_inv_iova(s, asid, addr, tg, 1, ttl); + return; + } +@@ -926,7 +925,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) + + num_pages = (mask + 1) >> granule; + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf); +- smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages, leaf); ++ smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages); + smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl); + addr += mask + 1; + } +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Implement-fault-injection.patch b/Revert-hw-arm-smmuv3-Implement-fault-injection.patch new file mode 100644 index 0000000000000000000000000000000000000000..a335500f6b067a4bc9368bc687bf1944ca81408f --- /dev/null +++ b/Revert-hw-arm-smmuv3-Implement-fault-injection.patch @@ -0,0 +1,104 @@ +From 822386d862324be3c334faff790c1f6a64c5455a Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:30 +0800 +Subject: [PATCH 12/36] Revert "hw/arm/smmuv3: Implement fault injection" + +This reverts commit d31c754470b4b651d0e19c66738fbcc8fc6abf3c. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 71 ------------------------------------------------- + 1 file changed, 71 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index ed932d3340..514ce9d57d 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -1664,76 +1664,6 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, + return -EINVAL; + } + +-struct iommu_fault; +- +-static inline int +-smmuv3_inject_faults(IOMMUMemoryRegion *iommu_mr, int count, +- struct iommu_fault *buf) +-{ +-#ifdef __linux__ +- SMMUDevice *sdev = container_of(iommu_mr, SMMUDevice, iommu); +- SMMUv3State *s3 = sdev->smmu; +- uint32_t sid = smmu_get_sid(sdev); +- int i; +- +- for (i = 0; i < count; i++) { +- SMMUEventInfo info = {}; +- struct iommu_fault_unrecoverable *record; +- +- if (buf[i].type != IOMMU_FAULT_DMA_UNRECOV) { +- continue; +- } +- +- info.sid = sid; +- record = &buf[i].event; +- +- switch (record->reason) { +- case IOMMU_FAULT_REASON_PASID_INVALID: +- info.type = SMMU_EVT_C_BAD_SUBSTREAMID; +- /* TODO further fill info.u.c_bad_substream */ +- break; +- case IOMMU_FAULT_REASON_PASID_FETCH: +- info.type = SMMU_EVT_F_CD_FETCH; +- break; +- case IOMMU_FAULT_REASON_BAD_PASID_ENTRY: +- info.type = SMMU_EVT_C_BAD_CD; +- /* TODO further fill info.u.c_bad_cd */ +- break; +- case IOMMU_FAULT_REASON_WALK_EABT: +- info.type = SMMU_EVT_F_WALK_EABT; +- info.u.f_walk_eabt.addr = record->addr; +- info.u.f_walk_eabt.addr2 = record->fetch_addr; +- break; +- case IOMMU_FAULT_REASON_PTE_FETCH: +- info.type = SMMU_EVT_F_TRANSLATION; +- info.u.f_translation.addr = record->addr; +- break; +- case IOMMU_FAULT_REASON_OOR_ADDRESS: +- info.type = SMMU_EVT_F_ADDR_SIZE; +- info.u.f_addr_size.addr = record->addr; +- break; +- case IOMMU_FAULT_REASON_ACCESS: +- info.type = SMMU_EVT_F_ACCESS; +- info.u.f_access.addr = record->addr; +- break; +- case IOMMU_FAULT_REASON_PERMISSION: +- info.type = SMMU_EVT_F_PERMISSION; +- info.u.f_permission.addr = record->addr; +- break; +- default: +- warn_report("%s Unexpected fault reason received from host: %d", +- __func__, record->reason); +- continue; +- } +- +- smmuv3_record_event(s3, &info); +- } +- return 0; +-#else +- return -1; +-#endif +-} +- + static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, + void *data) + { +@@ -1742,7 +1672,6 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, + imrc->translate = smmuv3_translate; + imrc->notify_flag_changed = smmuv3_notify_flag_changed; + imrc->get_attr = smmuv3_get_attr; +- imrc->inject_faults = smmuv3_inject_faults; + } + + static const TypeInfo smmuv3_type_info = { +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Improve-stage1-ASID-invalidatio.patch b/Revert-hw-arm-smmuv3-Improve-stage1-ASID-invalidatio.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f812bb509ec6f554ceca61efbbc01cd85a476dd --- /dev/null +++ b/Revert-hw-arm-smmuv3-Improve-stage1-ASID-invalidatio.patch @@ -0,0 +1,98 @@ +From 98ca0862f34c891a0e381bd382306398b88ac5bc Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:56 +0800 +Subject: [PATCH 33/36] Revert "hw/arm/smmuv3: Improve stage1 ASID + invalidation" + +This reverts commit de53feaa37a267a21ed30a642e1e64c5fcfbc4a4. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 44 ++------------------------------------------ + hw/arm/trace-events | 1 - + 2 files changed, 2 insertions(+), 43 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index f4de66827d..0e8fe646aa 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -840,31 +840,6 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + memory_region_notify_iommu_one(n, &event); + } + +-/** +- * smmuv3_notify_asid - call the notifier @n for a given asid +- * +- * @mr: IOMMU mr region handle +- * @n: notifier to be called +- * @asid: address space ID or negative value if we don't care +- */ +-static void smmuv3_notify_asid(IOMMUMemoryRegion *mr, +- IOMMUNotifier *n, int asid) +-{ +- IOMMUTLBEvent event = {}; +- +- event.type = IOMMU_NOTIFIER_UNMAP; +- event.entry.target_as = &address_space_memory; +- event.entry.perm = IOMMU_NONE; +- event.entry.granularity = IOMMU_INV_GRAN_PASID; +- event.entry.flags = IOMMU_INV_FLAGS_ARCHID; +- event.entry.arch_id = asid; +- event.entry.iova = n->start; +- event.entry.addr_mask = n->end - n->start; +- +- memory_region_notify_iommu_one(n, &event); +-} +- +- + /* invalidate an asid/iova range tuple in all mr's */ + static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, + uint8_t tg, uint64_t num_pages) +@@ -942,22 +917,6 @@ smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + return true; + } + +-static void smmuv3_s1_asid_inval(SMMUState *s, uint16_t asid) +-{ +- SMMUDevice *sdev; +- +- trace_smmuv3_s1_asid_inval(asid); +- QLIST_FOREACH(sdev, &s->devices_with_notifiers, next) { +- IOMMUMemoryRegion *mr = &sdev->iommu; +- IOMMUNotifier *n; +- +- IOMMU_NOTIFIER_FOREACH(n, mr) { +- smmuv3_notify_asid(mr, n, asid); +- } +- } +- smmu_iotlb_inv_asid(s, asid); +-} +- + static int smmuv3_cmdq_consume(SMMUv3State *s) + { + SMMUState *bs = ARM_SMMU(s); +@@ -1072,7 +1031,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) + uint16_t asid = CMD_ASID(&cmd); + + trace_smmuv3_cmdq_tlbi_nh_asid(asid); +- smmuv3_s1_asid_inval(bs, asid); ++ smmu_inv_notifiers_all(&s->smmu_state); ++ smmu_iotlb_inv_asid(bs, asid); + break; + } + case SMMU_CMD_TLBI_NH_ALL: +diff --git a/hw/arm/trace-events b/hw/arm/trace-events +index 1447ad5a90..2dee296c8f 100644 +--- a/hw/arm/trace-events ++++ b/hw/arm/trace-events +@@ -46,7 +46,6 @@ smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x" + smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)" + smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)" + smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d" +-smmuv3_s1_asid_inval(int asid) "asid=%d" + smmuv3_cmdq_tlbi_nh(void) "" + smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d" + smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x" +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Pass-stage-1-configurations-to-.patch b/Revert-hw-arm-smmuv3-Pass-stage-1-configurations-to-.patch new file mode 100644 index 0000000000000000000000000000000000000000..158b3d55c01799edf01d67fd2f82efbc42f0c516 --- /dev/null +++ b/Revert-hw-arm-smmuv3-Pass-stage-1-configurations-to-.patch @@ -0,0 +1,157 @@ +From 9682b8cd2454c00fbb4c4f7eb3e959187d9e6f1c Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:31 +0800 +Subject: [PATCH 13/36] Revert "hw/arm/smmuv3: Pass stage 1 configurations to + the host" + +This reverts commit 2e5929ec2a35a7a227dc7ba70a557a84993a366d. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmu-internal.h | 1 - + hw/arm/smmuv3.c | 71 ++++++------------------------------------ + hw/arm/trace-events | 1 - + 3 files changed, 9 insertions(+), 64 deletions(-) + +diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h +index 5ef8c598c6..2d75b31953 100644 +--- a/hw/arm/smmu-internal.h ++++ b/hw/arm/smmu-internal.h +@@ -105,7 +105,6 @@ typedef struct SMMUIOTLBPageInvInfo { + } SMMUIOTLBPageInvInfo; + + typedef struct SMMUSIDRange { +- SMMUState *state; + uint32_t start; + uint32_t end; + } SMMUSIDRange; +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 514ce9d57d..cceb3794d4 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -16,10 +16,6 @@ + * with this program; if not, see . + */ + +-#ifdef __linux__ +-#include "linux/iommu.h" +-#endif +- + #include "qemu/osdep.h" + #include "qemu/bitops.h" + #include "hw/irq.h" +@@ -936,61 +932,6 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) + } + } + +-static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) +-{ +-#ifdef __linux__ +- IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); +- SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid, +- .inval_ste_allowed = true}; +- IOMMUConfig iommu_config = {}; +- SMMUTransCfg *cfg; +- SMMUDevice *sdev; +- +- if (!mr) { +- return; +- } +- +- sdev = container_of(mr, SMMUDevice, iommu); +- +- /* flush QEMU config cache */ +- smmuv3_flush_config(sdev); +- +- if (!pci_device_is_pasid_ops_set(sdev->bus, sdev->devfn)) { +- return; +- } +- +- cfg = smmuv3_get_config(sdev, &event); +- +- if (!cfg) { +- return; +- } +- +- iommu_config.pasid_cfg.argsz = sizeof(struct iommu_pasid_table_config); +- iommu_config.pasid_cfg.version = PASID_TABLE_CFG_VERSION_1; +- iommu_config.pasid_cfg.format = IOMMU_PASID_FORMAT_SMMUV3; +- iommu_config.pasid_cfg.base_ptr = cfg->s1ctxptr; +- iommu_config.pasid_cfg.pasid_bits = 0; +- iommu_config.pasid_cfg.vendor_data.smmuv3.version = PASID_TABLE_SMMUV3_CFG_VERSION_1; +- +- if (cfg->disabled || cfg->bypassed) { +- iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_BYPASS; +- } else if (cfg->aborted) { +- iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_ABORT; +- } else { +- iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_TRANSLATE; +- } +- +- trace_smmuv3_notify_config_change(mr->parent_obj.name, +- iommu_config.pasid_cfg.config, +- iommu_config.pasid_cfg.base_ptr); +- +- if (pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config)) { +- error_report("Failed to pass PASID table to host for iommu mr %s (%m)", +- mr->parent_obj.name); +- } +-#endif +-} +- + static gboolean + smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + { +@@ -1001,7 +942,6 @@ smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + if (sid < sid_range->start || sid > sid_range->end) { + return false; + } +- smmuv3_notify_config_change(sid_range->state, sid); + trace_smmuv3_config_cache_inv(sid); + return true; + } +@@ -1072,14 +1012,22 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) + case SMMU_CMD_CFGI_STE: + { + uint32_t sid = CMD_SID(&cmd); ++ IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); ++ SMMUDevice *sdev; + + if (CMD_SSEC(&cmd)) { + cmd_error = SMMU_CERROR_ILL; + break; + } + ++ if (!mr) { ++ break; ++ } ++ + trace_smmuv3_cmdq_cfgi_ste(sid); +- smmuv3_notify_config_change(bs, sid); ++ sdev = container_of(mr, SMMUDevice, iommu); ++ smmuv3_flush_config(sdev); ++ + break; + } + case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ +@@ -1094,7 +1042,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) + } + + mask = (1ULL << (range + 1)) - 1; +- sid_range.state = bs; + sid_range.start = sid & ~mask; + sid_range.end = sid_range.start + mask; + +diff --git a/hw/arm/trace-events b/hw/arm/trace-events +index d9851d663e..1447ad5a90 100644 +--- a/hw/arm/trace-events ++++ b/hw/arm/trace-events +@@ -53,5 +53,4 @@ smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x" + smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s" + smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" + smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 +-smmuv3_notify_config_change(const char *name, uint8_t config, uint64_t s1ctxptr) "iommu mr=%s config=%d s1ctxptr=0x%"PRIx64 + +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Post-load-stage-1-configuration.patch b/Revert-hw-arm-smmuv3-Post-load-stage-1-configuration.patch new file mode 100644 index 0000000000000000000000000000000000000000..e10ded8e3f5f2010f7bf14c62a8abb6f9a62b67f --- /dev/null +++ b/Revert-hw-arm-smmuv3-Post-load-stage-1-configuration.patch @@ -0,0 +1,105 @@ +From c3dab32ec9b111e036b7de9cb8cb5a987b1764f3 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:16 +0800 +Subject: [PATCH 03/36] Revert "hw/arm/smmuv3: Post-load stage 1 configurations + to the host" + +This reverts commit 1b95c995f032c21bf6607dda8ede0f5856bb190a. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 33 +++++---------------------------- + 1 file changed, 5 insertions(+), 28 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 2bd9f22055..55e78db65d 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -936,7 +936,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) + } + } + +-static int smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) ++static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) + { + #ifdef __linux__ + IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); +@@ -945,10 +945,9 @@ static int smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) + IOMMUConfig iommu_config = {}; + SMMUTransCfg *cfg; + SMMUDevice *sdev; +- int ret; + + if (!mr) { +- return 0; ++ return; + } + + sdev = container_of(mr, SMMUDevice, iommu); +@@ -957,13 +956,13 @@ static int smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) + smmuv3_flush_config(sdev); + + if (!pci_device_is_pasid_ops_set(sdev->bus, sdev->devfn)) { +- return 0; ++ return; + } + + cfg = smmuv3_get_config(sdev, &event); + + if (!cfg) { +- return 0; ++ return; + } + + iommu_config.pasid_cfg.argsz = sizeof(struct iommu_pasid_table_config); +@@ -985,13 +984,10 @@ static int smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) + iommu_config.pasid_cfg.config, + iommu_config.pasid_cfg.base_ptr); + +- ret = pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config); +- if (ret) { ++ if (pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config)) { + error_report("Failed to pass PASID table to host for iommu mr %s (%m)", + mr->parent_obj.name); + } +- +- return ret; + #endif + } + +@@ -1561,24 +1557,6 @@ static void smmu_realize(DeviceState *d, Error **errp) + smmu_init_irq(s, dev); + } + +-static int smmuv3_post_load(void *opaque, int version_id) +-{ +- SMMUv3State *s3 = opaque; +- SMMUState *s = &(s3->smmu_state); +- SMMUDevice *sdev; +- int ret = 0; +- +- QLIST_FOREACH(sdev, &s->devices_with_notifiers, next) { +- uint32_t sid = smmu_get_sid(sdev); +- ret = smmuv3_notify_config_change(s, sid); +- if (ret) { +- break; +- } +- } +- +- return ret; +-} +- + static const VMStateDescription vmstate_smmuv3_queue = { + .name = "smmuv3_queue", + .version_id = 1, +@@ -1597,7 +1575,6 @@ static const VMStateDescription vmstate_smmuv3 = { + .version_id = 1, + .minimum_version_id = 1, + .priority = MIG_PRI_IOMMU, +- .post_load = smmuv3_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(features, SMMUv3State), + VMSTATE_UINT8(sid_size, SMMUv3State), +-- +2.27.0 + diff --git a/Revert-hw-arm-smmuv3-Store-the-PASID-table-GPA-in-th.patch b/Revert-hw-arm-smmuv3-Store-the-PASID-table-GPA-in-th.patch new file mode 100644 index 0000000000000000000000000000000000000000..22661e79007c06155d97cdfe15c80fe67eb2e4cb --- /dev/null +++ b/Revert-hw-arm-smmuv3-Store-the-PASID-table-GPA-in-th.patch @@ -0,0 +1,41 @@ +From 7d0023ef0c909bc569477e7676bc4c43734783a3 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:35 +0800 +Subject: [PATCH 16/36] Revert "hw/arm/smmuv3: Store the PASID table GPA in the + translation config" + +This reverts commit f937ce4124d57eea27d516957a2efa0e7fbdf198. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 1 - + include/hw/arm/smmu-common.h | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index e09e54a9aa..275f1db430 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -362,7 +362,6 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg, + "SMMUv3 S1 stalling fault model not allowed yet\n"); + goto bad_ste; + } +- cfg->s1ctxptr = STE_CTXPTR(ste); + return 0; + + bad_ste: +diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h +index d578339935..706be3c6d0 100644 +--- a/include/hw/arm/smmu-common.h ++++ b/include/hw/arm/smmu-common.h +@@ -76,7 +76,6 @@ typedef struct SMMUTransCfg { + uint8_t tbi; /* Top Byte Ignore */ + uint16_t asid; + SMMUTransTableInfo tt[2]; +- dma_addr_t s1ctxptr; + uint32_t iotlb_hits; /* counts IOTLB hits for this asid */ + uint32_t iotlb_misses; /* counts IOTLB misses for this asid */ + } SMMUTransCfg; +-- +2.27.0 + diff --git a/Revert-hw-virtio-virtio-iommu-pci-Enforce-the-device.patch b/Revert-hw-virtio-virtio-iommu-pci-Enforce-the-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..b3017089f753ded5c1573abdfd16c620ebde3988 --- /dev/null +++ b/Revert-hw-virtio-virtio-iommu-pci-Enforce-the-device.patch @@ -0,0 +1,49 @@ +From f66f64cf3ca968db2ca7f45bfd125ec7d85624e5 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Mon, 4 Dec 2023 17:30:02 +0800 +Subject: [PATCH] Revert "hw/virtio/virtio-iommu-pci: Enforce the device is + plugged on the root bus" + +This reverts commit a2323aa79da71c92e818306f1e18184619309a35. + +Signed-off-by: jiangdongxu +--- + hw/virtio/virtio-iommu-pci.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c +index 37eb2fb979..a160ae6b41 100644 +--- a/hw/virtio/virtio-iommu-pci.c ++++ b/hw/virtio/virtio-iommu-pci.c +@@ -44,7 +44,6 @@ static Property virtio_iommu_pci_properties[] = { + static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + { + VirtIOIOMMUPCI *dev = VIRTIO_IOMMU_PCI(vpci_dev); +- PCIBus *pbus = pci_get_bus(&vpci_dev->pci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); + +@@ -66,17 +65,11 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) { + error_setg(errp, "reserved region %d has an invalid type", i); + error_append_hint(errp, "Valid values are 0 and 1\n"); +- return; +- } ++ } + } +- if (!pci_bus_is_root(pbus)) { +- error_setg(errp, "virtio-iommu-pci must be plugged on the root bus"); +- return; +- } +- + object_property_set_link(OBJECT(dev), "primary-bus", +- OBJECT(pbus), &error_abort); +- ++ OBJECT(pci_get_bus(&vpci_dev->pci_dev)), ++ &error_abort); + virtio_pci_force_virtio_1(vpci_dev); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); + } +-- +2.27.0 + diff --git a/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch b/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch deleted file mode 100644 index 200e0b2df02607b11e3117863afd00a346419e27..0000000000000000000000000000000000000000 --- a/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 73a5bf472921068e6db10e7e325b7ac46f111834 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 18:36:05 -0400 -Subject: [PATCH] Revert "ide/ahci: Check for -ECANCELED in aio callbacks" - -This reverts commit 0d910cfeaf2076b116b4517166d5deb0fea76394. - -It's not correct to just ignore an error code in a callback; we need to -handle that error and possible report failure to the guest so that they -don't wait indefinitely for an operation that will now never finish. - -This ought to help cases reported by Nutanix where iSCSI returns a -legitimate -ECANCELED for certain operations which should be propagated -normally. - -Reported-by: Shaju Abraham -Signed-off-by: John Snow -Message-id: 20190729223605.7163-1-jsnow@redhat.com -Signed-off-by: John Snow -(cherry picked from commit 8ec41c4265714255d5a138f8b538faf3583dcff6) -Signed-off-by: Michael Roth ---- - hw/ide/ahci.c | 3 --- - hw/ide/core.c | 14 -------------- - 2 files changed, 17 deletions(-) - -diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c -index 00ba422a48..6aaf66534a 100644 ---- a/hw/ide/ahci.c -+++ b/hw/ide/ahci.c -@@ -1023,9 +1023,6 @@ static void ncq_cb(void *opaque, int ret) - IDEState *ide_state = &ncq_tfs->drive->port.ifs[0]; - - ncq_tfs->aiocb = NULL; -- if (ret == -ECANCELED) { -- return; -- } - - if (ret < 0) { - bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED; -diff --git a/hw/ide/core.c b/hw/ide/core.c -index 6afadf894f..8e1624f7ce 100644 ---- a/hw/ide/core.c -+++ b/hw/ide/core.c -@@ -722,9 +722,6 @@ static void ide_sector_read_cb(void *opaque, int ret) - s->pio_aiocb = NULL; - s->status &= ~BUSY_STAT; - -- if (ret == -ECANCELED) { -- return; -- } - if (ret != 0) { - if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO | - IDE_RETRY_READ)) { -@@ -840,10 +837,6 @@ static void ide_dma_cb(void *opaque, int ret) - uint64_t offset; - bool stay_active = false; - -- if (ret == -ECANCELED) { -- return; -- } -- - if (ret == -EINVAL) { - ide_dma_error(s); - return; -@@ -975,10 +968,6 @@ static void ide_sector_write_cb(void *opaque, int ret) - IDEState *s = opaque; - int n; - -- if (ret == -ECANCELED) { -- return; -- } -- - s->pio_aiocb = NULL; - s->status &= ~BUSY_STAT; - -@@ -1058,9 +1047,6 @@ static void ide_flush_cb(void *opaque, int ret) - - s->pio_aiocb = NULL; - -- if (ret == -ECANCELED) { -- return; -- } - if (ret < 0) { - /* XXX: What sector number to set here? */ - if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) { --- -2.23.0 diff --git a/Revert-iommu-Introduce-generic-header.patch b/Revert-iommu-Introduce-generic-header.patch new file mode 100644 index 0000000000000000000000000000000000000000..edea25ab3a5a539b85fee1baea1d886ee93ec2f5 --- /dev/null +++ b/Revert-iommu-Introduce-generic-header.patch @@ -0,0 +1,50 @@ +From 2916e0465befa35df9cce14b761177be55ccce4d Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:50 +0800 +Subject: [PATCH 28/36] Revert "iommu: Introduce generic header" + +This reverts commit 5e312f7b41ec48dc7dc9805af9f52aa8ed393bf9. + +Signed-off-by: Kunkun Jiang +--- + include/hw/iommu/iommu.h | 28 ---------------------------- + 1 file changed, 28 deletions(-) + delete mode 100644 include/hw/iommu/iommu.h + +diff --git a/include/hw/iommu/iommu.h b/include/hw/iommu/iommu.h +deleted file mode 100644 +index 12092bda7b..0000000000 +--- a/include/hw/iommu/iommu.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- * common header for iommu devices +- * +- * Copyright Red Hat, Inc. 2019 +- * +- * Authors: +- * Eric Auger +- * +- * This work is licensed under the terms of the GNU GPL, version 2. See +- * the COPYING file in the top-level directory. +- */ +- +-#ifndef QEMU_HW_IOMMU_IOMMU_H +-#define QEMU_HW_IOMMU_IOMMU_H +-#ifdef __linux__ +-#include +-#endif +- +-typedef struct IOMMUConfig { +- union { +-#ifdef __linux__ +- struct iommu_pasid_table_config pasid_cfg; +-#endif +- }; +-} IOMMUConfig; +- +- +-#endif /* QEMU_HW_IOMMU_IOMMU_H */ +-- +2.27.0 + diff --git a/Revert-memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-mem.patch b/Revert-memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-mem.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e140e502aab55bad30816f733738a9db2475d0d --- /dev/null +++ b/Revert-memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-mem.patch @@ -0,0 +1,28 @@ +From eb4958875239ccfabc03f28738d520c75db638d5 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:52 +0800 +Subject: [PATCH 30/36] Revert "memory: Add IOMMU_ATTR_MSI_TRANSLATE IOMMU + memory region attribute" + +This reverts commit 062923fd4e6d11e1b724f2dd059f8b0c6e65bf7a. + +Signed-off-by: Kunkun Jiang +--- + include/exec/memory.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 67d9061766..229c9cf85b 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -326,7 +326,6 @@ typedef struct MemoryRegionClass { + enum IOMMUMemoryRegionAttr { + IOMMU_ATTR_SPAPR_TCE_FD, + IOMMU_ATTR_VFIO_NESTED, +- IOMMU_ATTR_MSI_TRANSLATE, + }; + + /* +-- +2.27.0 + diff --git a/Revert-memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memor.patch b/Revert-memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memor.patch new file mode 100644 index 0000000000000000000000000000000000000000..642ba03d1a79fab4ae42c68f90b6442db2cd2b00 --- /dev/null +++ b/Revert-memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memor.patch @@ -0,0 +1,61 @@ +From 4c9e81175e15ca78c7ba7090ec20ea10c9e12751 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:53 +0800 +Subject: [PATCH 31/36] Revert "memory: Add IOMMU_ATTR_VFIO_NESTED IOMMU memory + region attribute" + +This reverts commit b380e3e0c30fb68dbbfb1397f3c374adfff77ac4. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmuv3.c | 12 ------------ + include/exec/memory.h | 3 +-- + 2 files changed, 1 insertion(+), 14 deletions(-) + +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 5a092506d3..f4de66827d 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -1593,17 +1593,6 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + return 0; + } + +-static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, +- enum IOMMUMemoryRegionAttr attr, +- void *data) +-{ +- if (attr == IOMMU_ATTR_VFIO_NESTED) { +- *(bool *) data = true; +- return 0; +- } +- return -EINVAL; +-} +- + static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, + void *data) + { +@@ -1611,7 +1600,6 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, + + imrc->translate = smmuv3_translate; + imrc->notify_flag_changed = smmuv3_notify_flag_changed; +- imrc->get_attr = smmuv3_get_attr; + } + + static const TypeInfo smmuv3_type_info = { +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 229c9cf85b..273f7f45d3 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -324,8 +324,7 @@ typedef struct MemoryRegionClass { + + + enum IOMMUMemoryRegionAttr { +- IOMMU_ATTR_SPAPR_TCE_FD, +- IOMMU_ATTR_VFIO_NESTED, ++ IOMMU_ATTR_SPAPR_TCE_FD + }; + + /* +-- +2.27.0 + diff --git a/Revert-memory-Add-new-fields-in-IOTLBEntry.patch b/Revert-memory-Add-new-fields-in-IOTLBEntry.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5bbe0c8c874982e574d7f900f85afbb522b04f3 --- /dev/null +++ b/Revert-memory-Add-new-fields-in-IOTLBEntry.patch @@ -0,0 +1,166 @@ +From 8cc370faf56aeaa060e1b4d9a307075bae982563 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:57 +0800 +Subject: [PATCH 34/36] Revert "memory: Add new fields in IOTLBEntry" + +This reverts commit da97cef20d4ee5a8f3942953836b35e7f7dd974f. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmu-common.c | 2 +- + hw/arm/smmuv3.c | 2 +- + hw/i386/intel_iommu.c | 6 +++--- + hw/ppc/spapr_iommu.c | 2 +- + hw/virtio/virtio-iommu.c | 4 ++-- + include/exec/memory.h | 36 +----------------------------------- + 6 files changed, 9 insertions(+), 43 deletions(-) + +diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c +index 730dd20db1..e09b9c13b7 100644 +--- a/hw/arm/smmu-common.c ++++ b/hw/arm/smmu-common.c +@@ -471,7 +471,7 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) + /* Unmap the whole notifier's range */ + static void smmu_unmap_notifier_range(IOMMUNotifier *n) + { +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + + event.type = IOMMU_NOTIFIER_UNMAP; + event.entry.target_as = &address_space_memory; +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 0e8fe646aa..3b43368be0 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -806,7 +806,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + uint8_t tg, uint64_t num_pages) + { + SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + uint8_t granule; + + if (!tg) { +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 6501d93f7e..5b865ac08c 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1197,7 +1197,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + uint32_t offset; + uint64_t slpte; + uint64_t subpage_size, subpage_mask; +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + uint64_t iova = start; + uint64_t iova_next; + int ret = 0; +@@ -2431,7 +2431,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) + { + VTDAddressSpace *vtd_dev_as; +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + struct VTDBus *vtd_bus; + hwaddr addr; + uint64_t sz; +@@ -3487,7 +3487,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + size = remain = end - start + 1; + + while (remain >= VTD_PAGE_SIZE) { +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + uint64_t mask = dma_aligned_pow2_mask(start, end, s->aw_bits); + uint64_t size = mask + 1; + +diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c +index 454df25d44..db01071858 100644 +--- a/hw/ppc/spapr_iommu.c ++++ b/hw/ppc/spapr_iommu.c +@@ -449,7 +449,7 @@ static void spapr_tce_reset(DeviceState *dev) + static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba, + target_ulong tce) + { +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift); + unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift; + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index 83ed2b82e6..1b23e8e18c 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -129,7 +129,7 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, + hwaddr virt_end, hwaddr paddr, + uint32_t flags) + { +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + IOMMUAccessFlags perm = IOMMU_ACCESS_FLAG(flags & VIRTIO_IOMMU_MAP_F_READ, + flags & VIRTIO_IOMMU_MAP_F_WRITE); + +@@ -154,7 +154,7 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, + static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, + hwaddr virt_end) + { +- IOMMUTLBEvent event = {}; ++ IOMMUTLBEvent event; + uint64_t delta = virt_end - virt_start; + + if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) { +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 273f7f45d3..4b5b431e45 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -116,48 +116,14 @@ typedef enum { + IOMMU_RW = 3, + } IOMMUAccessFlags; + +-/* Granularity of the cache invalidation */ +-typedef enum { +- IOMMU_INV_GRAN_ADDR = 0, +- IOMMU_INV_GRAN_PASID, +- IOMMU_INV_GRAN_DOMAIN, +-} IOMMUInvGranularity; +- + #define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | ((w) ? IOMMU_WO : 0)) + +-/** +- * struct IOMMUTLBEntry - IOMMU TLB entry +- * +- * Structure used when performing a translation or when notifying MAP or +- * UNMAP (invalidation) events +- * +- * @target_as: target address space +- * @iova: IO virtual address (input) +- * @translated_addr: translated address (output) +- * @addr_mask: address mask (0xfff means 4K binding), must be multiple of 2 +- * @perm: permission flag of the mapping (NONE encodes no mapping or +- * invalidation notification) +- * @granularity: granularity of the invalidation +- * @flags: informs whether the following fields are set +- * @arch_id: architecture specific ID tagging the TLB +- * @pasid: PASID tagging the TLB +- * @leaf: when @perm is NONE, indicates whether only caches for the last +- * level of translation need to be invalidated. +- */ + struct IOMMUTLBEntry { + AddressSpace *target_as; + hwaddr iova; + hwaddr translated_addr; +- hwaddr addr_mask; ++ hwaddr addr_mask; /* 0xfff = 4k translation */ + IOMMUAccessFlags perm; +- IOMMUInvGranularity granularity; +-#define IOMMU_INV_FLAGS_PASID (1 << 0) +-#define IOMMU_INV_FLAGS_ARCHID (1 << 1) +-#define IOMMU_INV_FLAGS_LEAF (1 << 2) +- uint32_t flags; +- uint32_t arch_id; +- uint32_t pasid; +- bool leaf; + }; + + /* +-- +2.27.0 + diff --git a/Revert-memory-Introduce-IOMMU-Memory-Region-inject_f.patch b/Revert-memory-Introduce-IOMMU-Memory-Region-inject_f.patch new file mode 100644 index 0000000000000000000000000000000000000000..8efb12280f25a98ca616ba0daa200b3a6569c8bd --- /dev/null +++ b/Revert-memory-Introduce-IOMMU-Memory-Region-inject_f.patch @@ -0,0 +1,87 @@ +From 3ab99dc1bf580607791aa402ad330720ce993ae2 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:51 +0800 +Subject: [PATCH 29/36] Revert "memory: Introduce IOMMU Memory Region + inject_faults API" + +This reverts commit d2dce19165f133935ff72e209f19bc43ab4d1421. + +Signed-off-by: Kunkun Jiang +--- + include/exec/memory.h | 24 ------------------------ + softmmu/memory.c | 10 ---------- + 2 files changed, 34 deletions(-) + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 7c3fe69d52..67d9061766 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -106,8 +106,6 @@ struct MemoryRegionSection { + bool nonvolatile; + }; + +-struct iommu_fault; +- + typedef struct IOMMUTLBEntry IOMMUTLBEntry; + + /* See address_space_translate: bit 0 is read, bit 1 is write. */ +@@ -528,19 +526,6 @@ struct IOMMUMemoryRegionClass { + int (*iommu_set_page_size_mask)(IOMMUMemoryRegion *iommu, + uint64_t page_size_mask, + Error **errp); +- +- /* +- * Inject @count faults into the IOMMU memory region +- * +- * Optional method: if this method is not provided, then +- * memory_region_injection_faults() will return -ENOENT +- * +- * @iommu: the IOMMU memory region to inject the faults in +- * @count: number of faults to inject +- * @buf: fault buffer +- */ +- int (*inject_faults)(IOMMUMemoryRegion *iommu, int count, +- struct iommu_fault *buf); + }; + + typedef struct RamDiscardListener RamDiscardListener; +@@ -1837,15 +1822,6 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr); + int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr, + uint64_t page_size_mask, + Error **errp); +-/** +- * memory_region_inject_faults : inject @count faults stored in @buf +- * +- * @iommu_mr: the IOMMU memory region +- * @count: number of faults to be injected +- * @buf: buffer containing the faults +- */ +-int memory_region_inject_faults(IOMMUMemoryRegion *iommu_mr, int count, +- struct iommu_fault *buf); + + /** + * memory_region_name: get a memory region's name +diff --git a/softmmu/memory.c b/softmmu/memory.c +index 9f98209ab2..7340e19ff5 100644 +--- a/softmmu/memory.c ++++ b/softmmu/memory.c +@@ -2111,16 +2111,6 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, + rdmc->unregister_listener(rdm, rdl); + } + +-int memory_region_inject_faults(IOMMUMemoryRegion *iommu_mr, int count, +- struct iommu_fault *buf) +-{ +- IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr); +- if (!imrc->inject_faults) { +- return -ENOENT; +- } +- return imrc->inject_faults(iommu_mr, count, buf); +-} +- + void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) + { + uint8_t mask = 1 << client; +-- +2.27.0 + diff --git a/Revert-monitor-limit-io-error-qmp-event-to-at-most-o.patch b/Revert-monitor-limit-io-error-qmp-event-to-at-most-o.patch new file mode 100644 index 0000000000000000000000000000000000000000..112161f6733b0f45f07bfb738342eefa9d12ad35 --- /dev/null +++ b/Revert-monitor-limit-io-error-qmp-event-to-at-most-o.patch @@ -0,0 +1,31 @@ +From e42b57adeac96c7d39b1c032ab3b66b7eff18cc8 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Tue, 29 Mar 2022 15:18:56 +0800 +Subject: [PATCH 2/2] Revert "monitor: limit io error qmp event to at most once + per 60s" + +This reverts commit 44f45b5c163efed5387dac40e229e0a50bf5921a. + +The commit 44f45b5c will reduse the IO-hang related log, which +is useful to solve the problem. + +Signed-off-by: Yan Wang +--- + monitor/monitor.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/monitor/monitor.c b/monitor/monitor.c +index 28206bedc4..257ef4ee54 100644 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -301,7 +301,6 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { + [QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS }, + [QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS }, + [QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE] = { 1000 * SCALE_MS }, +- [QAPI_EVENT_BLOCK_IO_ERROR] = { 60L * 1000 * SCALE_MS }, + }; + + /* +-- +2.27.0 + diff --git a/Revert-pci-Add-return_page_response-pci-ops.patch b/Revert-pci-Add-return_page_response-pci-ops.patch new file mode 100644 index 0000000000000000000000000000000000000000..cafc0a41c70770bfd59f2d6bf80c1ed3f0ec981c --- /dev/null +++ b/Revert-pci-Add-return_page_response-pci-ops.patch @@ -0,0 +1,84 @@ +From 9f843b181db3d73e86df140a41975a7645adc071 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:27 +0800 +Subject: [PATCH 10/36] Revert "pci: Add return_page_response pci ops" + +This reverts commit 228345cfa59c764e725e2d3680a4bc3ecb237609. + +Signed-off-by: Kunkun Jiang +--- + hw/pci/pci.c | 16 ---------------- + include/hw/iommu/iommu.h | 8 -------- + include/hw/pci/pci.h | 4 ---- + 3 files changed, 28 deletions(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 0743dc7c42..71076fff48 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -2797,22 +2797,6 @@ int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, + return -ENOENT; + } + +-int pci_device_return_page_response(PCIBus *bus, int32_t devfn, +- IOMMUPageResponse *resp) +-{ +- PCIDevice *dev; +- +- if (!bus) { +- return -EINVAL; +- } +- +- dev = bus->devices[devfn]; +- if (dev && dev->pasid_ops && dev->pasid_ops->return_page_response) { +- return dev->pasid_ops->return_page_response(bus, devfn, resp); +- } +- return -ENOENT; +-} +- + static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) + { + Range *range = opaque; +diff --git a/include/hw/iommu/iommu.h b/include/hw/iommu/iommu.h +index 5890f095b1..12092bda7b 100644 +--- a/include/hw/iommu/iommu.h ++++ b/include/hw/iommu/iommu.h +@@ -24,13 +24,5 @@ typedef struct IOMMUConfig { + }; + } IOMMUConfig; + +-typedef struct IOMMUPageResponse { +- union { +-#ifdef __linux__ +- struct iommu_page_response resp; +-#endif +- }; +-} IOMMUPageResponse; +- + + #endif /* QEMU_HW_IOMMU_IOMMU_H */ +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index bfe3a6bca7..4cf3dc6b43 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -268,8 +268,6 @@ typedef struct PCIReqIDCache PCIReqIDCache; + + struct PCIPASIDOps { + int (*set_pasid_table)(PCIBus *bus, int32_t devfn, IOMMUConfig *config); +- int (*return_page_response)(PCIBus *bus, int32_t devfn, +- IOMMUPageResponse *resp); + }; + typedef struct PCIPASIDOps PCIPASIDOps; + +@@ -510,8 +508,6 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); + void pci_setup_pasid_ops(PCIDevice *dev, PCIPASIDOps *ops); + bool pci_device_is_pasid_ops_set(PCIBus *bus, int32_t devfn); + int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, IOMMUConfig *config); +-int pci_device_return_page_response(PCIBus *bus, int32_t devfn, +- IOMMUPageResponse *resp); + + static inline void + pci_set_byte(uint8_t *config, uint8_t val) +-- +2.27.0 + diff --git a/Revert-pci-introduce-PCIPASIDOps-to-PCIDevice.patch b/Revert-pci-introduce-PCIPASIDOps-to-PCIDevice.patch new file mode 100644 index 0000000000000000000000000000000000000000..65862e9989e51e47e5e9d0c42985a77c2724e67f --- /dev/null +++ b/Revert-pci-introduce-PCIPASIDOps-to-PCIDevice.patch @@ -0,0 +1,104 @@ +From 87a125d3a175fd65f921dc7089450e13ce2ac457 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:49 +0800 +Subject: [PATCH 27/36] Revert "pci: introduce PCIPASIDOps to PCIDevice" + +This reverts commit c71485494970e7aa986be2b05bf7e2847017e264. + +Signed-off-by: Kunkun Jiang +--- + hw/pci/pci.c | 34 ---------------------------------- + include/hw/pci/pci.h | 11 ----------- + 2 files changed, 45 deletions(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 71076fff48..40e2516d99 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -2763,40 +2763,6 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) + bus->iommu_opaque = opaque; + } + +-void pci_setup_pasid_ops(PCIDevice *dev, PCIPASIDOps *ops) +-{ +- assert(ops && !dev->pasid_ops); +- dev->pasid_ops = ops; +-} +- +-bool pci_device_is_pasid_ops_set(PCIBus *bus, int32_t devfn) +-{ +- PCIDevice *dev; +- +- if (!bus) { +- return false; +- } +- +- dev = bus->devices[devfn]; +- return !!(dev && dev->pasid_ops); +-} +- +-int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, +- IOMMUConfig *config) +-{ +- PCIDevice *dev; +- +- if (!bus) { +- return -EINVAL; +- } +- +- dev = bus->devices[devfn]; +- if (dev && dev->pasid_ops && dev->pasid_ops->set_pasid_table) { +- return dev->pasid_ops->set_pasid_table(bus, devfn, config); +- } +- return -ENOENT; +-} +- + static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) + { + Range *range = opaque; +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index 4cf3dc6b43..5b36334a28 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -9,7 +9,6 @@ + + #include "hw/pci/pcie.h" + #include "qom/object.h" +-#include "hw/iommu/iommu.h" + + extern bool pci_available; + +@@ -266,11 +265,6 @@ struct PCIReqIDCache { + }; + typedef struct PCIReqIDCache PCIReqIDCache; + +-struct PCIPASIDOps { +- int (*set_pasid_table)(PCIBus *bus, int32_t devfn, IOMMUConfig *config); +-}; +-typedef struct PCIPASIDOps PCIPASIDOps; +- + struct PCIDevice { + DeviceState qdev; + bool partially_hotplugged; +@@ -367,7 +361,6 @@ struct PCIDevice { + /* ID of standby device in net_failover pair */ + char *failover_pair_id; + uint32_t acpi_index; +- PCIPASIDOps *pasid_ops; + }; + + void pci_register_bar(PCIDevice *pci_dev, int region_num, +@@ -505,10 +498,6 @@ typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); + AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); + void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); + +-void pci_setup_pasid_ops(PCIDevice *dev, PCIPASIDOps *ops); +-bool pci_device_is_pasid_ops_set(PCIBus *bus, int32_t devfn); +-int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, IOMMUConfig *config); +- + static inline void + pci_set_byte(uint8_t *config, uint8_t val) + { +-- +2.27.0 + diff --git a/Revert-qmp-add-command-to-query-used-memslots-of-vho.patch b/Revert-qmp-add-command-to-query-used-memslots-of-vho.patch new file mode 100644 index 0000000000000000000000000000000000000000..02f8797078723c92d08fabe7243a9cc1dbdfd5a5 --- /dev/null +++ b/Revert-qmp-add-command-to-query-used-memslots-of-vho.patch @@ -0,0 +1,133 @@ +From 92e9fb334c38cd21652ce8adde9ec01ab4412426 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Tue, 15 Feb 2022 15:18:17 +0800 +Subject: [PATCH] Revert "qmp: add command to query used memslots of vhost-net + and vhost-user" + +This reverts commit 1545a60a8b78490c7dc8909b7012bca63dba63cd. + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost-backend.c | 2 +- + hw/virtio/vhost-user.c | 2 +- + include/hw/virtio/vhost-backend.h | 2 -- + monitor/qmp-cmds.c | 12 ------------ + qapi/net.json | 18 ------------------ + qapi/pragma.json | 4 +--- + 6 files changed, 3 insertions(+), 37 deletions(-) + +diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c +index d8e1710758..2acfb750fd 100644 +--- a/hw/virtio/vhost-backend.c ++++ b/hw/virtio/vhost-backend.c +@@ -300,7 +300,7 @@ static void vhost_kernel_set_used_memslots(struct vhost_dev *dev) + vhost_kernel_used_memslots = dev->mem->nregions; + } + +-unsigned int vhost_kernel_get_used_memslots(void) ++static unsigned int vhost_kernel_get_used_memslots(void) + { + return vhost_kernel_used_memslots; + } +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 8f69a3b850..176cae9244 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -2544,7 +2544,7 @@ static void vhost_user_set_used_memslots(struct vhost_dev *dev) + vhost_user_used_memslots = counter; + } + +-unsigned int vhost_user_get_used_memslots(void) ++static unsigned int vhost_user_get_used_memslots(void) + { + return vhost_user_used_memslots; + } +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index 7bbc658161..a64708f456 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -190,6 +190,4 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, + + int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd); + +-unsigned int vhost_kernel_get_used_memslots(void); +-unsigned int vhost_user_get_used_memslots(void); + #endif /* VHOST_BACKEND_H */ +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index a138e7dd4b..d71beace6a 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -37,7 +37,6 @@ + #include "qapi/qapi-commands-machine.h" + #include "qapi/qapi-commands-misc.h" + #include "qapi/qapi-commands-ui.h" +-#include "qapi/qapi-commands-net.h" + #include "qapi/type-helpers.h" + #include "qapi/qmp/qerror.h" + #include "exec/ramlist.h" +@@ -45,7 +44,6 @@ + #include "hw/acpi/acpi_dev_interface.h" + #include "hw/intc/intc.h" + #include "hw/rdma/rdma.h" +-#include "hw/virtio/vhost-backend.h" + + NameInfo *qmp_query_name(Error **errp) + { +@@ -476,13 +474,3 @@ int64_t qmp_query_rtc_date_diff(Error **errp) + { + return get_rtc_date_diff(); + } +- +-uint32_t qmp_query_vhost_kernel_used_memslots(Error **errp) +-{ +- return vhost_kernel_get_used_memslots(); +-} +- +-uint32_t qmp_query_vhost_user_used_memslots(Error **errp) +-{ +- return vhost_user_get_used_memslots(); +-} +diff --git a/qapi/net.json b/qapi/net.json +index c9ff849eed..7fab2e7cd8 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -696,21 +696,3 @@ + ## + { 'event': 'FAILOVER_NEGOTIATED', + 'data': {'device-id': 'str'} } +- +-## +-# @query-vhost-kernel-used-memslots: +-# +-# Get vhost-kernel nic used memslots +-# +-# Since: 4.1 +-## +-{ 'command': 'query-vhost-kernel-used-memslots', 'returns': 'uint32' } +- +-## +-# @query-vhost-user-used-memslots: +-# +-# Get vhost-user nic used memslots +-# +-# Since: 4.1 +-## +-{ 'command': 'query-vhost-user-used-memslots', 'returns': 'uint32' } +diff --git a/qapi/pragma.json b/qapi/pragma.json +index d35c897acb..b37f6de445 100644 +--- a/qapi/pragma.json ++++ b/qapi/pragma.json +@@ -27,9 +27,7 @@ + 'query-tpm-models', + 'query-tpm-types', + 'ringbuf-read', +- 'query-rtc-date-diff', +- 'query-vhost-user-used-memslots', +- 'query-vhost-kernel-used-memslots' ], ++ 'query-rtc-date-diff' ], + # Externally visible types whose member names may use uppercase + 'member-name-exceptions': [ # visible in: + 'ACPISlotType', # query-acpi-ospm-status +-- +2.27.0 + diff --git a/Revert-update-linux-headers-Import-iommu.h.patch b/Revert-update-linux-headers-Import-iommu.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..8346a9bd39f8503913983b1ec165bf62529ad64c --- /dev/null +++ b/Revert-update-linux-headers-Import-iommu.h.patch @@ -0,0 +1,28 @@ +From 00e2515716eda5426bd999f812add9ff70204fc6 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:23:00 +0800 +Subject: [PATCH 36/36] Revert "update-linux-headers: Import iommu.h" + +This reverts commit 694acf3c321908d26ce508842b7bd076664ffbc6. + +Signed-off-by: Kunkun Jiang +--- + scripts/update-linux-headers.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh +index acde610733..fea4d6eb65 100755 +--- a/scripts/update-linux-headers.sh ++++ b/scripts/update-linux-headers.sh +@@ -144,7 +144,7 @@ done + + rm -rf "$output/linux-headers/linux" + mkdir -p "$output/linux-headers/linux" +-for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h iommu.h \ ++for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ + psci.h psp-sev.h userfaultfd.h mman.h; do + cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" + done +-- +2.27.0 + diff --git a/Revert-vfio-Add-vfio_prereg_listener_global_log_star.patch b/Revert-vfio-Add-vfio_prereg_listener_global_log_star.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b8f9670337759aad16489898f56edbc68948791 --- /dev/null +++ b/Revert-vfio-Add-vfio_prereg_listener_global_log_star.patch @@ -0,0 +1,65 @@ +From 92c1c6d689d9f501a3f242b085cbbcb22ee931b4 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:18 +0800 +Subject: [PATCH 04/36] Revert "vfio: Add + vfio_prereg_listener_global_log_start/stop in nested stage" + +This reverts commit 287c63ab540533f1f9642e753c091caa7e6e2511. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 65f3979492..20c820aa74 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1501,17 +1501,6 @@ static void vfio_listener_log_global_start(MemoryListener *listener) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); + +- /* For nested mode, vfio_prereg_listener is used to start dirty tracking */ +- if (container->iommu_type != VFIO_TYPE1_NESTING_IOMMU) { +- vfio_set_dirty_page_tracking(container, true); +- } +-} +- +-static void vfio_prereg_listener_log_global_start(MemoryListener *listener) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- + vfio_set_dirty_page_tracking(container, true); + } + +@@ -1519,17 +1508,6 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); + +- /* For nested mode, vfio_prereg_listener is used to stop dirty tracking */ +- if (container->iommu_type != VFIO_TYPE1_NESTING_IOMMU) { +- vfio_set_dirty_page_tracking(container, false); +- } +-} +- +-static void vfio_prereg_listener_log_global_stop(MemoryListener *listener) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- + vfio_set_dirty_page_tracking(container, false); + } + +@@ -1944,8 +1922,6 @@ static const MemoryListener vfio_memory_listener = { + static MemoryListener vfio_memory_prereg_listener = { + .region_add = vfio_prereg_listener_region_add, + .region_del = vfio_prereg_listener_region_del, +- .log_global_start = vfio_prereg_listener_log_global_start, +- .log_global_stop = vfio_prereg_listener_log_global_stop, + .log_sync = vfio_prereg_listener_log_sync, + .log_clear = vfio_prereg_listener_log_clear, + }; +-- +2.27.0 + diff --git a/Revert-vfio-Add-vfio_prereg_listener_log_clear-to-re.patch b/Revert-vfio-Add-vfio_prereg_listener_log_clear-to-re.patch new file mode 100644 index 0000000000000000000000000000000000000000..99a3a716230e9e48f7814b7b2b47198f33c25eaa --- /dev/null +++ b/Revert-vfio-Add-vfio_prereg_listener_log_clear-to-re.patch @@ -0,0 +1,81 @@ +From 609b216873bfa9377f624dabcf709930e1722ca7 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:20 +0800 +Subject: [PATCH 05/36] Revert "vfio: Add vfio_prereg_listener_log_clear to + re-enable mark dirty pages" + +This reverts commit 7086df6d90cd698a3e20cf4cf6e9a834f168cd8f. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 40 +--------------------------------------- + 1 file changed, 1 insertion(+), 39 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 20c820aa74..2506cd57ee 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1857,43 +1857,6 @@ static int vfio_physical_log_clear(VFIOContainer *container, + return ret; + } + +-static void vfio_prereg_listener_log_clear(MemoryListener *listener, +- MemoryRegionSection *section) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- +- if (!memory_region_is_ram(section->mr)) { +- return; +- } +- +- vfio_physical_log_clear(container, section); +-} +- +-static int vfio_clear_dirty_bitmap(VFIOContainer *container, +- MemoryRegionSection *section) +-{ +- if (memory_region_is_iommu(section->mr)) { +- /* +- * In nested mode, stage 2 (gpa->hpa) and stage 1 (giova->gpa) are +- * set up separately. It is inappropriate to pass 'giova' to kernel +- * to get dirty pages. We only need to focus on stage 2 mapping when +- * marking dirty pages. +- */ +- if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { +- return 0; +- } +- +- /* +- * TODO: x86. With the log_clear() interface added, x86 may inplement +- * its own method. +- */ +- } +- +- /* Here we assume that memory_region_is_ram(section->mr) == true */ +- return vfio_physical_log_clear(container, section); +-} +- + static void vfio_listener_log_clear(MemoryListener *listener, + MemoryRegionSection *section) + { +@@ -1905,7 +1868,7 @@ static void vfio_listener_log_clear(MemoryListener *listener, + } + + if (vfio_devices_all_dirty_tracking(container)) { +- vfio_clear_dirty_bitmap(container, section); ++ vfio_physical_log_clear(container, section); + } + } + +@@ -1923,7 +1886,6 @@ static MemoryListener vfio_memory_prereg_listener = { + .region_add = vfio_prereg_listener_region_add, + .region_del = vfio_prereg_listener_region_del, + .log_sync = vfio_prereg_listener_log_sync, +- .log_clear = vfio_prereg_listener_log_clear, + }; + + static void vfio_listener_release(VFIOContainer *container) +-- +2.27.0 + diff --git a/Revert-vfio-Add-vfio_prereg_listener_log_sync-in-nes.patch b/Revert-vfio-Add-vfio_prereg_listener_log_sync-in-nes.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2def5f968e0bc667decc5ddd1b92e3a9bd63478 --- /dev/null +++ b/Revert-vfio-Add-vfio_prereg_listener_log_sync-in-nes.patch @@ -0,0 +1,68 @@ +From 13253899d93b287a7e8d78bdff48978f633eb279 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:22 +0800 +Subject: [PATCH 06/36] Revert "vfio: Add vfio_prereg_listener_log_sync in + nested stage" + +This reverts commit f4523389bf57593484308124e06d67855bb79315. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 27 --------------------------- + 1 file changed, 27 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 2506cd57ee..6136b1ef61 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1579,22 +1579,6 @@ static int vfio_dma_sync_ram_section_dirty_bitmap(VFIOContainer *container, + int128_get64(section->size), ram_addr); + } + +-static void vfio_prereg_listener_log_sync(MemoryListener *listener, +- MemoryRegionSection *section) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- +- if (!memory_region_is_ram(section->mr) || +- !container->dirty_pages_supported) { +- return; +- } +- +- if (vfio_devices_all_dirty_tracking(container)) { +- vfio_dma_sync_ram_section_dirty_bitmap(container, section); +- } +-} +- + typedef struct { + IOMMUNotifier n; + VFIOGuestIOMMU *giommu; +@@ -1682,16 +1666,6 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, + if (memory_region_is_iommu(section->mr)) { + VFIOGuestIOMMU *giommu; + +- /* +- * In nested mode, stage 2 (gpa->hpa) and stage 1 (giova->gpa) are +- * set up separately. It is inappropriate to pass 'giova' to kernel +- * to get dirty pages. We only need to focus on stage 2 mapping when +- * marking dirty pages. +- */ +- if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { +- return 0; +- } +- + QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { + if (MEMORY_REGION(giommu->iommu) == section->mr && + giommu->n.start == section->offset_within_region) { +@@ -1885,7 +1859,6 @@ static const MemoryListener vfio_memory_listener = { + static MemoryListener vfio_memory_prereg_listener = { + .region_add = vfio_prereg_listener_region_add, + .region_del = vfio_prereg_listener_region_del, +- .log_sync = vfio_prereg_listener_log_sync, + }; + + static void vfio_listener_release(VFIOContainer *container) +-- +2.27.0 + diff --git a/Revert-vfio-Force-nested-if-iommu-requires-it.patch b/Revert-vfio-Force-nested-if-iommu-requires-it.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f85d5fd14e303301cb8e4e6d1f9f7b5d6a4bb25 --- /dev/null +++ b/Revert-vfio-Force-nested-if-iommu-requires-it.patch @@ -0,0 +1,97 @@ +From bac64f79264fd95b349004dd20b4ef7e9944fcb7 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:47 +0800 +Subject: [PATCH 26/36] Revert "vfio: Force nested if iommu requires it" + +This reverts commit e7eef5af743a53f0415267ebe9bba2e5f0e05816. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 36 ++++++++---------------------------- + 1 file changed, 8 insertions(+), 28 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index d7533637c9..6cb91e7ffd 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -2045,38 +2045,27 @@ static void vfio_put_address_space(VFIOAddressSpace *space) + * vfio_get_iommu_type - selects the richest iommu_type (v2 first) + */ + static int vfio_get_iommu_type(VFIOContainer *container, +- bool want_nested, + Error **errp) + { +- int iommu_types[] = { VFIO_TYPE1_NESTING_IOMMU, +- VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, ++ int iommu_types[] = { VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, + VFIO_SPAPR_TCE_v2_IOMMU, VFIO_SPAPR_TCE_IOMMU }; +- int i, ret = -EINVAL; ++ int i; + + for (i = 0; i < ARRAY_SIZE(iommu_types); i++) { + if (ioctl(container->fd, VFIO_CHECK_EXTENSION, iommu_types[i])) { +- if (iommu_types[i] == VFIO_TYPE1_NESTING_IOMMU && !want_nested) { +- continue; +- } +- ret = iommu_types[i]; +- break; ++ return iommu_types[i]; + } + } +- if (ret < 0) { +- error_setg(errp, "No available IOMMU models"); +- } else if (want_nested && ret != VFIO_TYPE1_NESTING_IOMMU) { +- error_setg(errp, "Nested mode requested but not supported"); +- ret = -EINVAL; +- } +- return ret; ++ error_setg(errp, "No available IOMMU models"); ++ return -EINVAL; + } + + static int vfio_init_container(VFIOContainer *container, int group_fd, +- bool want_nested, Error **errp) ++ Error **errp) + { + int iommu_type, dirty_log_manual_clear, ret; + +- iommu_type = vfio_get_iommu_type(container, want_nested, errp); ++ iommu_type = vfio_get_iommu_type(container, errp); + if (iommu_type < 0) { + return iommu_type; + } +@@ -2188,14 +2177,6 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + VFIOContainer *container; + int ret, fd; + VFIOAddressSpace *space; +- IOMMUMemoryRegion *iommu_mr; +- bool nested = false; +- +- if (memory_region_is_iommu(as->root)) { +- iommu_mr = IOMMU_MEMORY_REGION(as->root); +- memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_VFIO_NESTED, +- (void *)&nested); +- } + + space = vfio_get_address_space(as); + +@@ -2276,7 +2257,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + QLIST_INIT(&container->vrdl_list); + QLIST_INIT(&container->dma_list); + +- ret = vfio_init_container(container, group->fd, nested, errp); ++ ret = vfio_init_container(container, group->fd, errp); + if (ret) { + goto free_container_exit; + } +@@ -2288,7 +2269,6 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + } + + switch (container->iommu_type) { +- case VFIO_TYPE1_NESTING_IOMMU: + case VFIO_TYPE1v2_IOMMU: + case VFIO_TYPE1_IOMMU: + { +-- +2.27.0 + diff --git a/Revert-vfio-Helper-to-get-IRQ-info-including-capabil.patch b/Revert-vfio-Helper-to-get-IRQ-info-including-capabil.patch new file mode 100644 index 0000000000000000000000000000000000000000..0f4cf227d52058122034ebc878d4c3c69e2c8afe --- /dev/null +++ b/Revert-vfio-Helper-to-get-IRQ-info-including-capabil.patch @@ -0,0 +1,177 @@ +From 1ab4bff7e5d82a16a0d004fd964819d092325776 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:41 +0800 +Subject: [PATCH 21/36] Revert "vfio: Helper to get IRQ info including + capabilities" + +This reverts commit a4336765c99a876743c0ead89997ad6f97d7b442. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 97 ----------------------------------- + hw/vfio/trace-events | 1 - + include/hw/vfio/vfio-common.h | 7 --- + 3 files changed, 105 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index d05a485808..1f78af121d 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1919,25 +1919,6 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + return true; + } + +-struct vfio_info_cap_header * +-vfio_get_irq_info_cap(struct vfio_irq_info *info, uint16_t id) +-{ +- struct vfio_info_cap_header *hdr; +- void *ptr = info; +- +- if (!(info->flags & VFIO_IRQ_INFO_FLAG_CAPS)) { +- return NULL; +- } +- +- for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { +- if (hdr->id == id) { +- return hdr; +- } +- } +- +- return NULL; +-} +- + static int vfio_setup_region_sparse_mmaps(VFIORegion *region, + struct vfio_region_info *info) + { +@@ -2906,33 +2887,6 @@ retry: + return 0; + } + +-int vfio_get_irq_info(VFIODevice *vbasedev, int index, +- struct vfio_irq_info **info) +-{ +- size_t argsz = sizeof(struct vfio_irq_info); +- +- *info = g_malloc0(argsz); +- +- (*info)->index = index; +-retry: +- (*info)->argsz = argsz; +- +- if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, *info)) { +- g_free(*info); +- *info = NULL; +- return -errno; +- } +- +- if ((*info)->argsz > argsz) { +- argsz = (*info)->argsz; +- *info = g_realloc(*info, argsz); +- +- goto retry; +- } +- +- return 0; +-} +- + int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, + uint32_t subtype, struct vfio_region_info **info) + { +@@ -2968,42 +2922,6 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, + return -ENODEV; + } + +-int vfio_get_dev_irq_info(VFIODevice *vbasedev, uint32_t type, +- uint32_t subtype, struct vfio_irq_info **info) +-{ +- int i; +- +- for (i = 0; i < vbasedev->num_irqs; i++) { +- struct vfio_info_cap_header *hdr; +- struct vfio_irq_info_cap_type *cap_type; +- +- if (vfio_get_irq_info(vbasedev, i, info)) { +- continue; +- } +- +- hdr = vfio_get_irq_info_cap(*info, VFIO_IRQ_INFO_CAP_TYPE); +- if (!hdr) { +- g_free(*info); +- continue; +- } +- +- cap_type = container_of(hdr, struct vfio_irq_info_cap_type, header); +- +- trace_vfio_get_dev_irq(vbasedev->name, i, +- cap_type->type, cap_type->subtype); +- +- if (cap_type->type == type && cap_type->subtype == subtype) { +- return 0; +- } +- +- g_free(*info); +- } +- +- *info = NULL; +- return -ENODEV; +-} +- +- + bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) + { + struct vfio_region_info *info = NULL; +@@ -3019,21 +2937,6 @@ bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) + return ret; + } + +-bool vfio_has_irq_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +-{ +- struct vfio_region_info *info = NULL; +- bool ret = false; +- +- if (!vfio_get_region_info(vbasedev, region, &info)) { +- if (vfio_get_region_info_cap(info, cap_type)) { +- ret = true; +- } +- g_free(info); +- } +- +- return ret; +-} +- + /* + * Interfaces for IBM EEH (Enhanced Error Handling) + */ +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index f5fe201ab5..35bd415d6d 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -117,7 +117,6 @@ vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Re + vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" + vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" + vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" +-vfio_get_dev_irq(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" + vfio_dma_unmap_overflow_workaround(void) "" + vfio_iommu_addr_inv_iotlb(int asid, uint64_t addr, uint64_t size, uint64_t nb_granules, bool leaf) "nested IOTLB invalidate asid=%d, addr=0x%"PRIx64" granule_size=0x%"PRIx64" nb_granules=0x%"PRIx64" leaf=%d" + vfio_iommu_asid_inv_iotlb(int asid) "nested IOTLB invalidate asid=%d" +diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h +index 7fdca26fa0..a838a939e4 100644 +--- a/include/hw/vfio/vfio-common.h ++++ b/include/hw/vfio/vfio-common.h +@@ -254,13 +254,6 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + unsigned int *avail); + struct vfio_info_cap_header * + vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); +-int vfio_get_irq_info(VFIODevice *vbasedev, int index, +- struct vfio_irq_info **info); +-int vfio_get_dev_irq_info(VFIODevice *vbasedev, uint32_t type, +- uint32_t subtype, struct vfio_irq_info **info); +-bool vfio_has_irq_cap(VFIODevice *vbasedev, int irq, uint16_t cap_type); +-struct vfio_info_cap_header * +-vfio_get_irq_info_cap(struct vfio_irq_info *info, uint16_t id); + #endif + extern const MemoryListener vfio_prereg_listener; + +-- +2.27.0 + diff --git a/Revert-vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM.patch b/Revert-vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM.patch new file mode 100644 index 0000000000000000000000000000000000000000..0a8be2846c4d1781ddde062dbec0580fd45e6c37 --- /dev/null +++ b/Revert-vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM.patch @@ -0,0 +1,277 @@ +From e73a30ce20cf0686e7a08e061f8afa5c8c385361 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:45 +0800 +Subject: [PATCH 24/36] Revert "vfio: Introduce helpers to DMA map/unmap a RAM + section" + +This reverts commit dab969657d8ff8b175856f91b035b74849cf69ba. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 206 ++++++++++++++++++------------------------- + hw/vfio/trace-events | 4 +- + 2 files changed, 87 insertions(+), 123 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index b3dc090840..d358789f19 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -922,130 +922,13 @@ hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end) + return NULL; + } + +-static int vfio_dma_map_ram_section(VFIOContainer *container, +- MemoryRegionSection *section, Error **err) +-{ +- VFIOHostDMAWindow *hostwin; +- Int128 llend, llsize; +- hwaddr iova, end; +- void *vaddr; +- int ret; +- +- assert(memory_region_is_ram(section->mr)); +- +- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); +- llend = int128_make64(section->offset_within_address_space); +- llend = int128_add(llend, section->size); +- llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); +- end = int128_get64(int128_sub(llend, int128_one())); +- +- vaddr = memory_region_get_ram_ptr(section->mr) + +- section->offset_within_region + +- (iova - section->offset_within_address_space); +- +- hostwin = hostwin_from_range(container, iova, end); +- if (!hostwin) { +- error_setg(err, "Container %p can't map guest IOVA region" +- " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); +- return -EFAULT; +- } +- +- trace_vfio_dma_map_ram(iova, end, vaddr); +- +- llsize = int128_sub(llend, int128_make64(iova)); +- +- if (memory_region_is_ram_device(section->mr)) { +- hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; +- +- if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) { +- trace_vfio_listener_region_add_no_dma_map( +- memory_region_name(section->mr), +- section->offset_within_address_space, +- int128_getlo(section->size), +- pgmask + 1); +- return 0; +- } +- } +- +- ret = vfio_dma_map(container, iova, int128_get64(llsize), +- vaddr, section->readonly); +- if (ret) { +- error_setg(err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", " +- "0x%"HWADDR_PRIx", %p) = %d (%m)", +- container, iova, int128_get64(llsize), vaddr, ret); +- if (memory_region_is_ram_device(section->mr)) { +- /* Allow unexpected mappings not to be fatal for RAM devices */ +- error_report_err(*err); +- return 0; +- } +- return ret; +- } +- return 0; +-} +- +-static void vfio_dma_unmap_ram_section(VFIOContainer *container, +- MemoryRegionSection *section) +-{ +- Int128 llend, llsize; +- hwaddr iova, end; +- bool try_unmap = true; +- 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_and(llend, int128_exts64(qemu_real_host_page_mask)); +- +- if (int128_ge(int128_make64(iova), llend)) { +- return; +- } +- end = int128_get64(int128_sub(llend, int128_one())); +- +- llsize = int128_sub(llend, int128_make64(iova)); +- +- trace_vfio_dma_unmap_ram(iova, end); +- +- if (memory_region_is_ram_device(section->mr)) { +- hwaddr pgmask; +- VFIOHostDMAWindow *hostwin = hostwin_from_range(container, iova, end); +- +- assert(hostwin); /* or region_add() would have failed */ +- +- pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; +- try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); +- } else if (memory_region_has_ram_discard_manager(section->mr)) { +- vfio_unregister_ram_discard_listener(container, section); +- /* Unregistering will trigger an unmap. */ +- try_unmap = false; +- } +- +- if (try_unmap) { +- if (int128_eq(llsize, int128_2_64())) { +- /* The unmap ioctl doesn't accept a full 64-bit span. */ +- llsize = int128_rshift(llsize, 1); +- ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); +- if (ret) { +- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " +- "0x%"HWADDR_PRIx") = %d (%m)", +- container, iova, int128_get64(llsize), ret); +- } +- iova += int128_get64(llsize); +- } +- ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); +- if (ret) { +- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " +- "0x%"HWADDR_PRIx") = %d (%m)", +- container, iova, int128_get64(llsize), ret); +- } +- } +-} +- + static void vfio_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); + hwaddr iova, end; +- Int128 llend; ++ Int128 llend, llsize; ++ void *vaddr; + int ret; + VFIOHostDMAWindow *hostwin; + Error *err = NULL; +@@ -1209,7 +1092,38 @@ static void vfio_listener_region_add(MemoryListener *listener, + return; + } + +- if (vfio_dma_map_ram_section(container, section, &err)) { ++ vaddr = memory_region_get_ram_ptr(section->mr) + ++ section->offset_within_region + ++ (iova - section->offset_within_address_space); ++ ++ trace_vfio_listener_region_add_ram(iova, end, vaddr); ++ ++ llsize = int128_sub(llend, int128_make64(iova)); ++ ++ if (memory_region_is_ram_device(section->mr)) { ++ hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; ++ ++ if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) { ++ trace_vfio_listener_region_add_no_dma_map( ++ memory_region_name(section->mr), ++ section->offset_within_address_space, ++ int128_getlo(section->size), ++ pgmask + 1); ++ return; ++ } ++ } ++ ++ ret = vfio_dma_map(container, iova, int128_get64(llsize), ++ vaddr, section->readonly); ++ if (ret) { ++ error_setg(&err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", " ++ "0x%"HWADDR_PRIx", %p) = %d (%m)", ++ container, iova, int128_get64(llsize), vaddr, ret); ++ if (memory_region_is_ram_device(section->mr)) { ++ /* Allow unexpected mappings not to be fatal for RAM devices */ ++ error_report_err(err); ++ return; ++ } + goto fail; + } + +@@ -1243,6 +1157,10 @@ static void vfio_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); ++ hwaddr iova, end; ++ Int128 llend, llsize; ++ int ret; ++ bool try_unmap = true; + + if (vfio_listener_skipped_section(section)) { + trace_vfio_listener_region_del_skip( +@@ -1282,7 +1200,53 @@ static void vfio_listener_region_del(MemoryListener *listener, + */ + } + +- vfio_dma_unmap_ram_section(container, section); ++ 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_and(llend, int128_exts64(qemu_real_host_page_mask)); ++ ++ if (int128_ge(int128_make64(iova), llend)) { ++ return; ++ } ++ end = int128_get64(int128_sub(llend, int128_one())); ++ ++ llsize = int128_sub(llend, int128_make64(iova)); ++ ++ trace_vfio_listener_region_del(iova, end); ++ ++ if (memory_region_is_ram_device(section->mr)) { ++ hwaddr pgmask; ++ VFIOHostDMAWindow *hostwin = hostwin_from_range(container, iova, end); ++ ++ assert(hostwin); /* or region_add() would have failed */ ++ ++ pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; ++ try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); ++ } else if (memory_region_has_ram_discard_manager(section->mr)) { ++ vfio_unregister_ram_discard_listener(container, section); ++ /* Unregistering will trigger an unmap. */ ++ try_unmap = false; ++ } ++ ++ if (try_unmap) { ++ if (int128_eq(llsize, int128_2_64())) { ++ /* The unmap ioctl doesn't accept a full 64-bit span. */ ++ llsize = int128_rshift(llsize, 1); ++ ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); ++ if (ret) { ++ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " ++ "0x%"HWADDR_PRIx") = %d (%m)", ++ container, iova, int128_get64(llsize), ret); ++ } ++ iova += int128_get64(llsize); ++ } ++ ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); ++ if (ret) { ++ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " ++ "0x%"HWADDR_PRIx") = %d (%m)", ++ container, iova, int128_get64(llsize), ret); ++ } ++ } + + memory_region_unref(section->mr); + +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index a37563a315..0ef1b5f4a6 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -99,10 +99,10 @@ vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "i + vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add 0x%"PRIx64" - 0x%"PRIx64 + vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" + vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 +-vfio_dma_map_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" ++vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" + vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" + vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 +-vfio_dma_unmap_ram(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 ++vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 + vfio_disconnect_container(int fd) "close container->fd=%d" + vfio_put_group(int fd) "close group->fd=%d" + vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" +-- +2.27.0 + diff --git a/Revert-vfio-Introduce-helpers-to-mark-dirty-pages-of.patch b/Revert-vfio-Introduce-helpers-to-mark-dirty-pages-of.patch new file mode 100644 index 0000000000000000000000000000000000000000..8285b070f6004fc37d9a34104ca0646cfbd45cc3 --- /dev/null +++ b/Revert-vfio-Introduce-helpers-to-mark-dirty-pages-of.patch @@ -0,0 +1,63 @@ +From 9664a2d7b040a41d75067f4c58bf72c705e4a13b Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:23 +0800 +Subject: [PATCH 07/36] Revert "vfio: Introduce helpers to mark dirty pages of + a RAM section" + +This reverts commit 1675d767aa9bd496178b4d74e01a40dbbd97eccb. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 22 ++++++++-------------- + 1 file changed, 8 insertions(+), 14 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 6136b1ef61..bdfcc854fe 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1566,19 +1566,6 @@ err_out: + return ret; + } + +-static int vfio_dma_sync_ram_section_dirty_bitmap(VFIOContainer *container, +- MemoryRegionSection *section) +-{ +- ram_addr_t ram_addr; +- +- ram_addr = memory_region_get_ram_addr(section->mr) + +- section->offset_within_region; +- +- return vfio_get_dirty_bitmap(container, +- REAL_HOST_PAGE_ALIGN(section->offset_within_address_space), +- int128_get64(section->size), ram_addr); +-} +- + typedef struct { + IOMMUNotifier n; + VFIOGuestIOMMU *giommu; +@@ -1663,6 +1650,8 @@ static int vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainer *container, + static int vfio_sync_dirty_bitmap(VFIOContainer *container, + MemoryRegionSection *section) + { ++ ram_addr_t ram_addr; ++ + if (memory_region_is_iommu(section->mr)) { + VFIOGuestIOMMU *giommu; + +@@ -1693,7 +1682,12 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, + return vfio_sync_ram_discard_listener_dirty_bitmap(container, section); + } + +- return vfio_dma_sync_ram_section_dirty_bitmap(container, section); ++ ram_addr = memory_region_get_ram_addr(section->mr) + ++ section->offset_within_region; ++ ++ return vfio_get_dirty_bitmap(container, ++ REAL_HOST_PAGE_ALIGN(section->offset_within_address_space), ++ int128_get64(section->size), ram_addr); + } + + static void vfio_listener_log_sync(MemoryListener *listener, +-- +2.27.0 + diff --git a/Revert-vfio-Introduce-hostwin_from_range-helper.patch b/Revert-vfio-Introduce-hostwin_from_range-helper.patch new file mode 100644 index 0000000000000000000000000000000000000000..b130eff19ee950478afbd3c1329b978783f0e920 --- /dev/null +++ b/Revert-vfio-Introduce-hostwin_from_range-helper.patch @@ -0,0 +1,84 @@ +From 66fce3f7e9754345cf53afe3efd1b5bb5e322399 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:46 +0800 +Subject: [PATCH 25/36] Revert "vfio: Introduce hostwin_from_range helper" + +This reverts commit 85232739b4852f1a51dde58c9007ed0deb17c2f2. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index d358789f19..d7533637c9 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -909,19 +909,6 @@ static void vfio_unregister_ram_discard_listener(VFIOContainer *container, + g_free(vrdl); + } + +-static VFIOHostDMAWindow * +-hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end) +-{ +- VFIOHostDMAWindow *hostwin; +- +- QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { +- if (hostwin->min_iova <= iova && end <= hostwin->max_iova) { +- return hostwin; +- } +- } +- return NULL; +-} +- + static void vfio_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) + { +@@ -931,6 +918,7 @@ static void vfio_listener_region_add(MemoryListener *listener, + void *vaddr; + int ret; + VFIOHostDMAWindow *hostwin; ++ bool hostwin_found; + Error *err = NULL; + + if (vfio_listener_skipped_section(section)) { +@@ -1023,8 +1011,15 @@ static void vfio_listener_region_add(MemoryListener *listener, + #endif + } + +- hostwin = hostwin_from_range(container, iova, end); +- if (!hostwin) { ++ hostwin_found = false; ++ QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { ++ if (hostwin->min_iova <= iova && end <= hostwin->max_iova) { ++ hostwin_found = true; ++ break; ++ } ++ } ++ ++ if (!hostwin_found) { + error_setg(&err, "Container %p can't map guest IOVA region" + " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); + goto fail; +@@ -1216,9 +1211,16 @@ static void vfio_listener_region_del(MemoryListener *listener, + + if (memory_region_is_ram_device(section->mr)) { + hwaddr pgmask; +- VFIOHostDMAWindow *hostwin = hostwin_from_range(container, iova, end); ++ VFIOHostDMAWindow *hostwin; ++ bool hostwin_found = false; + +- assert(hostwin); /* or region_add() would have failed */ ++ QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { ++ if (hostwin->min_iova <= iova && end <= hostwin->max_iova) { ++ hostwin_found = true; ++ break; ++ } ++ } ++ assert(hostwin_found); /* or region_add() would have failed */ + + pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; + try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); +-- +2.27.0 + diff --git a/Revert-vfio-Pass-stage-1-MSI-bindings-to-the-host.patch b/Revert-vfio-Pass-stage-1-MSI-bindings-to-the-host.patch new file mode 100644 index 0000000000000000000000000000000000000000..f8a574876bfa4f9175673a4cef14ab36ead80b0e --- /dev/null +++ b/Revert-vfio-Pass-stage-1-MSI-bindings-to-the-host.patch @@ -0,0 +1,260 @@ +From 17190414cd411d23f1fc14c3d44d7b9f210f12b0 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:42 +0800 +Subject: [PATCH 22/36] Revert "vfio: Pass stage 1 MSI bindings to the host" + +This reverts commit 8b4fbe869f8a1f510896c86067d2e4fc3dc82eb9. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 59 --------------------------- + hw/vfio/pci.c | 76 +---------------------------------- + hw/vfio/trace-events | 2 - + include/hw/vfio/vfio-common.h | 12 ------ + 4 files changed, 2 insertions(+), 147 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 1f78af121d..58f8a43a43 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -774,65 +774,6 @@ static void vfio_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) + } + } + +-int vfio_iommu_set_msi_binding(VFIOContainer *container, int n, +- IOMMUTLBEntry *iotlb) +-{ +- struct vfio_iommu_type1_set_msi_binding ustruct; +- VFIOMSIBinding *binding; +- int ret; +- +- QLIST_FOREACH(binding, &container->msibinding_list, next) { +- if (binding->index == n) { +- return 0; +- } +- } +- +- ustruct.argsz = sizeof(struct vfio_iommu_type1_set_msi_binding); +- ustruct.iova = iotlb->iova; +- ustruct.flags = VFIO_IOMMU_BIND_MSI; +- ustruct.gpa = iotlb->translated_addr; +- ustruct.size = iotlb->addr_mask + 1; +- ret = ioctl(container->fd, VFIO_IOMMU_SET_MSI_BINDING , &ustruct); +- if (ret) { +- error_report("%s: failed to register the stage1 MSI binding (%m)", +- __func__); +- return ret; +- } +- binding = g_new0(VFIOMSIBinding, 1); +- binding->iova = ustruct.iova; +- binding->gpa = ustruct.gpa; +- binding->size = ustruct.size; +- binding->index = n; +- +- QLIST_INSERT_HEAD(&container->msibinding_list, binding, next); +- return 0; +-} +- +-int vfio_iommu_unset_msi_binding(VFIOContainer *container, int n) +-{ +- struct vfio_iommu_type1_set_msi_binding ustruct; +- VFIOMSIBinding *binding, *tmp; +- int ret; +- +- ustruct.argsz = sizeof(struct vfio_iommu_type1_set_msi_binding); +- QLIST_FOREACH_SAFE(binding, &container->msibinding_list, next, tmp) { +- if (binding->index != n) { +- continue; +- } +- ustruct.flags = VFIO_IOMMU_UNBIND_MSI; +- ustruct.iova = binding->iova; +- ret = ioctl(container->fd, VFIO_IOMMU_SET_MSI_BINDING , &ustruct); +- if (ret) { +- error_report("Failed to unregister the stage1 MSI binding " +- "for iova=0x%"PRIx64" (%m)", binding->iova); +- } +- QLIST_REMOVE(binding, next); +- g_free(binding); +- return ret; +- } +- return 0; +-} +- + static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) + { + VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 99c52a0944..ae5e014e5d 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -365,65 +365,6 @@ static void vfio_msi_interrupt(void *opaque) + notify(&vdev->pdev, nr); + } + +-static bool vfio_iommu_require_msi_binding(IOMMUMemoryRegion *iommu_mr) +-{ +- bool msi_translate = false, nested = false; +- +- memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_MSI_TRANSLATE, +- (void *)&msi_translate); +- memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_VFIO_NESTED, +- (void *)&nested); +- if (!nested || !msi_translate) { +- return false; +- } +- return true; +-} +- +-static int vfio_register_msi_binding(VFIOPCIDevice *vdev, +- int vector_n, bool set) +-{ +- VFIOContainer *container = vdev->vbasedev.group->container; +- PCIDevice *dev = &vdev->pdev; +- AddressSpace *as = pci_device_iommu_address_space(dev); +- IOMMUMemoryRegionClass *imrc; +- IOMMUMemoryRegion *iommu_mr; +- IOMMUTLBEntry entry; +- MSIMessage msg; +- +- if (as == &address_space_memory) { +- return 0; +- } +- +- iommu_mr = IOMMU_MEMORY_REGION(as->root); +- if (!vfio_iommu_require_msi_binding(iommu_mr)) { +- return 0; +- } +- +- /* MSI doorbell address is translated by an IOMMU */ +- +- if (!set) { /* unregister */ +- trace_vfio_unregister_msi_binding(vdev->vbasedev.name, vector_n); +- +- return vfio_iommu_unset_msi_binding(container, vector_n); +- } +- +- msg = pci_get_msi_message(dev, vector_n); +- imrc = memory_region_get_iommu_class_nocheck(iommu_mr); +- +- rcu_read_lock(); +- entry = imrc->translate(iommu_mr, msg.address, IOMMU_WO, 0); +- rcu_read_unlock(); +- +- if (entry.perm == IOMMU_NONE) { +- return -ENOENT; +- } +- +- trace_vfio_register_msi_binding(vdev->vbasedev.name, vector_n, +- msg.address, entry.translated_addr); +- +- return vfio_iommu_set_msi_binding(container, vector_n, &entry); +-} +- + static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + { + struct vfio_irq_set *irq_set; +@@ -441,7 +382,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + fds = (int32_t *)&irq_set->data; + + for (i = 0; i < vdev->nr_vectors; i++) { +- int ret, fd = -1; ++ int fd = -1; + + /* + * MSI vs MSI-X - The guest has direct access to MSI mask and pending +@@ -450,12 +391,6 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + * KVM signaling path only when configured and unmasked. + */ + if (vdev->msi_vectors[i].use) { +- ret = vfio_register_msi_binding(vdev, i, true); +- if (ret) { +- error_report("%s failed to register S1 MSI binding " +- "for vector %d(%d)", vdev->vbasedev.name, i, ret); +- goto out; +- } + if (vdev->msi_vectors[i].virq < 0 || + (msix && msix_is_masked(&vdev->pdev, i))) { + fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt); +@@ -469,7 +404,6 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + +-out: + g_free(irq_set); + + return ret; +@@ -784,8 +718,7 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) + + static void vfio_msix_disable(VFIOPCIDevice *vdev) + { +- int ret, i; +- ++ int i; + + msix_unset_vector_notifiers(&vdev->pdev); + +@@ -797,11 +730,6 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) + if (vdev->msi_vectors[i].use) { + vfio_msix_vector_release(&vdev->pdev, i); + msix_vector_unuse(&vdev->pdev, i); +- ret = vfio_register_msi_binding(vdev, i, false); +- if (ret) { +- error_report("%s: failed to unregister S1 MSI binding " +- "for vector %d(%d)", vdev->vbasedev.name, i, ret); +- } + } + } + +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index 35bd415d6d..20069935f5 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -120,8 +120,6 @@ vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype + vfio_dma_unmap_overflow_workaround(void) "" + vfio_iommu_addr_inv_iotlb(int asid, uint64_t addr, uint64_t size, uint64_t nb_granules, bool leaf) "nested IOTLB invalidate asid=%d, addr=0x%"PRIx64" granule_size=0x%"PRIx64" nb_granules=0x%"PRIx64" leaf=%d" + vfio_iommu_asid_inv_iotlb(int asid) "nested IOTLB invalidate asid=%d" +-vfio_register_msi_binding(const char *name, int vector, uint64_t giova, uint64_t gdb) "%s: register vector %d gIOVA=0x%"PRIx64 "-> gDB=0x%"PRIx64" stage 1 mapping" +-vfio_unregister_msi_binding(const char *name, int vector) "%s: unregister vector %d stage 1 mapping" + + # platform.c + vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" +diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h +index a838a939e4..0234f5e1b1 100644 +--- a/include/hw/vfio/vfio-common.h ++++ b/include/hw/vfio/vfio-common.h +@@ -74,14 +74,6 @@ typedef struct VFIOAddressSpace { + QLIST_ENTRY(VFIOAddressSpace) list; + } VFIOAddressSpace; + +-typedef struct VFIOMSIBinding { +- int index; +- hwaddr iova; +- hwaddr gpa; +- hwaddr size; +- QLIST_ENTRY(VFIOMSIBinding) next; +-} VFIOMSIBinding; +- + struct VFIOGroup; + + typedef struct VFIODMARange { +@@ -111,7 +103,6 @@ typedef struct VFIOContainer { + QLIST_HEAD(, VFIOGroup) group_list; + QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; + QLIST_HEAD(, VFIODMARange) dma_list; +- QLIST_HEAD(, VFIOMSIBinding) msibinding_list; + QLIST_ENTRY(VFIOContainer) next; + } VFIOContainer; + +@@ -231,9 +222,6 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); + void vfio_put_group(VFIOGroup *group); + int vfio_get_device(VFIOGroup *group, const char *name, + VFIODevice *vbasedev, Error **errp); +-int vfio_iommu_set_msi_binding(VFIOContainer *container, int n, +- IOMMUTLBEntry *entry); +-int vfio_iommu_unset_msi_binding(VFIOContainer *container, int n); + + extern const MemoryRegionOps vfio_region_ops; + typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; +-- +2.27.0 + diff --git a/Revert-vfio-Set-up-nested-stage-mappings.patch b/Revert-vfio-Set-up-nested-stage-mappings.patch new file mode 100644 index 0000000000000000000000000000000000000000..46f0127531cdefaa50d380f52c7633ef6b9332d9 --- /dev/null +++ b/Revert-vfio-Set-up-nested-stage-mappings.patch @@ -0,0 +1,266 @@ +From 72b7903e406b7011ccba7a3ebbdfe790b421e9fc Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:43 +0800 +Subject: [PATCH 23/36] Revert "vfio: Set up nested stage mappings" + +This reverts commit 96581a5ee46e89dbc9e1ebe247b00adefb1c7a41. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 139 ++----------------------------------------- + hw/vfio/pci.c | 21 ------- + hw/vfio/trace-events | 2 - + 3 files changed, 5 insertions(+), 157 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 58f8a43a43..b3dc090840 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -707,73 +707,6 @@ static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + return true; + } + +-/* Propagate a guest IOTLB invalidation to the host (nested mode) */ +-static void vfio_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +-{ +- VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); +- struct vfio_iommu_type1_cache_invalidate ustruct = {}; +- VFIOContainer *container = giommu->container; +- int ret; +- +- assert(iotlb->perm == IOMMU_NONE); +- +- ustruct.argsz = sizeof(ustruct); +- ustruct.flags = 0; +- ustruct.info.argsz = sizeof(struct iommu_cache_invalidate_info); +- ustruct.info.version = IOMMU_CACHE_INVALIDATE_INFO_VERSION_1; +- ustruct.info.cache = IOMMU_CACHE_INV_TYPE_IOTLB; +- +- switch (iotlb->granularity) { +- case IOMMU_INV_GRAN_DOMAIN: +- ustruct.info.granularity = IOMMU_INV_GRANU_DOMAIN; +- break; +- case IOMMU_INV_GRAN_PASID: +- { +- struct iommu_inv_pasid_info *pasid_info; +- int archid = -1; +- +- pasid_info = &ustruct.info.granu.pasid_info; +- ustruct.info.granularity = IOMMU_INV_GRANU_PASID; +- if (iotlb->flags & IOMMU_INV_FLAGS_ARCHID) { +- pasid_info->flags |= IOMMU_INV_ADDR_FLAGS_ARCHID; +- archid = iotlb->arch_id; +- } +- pasid_info->archid = archid; +- trace_vfio_iommu_asid_inv_iotlb(archid); +- break; +- } +- case IOMMU_INV_GRAN_ADDR: +- { +- hwaddr start = iotlb->iova + giommu->iommu_offset; +- struct iommu_inv_addr_info *addr_info; +- size_t size = iotlb->addr_mask + 1; +- int archid = -1; +- +- addr_info = &ustruct.info.granu.addr_info; +- ustruct.info.granularity = IOMMU_INV_GRANU_ADDR; +- if (iotlb->leaf) { +- addr_info->flags |= IOMMU_INV_ADDR_FLAGS_LEAF; +- } +- if (iotlb->flags & IOMMU_INV_FLAGS_ARCHID) { +- addr_info->flags |= IOMMU_INV_ADDR_FLAGS_ARCHID; +- archid = iotlb->arch_id; +- } +- addr_info->archid = archid; +- addr_info->addr = start; +- addr_info->granule_size = size; +- addr_info->nb_granules = 1; +- trace_vfio_iommu_addr_inv_iotlb(archid, start, size, +- 1, iotlb->leaf); +- break; +- } +- } +- +- ret = ioctl(container->fd, VFIO_IOMMU_CACHE_INVALIDATE, &ustruct); +- if (ret) { +- error_report("%p: failed to invalidate CACHE (%d)", container, ret); +- } +-} +- + static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) + { + VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); +@@ -1107,35 +1040,6 @@ static void vfio_dma_unmap_ram_section(VFIOContainer *container, + } + } + +-static void vfio_prereg_listener_region_add(MemoryListener *listener, +- MemoryRegionSection *section) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- Error *err = NULL; +- +- if (!memory_region_is_ram(section->mr)) { +- return; +- } +- +- vfio_dma_map_ram_section(container, section, &err); +- if (err) { +- error_report_err(err); +- } +-} +-static void vfio_prereg_listener_region_del(MemoryListener *listener, +- MemoryRegionSection *section) +-{ +- VFIOContainer *container = +- container_of(listener, VFIOContainer, prereg_listener); +- +- if (!memory_region_is_ram(section->mr)) { +- return; +- } +- +- vfio_dma_unmap_ram_section(container, section); +-} +- + static void vfio_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) + { +@@ -1246,10 +1150,9 @@ static void vfio_listener_region_add(MemoryListener *listener, + memory_region_ref(section->mr); + + if (memory_region_is_iommu(section->mr)) { +- IOMMUNotify notify; + VFIOGuestIOMMU *giommu; + IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); +- int iommu_idx, flags; ++ int iommu_idx; + + trace_vfio_listener_region_add_iommu(iova, end); + /* +@@ -1268,18 +1171,8 @@ static void vfio_listener_region_add(MemoryListener *listener, + llend = int128_sub(llend, int128_one()); + iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, + MEMTXATTRS_UNSPECIFIED); +- +- if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { +- /* IOTLB unmap notifier to propagate guest IOTLB invalidations */ +- flags = IOMMU_NOTIFIER_UNMAP; +- notify = vfio_iommu_unmap_notify; +- } else { +- /* MAP/UNMAP IOTLB notifier */ +- flags = IOMMU_NOTIFIER_IOTLB_EVENTS; +- notify = vfio_iommu_map_notify; +- } +- +- iommu_notifier_init(&giommu->n, notify, flags, ++ iommu_notifier_init(&giommu->n, vfio_iommu_map_notify, ++ IOMMU_NOTIFIER_IOTLB_EVENTS, + section->offset_within_region, + int128_get64(llend), + iommu_idx); +@@ -1299,9 +1192,7 @@ static void vfio_listener_region_add(MemoryListener *listener, + goto fail; + } + QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); +- if (flags & IOMMU_NOTIFIER_MAP) { +- memory_region_iommu_replay(giommu->iommu, &giommu->n); +- } ++ memory_region_iommu_replay(giommu->iommu, &giommu->n); + + return; + } +@@ -1781,16 +1672,10 @@ static const MemoryListener vfio_memory_listener = { + .log_clear = vfio_listener_log_clear, + }; + +-static MemoryListener vfio_memory_prereg_listener = { +- .region_add = vfio_prereg_listener_region_add, +- .region_del = vfio_prereg_listener_region_del, +-}; +- + static void vfio_listener_release(VFIOContainer *container) + { + memory_listener_unregister(&container->listener); +- if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU || +- container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { ++ if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { + memory_listener_unregister(&container->prereg_listener); + } + } +@@ -2466,20 +2351,6 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + vfio_get_iommu_info_migration(container, info); + } + g_free(info); +- +- if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { +- container->prereg_listener = vfio_memory_prereg_listener; +- memory_listener_register(&container->prereg_listener, +- &address_space_memory); +- if (container->error) { +- memory_listener_unregister(&container->prereg_listener); +- ret = -1; +- error_propagate_prepend(errp, container->error, +- "RAM memory listener initialization failed " +- "for container"); +- goto free_container_exit; +- } +- } + break; + } + case VFIO_SPAPR_TCE_v2_IOMMU: +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index ae5e014e5d..7b45353ce2 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2797,25 +2797,6 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) + vdev->req_enabled = false; + } + +-static int vfio_iommu_set_pasid_table(PCIBus *bus, int32_t devfn, +- IOMMUConfig *config) +-{ +- PCIDevice *pdev = bus->devices[devfn]; +- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); +- VFIOContainer *container = vdev->vbasedev.group->container; +- struct vfio_iommu_type1_set_pasid_table info; +- +- info.argsz = sizeof(info); +- info.flags = VFIO_PASID_TABLE_FLAG_SET; +- memcpy(&info.config, &config->pasid_cfg, sizeof(config->pasid_cfg)); +- +- return ioctl(container->fd, VFIO_IOMMU_SET_PASID_TABLE, &info); +-} +- +-static PCIPASIDOps vfio_pci_pasid_ops = { +- .set_pasid_table = vfio_iommu_set_pasid_table, +-}; +- + static void vfio_realize(PCIDevice *pdev, Error **errp) + { + VFIOPCIDevice *vdev = VFIO_PCI(pdev); +@@ -3127,8 +3108,6 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + vfio_register_req_notifier(vdev); + vfio_setup_resetfn_quirk(vdev); + +- pci_setup_pasid_ops(pdev, &vfio_pci_pasid_ops); +- + return; + + out_deregister: +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index 20069935f5..a37563a315 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -118,8 +118,6 @@ vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Devic + vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" + vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" + vfio_dma_unmap_overflow_workaround(void) "" +-vfio_iommu_addr_inv_iotlb(int asid, uint64_t addr, uint64_t size, uint64_t nb_granules, bool leaf) "nested IOTLB invalidate asid=%d, addr=0x%"PRIx64" granule_size=0x%"PRIx64" nb_granules=0x%"PRIx64" leaf=%d" +-vfio_iommu_asid_inv_iotlb(int asid) "nested IOTLB invalidate asid=%d" + + # platform.c + vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" +-- +2.27.0 + diff --git a/Revert-vfio-common-Add-address-alignment-check-in-vf.patch b/Revert-vfio-common-Add-address-alignment-check-in-vf.patch new file mode 100644 index 0000000000000000000000000000000000000000..6425c7b77f465c414eb85438cfcd061aefee34aa --- /dev/null +++ b/Revert-vfio-common-Add-address-alignment-check-in-vf.patch @@ -0,0 +1,44 @@ +From d0a16f250666ebd38c059ca86f161fade23640cf Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:09 +0800 +Subject: [PATCH 01/36] Revert "vfio/common: Add address alignment check in + vfio_listener_region_del" + +This reverts commit 00c553f53657bf4bc165d859187215dba7110246. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 4d45c2b625..89c49f5508 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1411,8 +1411,6 @@ static void vfio_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); +- hwaddr iova; +- Int128 llend; + + if (vfio_listener_skipped_section(section)) { + trace_vfio_listener_region_del_skip( +@@ -1462,14 +1460,6 @@ static void vfio_listener_region_del(MemoryListener *listener, + */ + } + +- 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_and(llend, int128_exts64(qemu_real_host_page_mask)); +- if (int128_ge(int128_make64(iova), llend)) { +- return; +- } +- + vfio_dma_unmap_ram_section(container, section); + + memory_region_unref(section->mr); +-- +2.27.0 + diff --git a/Revert-vfio-common-Avoid-unmap-ram-section-at-vfio_l.patch b/Revert-vfio-common-Avoid-unmap-ram-section-at-vfio_l.patch new file mode 100644 index 0000000000000000000000000000000000000000..de4377c3412f60a7cadbb9f3dd34beafc57466b1 --- /dev/null +++ b/Revert-vfio-common-Avoid-unmap-ram-section-at-vfio_l.patch @@ -0,0 +1,37 @@ +From 2dc27b19fd8a17b23b112e84b9d7286d8c5f30ca Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:25 +0800 +Subject: [PATCH 08/36] Revert "vfio/common: Avoid unmap ram section at + vfio_listener_region_del() in nested mode" + +This reverts commit 9d7b782a0b2c5288e82f3064b4c5b7bf18887280. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index bdfcc854fe..d05a485808 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1441,16 +1441,6 @@ static void vfio_listener_region_del(MemoryListener *listener, + } + } + +- /* +- * In nested mode, stage 2 (gpa->hpa) and the stage 1 +- * (giova->gpa) are set separately. The ram section +- * will be unmapped in vfio_prereg_listener_region_del(). +- * Hence it doesn't need to unmap ram section here. +- */ +- if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { +- return; +- } +- + /* + * FIXME: We assume the one big unmap below is adequate to + * remove any individual page mappings in the IOMMU which +-- +2.27.0 + diff --git a/Revert-vfio-common-Fix-incorrect-address-alignment-i.patch b/Revert-vfio-common-Fix-incorrect-address-alignment-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..52a4c32f6c25b69b10dd5f370eb07a2b71f29d35 --- /dev/null +++ b/Revert-vfio-common-Fix-incorrect-address-alignment-i.patch @@ -0,0 +1,33 @@ +From b5cee7126a75ea0e1797760fd5d7dfd89028b8a8 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:14 +0800 +Subject: [PATCH 02/36] Revert "vfio/common: Fix incorrect address alignment in + vfio_dma_map_ram_section" + +This reverts commit c2a4ce033db6ab74256e28da382c797a98047d4b. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 89c49f5508..65f3979492 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1059,10 +1059,10 @@ static int vfio_dma_map_ram_section(VFIOContainer *container, + + assert(memory_region_is_ram(section->mr)); + +- iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space); ++ iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + llend = int128_make64(section->offset_within_address_space); + llend = int128_add(llend, section->size); +- llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); ++ llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); + end = int128_get64(int128_sub(llend, int128_one())); + + vaddr = memory_region_get_ram_ptr(section->mr) + +-- +2.27.0 + diff --git a/Revert-vfio-pci-Implement-return_page_response-page-.patch b/Revert-vfio-pci-Implement-return_page_response-page-.patch new file mode 100644 index 0000000000000000000000000000000000000000..ba345328c0ed5ced58b019945ebbe4bd4a8cce6b --- /dev/null +++ b/Revert-vfio-pci-Implement-return_page_response-page-.patch @@ -0,0 +1,194 @@ +From 50e365a162cb7dd39d724fa1c5823e82d184af3a Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:26 +0800 +Subject: [PATCH 09/36] Revert "vfio/pci: Implement return_page_response page + response callback" + +This reverts commit 6bbf810edebdb89a6958519ee3adfb1888520231. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/pci.c | 123 -------------------------------------------------- + hw/vfio/pci.h | 2 - + 2 files changed, 125 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 8e24f9c7d1..c54e62fe8f 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2693,61 +2693,6 @@ out: + g_free(fault_region_info); + } + +-static void vfio_init_fault_response_regions(VFIOPCIDevice *vdev, Error **errp) +-{ +- struct vfio_region_info *fault_region_info = NULL; +- struct vfio_region_info_cap_fault *cap_fault; +- VFIODevice *vbasedev = &vdev->vbasedev; +- struct vfio_info_cap_header *hdr; +- char *fault_region_name; +- int ret; +- +- ret = vfio_get_dev_region_info(&vdev->vbasedev, +- VFIO_REGION_TYPE_NESTED, +- VFIO_REGION_SUBTYPE_NESTED_DMA_FAULT_RESPONSE, +- &fault_region_info); +- if (ret) { +- goto out; +- } +- +- hdr = vfio_get_region_info_cap(fault_region_info, +- VFIO_REGION_INFO_CAP_DMA_FAULT_RESPONSE); +- if (!hdr) { +- error_setg(errp, "failed to retrieve DMA FAULT RESPONSE capability"); +- goto out; +- } +- cap_fault = container_of(hdr, struct vfio_region_info_cap_fault, +- header); +- if (cap_fault->version != 1) { +- error_setg(errp, "Unsupported DMA FAULT RESPONSE API version %d", +- cap_fault->version); +- goto out; +- } +- +- fault_region_name = g_strdup_printf("%s DMA FAULT RESPONSE %d", +- vbasedev->name, +- fault_region_info->index); +- +- ret = vfio_region_setup(OBJECT(vdev), vbasedev, +- &vdev->dma_fault_response_region, +- fault_region_info->index, +- fault_region_name); +- g_free(fault_region_name); +- if (ret) { +- error_setg_errno(errp, -ret, +- "failed to set up the DMA FAULT RESPONSE region %d", +- fault_region_info->index); +- goto out; +- } +- +- ret = vfio_region_mmap(&vdev->dma_fault_response_region); +- if (ret) { +- error_setg_errno(errp, -ret, "Failed to mmap the DMA FAULT RESPONSE queue"); +- } +-out: +- g_free(fault_region_info); +-} +- + static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) + { + VFIODevice *vbasedev = &vdev->vbasedev; +@@ -2823,12 +2768,6 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) + return; + } + +- vfio_init_fault_response_regions(vdev, &err); +- if (err) { +- error_propagate(errp, err); +- return; +- } +- + irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; + + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); +@@ -3007,68 +2946,8 @@ static int vfio_iommu_set_pasid_table(PCIBus *bus, int32_t devfn, + return ioctl(container->fd, VFIO_IOMMU_SET_PASID_TABLE, &info); + } + +-static int vfio_iommu_return_page_response(PCIBus *bus, int32_t devfn, +- IOMMUPageResponse *resp) +-{ +- PCIDevice *pdev = bus->devices[devfn]; +- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); +- struct iommu_page_response *response = &resp->resp; +- struct vfio_region_dma_fault_response header; +- struct iommu_page_response *queue; +- char *queue_buffer = NULL; +- ssize_t bytes; +- +- if (!vdev->dma_fault_response_region.mem) { +- return -EINVAL; +- } +- +- /* read the header */ +- bytes = pread(vdev->vbasedev.fd, &header, sizeof(header), +- vdev->dma_fault_response_region.fd_offset); +- if (bytes != sizeof(header)) { +- error_report("%s unable to read the fault region header (0x%lx)", +- __func__, bytes); +- return -1; +- } +- +- /* Normally the fault queue is mmapped */ +- queue = (struct iommu_page_response *)vdev->dma_fault_response_region.mmaps[0].mmap; +- if (!queue) { +- size_t queue_size = header.nb_entries * header.entry_size; +- +- error_report("%s: fault queue not mmapped: slower fault handling", +- vdev->vbasedev.name); +- +- queue_buffer = g_malloc(queue_size); +- bytes = pread(vdev->vbasedev.fd, queue_buffer, queue_size, +- vdev->dma_fault_response_region.fd_offset + header.offset); +- if (bytes != queue_size) { +- error_report("%s unable to read the fault queue (0x%lx)", +- __func__, bytes); +- return -1; +- } +- +- queue = (struct iommu_page_response *)queue_buffer; +- } +- /* deposit the new response in the queue and increment the head */ +- memcpy(queue + header.head, response, header.entry_size); +- +- vdev->fault_response_head_index = +- (vdev->fault_response_head_index + 1) % header.nb_entries; +- bytes = pwrite(vdev->vbasedev.fd, &vdev->fault_response_head_index, 4, +- vdev->dma_fault_response_region.fd_offset); +- if (bytes != 4) { +- error_report("%s unable to write the fault response region head index (0x%lx)", +- __func__, bytes); +- } +- g_free(queue_buffer); +- +- return 0; +-} +- + static PCIPASIDOps vfio_pci_pasid_ops = { + .set_pasid_table = vfio_iommu_set_pasid_table, +- .return_page_response = vfio_iommu_return_page_response, + }; + + static void vfio_dma_fault_notifier_handler(void *opaque) +@@ -3532,7 +3411,6 @@ static void vfio_instance_finalize(Object *obj) + vfio_display_finalize(vdev); + vfio_bars_finalize(vdev); + vfio_region_finalize(&vdev->dma_fault_region); +- vfio_region_finalize(&vdev->dma_fault_response_region); + g_free(vdev->emulated_config_bits); + g_free(vdev->rom); + /* +@@ -3554,7 +3432,6 @@ static void vfio_exitfn(PCIDevice *pdev) + vfio_unregister_err_notifier(vdev); + vfio_unregister_ext_irq_notifiers(vdev); + vfio_region_exit(&vdev->dma_fault_region); +- vfio_region_exit(&vdev->dma_fault_response_region); + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); +diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h +index 61b3bf1303..03ac8919ef 100644 +--- a/hw/vfio/pci.h ++++ b/hw/vfio/pci.h +@@ -147,8 +147,6 @@ struct VFIOPCIDevice { + VFIOPCIExtIRQ *ext_irqs; + VFIORegion dma_fault_region; + uint32_t fault_tail_index; +- VFIORegion dma_fault_response_region; +- uint32_t fault_response_head_index; + int (*resetfn)(struct VFIOPCIDevice *); + uint32_t vendor_id; + uint32_t device_id; +-- +2.27.0 + diff --git a/Revert-vfio-pci-Implement-the-DMA-fault-handler.patch b/Revert-vfio-pci-Implement-the-DMA-fault-handler.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e4ba3b6a611a88157a65d9a33c0f12098578169 --- /dev/null +++ b/Revert-vfio-pci-Implement-the-DMA-fault-handler.patch @@ -0,0 +1,93 @@ +From 013220b686022a2e4ddb6a3d50af467275d25070 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:37 +0800 +Subject: [PATCH 18/36] Revert "vfio/pci: Implement the DMA fault handler" + +This reverts commit d33cc7eccb68c6a1488804c94ff5c1197ee0fc6e. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/pci.c | 50 -------------------------------------------------- + hw/vfio/pci.h | 1 - + 2 files changed, 51 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index c54e62fe8f..76bc9d3506 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2953,60 +2953,10 @@ static PCIPASIDOps vfio_pci_pasid_ops = { + static void vfio_dma_fault_notifier_handler(void *opaque) + { + VFIOPCIExtIRQ *ext_irq = opaque; +- VFIOPCIDevice *vdev = ext_irq->vdev; +- PCIDevice *pdev = &vdev->pdev; +- AddressSpace *as = pci_device_iommu_address_space(pdev); +- IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(as->root); +- struct vfio_region_dma_fault header; +- struct iommu_fault *queue; +- char *queue_buffer = NULL; +- ssize_t bytes; + + if (!event_notifier_test_and_clear(&ext_irq->notifier)) { + return; + } +- +- bytes = pread(vdev->vbasedev.fd, &header, sizeof(header), +- vdev->dma_fault_region.fd_offset); +- if (bytes != sizeof(header)) { +- error_report("%s unable to read the fault region header (0x%lx)", +- __func__, bytes); +- return; +- } +- +- /* Normally the fault queue is mmapped */ +- queue = (struct iommu_fault *)vdev->dma_fault_region.mmaps[0].mmap; +- if (!queue) { +- size_t queue_size = header.nb_entries * header.entry_size; +- +- error_report("%s: fault queue not mmapped: slower fault handling", +- vdev->vbasedev.name); +- +- queue_buffer = g_malloc(queue_size); +- bytes = pread(vdev->vbasedev.fd, queue_buffer, queue_size, +- vdev->dma_fault_region.fd_offset + header.offset); +- if (bytes != queue_size) { +- error_report("%s unable to read the fault queue (0x%lx)", +- __func__, bytes); +- return; +- } +- +- queue = (struct iommu_fault *)queue_buffer; +- } +- +- while (vdev->fault_tail_index != header.head) { +- memory_region_inject_faults(iommu_mr, 1, +- &queue[vdev->fault_tail_index]); +- vdev->fault_tail_index = +- (vdev->fault_tail_index + 1) % header.nb_entries; +- } +- bytes = pwrite(vdev->vbasedev.fd, &vdev->fault_tail_index, 4, +- vdev->dma_fault_region.fd_offset); +- if (bytes != 4) { +- error_report("%s unable to write the fault region tail index (0x%lx)", +- __func__, bytes); +- } +- g_free(queue_buffer); + } + + static int vfio_register_ext_irq_handler(VFIOPCIDevice *vdev, +diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h +index 03ac8919ef..eef91065f1 100644 +--- a/hw/vfio/pci.h ++++ b/hw/vfio/pci.h +@@ -146,7 +146,6 @@ struct VFIOPCIDevice { + EventNotifier req_notifier; + VFIOPCIExtIRQ *ext_irqs; + VFIORegion dma_fault_region; +- uint32_t fault_tail_index; + int (*resetfn)(struct VFIOPCIDevice *); + uint32_t vendor_id; + uint32_t device_id; +-- +2.27.0 + diff --git a/Revert-vfio-pci-Register-handler-for-iommu-fault.patch b/Revert-vfio-pci-Register-handler-for-iommu-fault.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ef811e63af8b80e771801d5576a2e03f4e1cd7a --- /dev/null +++ b/Revert-vfio-pci-Register-handler-for-iommu-fault.patch @@ -0,0 +1,161 @@ +From f32fc48313dadeb6469c00660bd96331e120030f Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:40 +0800 +Subject: [PATCH 20/36] Revert "vfio/pci: Register handler for iommu fault" + +This reverts commit 574455d1363e818905e05cd23ef0948e83a16a51. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/pci.c | 81 +-------------------------------------------------- + hw/vfio/pci.h | 7 ----- + 2 files changed, 1 insertion(+), 87 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 37a70932c6..99c52a0944 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2888,76 +2888,6 @@ static PCIPASIDOps vfio_pci_pasid_ops = { + .set_pasid_table = vfio_iommu_set_pasid_table, + }; + +-static void vfio_dma_fault_notifier_handler(void *opaque) +-{ +- VFIOPCIExtIRQ *ext_irq = opaque; +- +- if (!event_notifier_test_and_clear(&ext_irq->notifier)) { +- return; +- } +-} +- +-static int vfio_register_ext_irq_handler(VFIOPCIDevice *vdev, +- uint32_t type, uint32_t subtype, +- IOHandler *handler) +-{ +- int32_t fd, ext_irq_index, index; +- struct vfio_irq_info *irq_info; +- Error *err = NULL; +- EventNotifier *n; +- int ret; +- +- ret = vfio_get_dev_irq_info(&vdev->vbasedev, type, subtype, &irq_info); +- if (ret) { +- return ret; +- } +- index = irq_info->index; +- ext_irq_index = irq_info->index - VFIO_PCI_NUM_IRQS; +- g_free(irq_info); +- +- vdev->ext_irqs[ext_irq_index].vdev = vdev; +- vdev->ext_irqs[ext_irq_index].index = index; +- n = &vdev->ext_irqs[ext_irq_index].notifier; +- +- ret = event_notifier_init(n, 0); +- if (ret) { +- error_report("vfio: Unable to init event notifier for ext irq %d(%d)", +- ext_irq_index, ret); +- return ret; +- } +- +- fd = event_notifier_get_fd(n); +- qemu_set_fd_handler(fd, vfio_dma_fault_notifier_handler, NULL, +- &vdev->ext_irqs[ext_irq_index]); +- +- ret = vfio_set_irq_signaling(&vdev->vbasedev, index, 0, +- VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err); +- if (ret) { +- error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); +- qemu_set_fd_handler(fd, NULL, NULL, vdev); +- event_notifier_cleanup(n); +- } +- return ret; +-} +- +-static void vfio_unregister_ext_irq_notifiers(VFIOPCIDevice *vdev) +-{ +- VFIODevice *vbasedev = &vdev->vbasedev; +- Error *err = NULL; +- int i; +- +- for (i = 0; i < vbasedev->num_irqs - VFIO_PCI_NUM_IRQS; i++) { +- if (vfio_set_irq_signaling(vbasedev, i + VFIO_PCI_NUM_IRQS , 0, +- VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { +- error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); +- } +- qemu_set_fd_handler(event_notifier_get_fd(&vdev->ext_irqs[i].notifier), +- NULL, NULL, vdev); +- event_notifier_cleanup(&vdev->ext_irqs[i].notifier); +- } +- g_free(vdev->ext_irqs); +-} +- + static void vfio_realize(PCIDevice *pdev, Error **errp) + { + VFIOPCIDevice *vdev = VFIO_PCI(pdev); +@@ -2968,7 +2898,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + ssize_t len; + struct stat st; + int groupid; +- int i, ret, nb_ext_irqs; ++ int i, ret; + bool is_mdev; + + if (!vdev->vbasedev.sysfsdev) { +@@ -3056,11 +2986,6 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + goto error; + } + +- nb_ext_irqs = vdev->vbasedev.num_irqs - VFIO_PCI_NUM_IRQS; +- if (nb_ext_irqs > 0) { +- vdev->ext_irqs = g_new0(VFIOPCIExtIRQ, nb_ext_irqs); +- } +- + vfio_populate_device(vdev, &err); + if (err) { + error_propagate(errp, err); +@@ -3272,9 +3197,6 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + + vfio_register_err_notifier(vdev); + vfio_register_req_notifier(vdev); +- vfio_register_ext_irq_handler(vdev, VFIO_IRQ_TYPE_NESTED, +- VFIO_IRQ_SUBTYPE_DMA_FAULT, +- vfio_dma_fault_notifier_handler); + vfio_setup_resetfn_quirk(vdev); + + pci_setup_pasid_ops(pdev, &vfio_pci_pasid_ops); +@@ -3317,7 +3239,6 @@ static void vfio_exitfn(PCIDevice *pdev) + + vfio_unregister_req_notifier(vdev); + vfio_unregister_err_notifier(vdev); +- vfio_unregister_ext_irq_notifiers(vdev); + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); +diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h +index a8b06737fb..64777516d1 100644 +--- a/hw/vfio/pci.h ++++ b/hw/vfio/pci.h +@@ -114,12 +114,6 @@ typedef struct VFIOMSIXInfo { + unsigned long *pending; + } VFIOMSIXInfo; + +-typedef struct VFIOPCIExtIRQ { +- struct VFIOPCIDevice *vdev; +- EventNotifier notifier; +- uint32_t index; +-} VFIOPCIExtIRQ; +- + #define TYPE_VFIO_PCI "vfio-pci" + OBJECT_DECLARE_SIMPLE_TYPE(VFIOPCIDevice, VFIO_PCI) + +@@ -144,7 +138,6 @@ struct VFIOPCIDevice { + PCIHostDeviceAddress host; + EventNotifier err_notifier; + EventNotifier req_notifier; +- VFIOPCIExtIRQ *ext_irqs; + int (*resetfn)(struct VFIOPCIDevice *); + uint32_t vendor_id; + uint32_t device_id; +-- +2.27.0 + diff --git a/Revert-vfio-pci-Set-up-the-DMA-FAULT-region.patch b/Revert-vfio-pci-Set-up-the-DMA-FAULT-region.patch new file mode 100644 index 0000000000000000000000000000000000000000..eb3aa8a2c267be50450e9f839a5694e6da8b7d85 --- /dev/null +++ b/Revert-vfio-pci-Set-up-the-DMA-FAULT-region.patch @@ -0,0 +1,129 @@ +From 0e9cc7c0a60ace8baeab6e32f49770afbeec6f5d Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:38 +0800 +Subject: [PATCH 19/36] Revert "vfio/pci: Set up the DMA FAULT region" + +This reverts commit e701d0fef4fbb7935d6aa7d22d82eb2dcfee2431. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/pci.c | 64 --------------------------------------------------- + hw/vfio/pci.h | 1 - + 2 files changed, 65 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 76bc9d3506..37a70932c6 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2638,67 +2638,11 @@ int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) + return 0; + } + +-static void vfio_init_fault_regions(VFIOPCIDevice *vdev, Error **errp) +-{ +- struct vfio_region_info *fault_region_info = NULL; +- struct vfio_region_info_cap_fault *cap_fault; +- VFIODevice *vbasedev = &vdev->vbasedev; +- struct vfio_info_cap_header *hdr; +- char *fault_region_name; +- int ret; +- +- ret = vfio_get_dev_region_info(&vdev->vbasedev, +- VFIO_REGION_TYPE_NESTED, +- VFIO_REGION_SUBTYPE_NESTED_DMA_FAULT, +- &fault_region_info); +- if (ret) { +- goto out; +- } +- +- hdr = vfio_get_region_info_cap(fault_region_info, +- VFIO_REGION_INFO_CAP_DMA_FAULT); +- if (!hdr) { +- error_setg(errp, "failed to retrieve DMA FAULT capability"); +- goto out; +- } +- cap_fault = container_of(hdr, struct vfio_region_info_cap_fault, +- header); +- if (cap_fault->version != 1) { +- error_setg(errp, "Unsupported DMA FAULT API version %d", +- cap_fault->version); +- goto out; +- } +- +- fault_region_name = g_strdup_printf("%s DMA FAULT %d", +- vbasedev->name, +- fault_region_info->index); +- +- ret = vfio_region_setup(OBJECT(vdev), vbasedev, +- &vdev->dma_fault_region, +- fault_region_info->index, +- fault_region_name); +- g_free(fault_region_name); +- if (ret) { +- error_setg_errno(errp, -ret, +- "failed to set up the DMA FAULT region %d", +- fault_region_info->index); +- goto out; +- } +- +- ret = vfio_region_mmap(&vdev->dma_fault_region); +- if (ret) { +- error_setg_errno(errp, -ret, "Failed to mmap the DMA FAULT queue"); +- } +-out: +- g_free(fault_region_info); +-} +- + static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) + { + VFIODevice *vbasedev = &vdev->vbasedev; + struct vfio_region_info *reg_info; + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) }; +- Error *err = NULL; + int i, ret = -1; + + /* Sanity check device */ +@@ -2762,12 +2706,6 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) + } + } + +- vfio_init_fault_regions(vdev, &err); +- if (err) { +- error_propagate(errp, err); +- return; +- } +- + irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; + + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); +@@ -3360,7 +3298,6 @@ static void vfio_instance_finalize(Object *obj) + + vfio_display_finalize(vdev); + vfio_bars_finalize(vdev); +- vfio_region_finalize(&vdev->dma_fault_region); + g_free(vdev->emulated_config_bits); + g_free(vdev->rom); + /* +@@ -3381,7 +3318,6 @@ static void vfio_exitfn(PCIDevice *pdev) + vfio_unregister_req_notifier(vdev); + vfio_unregister_err_notifier(vdev); + vfio_unregister_ext_irq_notifiers(vdev); +- vfio_region_exit(&vdev->dma_fault_region); + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); +diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h +index eef91065f1..a8b06737fb 100644 +--- a/hw/vfio/pci.h ++++ b/hw/vfio/pci.h +@@ -145,7 +145,6 @@ struct VFIOPCIDevice { + EventNotifier err_notifier; + EventNotifier req_notifier; + VFIOPCIExtIRQ *ext_irqs; +- VFIORegion dma_fault_region; + int (*resetfn)(struct VFIOPCIDevice *); + uint32_t vendor_id; + uint32_t device_id; +-- +2.27.0 + diff --git a/Revert-vfio.h-and-iommu.h-header-update-against-5.10.patch b/Revert-vfio.h-and-iommu.h-header-update-against-5.10.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e27cd39e63c9fb0f9f506de5c400e0de7802b6e --- /dev/null +++ b/Revert-vfio.h-and-iommu.h-header-update-against-5.10.patch @@ -0,0 +1,703 @@ +From d3b9b26c9bb53b00b1441b3edad446ffea1ad8ff Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 18 Nov 2022 15:22:58 +0800 +Subject: [PATCH 35/36] Revert "vfio.h and iommu.h header update against 5.10" + +This reverts commit 36b65d7312a343cb636e6963b8262dce9420ebc6. + +Signed-off-by: Kunkun Jiang +--- + linux-headers/linux/iommu.h | 395 ------------------------------------ + linux-headers/linux/vfio.h | 220 +------------------- + 2 files changed, 2 insertions(+), 613 deletions(-) + delete mode 100644 linux-headers/linux/iommu.h + +diff --git a/linux-headers/linux/iommu.h b/linux-headers/linux/iommu.h +deleted file mode 100644 +index 773b7dc2d6..0000000000 +--- a/linux-headers/linux/iommu.h ++++ /dev/null +@@ -1,395 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +-/* +- * IOMMU user API definitions +- */ +- +-#ifndef IOMMU_H +-#define IOMMU_H +- +-#include +- +-#define IOMMU_FAULT_PERM_READ (1 << 0) /* read */ +-#define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */ +-#define IOMMU_FAULT_PERM_EXEC (1 << 2) /* exec */ +-#define IOMMU_FAULT_PERM_PRIV (1 << 3) /* privileged */ +- +-/* Generic fault types, can be expanded IRQ remapping fault */ +-enum iommu_fault_type { +- IOMMU_FAULT_DMA_UNRECOV = 1, /* unrecoverable fault */ +- IOMMU_FAULT_PAGE_REQ, /* page request fault */ +-}; +- +-enum iommu_fault_reason { +- IOMMU_FAULT_REASON_UNKNOWN = 0, +- +- /* Could not access the PASID table (fetch caused external abort) */ +- IOMMU_FAULT_REASON_PASID_FETCH, +- +- /* PASID entry is invalid or has configuration errors */ +- IOMMU_FAULT_REASON_BAD_PASID_ENTRY, +- +- /* +- * PASID is out of range (e.g. exceeds the maximum PASID +- * supported by the IOMMU) or disabled. +- */ +- IOMMU_FAULT_REASON_PASID_INVALID, +- +- /* +- * An external abort occurred fetching (or updating) a translation +- * table descriptor +- */ +- IOMMU_FAULT_REASON_WALK_EABT, +- +- /* +- * Could not access the page table entry (Bad address), +- * actual translation fault +- */ +- IOMMU_FAULT_REASON_PTE_FETCH, +- +- /* Protection flag check failed */ +- IOMMU_FAULT_REASON_PERMISSION, +- +- /* access flag check failed */ +- IOMMU_FAULT_REASON_ACCESS, +- +- /* Output address of a translation stage caused Address Size fault */ +- IOMMU_FAULT_REASON_OOR_ADDRESS, +-}; +- +-/** +- * struct iommu_fault_unrecoverable - Unrecoverable fault data +- * @reason: reason of the fault, from &enum iommu_fault_reason +- * @flags: parameters of this fault (IOMMU_FAULT_UNRECOV_* values) +- * @pasid: Process Address Space ID +- * @perm: requested permission access using by the incoming transaction +- * (IOMMU_FAULT_PERM_* values) +- * @addr: offending page address +- * @fetch_addr: address that caused a fetch abort, if any +- */ +-struct iommu_fault_unrecoverable { +- __u32 reason; +-#define IOMMU_FAULT_UNRECOV_PASID_VALID (1 << 0) +-#define IOMMU_FAULT_UNRECOV_ADDR_VALID (1 << 1) +-#define IOMMU_FAULT_UNRECOV_FETCH_ADDR_VALID (1 << 2) +- __u32 flags; +- __u32 pasid; +- __u32 perm; +- __u64 addr; +- __u64 fetch_addr; +-}; +- +-/** +- * struct iommu_fault_page_request - Page Request data +- * @flags: encodes whether the corresponding fields are valid and whether this +- * is the last page in group (IOMMU_FAULT_PAGE_REQUEST_* values). +- * When IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID is set, the page response +- * must have the same PASID value as the page request. When it is clear, +- * the page response should not have a PASID. +- * @pasid: Process Address Space ID +- * @grpid: Page Request Group Index +- * @perm: requested page permissions (IOMMU_FAULT_PERM_* values) +- * @addr: page address +- * @private_data: device-specific private information +- */ +-struct iommu_fault_page_request { +-#define IOMMU_FAULT_PAGE_REQUEST_PASID_VALID (1 << 0) +-#define IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE (1 << 1) +-#define IOMMU_FAULT_PAGE_REQUEST_PRIV_DATA (1 << 2) +-#define IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID (1 << 3) +- __u32 flags; +- __u32 pasid; +- __u32 grpid; +- __u32 perm; +- __u64 addr; +- __u64 private_data[2]; +-}; +- +-/** +- * struct iommu_fault - Generic fault data +- * @type: fault type from &enum iommu_fault_type +- * @padding: reserved for future use (should be zero) +- * @event: fault event, when @type is %IOMMU_FAULT_DMA_UNRECOV +- * @prm: Page Request message, when @type is %IOMMU_FAULT_PAGE_REQ +- * @padding2: sets the fault size to allow for future extensions +- */ +-struct iommu_fault { +- __u32 type; +- __u32 padding; +- union { +- struct iommu_fault_unrecoverable event; +- struct iommu_fault_page_request prm; +- __u8 padding2[56]; +- }; +-}; +- +-/** +- * enum iommu_page_response_code - Return status of fault handlers +- * @IOMMU_PAGE_RESP_SUCCESS: Fault has been handled and the page tables +- * populated, retry the access. This is "Success" in PCI PRI. +- * @IOMMU_PAGE_RESP_FAILURE: General error. Drop all subsequent faults from +- * this device if possible. This is "Response Failure" in PCI PRI. +- * @IOMMU_PAGE_RESP_INVALID: Could not handle this fault, don't retry the +- * access. This is "Invalid Request" in PCI PRI. +- */ +-enum iommu_page_response_code { +- IOMMU_PAGE_RESP_SUCCESS = 0, +- IOMMU_PAGE_RESP_INVALID, +- IOMMU_PAGE_RESP_FAILURE, +-}; +- +-/** +- * struct iommu_page_response - Generic page response information +- * @argsz: User filled size of this data +- * @version: API version of this structure +- * @flags: encodes whether the corresponding fields are valid +- * (IOMMU_FAULT_PAGE_RESPONSE_* values) +- * @pasid: Process Address Space ID +- * @grpid: Page Request Group Index +- * @code: response code from &enum iommu_page_response_code +- */ +-struct iommu_page_response { +- __u32 argsz; +-#define IOMMU_PAGE_RESP_VERSION_1 1 +- __u32 version; +-#define IOMMU_PAGE_RESP_PASID_VALID (1 << 0) +- __u32 flags; +- __u32 pasid; +- __u32 grpid; +- __u32 code; +-}; +- +-/* defines the granularity of the invalidation */ +-enum iommu_inv_granularity { +- IOMMU_INV_GRANU_DOMAIN, /* domain-selective invalidation */ +- IOMMU_INV_GRANU_PASID, /* PASID-selective invalidation */ +- IOMMU_INV_GRANU_ADDR, /* page-selective invalidation */ +- IOMMU_INV_GRANU_NR, /* number of invalidation granularities */ +-}; +- +-/** +- * struct iommu_inv_addr_info - Address Selective Invalidation Structure +- * +- * @flags: indicates the granularity of the address-selective invalidation +- * - If the PASID bit is set, the @pasid field is populated and the invalidation +- * relates to cache entries tagged with this PASID and matching the address +- * range. +- * - If ARCHID bit is set, @archid is populated and the invalidation relates +- * to cache entries tagged with this architecture specific ID and matching +- * the address range. +- * - Both PASID and ARCHID can be set as they may tag different caches. +- * - If neither PASID or ARCHID is set, global addr invalidation applies. +- * - The LEAF flag indicates whether only the leaf PTE caching needs to be +- * invalidated and other paging structure caches can be preserved. +- * @pasid: process address space ID +- * @archid: architecture-specific ID +- * @addr: first stage/level input address +- * @granule_size: page/block size of the mapping in bytes +- * @nb_granules: number of contiguous granules to be invalidated +- */ +-struct iommu_inv_addr_info { +-#define IOMMU_INV_ADDR_FLAGS_PASID (1 << 0) +-#define IOMMU_INV_ADDR_FLAGS_ARCHID (1 << 1) +-#define IOMMU_INV_ADDR_FLAGS_LEAF (1 << 2) +- __u32 flags; +- __u32 archid; +- __u64 pasid; +- __u64 addr; +- __u64 granule_size; +- __u64 nb_granules; +-}; +- +-/** +- * struct iommu_inv_pasid_info - PASID Selective Invalidation Structure +- * +- * @flags: indicates the granularity of the PASID-selective invalidation +- * - If the PASID bit is set, the @pasid field is populated and the invalidation +- * relates to cache entries tagged with this PASID and matching the address +- * range. +- * - If the ARCHID bit is set, the @archid is populated and the invalidation +- * relates to cache entries tagged with this architecture specific ID and +- * matching the address range. +- * - Both PASID and ARCHID can be set as they may tag different caches. +- * - At least one of PASID or ARCHID must be set. +- * @pasid: process address space ID +- * @archid: architecture-specific ID +- */ +-struct iommu_inv_pasid_info { +-#define IOMMU_INV_PASID_FLAGS_PASID (1 << 0) +-#define IOMMU_INV_PASID_FLAGS_ARCHID (1 << 1) +- __u32 flags; +- __u32 archid; +- __u64 pasid; +-}; +- +-/** +- * struct iommu_cache_invalidate_info - First level/stage invalidation +- * information +- * @argsz: User filled size of this data +- * @version: API version of this structure +- * @cache: bitfield that allows to select which caches to invalidate +- * @granularity: defines the lowest granularity used for the invalidation: +- * domain > PASID > addr +- * @padding: reserved for future use (should be zero) +- * @pasid_info: invalidation data when @granularity is %IOMMU_INV_GRANU_PASID +- * @addr_info: invalidation data when @granularity is %IOMMU_INV_GRANU_ADDR +- * +- * Not all the combinations of cache/granularity are valid: +- * +- * +--------------+---------------+---------------+---------------+ +- * | type / | DEV_IOTLB | IOTLB | PASID | +- * | granularity | | | cache | +- * +==============+===============+===============+===============+ +- * | DOMAIN | N/A | Y | Y | +- * +--------------+---------------+---------------+---------------+ +- * | PASID | Y | Y | Y | +- * +--------------+---------------+---------------+---------------+ +- * | ADDR | Y | Y | N/A | +- * +--------------+---------------+---------------+---------------+ +- * +- * Invalidations by %IOMMU_INV_GRANU_DOMAIN don't take any argument other than +- * @version and @cache. +- * +- * If multiple cache types are invalidated simultaneously, they all +- * must support the used granularity. +- */ +-struct iommu_cache_invalidate_info { +- __u32 argsz; +-#define IOMMU_CACHE_INVALIDATE_INFO_VERSION_1 1 +- __u32 version; +-/* IOMMU paging structure cache */ +-#define IOMMU_CACHE_INV_TYPE_IOTLB (1 << 0) /* IOMMU IOTLB */ +-#define IOMMU_CACHE_INV_TYPE_DEV_IOTLB (1 << 1) /* Device IOTLB */ +-#define IOMMU_CACHE_INV_TYPE_PASID (1 << 2) /* PASID cache */ +-#define IOMMU_CACHE_INV_TYPE_NR (3) +- __u8 cache; +- __u8 granularity; +- __u8 padding[6]; +- union { +- struct iommu_inv_pasid_info pasid_info; +- struct iommu_inv_addr_info addr_info; +- } granu; +-}; +- +-/** +- * struct iommu_gpasid_bind_data_vtd - Intel VT-d specific data on device and guest +- * SVA binding. +- * +- * @flags: VT-d PASID table entry attributes +- * @pat: Page attribute table data to compute effective memory type +- * @emt: Extended memory type +- * +- * Only guest vIOMMU selectable and effective options are passed down to +- * the host IOMMU. +- */ +-struct iommu_gpasid_bind_data_vtd { +-#define IOMMU_SVA_VTD_GPASID_SRE (1 << 0) /* supervisor request */ +-#define IOMMU_SVA_VTD_GPASID_EAFE (1 << 1) /* extended access enable */ +-#define IOMMU_SVA_VTD_GPASID_PCD (1 << 2) /* page-level cache disable */ +-#define IOMMU_SVA_VTD_GPASID_PWT (1 << 3) /* page-level write through */ +-#define IOMMU_SVA_VTD_GPASID_EMTE (1 << 4) /* extended mem type enable */ +-#define IOMMU_SVA_VTD_GPASID_CD (1 << 5) /* PASID-level cache disable */ +-#define IOMMU_SVA_VTD_GPASID_LAST (1 << 6) +- __u64 flags; +- __u32 pat; +- __u32 emt; +-}; +- +-#define IOMMU_SVA_VTD_GPASID_MTS_MASK (IOMMU_SVA_VTD_GPASID_CD | \ +- IOMMU_SVA_VTD_GPASID_EMTE | \ +- IOMMU_SVA_VTD_GPASID_PCD | \ +- IOMMU_SVA_VTD_GPASID_PWT) +- +-/** +- * struct iommu_gpasid_bind_data - Information about device and guest PASID binding +- * @argsz: User filled size of this data +- * @version: Version of this data structure +- * @format: PASID table entry format +- * @flags: Additional information on guest bind request +- * @gpgd: Guest page directory base of the guest mm to bind +- * @hpasid: Process address space ID used for the guest mm in host IOMMU +- * @gpasid: Process address space ID used for the guest mm in guest IOMMU +- * @addr_width: Guest virtual address width +- * @padding: Reserved for future use (should be zero) +- * @vtd: Intel VT-d specific data +- * +- * Guest to host PASID mapping can be an identity or non-identity, where guest +- * has its own PASID space. For non-identify mapping, guest to host PASID lookup +- * is needed when VM programs guest PASID into an assigned device. VMM may +- * trap such PASID programming then request host IOMMU driver to convert guest +- * PASID to host PASID based on this bind data. +- */ +-struct iommu_gpasid_bind_data { +- __u32 argsz; +-#define IOMMU_GPASID_BIND_VERSION_1 1 +- __u32 version; +-#define IOMMU_PASID_FORMAT_INTEL_VTD 1 +-#define IOMMU_PASID_FORMAT_LAST 2 +- __u32 format; +- __u32 addr_width; +-#define IOMMU_SVA_GPASID_VAL (1 << 0) /* guest PASID valid */ +- __u64 flags; +- __u64 gpgd; +- __u64 hpasid; +- __u64 gpasid; +- __u8 padding[8]; +- /* Vendor specific data */ +- union { +- struct iommu_gpasid_bind_data_vtd vtd; +- } vendor; +-}; +- +-/** +- * struct iommu_pasid_smmuv3 - ARM SMMUv3 Stream Table Entry stage 1 related +- * information +- * @version: API version of this structure +- * @s1fmt: STE s1fmt (format of the CD table: single CD, linear table +- * or 2-level table) +- * @s1dss: STE s1dss (specifies the behavior when @pasid_bits != 0 +- * and no PASID is passed along with the incoming transaction) +- * @padding: reserved for future use (should be zero) +- * +- * The PASID table is referred to as the Context Descriptor (CD) table on ARM +- * SMMUv3. Please refer to the ARM SMMU 3.x spec (ARM IHI 0070A) for full +- * details. +- */ +-struct iommu_pasid_smmuv3 { +-#define PASID_TABLE_SMMUV3_CFG_VERSION_1 1 +- __u32 version; +- __u8 s1fmt; +- __u8 s1dss; +- __u8 padding[2]; +-}; +- +-/** +- * struct iommu_pasid_table_config - PASID table data used to bind guest PASID +- * table to the host IOMMU +- * @argsz: User filled size of this data +- * @version: API version to prepare for future extensions +- * @base_ptr: guest physical address of the PASID table +- * @format: format of the PASID table +- * @pasid_bits: number of PASID bits used in the PASID table +- * @config: indicates whether the guest translation stage must +- * be translated, bypassed or aborted. +- * @padding: reserved for future use (should be zero) +- * @vendor_data.smmuv3: table information when @format is +- * %IOMMU_PASID_FORMAT_SMMUV3 +- */ +-struct iommu_pasid_table_config { +- __u32 argsz; +-#define PASID_TABLE_CFG_VERSION_1 1 +- __u32 version; +- __u64 base_ptr; +-#define IOMMU_PASID_FORMAT_SMMUV3 1 +- __u32 format; +- __u8 pasid_bits; +-#define IOMMU_PASID_CONFIG_TRANSLATE 1 +-#define IOMMU_PASID_CONFIG_BYPASS 2 +-#define IOMMU_PASID_CONFIG_ABORT 3 +- __u8 config; +- __u8 padding[2]; +- union { +- struct iommu_pasid_smmuv3 smmuv3; +- } vendor_data; +-}; +- +-#endif /* _UAPI_IOMMU_H */ +diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h +index cf8e208fac..f4ff038e8c 100644 +--- a/linux-headers/linux/vfio.h ++++ b/linux-headers/linux/vfio.h +@@ -14,7 +14,6 @@ + + #include + #include +-#include + + #define VFIO_API_VERSION 0 + +@@ -335,7 +334,6 @@ struct vfio_region_info_cap_type { + #define VFIO_REGION_TYPE_GFX (1) + #define VFIO_REGION_TYPE_CCW (2) + #define VFIO_REGION_TYPE_MIGRATION (3) +-#define VFIO_REGION_TYPE_NESTED (4) + + /* sub-types for VFIO_REGION_TYPE_PCI_* */ + +@@ -364,10 +362,6 @@ struct vfio_region_info_cap_type { + /* sub-types for VFIO_REGION_TYPE_GFX */ + #define VFIO_REGION_SUBTYPE_GFX_EDID (1) + +-/* sub-types for VFIO_REGION_TYPE_NESTED */ +-#define VFIO_REGION_SUBTYPE_NESTED_DMA_FAULT (1) +-#define VFIO_REGION_SUBTYPE_NESTED_DMA_FAULT_RESPONSE (2) +- + /** + * struct vfio_region_gfx_edid - EDID region layout. + * +@@ -727,30 +721,11 @@ struct vfio_irq_info { + #define VFIO_IRQ_INFO_MASKABLE (1 << 1) + #define VFIO_IRQ_INFO_AUTOMASKED (1 << 2) + #define VFIO_IRQ_INFO_NORESIZE (1 << 3) +-#define VFIO_IRQ_INFO_FLAG_CAPS (1 << 4) /* Info supports caps */ + __u32 index; /* IRQ index */ + __u32 count; /* Number of IRQs within this index */ +- __u32 cap_offset; /* Offset within info struct of first cap */ + }; + #define VFIO_DEVICE_GET_IRQ_INFO _IO(VFIO_TYPE, VFIO_BASE + 9) + +-/* +- * The irq type capability allows IRQs unique to a specific device or +- * class of devices to be exposed. +- * +- * The structures below define version 1 of this capability. +- */ +-#define VFIO_IRQ_INFO_CAP_TYPE 3 +- +-struct vfio_irq_info_cap_type { +- struct vfio_info_cap_header header; +- __u32 type; /* global per bus driver */ +- __u32 subtype; /* type specific */ +-}; +- +-#define VFIO_IRQ_TYPE_NESTED (1) +-#define VFIO_IRQ_SUBTYPE_DMA_FAULT (1) +- + /** + * VFIO_DEVICE_SET_IRQS - _IOW(VFIO_TYPE, VFIO_BASE + 10, struct vfio_irq_set) + * +@@ -852,8 +827,7 @@ enum { + VFIO_PCI_MSIX_IRQ_INDEX, + VFIO_PCI_ERR_IRQ_INDEX, + VFIO_PCI_REQ_IRQ_INDEX, +- VFIO_PCI_NUM_IRQS = 5 /* Fixed user ABI, IRQ indexes >=5 use */ +- /* device specific cap to define content */ ++ VFIO_PCI_NUM_IRQS + }; + + /* +@@ -1038,68 +1012,6 @@ struct vfio_device_feature { + */ + #define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) + +-/* +- * Capability exposed by the DMA fault region +- * @version: ABI version +- */ +-#define VFIO_REGION_INFO_CAP_DMA_FAULT 6 +- +-struct vfio_region_info_cap_fault { +- struct vfio_info_cap_header header; +- __u32 version; +-}; +- +-/* +- * Capability exposed by the DMA fault response region +- * @version: ABI version +- */ +-#define VFIO_REGION_INFO_CAP_DMA_FAULT_RESPONSE 7 +- +-struct vfio_region_info_cap_fault_response { +- struct vfio_info_cap_header header; +- __u32 version; +-}; +- +-/* +- * DMA Fault Region Layout +- * @tail: index relative to the start of the ring buffer at which the +- * consumer finds the next item in the buffer +- * @entry_size: fault ring buffer entry size in bytes +- * @nb_entries: max capacity of the fault ring buffer +- * @offset: ring buffer offset relative to the start of the region +- * @head: index relative to the start of the ring buffer at which the +- * producer (kernel) inserts items into the buffers +- */ +-struct vfio_region_dma_fault { +- /* Write-Only */ +- __u32 tail; +- /* Read-Only */ +- __u32 entry_size; +- __u32 nb_entries; +- __u32 offset; +- __u32 head; +-}; +- +-/* +- * DMA Fault Response Region Layout +- * @head: index relative to the start of the ring buffer at which the +- * producer (userspace) insert responses into the buffer +- * @entry_size: fault ring buffer entry size in bytes +- * @nb_entries: max capacity of the fault ring buffer +- * @offset: ring buffer offset relative to the start of the region +- * @tail: index relative to the start of the ring buffer at which the +- * consumer (kernel) finds the next item in the buffer +- */ +-struct vfio_region_dma_fault_response { +- /* Write-Only */ +- __u32 head; +- /* Read-Only */ +- __u32 entry_size; +- __u32 nb_entries; +- __u32 offset; +- __u32 tail; +-}; +- + /* -------- API for Type1 VFIO IOMMU -------- */ + + /** +@@ -1212,7 +1124,7 @@ struct vfio_iommu_type1_dma_map { + struct vfio_bitmap { + __u64 pgsize; /* page size for bitmap in bytes */ + __u64 size; /* in bytes */ +- __u64 *data; /* one bit per page */ ++ __u64 *data; /* one bit per page */ + }; + + /** +@@ -1338,134 +1250,6 @@ struct vfio_iommu_type1_dirty_bitmap_get { + + #define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) + +-/* +- * VFIO_IOMMU_BIND_PROCESS +- * +- * Allocate a PASID for a process address space, and use it to attach this +- * process to all devices in the container. Devices can then tag their DMA +- * traffic with the returned @pasid to perform transactions on the associated +- * virtual address space. Mapping and unmapping buffers is performed by standard +- * functions such as mmap and malloc. +- * +- * If flag is VFIO_IOMMU_BIND_PID, @pid contains the pid of a foreign process to +- * bind. Otherwise the current task is bound. Given that the caller owns the +- * device, setting this flag grants the caller read and write permissions on the +- * entire address space of foreign process described by @pid. Therefore, +- * permission to perform the bind operation on a foreign process is governed by +- * the ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check. See man ptrace(2) +- * for more information. +- * +- * On success, VFIO writes a Process Address Space ID (PASID) into @pasid. This +- * ID is unique to a process and can be used on all devices in the container. +- * +- * On fork, the child inherits the device fd and can use the bonds setup by its +- * parent. Consequently, the child has R/W access on the address spaces bound by +- * its parent. After an execv, the device fd is closed and the child doesn't +- * have access to the address space anymore. +- * +- * To remove a bond between process and container, VFIO_IOMMU_UNBIND ioctl is +- * issued with the same parameters. If a pid was specified in VFIO_IOMMU_BIND, +- * it should also be present for VFIO_IOMMU_UNBIND. Otherwise unbind the current +- * task from the container. +- */ +-struct vfio_iommu_type1_bind_process { +- __u32 flags; +-#define VFIO_IOMMU_BIND_PID (1 << 0) +- __u32 pasid; +- __s32 pid; +-}; +- +-/* +- * Only mode supported at the moment is VFIO_IOMMU_BIND_PROCESS, which takes +- * vfio_iommu_type1_bind_process in data. +- */ +-struct vfio_iommu_type1_bind { +- __u32 argsz; +- __u32 flags; +-#define VFIO_IOMMU_BIND_PROCESS (1 << 0) +- __u8 data[]; +-}; +- +-/* +- * VFIO_IOMMU_BIND - _IOWR(VFIO_TYPE, VFIO_BASE + 22, struct vfio_iommu_bind) +- * +- * Manage address spaces of devices in this container. Initially a TYPE1 +- * container can only have one address space, managed with +- * VFIO_IOMMU_MAP/UNMAP_DMA. +- * +- * An IOMMU of type VFIO_TYPE1_NESTING_IOMMU can be managed by both MAP/UNMAP +- * and BIND ioctls at the same time. MAP/UNMAP acts on the stage-2 (host) page +- * tables, and BIND manages the stage-1 (guest) page tables. Other types of +- * IOMMU may allow MAP/UNMAP and BIND to coexist, where MAP/UNMAP controls +- * non-PASID traffic and BIND controls PASID traffic. But this depends on the +- * underlying IOMMU architecture and isn't guaranteed. +- * +- * Availability of this feature depends on the device, its bus, the underlying +- * IOMMU and the CPU architecture. +- * +- * returns: 0 on success, -errno on failure. +- */ +-#define VFIO_IOMMU_BIND _IO(VFIO_TYPE, VFIO_BASE + 22) +- +-/* +- * VFIO_IOMMU_UNBIND - _IOWR(VFIO_TYPE, VFIO_BASE + 23, struct vfio_iommu_bind) +- * +- * Undo what was done by the corresponding VFIO_IOMMU_BIND ioctl. +- */ +-#define VFIO_IOMMU_UNBIND _IO(VFIO_TYPE, VFIO_BASE + 23) +- +-/* +- * VFIO_IOMMU_SET_PASID_TABLE - _IOWR(VFIO_TYPE, VFIO_BASE + 18, +- * struct vfio_iommu_type1_set_pasid_table) +- * +- * The SET operation passes a PASID table to the host while the +- * UNSET operation detaches the one currently programmed. It is +- * allowed to "SET" the table several times without unsetting as +- * long as the table config does not stay IOMMU_PASID_CONFIG_TRANSLATE. +- */ +-struct vfio_iommu_type1_set_pasid_table { +- __u32 argsz; +- __u32 flags; +-#define VFIO_PASID_TABLE_FLAG_SET (1 << 0) +-#define VFIO_PASID_TABLE_FLAG_UNSET (1 << 1) +- struct iommu_pasid_table_config config; /* used on SET */ +-}; +- +-#define VFIO_IOMMU_SET_PASID_TABLE _IO(VFIO_TYPE, VFIO_BASE + 18) +- +-/** +- * VFIO_IOMMU_CACHE_INVALIDATE - _IOWR(VFIO_TYPE, VFIO_BASE + 19, +- * struct vfio_iommu_type1_cache_invalidate) +- * +- * Propagate guest IOMMU cache invalidation to the host. +- */ +-struct vfio_iommu_type1_cache_invalidate { +- __u32 argsz; +- __u32 flags; +- struct iommu_cache_invalidate_info info; +-}; +-#define VFIO_IOMMU_CACHE_INVALIDATE _IO(VFIO_TYPE, VFIO_BASE + 19) +- +-/** +- * VFIO_IOMMU_SET_MSI_BINDING - _IOWR(VFIO_TYPE, VFIO_BASE + 20, +- * struct vfio_iommu_type1_set_msi_binding) +- * +- * Pass a stage 1 MSI doorbell mapping to the host so that this +- * latter can build a nested stage2 mapping. Or conversely tear +- * down a previously bound stage 1 MSI binding. +- */ +-struct vfio_iommu_type1_set_msi_binding { +- __u32 argsz; +- __u32 flags; +-#define VFIO_IOMMU_BIND_MSI (1 << 0) +-#define VFIO_IOMMU_UNBIND_MSI (1 << 1) +- __u64 iova; /* MSI guest IOVA */ +- /* Fields below are used on BIND */ +- __u64 gpa; /* MSI guest physical address */ +- __u64 size; /* size of stage1 mapping (bytes) */ +-}; +-#define VFIO_IOMMU_SET_MSI_BINDING _IO(VFIO_TYPE, VFIO_BASE + 20) +- + /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ + + /* +-- +2.27.0 + diff --git a/Revert-vhost-add-support-for-configure-interrupt.patch b/Revert-vhost-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..e33069230c0926a876a8d82a69d9d3c3b8a372f2 --- /dev/null +++ b/Revert-vhost-add-support-for-configure-interrupt.patch @@ -0,0 +1,163 @@ +From 529074fd45a543a9259441e02652c3ac60673d07 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:53:34 +0800 +Subject: [PATCH] Revert "vhost: add support for configure interrupt" + +This reverts commit f7220a7ce21604a4bc6260ccca4dc9068c1f27f2. + +Fixes: f7220a7ce2 ("vhost: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 76 --------------------------------------- + include/hw/virtio/vhost.h | 4 --- + 2 files changed, 80 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index caa53443ab..2f9bb96d63 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1581,67 +1581,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + } + } + +-bool vhost_config_pending(struct vhost_dev *hdev) +-{ +- assert(hdev->vhost_ops); +- if ((hdev->started == false) || +- (hdev->vhost_ops->vhost_set_config_call == NULL)) { +- return false; +- } +- +- EventNotifier *notifier = +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; +- return event_notifier_test_and_clear(notifier); +-} +- +-void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) +-{ +- int fd; +- int r; +- EventNotifier *notifier = +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; +- EventNotifier *config_notifier = &vdev->config_notifier; +- assert(hdev->vhost_ops); +- +- if ((hdev->started == false) || +- (hdev->vhost_ops->vhost_set_config_call == NULL)) { +- return; +- } +- if (mask) { +- assert(vdev->use_guest_notifier_mask); +- fd = event_notifier_get_fd(notifier); +- } else { +- fd = event_notifier_get_fd(config_notifier); +- } +- r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); +- if (r < 0) { +- VHOST_OPS_DEBUG(r, "vhost_set_config_call failed"); +- } +-} +- +-static void vhost_stop_config_intr(struct vhost_dev *dev) +-{ +- int fd = -1; +- assert(dev->vhost_ops); +- if (dev->vhost_ops->vhost_set_config_call) { +- dev->vhost_ops->vhost_set_config_call(dev, fd); +- } +-} +- +-static void vhost_start_config_intr(struct vhost_dev *dev) +-{ +- int r; +- +- assert(dev->vhost_ops); +- int fd = event_notifier_get_fd(&dev->vdev->config_notifier); +- if (dev->vhost_ops->vhost_set_config_call) { +- r = dev->vhost_ops->vhost_set_config_call(dev, fd); +- if (!r) { +- event_notifier_set(&dev->vdev->config_notifier); +- } +- } +-} +- + uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features) + { +@@ -1854,16 +1793,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + +- r = event_notifier_init( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); +- if (r < 0) { +- return r; +- } +- event_notifier_test_and_clear( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +- if (!vdev->use_guest_notifier_mask) { +- vhost_config_mask(hdev, vdev, true); +- } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1896,7 +1825,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } +- vhost_start_config_intr(hdev); + return 0; + fail_log: + vhost_log_put(hdev, false); +@@ -1922,9 +1850,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); +- event_notifier_test_and_clear( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +- event_notifier_test_and_clear(&vdev->config_notifier); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); +@@ -1942,7 +1867,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + memory_listener_unregister(&hdev->iommu_listener); + } +- vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + hdev->vdev = NULL; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 2ae5c3bfd8..86f36f0106 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -29,7 +29,6 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; +- EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -38,7 +37,6 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) +-#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -118,8 +116,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +-bool vhost_config_pending(struct vhost_dev *hdev); +-void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. +-- +2.27.0 + diff --git a/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch b/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a33b479461f428e4205c98d475909d28aef3378 --- /dev/null +++ b/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch @@ -0,0 +1,36 @@ +From 0ad1ce1ff54a4d654c00e4a3b95361b519f4fd37 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:43:37 +0800 +Subject: [PATCH] Revert "vhost: introduce new VhostOps vhost_set_config_call" + +This reverts commit af8377d0e9437401ad30d80a27ab1fcf8252fad1. + +Signed-off-by: fangyi +--- + include/hw/virtio/vhost-backend.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index bd1c7dfe4f..a64708f456 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,8 +125,6 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); +-typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, +- int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -175,7 +173,6 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; +- vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/Revert-vhost-vdpa-add-support-for-config-interrupt.patch b/Revert-vhost-vdpa-add-support-for-config-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..725ea3bb7685e708936022754a8012ae96f06cdb --- /dev/null +++ b/Revert-vhost-vdpa-add-support-for-config-interrupt.patch @@ -0,0 +1,56 @@ +From 92df45517567838512512f093f418067c857e8dc Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:58:20 +0800 +Subject: [PATCH] Revert "vhost-vdpa: add support for config interrupt" + +This reverts commit 634f7c89fbd78f57d00d5d6b39c0ade9df1fe27f. + +Fixes: 634f7c89fb ("vhost-vdpa: add support for config interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 - + hw/virtio/vhost-vdpa.c | 7 ------- + 2 files changed, 8 deletions(-) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 39c36ff7a6..650e521e35 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -53,7 +53,6 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 +-vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d8fba0b714..25a2f570a2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -737,12 +737,6 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } +-static int vhost_vdpa_set_config_call(struct vhost_dev *dev, +- int fd) +-{ +- trace_vhost_vdpa_set_config_call(dev, fd); +- return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); +-} + + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) +@@ -823,7 +817,6 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, +- .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/Revert-virtio-add-support-for-configure-interrupt.patch b/Revert-virtio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..41dfe165aa7a468d14e81188cb0e834efbe431f3 --- /dev/null +++ b/Revert-virtio-add-support-for-configure-interrupt.patch @@ -0,0 +1,101 @@ +From 3ee9abc7cdd10ccb7057a523326fec21fb01a7bb Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:55:19 +0800 +Subject: [PATCH] Revert "virtio: add support for configure interrupt" + +This reverts commit 081f864f56307551f59c5e934e3f30a7290d0faa. + +Fixes: 081f864f56 ("virtio: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 ----------------------------- + include/hw/virtio/virtio.h | 4 ---- + 2 files changed, 33 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 05409b84d1..c1497f59aa 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3547,14 +3547,7 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } +-static void virtio_config_guest_notifier_read(EventNotifier *n) +-{ +- VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + +- if (event_notifier_test_and_clear(n)) { +- virtio_notify_config(vdev); +- } +-} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3571,23 +3564,6 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + +-void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, +- bool assign, bool with_irqfd) +-{ +- EventNotifier *n; +- n = &vdev->config_notifier; +- if (assign && !with_irqfd) { +- event_notifier_set_handler(n, virtio_config_guest_notifier_read); +- } else { +- event_notifier_set_handler(n, NULL); +- } +- if (!assign) { +- /* Test and clear notifier before closing it,*/ +- /* in case poll callback didn't have time to run. */ +- virtio_config_guest_notifier_read(n); +- } +-} +- + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3661,11 +3637,6 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + +-EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) +-{ +- return &vdev->config_notifier; +-} +- + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 8788ccd1f3..c113a5b864 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -112,7 +112,6 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; +- EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -316,14 +315,11 @@ uint16_t virtio_get_queue_index(VirtQueue *vq); + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd); +-void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, +- bool assign, bool with_irqfd); + int virtio_device_start_ioeventfd(VirtIODevice *vdev); + int virtio_device_grab_ioeventfd(VirtIODevice *vdev); + void virtio_device_release_ioeventfd(VirtIODevice *vdev); + bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); + EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); +-EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); + void virtio_queue_host_notifier_read(EventNotifier *n); + void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, +-- +2.27.0 + diff --git a/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch b/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000000000000000000000000000000000000..b87ac1372ca8fb968bdad497358035b407735089 --- /dev/null +++ b/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,161 @@ +From 01e4e3aa5f2e2e44b72e81e76a74821edf2debd3 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:05:16 +0800 +Subject: [PATCH] Revert "virtio: introduce macro IRTIO_CONFIG_IRQ_IDX" + +This reverts commit bf1d85c166c19af95dbd27b1faba1d2909732323. + +Fixes: bf1d85c166 ("virtio: introduce macro IRTIO_CONFIG_IRQ_IDX") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 6 ------ + hw/net/virtio-net.c | 10 ++-------- + hw/virtio/vhost-user-fs.c | 6 ------ + hw/virtio/vhost-vsock-common.c | 6 ------ + hw/virtio/virtio-crypto.c | 6 ------ + include/hw/virtio/virtio.h | 3 --- + 6 files changed, 2 insertions(+), 35 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 73ad3d84c9..49df56cd14 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,9 +485,6 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -496,9 +493,6 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 7537f44d10..3bd786cc22 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3195,9 +3195,6 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3207,11 +3204,8 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } +- +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), ++ vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 90c2bc9c5d..fc7dcc96ef 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,9 +161,6 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -171,9 +168,6 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index b1f0d46209..ed706681ac 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,9 +125,6 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -136,9 +133,6 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 52ba34ef1e..274c7b4dea 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,9 +953,6 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -966,9 +963,6 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index c113a5b864..7472145821 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -68,9 +68,6 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + +-/* special index value used internally for config irqs */ +-#define VIRTIO_CONFIG_IRQ_IDX -1 +- + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/Revert-virtio-mmio-add-support-for-configure-interru.patch b/Revert-virtio-mmio-add-support-for-configure-interru.patch new file mode 100644 index 0000000000000000000000000000000000000000..b87a9798a28fb85308f20c690ae64cfcee56b40b --- /dev/null +++ b/Revert-virtio-mmio-add-support-for-configure-interru.patch @@ -0,0 +1,64 @@ +From 9633634fe4395000e88c8ab829ec756c7132d3bf Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:48:17 +0800 +Subject: [PATCH] Revert "virtio-mmio: add support for configure interrupt" + +This reverts commit d48185f1a40d4e4ed2fa2873a42b2a5eb8748256. + +Fixes: d48185f1a4 ("virtio-mmio: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 --------------------------- + 1 file changed, 27 deletions(-) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 809132018b..72da12fea5 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,30 +673,7 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } +-static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign) +-{ +- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- bool with_irqfd = false; +- EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); +- int r = 0; + +- if (assign) { +- r = event_notifier_init(notifier, 0); +- if (r < 0) { +- return r; +- } +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- } else { +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- event_notifier_cleanup(notifier); +- } +- if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { +- vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); +- } +- return r; +-} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -718,10 +695,6 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } +- r = virtio_mmio_set_config_guest_notifier(d, assign); +- if (r < 0) { +- goto assign_error; +- } + + return 0; + +-- +2.27.0 + diff --git a/Revert-virtio-net-add-support-for-configure-interrup.patch b/Revert-virtio-net-add-support-for-configure-interrup.patch new file mode 100644 index 0000000000000000000000000000000000000000..845af47c343c5a50da512bf3e1e11f3004419034 --- /dev/null +++ b/Revert-virtio-net-add-support-for-configure-interrup.patch @@ -0,0 +1,52 @@ +From 4f6f9e62214a008523b054c82d663d14d82a2c86 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:50:43 +0800 +Subject: [PATCH] Revert "virtio-net: add support for configure interrupt" + +This reverts commit 497679d51087090d5a22fd265d1b96cf92d49d9d. + +Fixes: 497679d510 ("virtio-net: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 9 --------- + include/net/vhost_net.h | 2 -- + 2 files changed, 11 deletions(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index d5a92144bb..bea053a742 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -524,15 +524,6 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + +-bool vhost_net_config_pending(VHostNetState *net) +-{ +- return vhost_config_pending(&net->dev); +-} +- +-void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) +-{ +- vhost_config_mask(&net->dev, dev, mask); +-} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 1844f0ed46..7bdbf484e4 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,8 +39,6 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); +-bool vhost_net_config_pending(VHostNetState *net); +-void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/Revert-virtio-pci-add-support-for-configure-interrup.patch b/Revert-virtio-pci-add-support-for-configure-interrup.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ce8a4be4715ab23b1b6feb1d7747a477e94bd08 --- /dev/null +++ b/Revert-virtio-pci-add-support-for-configure-interrup.patch @@ -0,0 +1,215 @@ +From b97597030e537248f3986589cfc4a32a3e7eb8f5 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:46:06 +0800 +Subject: [PATCH] Revert "virtio-pci: add support for configure interrupt" + +This reverts commit d5d24d859c3957ea1674d0e102f96439cdbfe93a. + +Fixes: d5d24d859c ("virtio-pci: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 92 ++++++------------------------------------ + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 13 insertions(+), 83 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 90237f523e..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,8 +812,7 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- *n = virtio_config_get_guest_notifier(vdev); +- *vector = vdev->config_vector; ++ return -1; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -888,10 +887,6 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + +-static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) +-{ +- return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +-} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -929,11 +924,6 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + +-static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) +-{ +- kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +-} +- + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1015,17 +1005,9 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- /* unmask config intr */ +- n = virtio_config_get_guest_notifier(vdev); +- ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, +- msg, n); +- if (ret < 0) { +- goto undo_config; +- } ++ + return 0; +-undo_config: +- n = virtio_config_get_guest_notifier(vdev); +- virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); ++ + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1059,8 +1041,6 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } +- n = virtio_config_get_guest_notifier(vdev); +- virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1092,34 +1072,6 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } +- /* poll the config intr */ +- ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, +- &vector); +- if (ret < 0) { +- return; +- } +- if (vector < vector_start || vector >= vector_end || +- !msix_is_masked(dev, vector)) { +- return; +- } +- if (k->guest_notifier_pending) { +- if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { +- msix_set_pending(dev, vector); +- } +- } else if (event_notifier_test_and_clear(notifier)) { +- msix_set_pending(dev, vector); +- } +-} +- +-void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, +- int n, bool assign, +- bool with_irqfd) +-{ +- if (n == VIRTIO_CONFIG_IRQ_IDX) { +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); +- } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1128,25 +1080,17 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = NULL; +- EventNotifier *notifier = NULL; +- +- if (n == VIRTIO_CONFIG_IRQ_IDX) { +- notifier = virtio_config_get_guest_notifier(vdev); +- } else { +- vq = virtio_get_queue(vdev, n); +- notifier = virtio_queue_get_guest_notifier(vq); +- } ++ VirtQueue *vq = virtio_get_queue(vdev, n); ++ EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); ++ virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); + } else { +- virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, +- with_irqfd); ++ virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1188,7 +1132,6 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { + kvm_virtio_pci_vector_release(proxy, nvqs); +- kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1204,11 +1147,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, +- with_irqfd); +- if (r < 0) { +- goto config_assign_error; +- } ++ + /* Must set vector notifier after guest notifier has been assigned */ + if ((with_irqfd || k->guest_notifier_mask) && assign) { + if (with_irqfd) { +@@ -1217,14 +1156,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_nr_vectors_allocated(&proxy->pci_dev)); + r = kvm_virtio_pci_vector_use(proxy, nvqs); + if (r < 0) { +- goto config_assign_error; ++ goto assign_error; + } + } +- r = kvm_virtio_pci_vector_config_use(proxy); +- if (r < 0) { +- goto config_error; +- } +- r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, ++ r = msix_set_vector_notifiers(&proxy->pci_dev, ++ virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1239,11 +1175,7 @@ notifiers_error: + assert(assign); + kvm_virtio_pci_vector_release(proxy, nvqs); + } +-config_error: +- kvm_virtio_pci_vector_config_release(proxy); +-config_assign_error: +- virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, +- with_irqfd); ++ + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index 6d8e071d8d..d95b1a13a5 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,7 +256,5 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +-void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, +- int n, bool assign, +- bool with_irqfd); ++ + #endif +-- +2.27.0 + diff --git a/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch b/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch new file mode 100644 index 0000000000000000000000000000000000000000..deda743bbaec5d395b57755c5c350524db3ba722 --- /dev/null +++ b/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch @@ -0,0 +1,255 @@ +From 38c0a07985c6616c43ee98caf7054ddd49dcd34e Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:02:59 +0800 +Subject: [PATCH] Revert "virtio-pci: decouple notifier from interrupt process" + +This reverts commit e3480ef81f6fb61cc9c04e3b5be8b7e84484fc05. + +Fixes: e3480ef81f ("virtio-pci: decouple notifier from interrupt process") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++--------------------------- + 1 file changed, 31 insertions(+), 57 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..21c0ec3b1b 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,41 +789,29 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- EventNotifier *n, ++ unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- EventNotifier *n , ++ unsigned int queue_no, + unsigned int vector) + { ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } +-static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, +- EventNotifier **n, unsigned int *vector) +-{ +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq; +- +- if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; +- } else { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- return -1; +- } +- *vector = virtio_queue_vector(vdev, queue_no); +- vq = virtio_get_queue(vdev, queue_no); +- *n = virtio_queue_get_guest_notifier(vq); +- } +- return 0; +-} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -832,15 +820,12 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- EventNotifier *n; ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -852,7 +837,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -868,11 +853,7 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -886,16 +867,12 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- EventNotifier *n; +- int ret ; ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -903,20 +880,21 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg, +- EventNotifier *n) ++ MSIMessage msg) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -943,15 +921,14 @@ static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + } + return ret; + } + +-static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector, +- EventNotifier *n) ++ unsigned int vector) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -962,7 +939,7 @@ static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + } + +@@ -972,7 +949,6 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); +- EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -981,8 +957,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- n = virtio_queue_get_guest_notifier(vq); +- ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); ++ ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); + if (ret < 0) { + goto undo; + } +@@ -998,8 +973,7 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- n = virtio_queue_get_guest_notifier(vq); +- virtio_pci_one_vector_mask(proxy, index, vector, n); ++ virtio_pci_vq_vector_mask(proxy, index, vector); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -1012,17 +986,15 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); +- EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); +- n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_one_vector_mask(proxy, index, vector, n); ++ virtio_pci_vq_vector_mask(proxy, index, vector); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1038,17 +1010,19 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- int ret; ++ VirtQueue *vq; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); +- if (ret < 0) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } ++ vq = virtio_get_queue(vdev, queue_no); ++ notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/Revert-virtio-pci-decouple-the-single-vector-from-th.patch b/Revert-virtio-pci-decouple-the-single-vector-from-th.patch new file mode 100644 index 0000000000000000000000000000000000000000..45fa977abb728ec2043f1b54175e7adf5b4bd9ac --- /dev/null +++ b/Revert-virtio-pci-decouple-the-single-vector-from-th.patch @@ -0,0 +1,192 @@ +From 074043d5d6c2610a320d2bc7d8649b7eff9c806e Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:01:17 +0800 +Subject: [PATCH] Revert "virtio-pci: decouple the single vector from the + interrupt process" + +This reverts commit 316011b8a74e777eb3ba03171cd701a291c28867. + +Fixes: 316011b8a7 ("virtio-pci: decouple the single vector from the interrupt process") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 ++++++++++++++++++----------------------- + 1 file changed, 58 insertions(+), 73 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,6 +762,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, ++ unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -824,103 +825,87 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +- unsigned int vector; +- int ret; +- EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return ret; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return 0; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, vector); +- if (ret < 0) { +- goto undo; +- } +- /* +- * If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ unsigned int vector; ++ int ret, queue_no; ++ EventNotifier *n; ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ break; ++ } ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); + if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } ++ /* If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++ goto undo; ++ } ++ } + } +- + return 0; +-undo: + +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return ret; +- } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return ret; ++undo: ++ while (--queue_no >= 0) { ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; + } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- return ret; +-} +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) +-{ +- int queue_no; +- int ret = 0; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- return -1; ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } +- ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + } + return ret; + } + +- +-static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, +- int queue_no) ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + { ++ PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- EventNotifier *n; +- int ret; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- PCIDevice *dev = &proxy->pci_dev; +- +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return; +- } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); +-} +- +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) +-{ + int queue_no; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- kvm_virtio_pci_vector_release_one(proxy, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; ++ } ++ /* If guest supports masking, clean up irqfd now. ++ * Otherwise, it was cleaned when masked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-- +2.27.0 + diff --git a/Revert-vtimer-compat-cross-version-migration-from-v4.patch b/Revert-vtimer-compat-cross-version-migration-from-v4.patch deleted file mode 100644 index 082f1763f9b445ba3816e2051c47129a6c64528a..0000000000000000000000000000000000000000 --- a/Revert-vtimer-compat-cross-version-migration-from-v4.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ced290d644a00e18e70046194d042bcaa2703b65 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 27 May 2020 11:16:53 +0800 -Subject: [PATCH] Revert: "vtimer: compat cross version migration from v4.0.1" - -This reverts commit patch: -vtimer-compat-cross-version-migration-from-v4.0.1.patch - -Signed-off-by: Ying Fang - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 2609113d..86eb79cd 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -261,7 +261,6 @@ typedef struct CPUARMState { - uint64_t elr_el[4]; /* AArch64 exception link regs */ - uint64_t sp_el[4]; /* AArch64 banked stack pointers */ - -- uint64_t vtimer; /* Timer tick when vcpu is stopped */ - - /* System control coprocessor (cp15) */ - struct { -diff --git a/target/arm/machine.c b/target/arm/machine.c -index ec28b839..ee3c59a6 100644 ---- a/target/arm/machine.c -+++ b/target/arm/machine.c -@@ -814,7 +814,6 @@ const VMStateDescription vmstate_arm_cpu = { - VMSTATE_UINT32(env.exception.syndrome, ARMCPU), - VMSTATE_UINT32(env.exception.fsr, ARMCPU), - VMSTATE_UINT64(env.exception.vaddress, ARMCPU), -- VMSTATE_UINT64(env.vtimer, ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), - { --- -2.23.0 - diff --git a/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch b/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch deleted file mode 100644 index bc1fd44d163beb57f08c3b58918d305772b0c362..0000000000000000000000000000000000000000 --- a/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 843f593280b93e03bb7b0d0001da7488d61f13f6 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Mon, 6 Apr 2020 08:55:17 +0800 -Subject: [PATCH] Typo: Correct the name of CPU hotplug memory region - -Replace "acpi-mem-hotplug" with "acpi-cpu-hotplug" - -Signed-off-by: Keqian Zhu ---- - hw/acpi/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index 7a90c8f82d..0c0bfe479a 100644 ---- a/hw/acpi/cpu.c -+++ b/hw/acpi/cpu.c -@@ -203,7 +203,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, - state->devs[i].arch_id = id_list->cpus[i].arch_id; - } - memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, -- "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); -+ "acpi-cpu-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); - memory_region_add_subregion(as, base_addr, &state->ctrl_reg); - } - --- -2.19.1 diff --git a/Update-bench-code-for-addressing-CI-problem.patch b/Update-bench-code-for-addressing-CI-problem.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f808f139c366ca7130655bef11cefbd8ec56e86 --- /dev/null +++ b/Update-bench-code-for-addressing-CI-problem.patch @@ -0,0 +1,615 @@ +From 4fe9da6fdaa5a9a12fdb26bf2a8c5abfccabf9e9 Mon Sep 17 00:00:00 2001 +From: ling xu +Date: Wed, 16 Nov 2022 23:29:23 +0800 +Subject: [PATCH] Update bench-code for addressing CI problem + +mainline inclusion +from mainline-v8.0.0-rc0 +commit cc98c9fd5c17b8ab62ad91b183060d8f70b9d00d +category: feature +feature: AVX512 support for xbzrle_encode_buffer +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Z50P + +Intel-SIG: commit cc98c9fd5c17 ("Update bench-code for addressing CI problem") + +------------------------------------- + +Update bench-code for addressing CI problem + +Unit test code is in test-xbzrle.c, and benchmark code is in xbzrle-bench.c +for performance benchmarking. we have modified xbzrle-bench.c to address +CI problem. + +Signed-off-by: ling xu +Co-authored-by: Zhou Zhao +Co-authored-by: Jun Jin +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Aichun Shi +--- + tests/bench/meson.build | 6 + + tests/bench/xbzrle-bench.c | 469 +++++++++++++++++++++++++++++++++++++ + tests/unit/test-xbzrle.c | 39 ++- + 3 files changed, 509 insertions(+), 5 deletions(-) + create mode 100644 tests/bench/xbzrle-bench.c + +diff --git a/tests/bench/meson.build b/tests/bench/meson.build +index 00b3c209dc..54bc8938a8 100644 +--- a/tests/bench/meson.build ++++ b/tests/bench/meson.build +@@ -3,6 +3,12 @@ qht_bench = executable('qht-bench', + sources: 'qht-bench.c', + dependencies: [qemuutil]) + ++if have_system ++xbzrle_bench = executable('xbzrle-bench', ++ sources: 'xbzrle-bench.c', ++ dependencies: [qemuutil,migration]) ++endif ++ + executable('atomic_add-bench', + sources: files('atomic_add-bench.c'), + dependencies: [qemuutil], +diff --git a/tests/bench/xbzrle-bench.c b/tests/bench/xbzrle-bench.c +new file mode 100644 +index 0000000000..8848a3a32d +--- /dev/null ++++ b/tests/bench/xbzrle-bench.c +@@ -0,0 +1,469 @@ ++/* ++ * Xor Based Zero Run Length Encoding unit tests. ++ * ++ * Copyright 2013 Red Hat, Inc. and/or its affiliates ++ * ++ * Authors: ++ * Orit Wasserman ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++#include "qemu/osdep.h" ++#include "qemu/cutils.h" ++#include "../migration/xbzrle.h" ++ ++#if defined(CONFIG_AVX512BW_OPT) ++#define XBZRLE_PAGE_SIZE 4096 ++static bool is_cpu_support_avx512bw; ++#include "qemu/cpuid.h" ++static void __attribute__((constructor)) init_cpu_flag(void) ++{ ++ unsigned max = __get_cpuid_max(0, NULL); ++ int a, b, c, d; ++ is_cpu_support_avx512bw = false; ++ if (max >= 1) { ++ __cpuid(1, a, b, c, d); ++ /* We must check that AVX is not just available, but usable. */ ++ if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { ++ int bv; ++ __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); ++ __cpuid_count(7, 0, a, b, c, d); ++ /* 0xe6: ++ * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 ++ * and ZMM16-ZMM31 state are enabled by OS) ++ * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) ++ */ ++ if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { ++ is_cpu_support_avx512bw = true; ++ } ++ } ++ } ++ return ; ++} ++ ++struct ResTime { ++ float t_raw; ++ float t_512; ++}; ++ ++ ++/* Function prototypes ++int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, ++ uint8_t *dst, int dlen); ++*/ ++static void encode_decode_zero(struct ResTime *res) ++{ ++ uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ int i = 0; ++ int dlen = 0, dlen512 = 0; ++ int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); ++ ++ for (i = diff_len; i > 0; i--) { ++ buffer[1000 + i] = i; ++ buffer512[1000 + i] = i; ++ } ++ ++ buffer[1000 + diff_len + 3] = 103; ++ buffer[1000 + diff_len + 5] = 105; ++ ++ buffer512[1000 + diff_len + 3] = 103; ++ buffer512[1000 + diff_len + 5] = 105; ++ ++ /* encode zero page */ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ dlen = xbzrle_encode_buffer(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ g_assert(dlen == 0); ++ ++ t_start512 = clock(); ++ dlen512 = xbzrle_encode_buffer_avx512(buffer512, buffer512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ g_assert(dlen512 == 0); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(buffer); ++ g_free(compressed); ++ g_free(buffer512); ++ g_free(compressed512); ++ ++} ++ ++static void test_encode_decode_zero_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_zero(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("Zero test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++ ++static void encode_decode_unchanged(struct ResTime *res) ++{ ++ uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ int i = 0; ++ int dlen = 0, dlen512 = 0; ++ int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); ++ ++ for (i = diff_len; i > 0; i--) { ++ test[1000 + i] = i + 4; ++ test512[1000 + i] = i + 4; ++ } ++ ++ test[1000 + diff_len + 3] = 107; ++ test[1000 + diff_len + 5] = 109; ++ ++ test512[1000 + diff_len + 3] = 107; ++ test512[1000 + diff_len + 5] = 109; ++ ++ /* test unchanged buffer */ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ dlen = xbzrle_encode_buffer(test, test, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ g_assert(dlen == 0); ++ ++ t_start512 = clock(); ++ dlen512 = xbzrle_encode_buffer_avx512(test512, test512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ g_assert(dlen512 == 0); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(test); ++ g_free(compressed); ++ g_free(test512); ++ g_free(compressed512); ++ ++} ++ ++static void test_encode_decode_unchanged_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_unchanged(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("Unchanged test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++ ++static void encode_decode_1_byte(struct ResTime *res) ++{ ++ uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); ++ int dlen = 0, rc = 0, dlen512 = 0, rc512 = 0; ++ uint8_t buf[2]; ++ uint8_t buf512[2]; ++ ++ test[XBZRLE_PAGE_SIZE - 1] = 1; ++ test512[XBZRLE_PAGE_SIZE - 1] = 1; ++ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ dlen = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2)); ++ ++ rc = xbzrle_decode_buffer(compressed, dlen, buffer, XBZRLE_PAGE_SIZE); ++ g_assert(rc == XBZRLE_PAGE_SIZE); ++ g_assert(memcmp(test, buffer, XBZRLE_PAGE_SIZE) == 0); ++ ++ t_start512 = clock(); ++ dlen512 = xbzrle_encode_buffer_avx512(buffer512, test512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ g_assert(dlen512 == (uleb128_encode_small(&buf512[0], 4095) + 2)); ++ ++ rc512 = xbzrle_decode_buffer(compressed512, dlen512, buffer512, ++ XBZRLE_PAGE_SIZE); ++ g_assert(rc512 == XBZRLE_PAGE_SIZE); ++ g_assert(memcmp(test512, buffer512, XBZRLE_PAGE_SIZE) == 0); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(buffer); ++ g_free(compressed); ++ g_free(test); ++ g_free(buffer512); ++ g_free(compressed512); ++ g_free(test512); ++ ++} ++ ++static void test_encode_decode_1_byte_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_1_byte(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("1 byte test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++ ++static void encode_decode_overflow(struct ResTime *res) ++{ ++ uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ int i = 0, rc = 0, rc512 = 0; ++ ++ for (i = 0; i < XBZRLE_PAGE_SIZE / 2 - 1; i++) { ++ test[i * 2] = 1; ++ test512[i * 2] = 1; ++ } ++ ++ /* encode overflow */ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ rc = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ g_assert(rc == -1); ++ ++ t_start512 = clock(); ++ rc512 = xbzrle_encode_buffer_avx512(buffer512, test512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ g_assert(rc512 == -1); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(buffer); ++ g_free(compressed); ++ g_free(test); ++ g_free(buffer512); ++ g_free(compressed512); ++ g_free(test512); ++ ++} ++ ++static void test_encode_decode_overflow_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_overflow(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("Overflow test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++ ++static void encode_decode_range_avx512(struct ResTime *res) ++{ ++ uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); ++ uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); ++ uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ int i = 0, rc = 0, rc512 = 0; ++ int dlen = 0, dlen512 = 0; ++ ++ int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); ++ ++ for (i = diff_len; i > 0; i--) { ++ buffer[1000 + i] = i; ++ test[1000 + i] = i + 4; ++ buffer512[1000 + i] = i; ++ test512[1000 + i] = i + 4; ++ } ++ ++ buffer[1000 + diff_len + 3] = 103; ++ test[1000 + diff_len + 3] = 107; ++ ++ buffer[1000 + diff_len + 5] = 105; ++ test[1000 + diff_len + 5] = 109; ++ ++ buffer512[1000 + diff_len + 3] = 103; ++ test512[1000 + diff_len + 3] = 107; ++ ++ buffer512[1000 + diff_len + 5] = 105; ++ test512[1000 + diff_len + 5] = 109; ++ ++ /* test encode/decode */ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); ++ g_assert(rc < XBZRLE_PAGE_SIZE); ++ g_assert(memcmp(test, buffer, XBZRLE_PAGE_SIZE) == 0); ++ ++ t_start512 = clock(); ++ dlen512 = xbzrle_encode_buffer_avx512(test512, buffer512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ rc512 = xbzrle_decode_buffer(compressed512, dlen512, test512, XBZRLE_PAGE_SIZE); ++ g_assert(rc512 < XBZRLE_PAGE_SIZE); ++ g_assert(memcmp(test512, buffer512, XBZRLE_PAGE_SIZE) == 0); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(buffer); ++ g_free(compressed); ++ g_free(test); ++ g_free(buffer512); ++ g_free(compressed512); ++ g_free(test512); ++ ++} ++ ++static void test_encode_decode_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_range_avx512(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("Encode decode test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++ ++static void encode_decode_random(struct ResTime *res) ++{ ++ uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); ++ uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); ++ uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); ++ int i = 0, rc = 0, rc512 = 0; ++ int dlen = 0, dlen512 = 0; ++ ++ int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1); ++ /* store the index of diff */ ++ int dirty_index[diff_len]; ++ for (int j = 0; j < diff_len; j++) { ++ dirty_index[j] = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1); ++ } ++ for (i = diff_len - 1; i >= 0; i--) { ++ buffer[dirty_index[i]] = i; ++ test[dirty_index[i]] = i + 4; ++ buffer512[dirty_index[i]] = i; ++ test512[dirty_index[i]] = i + 4; ++ } ++ ++ time_t t_start, t_end, t_start512, t_end512; ++ t_start = clock(); ++ dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, ++ XBZRLE_PAGE_SIZE); ++ t_end = clock(); ++ float time_val = difftime(t_end, t_start); ++ rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); ++ g_assert(rc < XBZRLE_PAGE_SIZE); ++ ++ t_start512 = clock(); ++ dlen512 = xbzrle_encode_buffer_avx512(test512, buffer512, XBZRLE_PAGE_SIZE, ++ compressed512, XBZRLE_PAGE_SIZE); ++ t_end512 = clock(); ++ float time_val512 = difftime(t_end512, t_start512); ++ rc512 = xbzrle_decode_buffer(compressed512, dlen512, test512, XBZRLE_PAGE_SIZE); ++ g_assert(rc512 < XBZRLE_PAGE_SIZE); ++ ++ res->t_raw = time_val; ++ res->t_512 = time_val512; ++ ++ g_free(buffer); ++ g_free(compressed); ++ g_free(test); ++ g_free(buffer512); ++ g_free(compressed512); ++ g_free(test512); ++ ++} ++ ++static void test_encode_decode_random_avx512(void) ++{ ++ int i; ++ float time_raw = 0.0, time_512 = 0.0; ++ struct ResTime res; ++ for (i = 0; i < 10000; i++) { ++ encode_decode_random(&res); ++ time_raw += res.t_raw; ++ time_512 += res.t_512; ++ } ++ printf("Random test:\n"); ++ printf("Raw xbzrle_encode time is %f ms\n", time_raw); ++ printf("512 xbzrle_encode time is %f ms\n", time_512); ++} ++#endif ++ ++int main(int argc, char **argv) ++{ ++ g_test_init(&argc, &argv, NULL); ++ g_test_rand_int(); ++ #if defined(CONFIG_AVX512BW_OPT) ++ if (likely(is_cpu_support_avx512bw)) { ++ g_test_add_func("/xbzrle/encode_decode_zero", test_encode_decode_zero_avx512); ++ g_test_add_func("/xbzrle/encode_decode_unchanged", ++ test_encode_decode_unchanged_avx512); ++ g_test_add_func("/xbzrle/encode_decode_1_byte", test_encode_decode_1_byte_avx512); ++ g_test_add_func("/xbzrle/encode_decode_overflow", ++ test_encode_decode_overflow_avx512); ++ g_test_add_func("/xbzrle/encode_decode", test_encode_decode_avx512); ++ g_test_add_func("/xbzrle/encode_decode_random", test_encode_decode_random_avx512); ++ } ++ #endif ++ return g_test_run(); ++} +diff --git a/tests/unit/test-xbzrle.c b/tests/unit/test-xbzrle.c +index 795d6f1cba..baa364b443 100644 +--- a/tests/unit/test-xbzrle.c ++++ b/tests/unit/test-xbzrle.c +@@ -17,6 +17,35 @@ + + #define XBZRLE_PAGE_SIZE 4096 + ++int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int, ++ uint8_t *, int) = xbzrle_encode_buffer; ++#if defined(CONFIG_AVX512BW_OPT) ++#include "qemu/cpuid.h" ++static void __attribute__((constructor)) init_cpu_flag(void) ++{ ++ unsigned max = __get_cpuid_max(0, NULL); ++ int a, b, c, d; ++ if (max >= 1) { ++ __cpuid(1, a, b, c, d); ++ /* We must check that AVX is not just available, but usable. */ ++ if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { ++ int bv; ++ __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); ++ __cpuid_count(7, 0, a, b, c, d); ++ /* 0xe6: ++ * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 ++ * and ZMM16-ZMM31 state are enabled by OS) ++ * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) ++ */ ++ if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { ++ xbzrle_encode_buffer_func = xbzrle_encode_buffer_avx512; ++ } ++ } ++ } ++ return ; ++} ++#endif ++ + static void test_uleb(void) + { + uint32_t i, val; +@@ -55,7 +84,7 @@ static void test_encode_decode_zero(void) + buffer[1000 + diff_len + 5] = 105; + + /* encode zero page */ +- dlen = xbzrle_encode_buffer(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, ++ dlen = xbzrle_encode_buffer_func(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + g_assert(dlen == 0); + +@@ -79,7 +108,7 @@ static void test_encode_decode_unchanged(void) + test[1000 + diff_len + 5] = 109; + + /* test unchanged buffer */ +- dlen = xbzrle_encode_buffer(test, test, XBZRLE_PAGE_SIZE, compressed, ++ dlen = xbzrle_encode_buffer_func(test, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + g_assert(dlen == 0); + +@@ -97,7 +126,7 @@ static void test_encode_decode_1_byte(void) + + test[XBZRLE_PAGE_SIZE - 1] = 1; + +- dlen = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, ++ dlen = xbzrle_encode_buffer_func(buffer, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2)); + +@@ -122,7 +151,7 @@ static void test_encode_decode_overflow(void) + } + + /* encode overflow */ +- rc = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, ++ rc = xbzrle_encode_buffer_func(buffer, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + g_assert(rc == -1); + +@@ -153,7 +182,7 @@ static void encode_decode_range(void) + test[1000 + diff_len + 5] = 109; + + /* test encode/decode */ +- dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, ++ dlen = xbzrle_encode_buffer_func(test, buffer, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + + rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); +-- +2.27.0 + diff --git a/Use-post-increment-only-in-inffast.c.patch b/Use-post-increment-only-in-inffast.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5d16d054cf49281aea941f54758d69e981d7a8c --- /dev/null +++ b/Use-post-increment-only-in-inffast.c.patch @@ -0,0 +1,250 @@ +From 97021cac0565f57d14a3e285399dd2208c66c358 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Sat, 12 Feb 2022 15:00:25 +0800 +Subject: [PATCH] Use post-increment only in inffast.c. + +Fix CVE-2016-9841 + +patch link: https://github.com/madler/zlib/commit/9aaec95 + +An old inffast.c optimization turns out to not be optimal anymore +with modern compilers, and furthermore was not compliant with the +C standard, for which decrementing a pointer before its allocated +memory is undefined. Per the recommendation of a security audit of +the zlib code by Trail of Bits and TrustInSoft, in support of the +Mozilla Foundation, this "optimization" was removed, in order to +avoid the possibility of undefined behavior. + +Signed-off-by: Yan Wang +--- + roms/u-boot/lib/zlib/inffast.c | 87 +++++++++++++++++------------------------- + 1 file changed, 34 insertions(+), 53 deletions(-) + +diff --git a/roms/u-boot/lib/zlib/inffast.c b/roms/u-boot/lib/zlib/inffast.c +index e3c7f3b..cdc778e 100644 +--- a/roms/u-boot/lib/zlib/inffast.c ++++ b/roms/u-boot/lib/zlib/inffast.c +@@ -12,25 +12,6 @@ + + #ifndef ASMINF + +-/* Allow machine dependent optimization for post-increment or pre-increment. +- Based on testing to date, +- Pre-increment preferred for: +- - PowerPC G3 (Adler) +- - MIPS R5000 (Randers-Pehrson) +- Post-increment preferred for: +- - none +- No measurable difference: +- - Pentium III (Anderson) +- - M68060 (Nikl) +- */ +-#ifdef POSTINC +-# define OFF 0 +-# define PUP(a) *(a)++ +-#else +-# define OFF 1 +-# define PUP(a) *++(a) +-#endif +- + /* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is +@@ -97,7 +78,7 @@ void inflate_fast(z_streamp strm, unsigned start) + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; +- in = strm->next_in - OFF; ++ in = strm->next_in; + last = in + (strm->avail_in - 5); + if (in > last && strm->avail_in > 5) { + /* +@@ -107,7 +88,7 @@ void inflate_fast(z_streamp strm, unsigned start) + strm->avail_in = 0xffffffff - (uintptr_t)in; + last = in + (strm->avail_in - 5); + } +- out = strm->next_out - OFF; ++ out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + #ifdef INFLATE_STRICT +@@ -128,9 +109,9 @@ void inflate_fast(z_streamp strm, unsigned start) + input data or output space */ + do { + if (bits < 15) { +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; + } + this = lcode[hold & lmask]; +@@ -143,14 +124,14 @@ void inflate_fast(z_streamp strm, unsigned start) + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); +- PUP(out) = (unsigned char)(this.val); ++ *out++ = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); +@@ -159,9 +140,9 @@ void inflate_fast(z_streamp strm, unsigned start) + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; + } + this = dcode[hold & dmask]; +@@ -174,10 +155,10 @@ void inflate_fast(z_streamp strm, unsigned start) + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { +- hold += (unsigned long)(PUP(in)) << bits; ++ hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } +@@ -200,13 +181,13 @@ void inflate_fast(z_streamp strm, unsigned start) + state->mode = BAD; + break; + } +- from = window - OFF; ++ from = window; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { +- PUP(out) = PUP(from); ++ *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } +@@ -217,14 +198,14 @@ void inflate_fast(z_streamp strm, unsigned start) + if (op < len) { /* some from end of window */ + len -= op; + do { +- PUP(out) = PUP(from); ++ *out++ = *from++; + } while (--op); +- from = window - OFF; ++ from = window; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { +- PUP(out) = PUP(from); ++ *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } +@@ -235,21 +216,21 @@ void inflate_fast(z_streamp strm, unsigned start) + if (op < len) { /* some from window */ + len -= op; + do { +- PUP(out) = PUP(from); ++ *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { +- PUP(out) = PUP(from); +- PUP(out) = PUP(from); +- PUP(out) = PUP(from); ++ *out++ = *from++; ++ *out++ = *from++; ++ *out++ = *from++; + len -= 3; + } + if (len) { +- PUP(out) = PUP(from); ++ *out++ = *from++; + if (len > 1) +- PUP(out) = PUP(from); ++ *out++ = *from++; + } + } + else { +@@ -259,25 +240,25 @@ void inflate_fast(z_streamp strm, unsigned start) + from = out - dist; /* copy direct from output */ + /* minimum length is three */ + /* Align out addr */ +- if (!((long)(out - 1 + OFF) & 1)) { +- PUP(out) = PUP(from); ++ if (!((long)(out - 1) & 1)) { ++ *out++ = *from++; + len--; + } +- sout = (unsigned short *)(out - OFF); ++ sout = (unsigned short *)(out); + if (dist > 2 ) { + unsigned short *sfrom; + +- sfrom = (unsigned short *)(from - OFF); ++ sfrom = (unsigned short *)(from); + loops = len >> 1; + do +- PUP(sout) = get_unaligned(++sfrom); ++ *sout++ = get_unaligned(++sfrom); + while (--loops); +- out = (unsigned char *)sout + OFF; +- from = (unsigned char *)sfrom + OFF; ++ out = (unsigned char *)sout; ++ from = (unsigned char *)sfrom; + } else { /* dist == 1 or dist == 2 */ + unsigned short pat16; + +- pat16 = *(sout-2+2*OFF); ++ pat16 = *(sout-2); + if (dist == 1) + #if defined(__BIG_ENDIAN) + pat16 = (pat16 & 0xff) | ((pat16 & 0xff ) << 8); +@@ -288,12 +269,12 @@ void inflate_fast(z_streamp strm, unsigned start) + #endif + loops = len >> 1; + do +- PUP(sout) = pat16; ++ *sout++ = pat16; + while (--loops); +- out = (unsigned char *)sout + OFF; ++ out = (unsigned char *)sout; + } + if (len & 1) +- PUP(out) = PUP(from); ++ *out++ = *from++; + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ +@@ -329,8 +310,8 @@ void inflate_fast(z_streamp strm, unsigned start) + hold &= (1U << bits) - 1; + + /* update state and return */ +- strm->next_in = in + OFF; +- strm->next_out = out + OFF; ++ strm->next_in = in; ++ strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); +-- +1.9.1 + diff --git a/accel-kvm-Add-pre-park-vCPU-support.patch b/accel-kvm-Add-pre-park-vCPU-support.patch index 9bc81178581c30504ca1b32d1f47ba8cbc1a5b85..e3433842aefc7dd4faf0e827c8824f0898363652 100644 --- a/accel-kvm-Add-pre-park-vCPU-support.patch +++ b/accel-kvm-Add-pre-park-vCPU-support.patch @@ -1,4 +1,4 @@ -From 135119d2e82e99adc67346572c761fbe54d73e4a Mon Sep 17 00:00:00 2001 +From c950cda47386360e37a89dfa7029d83e33888a40 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 13:04:40 +0800 Subject: [PATCH] accel/kvm: Add pre-park vCPU support @@ -14,13 +14,13 @@ Signed-off-by: Salil Mehta 2 files changed, 24 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index f450f25295..84edbe8bb1 100644 +index 8a98446b7c..f2ce5cd45a 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c -@@ -339,6 +339,29 @@ err: - return ret; +@@ -433,6 +433,29 @@ void kvm_destroy_vcpu(CPUState *cpu) + } } - + +int kvm_create_parked_vcpu(unsigned long vcpu_id) +{ + KVMState *s = kvm_state; @@ -48,16 +48,17 @@ index f450f25295..84edbe8bb1 100644 { struct KVMParkedVcpu *cpu; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h -index acd90aebb6..565adb4e2c 100644 +index 7b22aeb6ae..2623775c27 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h -@@ -216,6 +216,7 @@ int kvm_has_many_ioeventfds(void); +@@ -221,6 +221,7 @@ int kvm_has_pit_state2(void); + int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); int kvm_has_intx_set_mask(void); - +int kvm_create_parked_vcpu(unsigned long vcpu_id); - int kvm_init_vcpu(CPUState *cpu); - int kvm_cpu_exec(CPUState *cpu); - int kvm_destroy_vcpu(CPUState *cpu); --- -2.19.1 + + /** + * kvm_arm_supports_user_irq +-- +2.27.0 + diff --git a/accel-kvm-Fix-memory-waste-under-mismatch-page-size.patch b/accel-kvm-Fix-memory-waste-under-mismatch-page-size.patch deleted file mode 100644 index daff52e901686e17c1c492e899165b773db96258..0000000000000000000000000000000000000000 --- a/accel-kvm-Fix-memory-waste-under-mismatch-page-size.patch +++ /dev/null @@ -1,45 +0,0 @@ -From b50b9a0e2e5e8262c830df5994f3abbe0a37655a Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Thu, 17 Dec 2020 09:49:40 +0800 -Subject: [PATCH] accel: kvm: Fix memory waste under mismatch page size - -When handle dirty log, we face qemu_real_host_page_size and -TARGET_PAGE_SIZE. The first one is the granule of KVM dirty -bitmap, and the second one is the granule of QEMU dirty bitmap. - -As qemu_real_host_page_size >= TARGET_PAGE_SIZE (kvm_init() -enforced it), misuse TARGET_PAGE_SIZE to init kvmslot dirty_bmap -may waste memory. For example, when qemu_real_host_page_size is -64K and TARGET_PAGE_SIZE is 4K, it wastes 93.75% (15/16) memory. - -Signed-off-by: Keqian Zhu -Reviewed-by: Andrew Jones -Reviewed-by: Peter Xu -Message-Id: <20201217014941.22872-2-zhukeqian1@huawei.com> -Signed-off-by: Paolo Bonzini -Signed-off-by: Kunkun Jiang ---- - accel/kvm/kvm-all.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 5a6b89cc2a..4daff563a0 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -551,8 +551,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem) - * too, in most cases). - * So for now, let's align to 64 instead of HOST_LONG_BITS here, in - * a hope that sizeof(long) won't become >8 any time soon. -+ * -+ * Note: the granule of kvm dirty log is qemu_real_host_page_size. -+ * And mem->memory_size is aligned to it (otherwise this mem can't -+ * be registered to KVM). - */ -- hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), -+ hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size, - /*HOST_LONG_BITS*/ 64) / 8; - mem->dirty_bmap = g_malloc0(bitmap_size); - } --- -2.27.0 - diff --git a/accel-kvm-Free-as-when-an-error-occurred.patch b/accel-kvm-Free-as-when-an-error-occurred.patch new file mode 100644 index 0000000000000000000000000000000000000000..64aa45f85e39c25132fcdea3c2ea047c9d368490 --- /dev/null +++ b/accel-kvm-Free-as-when-an-error-occurred.patch @@ -0,0 +1,35 @@ +From 6ccda2ece6d08b1bf0622109c2a1f3eeca813089 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 28 Aug 2023 19:43:06 +0800 +Subject: [PATCH] accel/kvm: Free as when an error occurred + +cheery-pick from 4625742cd2aeb1400407889a2f7a5b4c75437818 + +An error may occur after s->as is allocated, for example if the +KVM_CREATE_VM ioctl call fails. + +Signed-off-by: Akihiko Odaki +Message-id: 20230727073134.134102-6-akihiko.odaki@daynix.com +Reviewed-by: Peter Maydell +[PMM: tweaked commit message] +Signed-off-by: Peter Maydell +Signed-off-by: qihao_yewu +--- + 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 799d993f6c..9c8d3a916e 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2589,6 +2589,7 @@ err: + if (s->fd != -1) { + close(s->fd); + } ++ g_free(s->as); + g_free(s->memory_listener.slots); + + return ret; +-- +2.41.0.windows.1 + diff --git a/accel-kvm-Make-kvm_dirty_ring_reaper_init-void.patch b/accel-kvm-Make-kvm_dirty_ring_reaper_init-void.patch new file mode 100644 index 0000000000000000000000000000000000000000..d65b940990f8107458942c91d0ced7f6a312df0f --- /dev/null +++ b/accel-kvm-Make-kvm_dirty_ring_reaper_init-void.patch @@ -0,0 +1,58 @@ +From e11f4d10f843f46a8659d0134220f8712f15b451 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 28 Aug 2023 19:04:32 +0800 +Subject: [PATCH] accel/kvm: Make kvm_dirty_ring_reaper_init() void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 43a5e377f42d1d3ed12ea562196f723b354ce411 + +The returned value was always zero and had no meaning. + +Signed-off-by: Akihiko Odaki +Message-id: 20230727073134.134102-7-akihiko.odaki@daynix.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: qihao_yewu +--- + accel/kvm/kvm-all.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 799d993f6c..83881e1d96 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -1436,15 +1436,13 @@ static void *kvm_dirty_ring_reaper_thread(void *data) + return NULL; + } + +-static int kvm_dirty_ring_reaper_init(KVMState *s) ++static void kvm_dirty_ring_reaper_init(KVMState *s) + { + struct KVMDirtyRingReaper *r = &s->reaper; + + qemu_thread_create(&r->reaper_thr, "kvm-reaper", + kvm_dirty_ring_reaper_thread, + s, QEMU_THREAD_JOINABLE); +- +- return 0; + } + + static void kvm_region_add(MemoryListener *listener, +@@ -2573,10 +2571,7 @@ static int kvm_init(MachineState *ms) + } + + if (s->kvm_dirty_ring_size) { +- ret = kvm_dirty_ring_reaper_init(s); +- if (ret) { +- goto err; +- } ++ kvm_dirty_ring_reaper_init(s); + } + + return 0; +-- +2.41.0.windows.1 + diff --git a/accel-kvm-kvm-all-Introduce-kvm_dirty_ring_size-func.patch b/accel-kvm-kvm-all-Introduce-kvm_dirty_ring_size-func.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e9274e1b505f296a1a8ee8ea23cffcb2dab352e --- /dev/null +++ b/accel-kvm-kvm-all-Introduce-kvm_dirty_ring_size-func.patch @@ -0,0 +1,66 @@ +From 85583352f3bc28badd4cb336517f6a4eb440d5b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:34 +0800 +Subject: [PATCH 2/3] accel/kvm/kvm-all: Introduce kvm_dirty_ring_size function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce kvm_dirty_ring_size util function to help calculate +dirty ring ful time. + +Signed-off-by: Hyman Huang(黄勇) +Acked-by: Peter Xu +Message-Id: +Signed-off-by: Dr. David Alan Gilbert +--- + accel/kvm/kvm-all.c | 5 +++++ + accel/stubs/kvm-stub.c | 5 +++++ + include/sysemu/kvm.h | 2 ++ + 3 files changed, 12 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 3bc6eb6294..d0c4310507 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2332,6 +2332,11 @@ bool kvm_dirty_ring_enabled(void) + return kvm_state->kvm_dirty_ring_size ? true : false; + } + ++uint32_t kvm_dirty_ring_size(void) ++{ ++ return kvm_state->kvm_dirty_ring_size; ++} ++ + static int kvm_init(MachineState *ms) + { + MachineClass *mc = MACHINE_GET_CLASS(ms); +diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c +index 5319573e00..1128cb2928 100644 +--- a/accel/stubs/kvm-stub.c ++++ b/accel/stubs/kvm-stub.c +@@ -152,4 +152,9 @@ bool kvm_dirty_ring_enabled(void) + { + return false; + } ++ ++uint32_t kvm_dirty_ring_size(void) ++{ ++ return 0; ++} + #endif +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 2623775c27..19c5c8402a 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -549,4 +549,6 @@ bool kvm_cpu_check_are_resettable(void); + bool kvm_arch_cpu_check_are_resettable(void); + + bool kvm_dirty_ring_enabled(void); ++ ++uint32_t kvm_dirty_ring_size(void); + #endif +-- +2.27.0 + diff --git a/accel-kvm-kvm-all-Refactor-per-vcpu-dirty-ring-reapi.patch b/accel-kvm-kvm-all-Refactor-per-vcpu-dirty-ring-reapi.patch new file mode 100644 index 0000000000000000000000000000000000000000..bec0b4ae7caed2091b9e86430974b892475a0dbe --- /dev/null +++ b/accel-kvm-kvm-all-Refactor-per-vcpu-dirty-ring-reapi.patch @@ -0,0 +1,106 @@ +From c6f781e50e75fc2e6b819291b6c5ce6c212f018b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:30 +0800 +Subject: [PATCH 1/3] accel/kvm/kvm-all: Refactor per-vcpu dirty ring reaping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a non-required argument 'CPUState' to kvm_dirty_ring_reap so +that it can cover single vcpu dirty-ring-reaping scenario. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Peter Xu +Message-Id: +Signed-off-by: Dr. David Alan Gilbert +--- + accel/kvm/kvm-all.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index f2ce5cd45a..3bc6eb6294 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -773,17 +773,20 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu) + } + + /* Must be with slots_lock held */ +-static uint64_t kvm_dirty_ring_reap_locked(KVMState *s) ++static uint64_t kvm_dirty_ring_reap_locked(KVMState *s, CPUState* cpu) + { + int ret; +- CPUState *cpu; + uint64_t total = 0; + int64_t stamp; + + stamp = get_clock(); + +- CPU_FOREACH(cpu) { +- total += kvm_dirty_ring_reap_one(s, cpu); ++ if (cpu) { ++ total = kvm_dirty_ring_reap_one(s, cpu); ++ } else { ++ CPU_FOREACH(cpu) { ++ total += kvm_dirty_ring_reap_one(s, cpu); ++ } + } + + if (total) { +@@ -804,7 +807,7 @@ static uint64_t kvm_dirty_ring_reap_locked(KVMState *s) + * Currently for simplicity, we must hold BQL before calling this. We can + * consider to drop the BQL if we're clear with all the race conditions. + */ +-static uint64_t kvm_dirty_ring_reap(KVMState *s) ++static uint64_t kvm_dirty_ring_reap(KVMState *s, CPUState *cpu) + { + uint64_t total; + +@@ -824,7 +827,7 @@ static uint64_t kvm_dirty_ring_reap(KVMState *s) + * reset below. + */ + kvm_slots_lock(); +- total = kvm_dirty_ring_reap_locked(s); ++ total = kvm_dirty_ring_reap_locked(s, cpu); + kvm_slots_unlock(); + + return total; +@@ -871,7 +874,7 @@ static void kvm_dirty_ring_flush(void) + * vcpus out in a synchronous way. + */ + kvm_cpu_synchronize_kick_all(); +- kvm_dirty_ring_reap(kvm_state); ++ kvm_dirty_ring_reap(kvm_state, NULL); + trace_kvm_dirty_ring_flush(1); + } + +@@ -1415,7 +1418,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, + * Not easy. Let's cross the fingers until it's fixed. + */ + if (kvm_state->kvm_dirty_ring_size) { +- kvm_dirty_ring_reap_locked(kvm_state); ++ kvm_dirty_ring_reap_locked(kvm_state, NULL); + } else { + kvm_slot_get_dirty_log(kvm_state, mem); + } +@@ -1487,7 +1490,7 @@ static void *kvm_dirty_ring_reaper_thread(void *data) + r->reaper_state = KVM_DIRTY_RING_REAPER_REAPING; + + qemu_mutex_lock_iothread(); +- kvm_dirty_ring_reap(s); ++ kvm_dirty_ring_reap(s, NULL); + qemu_mutex_unlock_iothread(); + + r->reaper_iteration++; +@@ -2957,7 +2960,7 @@ int kvm_cpu_exec(CPUState *cpu) + */ + trace_kvm_dirty_ring_full(cpu->cpu_index); + qemu_mutex_lock_iothread(); +- kvm_dirty_ring_reap(kvm_state); ++ kvm_dirty_ring_reap(kvm_state, NULL); + qemu_mutex_unlock_iothread(); + ret = 0; + break; +-- +2.27.0 + diff --git a/accel-tcg-Optimize-jump-cache-flush-during-tlb-range.patch b/accel-tcg-Optimize-jump-cache-flush-during-tlb-range.patch new file mode 100644 index 0000000000000000000000000000000000000000..403e3bb6221e1331bc769b8a6cfbccc48c5fb773 --- /dev/null +++ b/accel-tcg-Optimize-jump-cache-flush-during-tlb-range.patch @@ -0,0 +1,49 @@ +From 28ca488c585c556ce04419f927d13d46771e1ea4 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 18 Jul 2023 06:29:51 +0000 +Subject: [PATCH] accel/tcg: Optimize jump cache flush during tlb range flush + mainline inclusion commit cfc2a2d69d59f02b32df3098ce17e10ab86d43c6 category: + bugfix + +--------------------------------------------------------------- + +When the length of the range is large enough, clearing the whole cache is +faster than iterating over the (possibly extremely large) set of pages +contained in the range. + +This mimics the pre-existing similar optimization done on the flush of the +tlb itself. + +Signed-off-by: Idan Horowitz +Message-Id: <20220110164754.1066025-1-idan.horowitz@gmail.com> +Reviewed-by: Richard Henderson +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + accel/tcg/cputlb.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c +index b69a953447..03526fa1ab 100644 +--- a/accel/tcg/cputlb.c ++++ b/accel/tcg/cputlb.c +@@ -783,6 +783,15 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, + } + qemu_spin_unlock(&env_tlb(env)->c.lock); + ++ /* ++ * If the length is larger than the jump cache size, then it will take ++ * longer to clear each entry individually than it will to clear it all. ++ */ ++ if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) { ++ cpu_tb_jmp_cache_clear(cpu); ++ return; ++ } ++ + for (target_ulong i = 0; i < d.len; i += TARGET_PAGE_SIZE) { + tb_flush_jmp_cache(cpu, d.addr + i); + } +-- +2.41.0.windows.1 + diff --git a/accel-tcg-cpu-exec-Fix-precise-single-stepping-after.patch b/accel-tcg-cpu-exec-Fix-precise-single-stepping-after.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd77f90f5700c110aa8c3478320750c01770b585 --- /dev/null +++ b/accel-tcg-cpu-exec-Fix-precise-single-stepping-after.patch @@ -0,0 +1,48 @@ +From ddca9c0cba8e3c858b7998c67ae2739f58b5b681 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 21 Jul 2023 06:41:38 +0000 +Subject: [PATCH] accel/tcg/cpu-exec: Fix precise single-stepping after + interrupt mainline inclusion commit 5b7b197c87cefbd24bd1936614fd4e00ccc279ab + category: bugfix + +--------------------------------------------------------------- + +In some cases, cpu->exit_request can be false after handling the +interrupt, leading to another TB being executed instead of returning +to the main loop. + +Fix this by returning true unconditionally when in single-step mode. + +Fixes: ba3c35d9c402 ("tcg/cpu-exec: precise single-stepping after an interrupt") +Signed-off-by: Luc Michel +Message-Id: <20220214132656.11397-1-lmichel@kalray.eu> +[rth: Unlock iothread mutex; simplify indentation] +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + accel/tcg/cpu-exec.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c +index 409ec8c38c..7fb87afedc 100644 +--- a/accel/tcg/cpu-exec.c ++++ b/accel/tcg/cpu-exec.c +@@ -798,8 +798,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, + * raised when single-stepping so that GDB doesn't miss the + * next instruction. + */ +- cpu->exception_index = +- (cpu->singlestep_enabled ? EXCP_DEBUG : -1); ++ if (unlikely(cpu->singlestep_enabled)) { ++ cpu->exception_index = EXCP_DEBUG; ++ qemu_mutex_unlock_iothread(); ++ return true; ++ } ++ cpu->exception_index = -1; + *last_tb = NULL; + } + /* The target hook may have updated the 'cpu->interrupt_request'; +-- +2.41.0.windows.1 + diff --git a/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch index 0506d1b73c1586699dd0fe92254baa5d0af26a7b..49477add34fd88544d959e8e973d97fa348a022c 100644 --- a/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch +++ b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch @@ -1,4 +1,4 @@ -From 107c267ebe5b8c461268a4ff8384ad2f2b9e8ce0 Mon Sep 17 00:00:00 2001 +From 1ab75151c0a486ebdbe50d29c9677c7bc1f05929 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Wed, 22 Apr 2020 16:11:13 +0800 Subject: [PATCH] acpi/cpu: Prepare build_cpus_aml for arm virt @@ -17,16 +17,16 @@ Besides, CPU CPPC building is injected. Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/acpi/cpu.c | 32 +++++++++++++++++++++++++------- + hw/acpi/cpu.c | 27 ++++++++++++++++++++------- hw/i386/acpi-build.c | 2 +- include/hw/acpi/cpu.h | 3 ++- - 3 files changed, 28 insertions(+), 9 deletions(-) + 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index 0c0bfe479a..72ad1fcff2 100644 +index b20903ea30..a9c2ee952a 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c -@@ -314,7 +314,8 @@ const VMStateDescription vmstate_cpu_hotplug = { +@@ -343,7 +343,8 @@ const VMStateDescription vmstate_cpu_hotplug = { void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, hwaddr io_base, const char *res_root, @@ -36,9 +36,9 @@ index 0c0bfe479a..72ad1fcff2 100644 { Aml *ifctx; Aml *field; -@@ -342,13 +343,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +@@ -371,13 +372,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); - + crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, - ACPI_CPU_HOTPLUG_REG_LEN)); @@ -50,18 +50,18 @@ index 0c0bfe479a..72ad1fcff2 100644 + ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); + } aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); - + /* declare CPU hotplug MMIO region with related access fields */ aml_append(cpu_ctrl_dev, - aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), + aml_operation_region("PRST", rs, aml_int(io_base), ACPI_CPU_HOTPLUG_REG_LEN)); - + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, -@@ -517,6 +523,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +@@ -663,6 +669,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(dev, aml_name_decl("_UID", uid)); } - + + assert(adevc); + if (adevc->cpu_cppc) { + adevc->cpu_cppc(adev, i, arch_ids->len, dev); @@ -70,22 +70,10 @@ index 0c0bfe479a..72ad1fcff2 100644 method = aml_method("_STA", 0, AML_SERIALIZED); aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid))); aml_append(dev, method); -@@ -535,6 +546,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - apic->flags = cpu_to_le32(1); - break; - } -+ case ACPI_APIC_GENERIC_CPU_INTERFACE: { -+ AcpiMadtGenericCpuInterface *gicc = (void *)madt_buf->data; -+ gicc->flags = cpu_to_le32(1); -+ break; -+ } - default: - assert(0); - } -@@ -570,9 +586,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +@@ -703,9 +714,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(sb_scope, cpus_dev); aml_append(table, sb_scope); - + - method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); - aml_append(table, method); @@ -94,35 +82,36 @@ index 0c0bfe479a..72ad1fcff2 100644 + aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); + aml_append(table, method); + } - + g_free(cphp_res_path); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index 749218561a..c97731ecb3 100644 +index a99c6e4fe3..1ce2d67c2e 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c -@@ -1869,7 +1869,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - .acpi_1_compatible = true, .has_legacy_cphp = true +@@ -1513,7 +1513,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + .fw_unplugs_cpu = pm->smi_on_cpu_unplug, }; build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, - "\\_SB.PCI0", "\\_GPE._E02"); + "\\_SB.PCI0", "\\_GPE._E02", AML_SYSTEM_IO); } - + if (pcms->memhp_io_base && nr_mem) { diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h -index 62f0278ba2..a30ec84a4f 100644 +index 999caaf510..a0fdc44bdd 100644 --- a/include/hw/acpi/cpu.h +++ b/include/hw/acpi/cpu.h -@@ -55,7 +55,8 @@ typedef struct CPUHotplugFeatures { +@@ -58,7 +58,8 @@ typedef struct CPUHotplugFeatures { void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, hwaddr io_base, const char *res_root, - const char *event_handler_method); + const char *event_handler_method, + AmlRegionSpace rs); - + void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list); + +-- +2.27.0 --- -2.19.1 diff --git a/acpi-fix-QEMU-crash-when-started-with-SLIC-table.patch b/acpi-fix-QEMU-crash-when-started-with-SLIC-table.patch new file mode 100644 index 0000000000000000000000000000000000000000..8532cce569d605f136aa1becfa4b638fe293bf1c --- /dev/null +++ b/acpi-fix-QEMU-crash-when-started-with-SLIC-table.patch @@ -0,0 +1,90 @@ +From ad7b272f693e2fbf4a74c47f566b6c3f8c27247c Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 27 Dec 2021 14:31:17 -0500 +Subject: [PATCH 1/6] acpi: fix QEMU crash when started with SLIC table +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +if QEMU is started with used provided SLIC table blob, + + -acpitable sig=SLIC,oem_id='CRASH ',oem_table_id="ME",oem_rev=00002210,asl_compiler_id="",asl_compiler_rev=00000000,data=/dev/null +it will assert with: + + hw/acpi/aml-build.c:61:build_append_padded_str: assertion failed: (len <= maxlen) + +and following backtrace: + + ... + build_append_padded_str (array=0x555556afe320, str=0x555556afdb2e "CRASH ME", maxlen=0x6, pad=0x20) at hw/acpi/aml-build.c:61 + acpi_table_begin (desc=0x7fffffffd1b0, array=0x555556afe320) at hw/acpi/aml-build.c:1727 + build_fadt (tbl=0x555556afe320, linker=0x555557ca3830, f=0x7fffffffd318, oem_id=0x555556afdb2e "CRASH ME", oem_table_id=0x555556afdb34 "ME") at hw/acpi/aml-build.c:2064 + ... + +which happens due to acpi_table_begin() expecting NULL terminated +oem_id and oem_table_id strings, which is normally the case, but +in case of user provided SLIC table, oem_id points to table's blob +directly and as result oem_id became longer than expected. + +Fix issue by handling oem_id consistently and make acpi_get_slic_oem() +return NULL terminated strings. + +PS: +After [1] refactoring, oem_id semantics became inconsistent, where +NULL terminated string was coming from machine and old way pointer +into byte array coming from -acpitable option. That used to work +since build_header() wasn't expecting NULL terminated string and +blindly copied the 1st 6 bytes only. + +However commit [2] broke that by replacing build_header() with +acpi_table_begin(), which was expecting NULL terminated string +and was checking oem_id size. + +1) 602b45820 ("acpi: Permit OEM ID and OEM table ID fields to be changed") +2) +Fixes: 4b56e1e4eb08 ("acpi: build_fadt: use acpi_table_begin()/acpi_table_end() instead of build_header()") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/786 +Signed-off-by: Igor Mammedov +Message-Id: <20211227193120.1084176-2-imammedo@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Denis Lisov +Tested-by: Alexander Tsoy +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/acpi/core.c | 4 ++-- + hw/i386/acpi-build.c | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/acpi/core.c b/hw/acpi/core.c +index eb631caa91..a2d790d432 100644 +--- a/hw/acpi/core.c ++++ b/hw/acpi/core.c +@@ -346,8 +346,8 @@ int acpi_get_slic_oem(AcpiSlicOem *oem) + struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length)); + + if (memcmp(hdr->sig, "SLIC", 4) == 0) { +- oem->id = hdr->oem_id; +- oem->table_id = hdr->oem_table_id; ++ oem->id = g_strndup(hdr->oem_id, 6); ++ oem->table_id = g_strndup(hdr->oem_table_id, 8); + return 0; + } + } +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 1ce2d67c2e..0ec2932ec2 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2721,6 +2721,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) + + /* Cleanup memory that's no longer used. */ + g_array_free(table_offsets, true); ++ g_free(slic_oem.id); ++ g_free(slic_oem.table_id); + } + + static void acpi_ram_update(MemoryRegion *mr, GArray *data) +-- +2.27.0 + diff --git a/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch b/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch deleted file mode 100644 index f4e0a25c050e7948c1c7e1e2e0721c0b43d27fcc..0000000000000000000000000000000000000000 --- a/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 3cd6df0b9e7d7b544673ce9a63b405e236d8265b Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Fri, 10 Apr 2020 10:05:54 +0800 -Subject: [PATCH] acpi/ged: Add virt_madt_cpu_entry to madt_cpu hook - -In build_cpus_aml, we will invoke this hook to build _MAT -aml mehtod for cpus. - -Signed-off-by: Keqian Zhu -Signed-off-by: Salil Mehta ---- - hw/acpi/generic_event_device.c | 1 + - include/hw/acpi/generic_event_device.h | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c -index 9cee90cc70..b834ae3ff6 100644 ---- a/hw/acpi/generic_event_device.c -+++ b/hw/acpi/generic_event_device.c -@@ -288,6 +288,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) - hc->plug = acpi_ged_device_plug_cb; - - adevc->send_event = acpi_ged_send_event; -+ adevc->madt_cpu = virt_madt_cpu_entry; - } - - static const TypeInfo acpi_ged_info = { -diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h -index d157eac088..f99efad7a3 100644 ---- a/include/hw/acpi/generic_event_device.h -+++ b/include/hw/acpi/generic_event_device.h -@@ -61,6 +61,7 @@ - - #include "hw/sysbus.h" - #include "hw/acpi/memory_hotplug.h" -+#include "hw/arm/virt.h" - - #define ACPI_POWER_BUTTON_DEVICE "PWRB" - --- -2.19.1 diff --git a/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch b/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch index 57247e6797da5a977685f737e9454427ab2c41df..12a279ea615113b4d249e5bf8524f961778fb3b3 100644 --- a/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch +++ b/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch @@ -1,4 +1,4 @@ -From 05d22b55133db1a2526cfe305102e075e883b5e2 Mon Sep 17 00:00:00 2001 +From 603cbcc5efdd35f518a5bd0a5067d40c2c4eb8d6 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 3 Apr 2020 15:41:01 +0800 Subject: [PATCH] acpi/ged: Extend ACPI GED to support CPU hotplug @@ -26,45 +26,45 @@ Signed-off-by: Salil Mehta 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst -index 911a98255b..deb481555d 100644 +index 0bd3f9399f..3acd6fcd8b 100644 --- a/docs/specs/acpi_hw_reduced_hotplug.rst +++ b/docs/specs/acpi_hw_reduced_hotplug.rst -@@ -63,7 +63,8 @@ GED IO interface (4 byte access) - bits: +@@ -64,7 +64,8 @@ GED IO interface (4 byte access) 0: Memory hotplug event 1: System power down event -- 2-31: Reserved -+ 2: CPU hotplug event -+ 3-31: Reserved - + 2: NVDIMM hotplug event +- 3-31: Reserved ++ 3: CPU hotplug event ++ 4-31: Reserved + **write_access:** - + diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index 72ad1fcff2..cb6bb67f3c 100644 +index a9c2ee952a..f9ce0a7f41 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -6,7 +6,6 @@ #include "trace.h" #include "sysemu/numa.h" - + -#define ACPI_CPU_HOTPLUG_REG_LEN 12 #define ACPI_CPU_SELECTOR_OFFSET_WR 0 #define ACPI_CPU_FLAGS_OFFSET_RW 4 #define ACPI_CPU_CMD_OFFSET_WR 5 diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c -index 82139b4314..478a4ee87c 100644 +index e28457a7d1..042a8ef8a5 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c -@@ -23,6 +23,7 @@ - static const uint32_t ged_supported_events[] = { +@@ -25,6 +25,7 @@ static const uint32_t ged_supported_events[] = { ACPI_GED_MEM_HOTPLUG_EVT, ACPI_GED_PWR_DOWN_EVT, + ACPI_GED_NVDIMM_HOTPLUG_EVT, + ACPI_GED_CPU_HOTPLUG_EVT, }; - + /* -@@ -110,6 +111,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, - aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), +@@ -117,6 +118,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, + aml_notify(aml_name("\\_SB.NVDR"), aml_int(0x80))); break; + case ACPI_GED_CPU_HOTPLUG_EVT: @@ -73,28 +73,28 @@ index 82139b4314..478a4ee87c 100644 default: /* * Please make sure all the events in ged_supported_events[] -@@ -176,6 +180,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, - - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { +@@ -234,6 +238,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, + } else { acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); + } + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); } else { error_setg(errp, "virt: device plug request for unsupported device" " type: %s", object_get_typename(OBJECT(dev))); -@@ -192,6 +198,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) - sel = ACPI_GED_MEM_HOTPLUG_EVT; - } else if (ev & ACPI_POWER_DOWN_STATUS) { +@@ -279,6 +285,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) sel = ACPI_GED_PWR_DOWN_EVT; + } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) { + sel = ACPI_GED_NVDIMM_HOTPLUG_EVT; + } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { + sel = ACPI_GED_CPU_HOTPLUG_EVT; } else { /* Unknown event. Return without generating interrupt. */ warn_report("GED: Unsupported event %d. No irq injected", ev); -@@ -224,6 +232,16 @@ static const VMStateDescription vmstate_memhp_state = { +@@ -311,6 +319,16 @@ static const VMStateDescription vmstate_memhp_state = { } }; - + +static const VMStateDescription vmstate_cpuhp_state = { + .name = "acpi-ged/cpuhp", + .version_id = 1, @@ -108,26 +108,26 @@ index 82139b4314..478a4ee87c 100644 static const VMStateDescription vmstate_ged_state = { .name = "acpi-ged-state", .version_id = 1, -@@ -244,6 +262,7 @@ static const VMStateDescription vmstate_acpi_ged = { - }, +@@ -360,6 +378,7 @@ static const VMStateDescription vmstate_acpi_ged = { .subsections = (const VMStateDescription * []) { &vmstate_memhp_state, + &vmstate_ghes_state, + &vmstate_cpuhp_state, NULL } }; -@@ -254,6 +273,7 @@ static void acpi_ged_initfn(Object *obj) +@@ -370,6 +389,7 @@ static void acpi_ged_initfn(Object *obj) AcpiGedState *s = ACPI_GED(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); GEDState *ged_st = &s->ged_state; + MachineClass *mc; - - memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st, + + memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st, TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); -@@ -273,6 +293,21 @@ static void acpi_ged_initfn(Object *obj) - sysbus_init_mmio(sbd, &s->container_memhp); - acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), - &s->memhp_state, 0); +@@ -393,6 +413,21 @@ static void acpi_ged_initfn(Object *obj) + memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st, + TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT); + sysbus_init_mmio(sbd, &ged_st->regs); + + mc = MACHINE_GET_CLASS(qdev_get_machine()); + if (!mc->possible_cpu_arch_ids) { @@ -144,54 +144,54 @@ index 82139b4314..478a4ee87c 100644 + cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), + &s->cpuhp_state, 0); } - + static void acpi_ged_class_init(ObjectClass *class, void *data) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig -index ad7f7c089b..15e18b0a48 100644 +index 2d37d29f02..006a4b4c4b 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig -@@ -24,6 +24,7 @@ config ARM_VIRT +@@ -27,6 +27,7 @@ config ARM_VIRT select DIMM - select ACPI_MEMORY_HOTPLUG select ACPI_HW_REDUCED + select ACPI_APEI + select ACPI_CPU_HOTPLUG - + config CHEETAH bool diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h -index a30ec84a4f..e726414459 100644 +index a0fdc44bdd..d521025830 100644 --- a/include/hw/acpi/cpu.h +++ b/include/hw/acpi/cpu.h @@ -17,6 +17,8 @@ #include "hw/acpi/aml-build.h" #include "hw/hotplug.h" - + +#define ACPI_CPU_HOTPLUG_REG_LEN 12 + typedef struct AcpiCpuStatus { struct CPUState *cpu; uint64_t arch_id; diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h -index f99efad7a3..e702ff1e18 100644 +index d49217c445..6bb2ade385 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h -@@ -62,6 +62,7 @@ - #include "hw/sysbus.h" +@@ -63,6 +63,7 @@ #include "hw/acpi/memory_hotplug.h" - #include "hw/arm/virt.h" + #include "hw/acpi/ghes.h" + #include "qom/object.h" +#include "hw/acpi/cpu.h" - + #define ACPI_POWER_BUTTON_DEVICE "PWRB" - -@@ -83,6 +84,7 @@ - */ + +@@ -97,6 +98,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 #define ACPI_GED_PWR_DOWN_EVT 0x2 -+#define ACPI_GED_CPU_HOTPLUG_EVT 0x4 - + #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 ++#define ACPI_GED_CPU_HOTPLUG_EVT 0x8 + typedef struct GEDState { - MemoryRegion io; -@@ -93,6 +95,8 @@ typedef struct AcpiGedState { + MemoryRegion evt; +@@ -108,6 +110,8 @@ struct AcpiGedState { SysBusDevice parent_obj; MemHotplugState memhp_state; MemoryRegion container_memhp; @@ -200,5 +200,6 @@ index f99efad7a3..e702ff1e18 100644 GEDState ged_state; uint32_t ged_event_bitmap; qemu_irq irq; --- -2.19.1 +-- +2.27.0 + diff --git a/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch b/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch index 30f210b33b66332cc0c16b5d2ddb706a177a2130..47d18ea6aa6fff4b8e8fce353f5fa0c3405b8291 100644 --- a/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch +++ b/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch @@ -1,4 +1,4 @@ -From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 Mon Sep 17 00:00:00 2001 +From 8bd05cdb811e868c54ef28ac558c7efb7cf610b9 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 13:40:44 +0800 Subject: [PATCH] acpi/madt: Add pre-sizing capability to MADT GICC struct @@ -9,87 +9,76 @@ of MADT GICC struct, so we should pre-sizing MADT GICC too. Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/arm/virt-acpi-build.c | 26 +++++++++++++++++++++----- - include/hw/acpi/acpi-defs.h | 1 + - 2 files changed, 22 insertions(+), 5 deletions(-) + hw/arm/virt-acpi-build.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index dbe9acb148..efac788ba1 100644 +index 7cb320d9f2..a16b54086e 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -678,6 +678,13 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const MemMapEntry *memmap = vms->memmap; - AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc)); - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid)); +@@ -787,8 +787,16 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int i, + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); + uint64_t physical_base_address = 0, gich = 0, gicv = 0; + uint32_t vgic_interrupt = vms->virt ? PPI(ARCH_GIC_MAINT_IRQ) : 0; +- uint32_t pmu_interrupt = arm_feature(&armcpu->env, ARM_FEATURE_PMU) ? +- PPI(VIRTUAL_PMU_IRQ) : 0; ++ uint32_t pmu_interrupt, enabled; + static bool pmu; + -+ if (uid == 0) { ++ if (i == 0) { + pmu = arm_feature(&armcpu->env, ARM_FEATURE_PMU); + } + /* FEATURE_PMU should be all enabled or disabled for CPUs */ + assert(!armcpu || arm_feature(&armcpu->env, ARM_FEATURE_PMU) == pmu); - - gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; - gicc->length = sizeof(*gicc); -@@ -687,11 +694,15 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); - } - gicc->cpu_interface_number = cpu_to_le32(uid); -- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); -+ gicc->arm_mpidr = possible_cpus->cpus[uid].arch_id; - gicc->uid = cpu_to_le32(uid); -- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); -+ if (armcpu) { -+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); -+ } else { -+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_DISABLED); -+ } - -- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { -+ if (pmu) { - gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); - } - if (vms->virt) { -@@ -704,12 +715,17 @@ static void - build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) ++ pmu_interrupt = pmu ? PPI(VIRTUAL_PMU_IRQ) : 0; ++ enabled = armcpu || force_enabled ? 1 /* Enabled */ : 0 /* Disabled */; + + if (vms->gic_version == 2) { + physical_base_address = memmap[VIRT_GIC_CPU].base; +@@ -803,7 +811,7 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int i, + build_append_int_noprefix(table_data, i, 4); /* GIC ID */ + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ + /* Flags */ +- build_append_int_noprefix(table_data, 1, 4); /* Enabled */ ++ build_append_int_noprefix(table_data, enabled, 4); /* Enabled */ + /* Parking Protocol Version */ + build_append_int_noprefix(table_data, 0, 4); + /* Performance Interrupt GSIV */ +@@ -817,7 +825,7 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int i, + build_append_int_noprefix(table_data, vgic_interrupt, 4); + build_append_int_noprefix(table_data, 0, 8); /* GICR Base Address*/ + /* MPIDR */ +- build_append_int_noprefix(table_data, armcpu->mp_affinity, 8); ++ build_append_int_noprefix(table_data, possible_cpus->cpus[i].arch_id, 8); + } + + static void +@@ -825,9 +833,14 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + int i; VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); + MachineClass *mc = MACHINE_GET_CLASS(vms); + MachineState *ms = MACHINE(vms); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); - int madt_start = table_data->len; const MemMapEntry *memmap = vms->memmap; - const int *irqmap = vms->irqmap; - AcpiMultipleApicTable *madt; - AcpiMadtGenericDistributor *gicd; - AcpiMadtGenericMsiFrame *gic_msi; + AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + /* The MADT GICC numbers */ -+ int num_cpu = vms->smp_cpus; - int i; - - madt = acpi_data_push(table_data, sizeof *madt); -@@ -720,8 +736,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); - gicd->version = vms->gic_version; - -- for (i = 0; i < vms->smp_cpus; i++) { -- virt_madt_cpu_entry(NULL, i, NULL, table_data); ++ int num_cpu = ms->smp.cpus; + + acpi_table_begin(&table, table_data); + /* Local Interrupt Controller Address */ +@@ -846,8 +859,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + build_append_int_noprefix(table_data, vms->gic_version, 1); + build_append_int_noprefix(table_data, 0, 3); /* Reserved */ + +- for (i = 0; i < MACHINE(vms)->smp.cpus; i++) { +- virt_madt_cpu_entry(NULL, i, NULL, table_data, false); + for (i = 0; i < num_cpu; i++) { -+ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data); ++ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data, false); } - + if (vms->gic_version == 3) { -diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h -index 39ae91d3b8..6bfa7f9152 100644 ---- a/include/hw/acpi/acpi-defs.h -+++ b/include/hw/acpi/acpi-defs.h -@@ -306,6 +306,7 @@ typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface; - - /* GICC CPU Interface Flags */ - #define ACPI_MADT_GICC_ENABLED 1 -+#define ACPI_MADT_GICC_DISABLED 0 +-- +2.27.0 - struct AcpiMadtGenericDistributor { - ACPI_SUB_HEADER_DEF --- -2.19.1 diff --git a/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch b/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch index 6bda35c51a3952121a155081bf0a37ce3534da25..d322c8d1098dedcfcdc328c8e5e9c5b2bf035010 100644 --- a/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch +++ b/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch @@ -1,4 +1,4 @@ -From a3097eed8b642dc6fe891112340821e869b90cc2 Mon Sep 17 00:00:00 2001 +From 4f50ed900713acc14c971c07165fa83670d3f2b8 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 13 Jan 2020 19:02:20 +0800 Subject: [PATCH] acpi/madt: Factor out the building of MADT GICC struct @@ -10,99 +10,127 @@ out the GICC building code from ACPI MADT and reuse it in build_cpus_aml. Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/arm/virt-acpi-build.c | 51 +++++++++++++++++++++++----------------- - include/hw/arm/virt.h | 3 +++ - 2 files changed, 32 insertions(+), 22 deletions(-) + hw/arm/virt-acpi-build.c | 77 ++++++++++++++++++++++------------------ + include/hw/arm/virt.h | 4 +++ + 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index f48733d9f2..4b6aace433 100644 +index 1ca705654b..64b1ed8672 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -664,6 +664,34 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - table_data->len - gtdt_start, 2, NULL, NULL); +@@ -771,6 +771,48 @@ static void build_append_gicr(GArray *table_data, uint64_t base, uint32_t size) + build_append_int_noprefix(table_data, size, 4); /* Discovery Range Length */ } - -+void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *possible_cpus, GArray *entry) + ++void virt_madt_cpu_entry(AcpiDeviceIf *adev, int i, ++ const CPUArchIdList *possible_cpus, GArray *table_data, ++ bool force_enabled) +{ + VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); + const MemMapEntry *memmap = vms->memmap; -+ AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc)); -+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid)); ++ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); ++ uint64_t physical_base_address = 0, gich = 0, gicv = 0; ++ uint32_t vgic_interrupt = vms->virt ? PPI(ARCH_GIC_MAINT_IRQ) : 0; ++ uint32_t pmu_interrupt = arm_feature(&armcpu->env, ARM_FEATURE_PMU) ? ++ PPI(VIRTUAL_PMU_IRQ) : 0; + -+ gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; -+ gicc->length = sizeof(*gicc); + if (vms->gic_version == 2) { -+ gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); -+ gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base); -+ gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); ++ physical_base_address = memmap[VIRT_GIC_CPU].base; ++ gicv = memmap[VIRT_GIC_VCPU].base; ++ gich = memmap[VIRT_GIC_HYP].base; + } -+ gicc->cpu_interface_number = cpu_to_le32(uid); -+ gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); -+ gicc->uid = cpu_to_le32(uid); -+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); + -+ if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { -+ gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); -+ } -+ if (vms->virt) { -+ gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ)); -+ } ++ /* 5.2.12.14 GIC Structure */ ++ build_append_int_noprefix(table_data, 0xB, 1); /* Type */ ++ build_append_int_noprefix(table_data, 76, 1); /* Length */ ++ build_append_int_noprefix(table_data, 0, 2); /* Reserved */ ++ build_append_int_noprefix(table_data, i, 4); /* GIC ID */ ++ build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ ++ /* Flags */ ++ build_append_int_noprefix(table_data, 1, 4); /* Enabled */ ++ /* Parking Protocol Version */ ++ build_append_int_noprefix(table_data, 0, 4); ++ /* Performance Interrupt GSIV */ ++ build_append_int_noprefix(table_data, pmu_interrupt, 4); ++ build_append_int_noprefix(table_data, 0, 8); /* Parked Address */ ++ /* Physical Base Address */ ++ build_append_int_noprefix(table_data, physical_base_address, 8); ++ build_append_int_noprefix(table_data, gicv, 8); /* GICV */ ++ build_append_int_noprefix(table_data, gich, 8); /* GICH */ ++ /* VGIC Maintenance interrupt */ ++ build_append_int_noprefix(table_data, vgic_interrupt, 4); ++ build_append_int_noprefix(table_data, 0, 8); /* GICR Base Address*/ ++ /* MPIDR */ ++ build_append_int_noprefix(table_data, armcpu->mp_affinity, 8); +} + - /* MADT */ static void build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) -@@ -686,28 +714,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - gicd->version = vms->gic_version; - - for (i = 0; i < vms->smp_cpus; i++) { -- AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data, -- sizeof(*gicc)); + { +@@ -798,40 +840,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + build_append_int_noprefix(table_data, 0, 3); /* Reserved */ + + for (i = 0; i < MACHINE(vms)->smp.cpus; i++) { - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); +- uint64_t physical_base_address = 0, gich = 0, gicv = 0; +- uint32_t vgic_interrupt = vms->virt ? PPI(ARCH_GIC_MAINT_IRQ) : 0; +- uint32_t pmu_interrupt = arm_feature(&armcpu->env, ARM_FEATURE_PMU) ? +- PPI(VIRTUAL_PMU_IRQ) : 0; - -- gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; -- gicc->length = sizeof(*gicc); - if (vms->gic_version == 2) { -- gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); -- gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base); -- gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); +- physical_base_address = memmap[VIRT_GIC_CPU].base; +- gicv = memmap[VIRT_GIC_VCPU].base; +- gich = memmap[VIRT_GIC_HYP].base; - } -- gicc->cpu_interface_number = cpu_to_le32(i); -- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); -- gicc->uid = cpu_to_le32(i); -- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); - -- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { -- gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); -- } -- if (vms->virt) { -- gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ)); -- } -+ virt_madt_cpu_entry(NULL, i, NULL, table_data); +- /* 5.2.12.14 GIC Structure */ +- build_append_int_noprefix(table_data, 0xB, 1); /* Type */ +- build_append_int_noprefix(table_data, 76, 1); /* Length */ +- build_append_int_noprefix(table_data, 0, 2); /* Reserved */ +- build_append_int_noprefix(table_data, i, 4); /* GIC ID */ +- build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ +- /* Flags */ +- build_append_int_noprefix(table_data, 1, 4); /* Enabled */ +- /* Parking Protocol Version */ +- build_append_int_noprefix(table_data, 0, 4); +- /* Performance Interrupt GSIV */ +- build_append_int_noprefix(table_data, pmu_interrupt, 4); +- build_append_int_noprefix(table_data, 0, 8); /* Parked Address */ +- /* Physical Base Address */ +- build_append_int_noprefix(table_data, physical_base_address, 8); +- build_append_int_noprefix(table_data, gicv, 8); /* GICV */ +- build_append_int_noprefix(table_data, gich, 8); /* GICH */ +- /* VGIC Maintenance interrupt */ +- build_append_int_noprefix(table_data, vgic_interrupt, 4); +- build_append_int_noprefix(table_data, 0, 8); /* GICR Base Address*/ +- /* MPIDR */ +- build_append_int_noprefix(table_data, armcpu->mp_affinity, 8); ++ virt_madt_cpu_entry(NULL, i, NULL, table_data, false); } - + if (vms->gic_version == 3) { diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 3dfefca93b..6b1f10b231 100644 +index a4356cf736..36639e8d3e 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -37,6 +37,7 @@ - #include "hw/block/flash.h" +@@ -38,6 +38,7 @@ #include "sysemu/kvm.h" #include "hw/intc/arm_gicv3_common.h" + #include "qom/object.h" +#include "hw/acpi/acpi_dev_interface.h" - + #define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 -@@ -154,6 +155,8 @@ typedef struct { - OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - +@@ -181,6 +182,9 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE) + void virt_acpi_setup(VirtMachineState *vms); + bool virt_is_acpi_enabled(VirtMachineState *vms); +void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *cpu_list, GArray *entry); - ++ const CPUArchIdList *cpu_list, GArray *entry, ++ bool force_enabled); + /* Return the number of used redistributor regions */ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) --- -2.19.1 +-- +2.27.0 + diff --git a/acpi-modify-build_ppt-del-macro-add-arm-build_pptt.patch b/acpi-modify-build_ppt-del-macro-add-arm-build_pptt.patch new file mode 100644 index 0000000000000000000000000000000000000000..a877196b6bde891c0ac037df6320e68bfce06fec --- /dev/null +++ b/acpi-modify-build_ppt-del-macro-add-arm-build_pptt.patch @@ -0,0 +1,100 @@ +From 69564ae0e54345391ceceadb6cde9a09db01c2d9 Mon Sep 17 00:00:00 2001 +From: saarloos <9090-90-90-9090@163.com> +Date: Mon, 23 May 2022 20:59:51 +0800 +Subject: [PATCH] arm/acpi: Fix when make qemu-system-aarch64 at x86_64 host + bios_tables_test fail reason: __aarch64__ macro let build_pptt at x86_64 and + aarch64 host build different function that let bios_tables_test fail. + +Signed-off-by: Yangzi Zhang +--- + hw/acpi/aml-build.c | 5 +---- + hw/arm/virt-acpi-build.c | 2 +- + include/hw/acpi/aml-build.h | 7 +++---- + 3 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index c4edaafa4a..39b8d807c0 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2016,7 +2016,6 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + } + } + +-#ifdef __aarch64__ + /* + * ACPI spec, Revision 6.3 + * 5.2.29.2 Cache Type Structure (Type 1) +@@ -2072,7 +2071,7 @@ static void build_cache_hierarchy_node(GArray *tbl, uint32_t next_level, + * ACPI spec, Revision 6.3 + * 5.2.29 Processor Properties Topology Table (PPTT) + */ +-void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, ++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); +@@ -2172,7 +2171,6 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + acpi_table_end(linker, &table); + } + +-#else + /* + * ACPI spec, Revision 6.3 + * 5.2.29 Processor Properties Topology Table (PPTT) +@@ -2263,7 +2261,6 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + g_queue_free(list); + acpi_table_end(linker, &table); + } +-#endif + + /* build rev1/rev3/rev5.1 FADT */ + void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 1101161d70..89cecdd8e6 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -1070,7 +1070,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) + + if (!vmc->no_cpu_topology) { + acpi_add_table(table_offsets, tables_blob); +- build_pptt(tables_blob, tables->linker, ms, ++ build_pptt_arm(tables_blob, tables->linker, ms, + vms->oem_id, vms->oem_table_id); + } + +diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h +index 2e00d2e208..5e9b72c024 100644 +--- a/include/hw/acpi/aml-build.h ++++ b/include/hw/acpi/aml-build.h +@@ -221,9 +221,7 @@ struct AcpiBuildTables { + BIOSLinker *linker; + } AcpiBuildTables; + +-#ifdef __aarch64__ + /* Definitions of the hardcoded cache info*/ +- + typedef enum { + ARM_L1D_CACHE, + ARM_L1I_CACHE, +@@ -266,8 +264,6 @@ struct offset_status { + uint32_t l1i_offset; + }; + +-#endif +- + typedef + struct CrsRangeEntry { + uint64_t base; +@@ -542,6 +538,9 @@ void build_slit(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_pptt_arm(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, + const char *oem_id, const char *oem_table_id); + +-- +2.35.1.windows.2 + diff --git a/acpi-pcihp-pcie-set-power-on-cap-on-parent-slot.patch b/acpi-pcihp-pcie-set-power-on-cap-on-parent-slot.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a70fcc60f27a127024e2d9cfe506f268685a4e1 --- /dev/null +++ b/acpi-pcihp-pcie-set-power-on-cap-on-parent-slot.patch @@ -0,0 +1,121 @@ +From 6c92ab0387c2af443142a0cc47134389711a14dc Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Tue, 1 Mar 2022 10:11:59 -0500 +Subject: [PATCH 5/6] acpi: pcihp: pcie: set power on cap on parent slot + +on creation a PCIDevice has power turned on at the end of pci_qdev_realize() +however later on if PCIe slot isn't populated with any children +it's power is turned off. It's fine if native hotplug is used +as plug callback will power slot on among other things. +However when ACPI hotplug is enabled it replaces native PCIe plug +callbacks with ACPI specific ones (acpi_pcihp_device_*plug_cb) and +as result slot stays powered off. It works fine as ACPI hotplug +on guest side takes care of enumerating/initializing hotplugged +device. But when later guest is migrated, call chain introduced by] +commit d5daff7d312 (pcie: implement slot power control for pcie root ports) + + pcie_cap_slot_post_load() + -> pcie_cap_update_power() + -> pcie_set_power_device() + -> pci_set_power() + -> pci_update_mappings() + +will disable earlier initialized BARs for the hotplugged device +in powered off slot due to commit 23786d13441 (pci: implement power state) +which disables BARs if power is off. + +Fix it by setting PCI_EXP_SLTCTL_PCC to PCI_EXP_SLTCTL_PWR_ON +on slot (root port/downstream port) at the time a device +hotplugged into it. As result PCI_EXP_SLTCTL_PWR_ON is migrated +to target and above call chain keeps device plugged into it +powered on. + +Fixes: d5daff7d312 ("pcie: implement slot power control for pcie root ports") +Fixes: 23786d13441 ("pci: implement power state") +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2053584 +Suggested-by: "Michael S. Tsirkin" +Signed-off-by: Igor Mammedov +Message-Id: <20220301151200.3507298-3-imammedo@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: wanbo +--- + hw/acpi/pcihp.c | 12 +++++++++++- + hw/pci/pcie.c | 11 +++++++++++ + include/hw/pci/pcie.h | 1 + + 3 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c +index a5e182dd3a..be0e846b34 100644 +--- a/hw/acpi/pcihp.c ++++ b/hw/acpi/pcihp.c +@@ -32,6 +32,7 @@ + #include "hw/pci/pci_bridge.h" + #include "hw/pci/pci_host.h" + #include "hw/pci/pcie_port.h" ++#include "hw/pci-bridge/xio3130_downstream.h" + #include "hw/i386/acpi-build.h" + #include "hw/acpi/acpi.h" + #include "hw/pci/pci_bus.h" +@@ -341,6 +342,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, + { + PCIDevice *pdev = PCI_DEVICE(dev); + int slot = PCI_SLOT(pdev->devfn); ++ PCIDevice *bridge; ++ PCIBus *bus; + int bsel; + + /* Don't send event when device is enabled during qemu machine creation: +@@ -370,7 +373,14 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, + return; + } + +- bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev)); ++ bus = pci_get_bus(pdev); ++ bridge = pci_bridge_get_device(bus); ++ if (object_dynamic_cast(OBJECT(bridge), TYPE_PCIE_ROOT_PORT) || ++ object_dynamic_cast(OBJECT(bridge), TYPE_XIO3130_DOWNSTREAM)) { ++ pcie_cap_slot_enable_power(bridge); ++ } ++ ++ bsel = acpi_pcihp_get_bsel(bus); + g_assert(bsel >= 0); + s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); + acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); +diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c +index 30c09ed943..a2d1ae6021 100644 +--- a/hw/pci/pcie.c ++++ b/hw/pci/pcie.c +@@ -365,6 +365,17 @@ static void hotplug_event_clear(PCIDevice *dev) + } + } + ++void pcie_cap_slot_enable_power(PCIDevice *dev) ++{ ++ uint8_t *exp_cap = dev->config + dev->exp.exp_cap; ++ uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP); ++ ++ if (sltcap & PCI_EXP_SLTCAP_PCP) { ++ pci_set_word_by_mask(exp_cap + PCI_EXP_SLTCTL, ++ PCI_EXP_SLTCTL_PCC, PCI_EXP_SLTCTL_PWR_ON); ++ } ++} ++ + static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque) + { + bool *power = opaque; +diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h +index 6063bee0ec..c27368d077 100644 +--- a/include/hw/pci/pcie.h ++++ b/include/hw/pci/pcie.h +@@ -112,6 +112,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len); + int pcie_cap_slot_post_load(void *opaque, int version_id); + void pcie_cap_slot_push_attention_button(PCIDevice *dev); ++void pcie_cap_slot_enable_power(PCIDevice *dev); + + void pcie_cap_root_init(PCIDevice *dev); + void pcie_cap_root_reset(PCIDevice *dev); +-- +2.27.0 + diff --git a/acpi-validate-hotplug-selector-on-access.patch b/acpi-validate-hotplug-selector-on-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..0506bd943319533917a0fdbd2b948e6b18729a12 --- /dev/null +++ b/acpi-validate-hotplug-selector-on-access.patch @@ -0,0 +1,41 @@ +From 1205bf5738346fe9f217f5db08500b12b812aafa Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Tue, 21 Dec 2021 09:45:44 -0500 +Subject: [PATCH 1/2] acpi: validate hotplug selector on access +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When bus is looked up on a pci write, we didn't +validate that the lookup succeeded. +Fuzzers thus can trigger QEMU crash by dereferencing the NULL +bus pointer. + +Fixes: b32bd763a1 ("pci: introduce acpi-index property for PCI device") +Fixes: CVE-2021-4158 +Cc: "Igor Mammedov" +Fixes: https://gitlab.com/qemu-project/qemu/-/issues/770 +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Ani Sinha +--- + hw/acpi/pcihp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c +index 30405b5113..a5e182dd3a 100644 +--- a/hw/acpi/pcihp.c ++++ b/hw/acpi/pcihp.c +@@ -491,6 +491,9 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data, + } + + bus = acpi_pcihp_find_hotplug_bus(s, s->hotplug_select); ++ if (!bus) { ++ break; ++ } + QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { + Object *o = OBJECT(kid->child); + PCIDevice *dev = PCI_DEVICE(o); +-- +2.27.0 + diff --git a/add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch b/add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch new file mode 100644 index 0000000000000000000000000000000000000000..0bc4707a244ebc8366648250c75755e8446c6e44 --- /dev/null +++ b/add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch @@ -0,0 +1,74 @@ +From ec35c96006851a956a7e401f29af0ffe137c4bb9 Mon Sep 17 00:00:00 2001 +From: Jiadong Zeng +Date: Tue, 8 Feb 2022 22:56:37 +0800 +Subject: [PATCH] add Phytium's CPU models: FT-2000+ and Tengyun-S2500. + +Signed-off-by: Jiadong Zeng +Signed-off-by: Mingwang Li +--- + hw/arm/virt.c | 2 ++ + target/arm/cpu64.c | 28 ++++++++++++++++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index a4a35584e9..3c972fdab0 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -202,6 +202,8 @@ static const char *valid_cpus[] = { + ARM_CPU_TYPE_NAME("cortex-a57"), + ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("Kunpeng-920"), ++ ARM_CPU_TYPE_NAME("FT-2000+"), ++ ARM_CPU_TYPE_NAME("Tengyun-S2500"), + ARM_CPU_TYPE_NAME("a64fx"), + ARM_CPU_TYPE_NAME("host"), + ARM_CPU_TYPE_NAME("max"), +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 556b6f3691..08d886de7b 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -676,6 +676,32 @@ static Property arm_cpu_pauth_property = + static Property arm_cpu_pauth_impdef_property = + DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false); + ++static void aarch64_max_ft2000plus_initfn(Object *obj) ++{ ++ ARMCPU *cpu = ARM_CPU(obj); ++ ++ if (kvm_enabled()) { ++ kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_add_vcpu_properties(obj); ++ } else { ++ aarch64_a72_initfn(obj); ++ cpu->midr = 0x70186622; ++ } ++} ++ ++static void aarch64_max_tengyun_s2500_initfn(Object *obj) ++{ ++ ARMCPU *cpu = ARM_CPU(obj); ++ ++ if (kvm_enabled()) { ++ kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_add_vcpu_properties(obj); ++ } else { ++ aarch64_a72_initfn(obj); ++ cpu->midr = 0x70186632; ++ } ++} ++ + /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); + * otherwise, a CPU with as many features enabled as our emulation supports. + * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; +@@ -914,6 +940,8 @@ static const ARMCPUInfo aarch64_cpus[] = { + { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, + { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "Kunpeng-920", .initfn = aarch64_kunpeng_920_initfn}, ++ { .name = "FT-2000+", .initfn = aarch64_max_ft2000plus_initfn }, ++ { .name = "Tengyun-S2500", .initfn = aarch64_max_tengyun_s2500_initfn }, + { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, + { .name = "max", .initfn = aarch64_max_initfn }, + }; +-- +2.27.0 + diff --git a/aio-posix-fix-build-failure-io_uring-2.2.patch b/aio-posix-fix-build-failure-io_uring-2.2.patch new file mode 100644 index 0000000000000000000000000000000000000000..8096bc124f14b7667d2219628bc0acde406a6758 --- /dev/null +++ b/aio-posix-fix-build-failure-io_uring-2.2.patch @@ -0,0 +1,56 @@ +From f900bc66931458b824274027417b6375610c8d9a Mon Sep 17 00:00:00 2001 +From: Haiyue Wang +Date: Tue, 22 Feb 2022 00:24:01 +0800 +Subject: [PATCH] aio-posix: fix build failure io_uring 2.2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The io_uring fixed "Don't truncate addr fields to 32-bit on 32-bit": +https://git.kernel.dk/cgit/liburing/commit/?id=d84c29b19ed0b130000619cff40141bb1fc3615b + +This leads to build failure: +../util/fdmon-io_uring.c: In function ‘add_poll_remove_sqe’: +../util/fdmon-io_uring.c:182:36: error: passing argument 2 of ‘io_uring_prep_poll_remove’ makes integer from pointer without a cast [-Werror=int-conversion] + 182 | io_uring_prep_poll_remove(sqe, node); + | ^~~~ + | | + | AioHandler * +In file included from /root/io/qemu/include/block/aio.h:18, + from ../util/aio-posix.h:20, + from ../util/fdmon-io_uring.c:49: +/usr/include/liburing.h:415:17: note: expected ‘__u64’ {aka ‘long long unsigned int’} but argument is of type ‘AioHandler *’ + 415 | __u64 user_data) + | ~~~~~~^~~~~~~~~ +cc1: all warnings being treated as errors + +Use LIBURING_HAVE_DATA64 to check whether the io_uring supports 64-bit +variants of the get/set userdata, to convert the paramter to the right +data type. + +Signed-off-by: Haiyue Wang +Message-Id: <20220221162401.45415-1-haiyue.wang@intel.com> +Signed-off-by: Stefan Hajnoczi +--- + util/fdmon-io_uring.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c +index 1461dfa407..ab43052dd7 100644 +--- a/util/fdmon-io_uring.c ++++ b/util/fdmon-io_uring.c +@@ -179,7 +179,11 @@ static void add_poll_remove_sqe(AioContext *ctx, AioHandler *node) + { + struct io_uring_sqe *sqe = get_sqe(ctx); + ++#ifdef LIBURING_HAVE_DATA64 ++ io_uring_prep_poll_remove(sqe, (__u64)(uintptr_t)node); ++#else + io_uring_prep_poll_remove(sqe, node); ++#endif + } + + /* Add a timeout that self-cancels when another cqe becomes ready */ +-- +2.41.0.windows.1 + diff --git a/aio-posix-fix-race-between-epoll-upgrade-and-aio_set.patch b/aio-posix-fix-race-between-epoll-upgrade-and-aio_set.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d2aed800cfbe2c3d3779f7df0520e4408ea392c --- /dev/null +++ b/aio-posix-fix-race-between-epoll-upgrade-and-aio_set.patch @@ -0,0 +1,82 @@ +From 4ab8e11adf5878d1f298a682b37d7de4632a3a8b Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 28 Apr 2023 15:22:07 +0800 +Subject: [PATCH] aio-posix: fix race between epoll upgrade and + aio_set_fd_handler() + +If another thread calls aio_set_fd_handler() while the IOThread event +loop is upgrading from ppoll(2) to epoll(7) then we might miss new +AioHandlers. The epollfd will not monitor the new AioHandler's fd, +resulting in hangs. + +Take the AioHandler list lock while upgrading to epoll. This prevents +AioHandlers from changing while epoll is being set up. If we cannot lock +because we're in a nested event loop, then don't upgrade to epoll (it +will happen next time we're not in a nested call). + +The downside to taking the lock is that the aio_set_fd_handler() thread +has to wait until the epoll upgrade is finished, which involves many +epoll_ctl(2) system calls. However, this scenario is rare and I couldn't +think of another solution that is still simple. + +origin commit: https://gitlab.com/qemu-project/qemu/-/commit/e62da98527fa35fe5f532cded01a33edf9fbe7b2 +Signed-off-by: Meiyang Wang +Reported-by: Qing Wang +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2090998 +Cc: Paolo Bonzini +Cc: Fam Zheng +Signed-off-by: Stefan Hajnoczi +Message-Id: <20230323144859.1338495-1-stefanha@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +--- + util/fdmon-epoll.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c +index e11a8a022e..1683aa1105 100644 +--- a/util/fdmon-epoll.c ++++ b/util/fdmon-epoll.c +@@ -127,6 +127,8 @@ static bool fdmon_epoll_try_enable(AioContext *ctx) + + bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd) + { ++ bool ok; ++ + if (ctx->epollfd < 0) { + return false; + } +@@ -136,14 +138,23 @@ bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd) + return false; + } + +- if (npfd >= EPOLL_ENABLE_THRESHOLD) { +- if (fdmon_epoll_try_enable(ctx)) { +- return true; +- } else { +- fdmon_epoll_disable(ctx); +- } ++ if (npfd < EPOLL_ENABLE_THRESHOLD) { ++ return false; ++ } ++ ++ /* The list must not change while we add fds to epoll */ ++ if (!qemu_lockcnt_dec_if_lock(&ctx->list_lock)) { ++ return false; ++ } ++ ++ ok = fdmon_epoll_try_enable(ctx); ++ ++ qemu_lockcnt_inc_and_unlock(&ctx->list_lock); ++ ++ if (!ok) { ++ fdmon_epoll_disable(ctx); + } +- return false; ++ return ok; + } + + void fdmon_epoll_setup(AioContext *ctx) +-- +2.27.0 + diff --git a/aio-posix-zero-out-io_uring-sqe-user_data.patch b/aio-posix-zero-out-io_uring-sqe-user_data.patch new file mode 100644 index 0000000000000000000000000000000000000000..5c038442acb64408743ae6719a63e9bae44aa7f6 --- /dev/null +++ b/aio-posix-zero-out-io_uring-sqe-user_data.patch @@ -0,0 +1,44 @@ +From c670a3038a0b7dffda79672a63c84609459218c6 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 12 Sep 2023 10:22:09 +0800 +Subject: [PATCH] aio-posix: zero out io_uring sqe user_data + +cheery-pick from 87ec6f55af38e29be5b2b65a8acf84da73e06d06 + +liburing does not clear sqe->user_data. We must do it ourselves to avoid +undefined behavior in process_cqe() when user_data is used. + +Note that fdmon-io_uring is currently disabled, so this is a latent bug +that does not affect users. Let's merge this fix now to make it easier +to enable fdmon-io_uring in the future (and I'm working on that). + +Signed-off-by: Stefan Hajnoczi +Message-ID: <20230426212639.82310-1-stefanha@redhat.com> +Signed-off-by: qihao_yewu +--- + util/fdmon-io_uring.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c +index ab43052dd7..35165bcb46 100644 +--- a/util/fdmon-io_uring.c ++++ b/util/fdmon-io_uring.c +@@ -184,6 +184,7 @@ static void add_poll_remove_sqe(AioContext *ctx, AioHandler *node) + #else + io_uring_prep_poll_remove(sqe, node); + #endif ++ io_uring_sqe_set_data(sqe, NULL); + } + + /* Add a timeout that self-cancels when another cqe becomes ready */ +@@ -197,6 +198,7 @@ static void add_timeout_sqe(AioContext *ctx, int64_t ns) + + sqe = get_sqe(ctx); + io_uring_prep_timeout(sqe, &ts, 1, 0); ++ io_uring_sqe_set_data(sqe, NULL); + } + + /* Add sqes from ctx->submit_list for submission */ +-- +2.41.0.windows.1 + diff --git a/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch b/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch deleted file mode 100644 index 7926e7fa0db4ef16737a89782ea661273ef8c4d3..0000000000000000000000000000000000000000 --- a/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 929d29ec7bf9dd6ec3802bea2148a041ff30d59b Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Tue, 14 Apr 2020 21:17:09 +0800 -Subject: [PATCH] aio-wait: delegate polling of main AioContext if BQL not held - -Any thread that is not a iothread returns NULL for qemu_get_current_aio_context(). -As a result, it would also return true for -in_aio_context_home_thread(qemu_get_aio_context()), causing -AIO_WAIT_WHILE to invoke aio_poll() directly. This is incorrect -if the BQL is not held, because aio_poll() does not expect to -run concurrently from multiple threads, and it can actually -happen when savevm writes to the vmstate file from the -migration thread. - -Therefore, restrict in_aio_context_home_thread to return true -for the main AioContext only if the BQL is held. - -The function is moved to aio-wait.h because it is mostly used -there and to avoid a circular reference between main-loop.h -and block/aio.h. - -Signed-off-by: Paolo Bonzini -Message-Id: <20200407140746.8041-5-pbonzini@redhat.com> -Signed-off-by: Stefan Hajnoczi ---- - include/block/aio-wait.h | 22 ++++++++++++++++++++++ - include/block/aio.h | 29 ++++++++++------------------- - 2 files changed, 32 insertions(+), 19 deletions(-) - -diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h -index afeeb18f..716d2639 100644 ---- a/include/block/aio-wait.h -+++ b/include/block/aio-wait.h -@@ -26,6 +26,7 @@ - #define QEMU_AIO_WAIT_H - - #include "block/aio.h" -+#include "qemu/main-loop.h" - - /** - * AioWait: -@@ -124,4 +125,25 @@ void aio_wait_kick(void); - */ - void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque); - -+/** -+ * in_aio_context_home_thread: -+ * @ctx: the aio context -+ * -+ * Return whether we are running in the thread that normally runs @ctx. Note -+ * that acquiring/releasing ctx does not affect the outcome, each AioContext -+ * still only has one home thread that is responsible for running it. -+ */ -+static inline bool in_aio_context_home_thread(AioContext *ctx) -+{ -+ if (ctx == qemu_get_current_aio_context()) { -+ return true; -+ } -+ -+ if (ctx == qemu_get_aio_context()) { -+ return qemu_mutex_iothread_locked(); -+ } else { -+ return false; -+ } -+} -+ - #endif /* QEMU_AIO_WAIT_H */ -diff --git a/include/block/aio.h b/include/block/aio.h -index 6b0d52f7..9d28e247 100644 ---- a/include/block/aio.h -+++ b/include/block/aio.h -@@ -60,12 +60,16 @@ struct AioContext { - QLIST_HEAD(, AioHandler) aio_handlers; - - /* Used to avoid unnecessary event_notifier_set calls in aio_notify; -- * accessed with atomic primitives. If this field is 0, everything -- * (file descriptors, bottom halves, timers) will be re-evaluated -- * before the next blocking poll(), thus the event_notifier_set call -- * can be skipped. If it is non-zero, you may need to wake up a -- * concurrent aio_poll or the glib main event loop, making -- * event_notifier_set necessary. -+ * only written from the AioContext home thread, or under the BQL in -+ * the case of the main AioContext. However, it is read from any -+ * thread so it is still accessed with atomic primitives. -+ * -+ * If this field is 0, everything (file descriptors, bottom halves, -+ * timers) will be re-evaluated before the next blocking poll() or -+ * io_uring wait; therefore, the event_notifier_set call can be -+ * skipped. If it is non-zero, you may need to wake up a concurrent -+ * aio_poll or the glib main event loop, making event_notifier_set -+ * necessary. - * - * Bit 0 is reserved for GSource usage of the AioContext, and is 1 - * between a call to aio_ctx_prepare and the next call to aio_ctx_check. -@@ -580,19 +584,6 @@ void aio_co_enter(AioContext *ctx, struct Coroutine *co); - */ - AioContext *qemu_get_current_aio_context(void); - --/** -- * in_aio_context_home_thread: -- * @ctx: the aio context -- * -- * Return whether we are running in the thread that normally runs @ctx. Note -- * that acquiring/releasing ctx does not affect the outcome, each AioContext -- * still only has one home thread that is responsible for running it. -- */ --static inline bool in_aio_context_home_thread(AioContext *ctx) --{ -- return ctx == qemu_get_current_aio_context(); --} -- - /** - * aio_context_setup: - * @ctx: the aio context --- -2.23.0 diff --git a/apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch b/apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch deleted file mode 100644 index 4a96fc5ce1372f0e2f59ab9019cf8d72e0ee7bee..0000000000000000000000000000000000000000 --- a/apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 3bdd21c4b7d80cacc6b5f1b26ab52ef3a0aceb06 Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 16 Oct 2019 10:29:32 +0800 -Subject: [PATCH 7/8] apic: Use 32bit APIC ID for migration instance ID - -Migration is silently broken now with x2apic config like this: - - -smp 200,maxcpus=288,sockets=2,cores=72,threads=2 \ - -device intel-iommu,intremap=on,eim=on - -After migration, the guest kernel could hang at anything, due to -x2apic bit not migrated correctly in IA32_APIC_BASE on some vcpus, so -any operations related to x2apic could be broken then (e.g., RDMSR on -x2apic MSRs could fail because KVM would think that the vcpu hasn't -enabled x2apic at all). - -The issue is that the x2apic bit was never applied correctly for vcpus -whose ID > 255 when migrate completes, and that's because when we -migrate APIC we use the APICCommonState.id as instance ID of the -migration stream, while that's too short for x2apic. - -Let's use the newly introduced initial_apic_id for that. - -Signed-off-by: Peter Xu -Reviewed-by: Juan Quintela -Reviewed-by: Eduardo Habkost -Signed-off-by: Juan Quintela ---- - hw/intc/apic_common.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c -index 07adba0..2c0cb1e 100644 ---- a/hw/intc/apic_common.c -+++ b/hw/intc/apic_common.c -@@ -313,7 +313,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp) - APICCommonState *s = APIC_COMMON(dev); - APICCommonClass *info; - static DeviceState *vapic; -- uint32_t instance_id = s->id; -+ uint32_t instance_id = s->initial_apic_id; -+ -+ /* Normally initial APIC ID should be no more than hundreds */ -+ assert(instance_id != VMSTATE_INSTANCE_ID_ANY); - - info = APIC_COMMON_GET_CLASS(s); - info->realize(dev, errp); --- -1.8.3.1 - diff --git a/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch b/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch deleted file mode 100644 index 68814a8d8135faf707bacbff017fe8bc84d71f54..0000000000000000000000000000000000000000 --- a/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 6d795b30ff09bc1f799daa454f776d682cc77197 Mon Sep 17 00:00:00 2001 -From: zhanghao1 -Date: Tue, 11 May 2021 20:17:16 +0800 -Subject: [PATCH] arm/cpu: Fixed function undefined error at compile time under - arm - - Add the compilation option CONFIG_KVM while using - "kvm_arm_cpu_feature_supported" and "kvm_arm_get_one_reg". - In arm, the default value of CONFIG_KVM is no. - - While the target is arm, the compilation fails because - the function "kvm_arm_cpu_feature_supporte" is declared - or the function "kvm_arm_get_one_reg" is not defined. - -Signed-off-by: zhanghao1 ---- - target/arm/helper.c | 4 ++++ - target/arm/kvm_arm.h | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/target/arm/helper.c b/target/arm/helper.c -index bddd355fa0..9d2b2659f6 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -284,6 +284,7 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) - - newval = read_raw_cp_reg(&cpu->env, ri); - if (kvm_sync) { -+#ifdef CONFIG_KVM - if (is_id_reg(ri)) { - /* Only sync if we can sync to KVM successfully. */ - uint64_t oldval; -@@ -306,6 +307,7 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) - - kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); - } else { -+#endif - /* - * Only sync if the previous list->cpustate sync succeeded. - * Rather than tracking the success/failure state for every -@@ -324,7 +326,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) - } - - write_raw_cp_reg(&cpu->env, ri, newval); -+#ifdef CONFIG_KVM - } -+#endif - } - cpu->cpreg_values[i] = newval; - } -diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 49e80878f4..a223967d4d 100644 ---- a/target/arm/kvm_arm.h -+++ b/target/arm/kvm_arm.h -@@ -312,6 +312,10 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) - - static inline void kvm_arm_add_vcpu_properties(Object *obj) {} - -+static inline bool kvm_arm_cpu_feature_supported(void) { -+ return false; -+} -+ - static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - { - return -ENOENT; --- -2.27.0 - diff --git a/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch b/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch index 84903c34d5a86cac12aadf7d35271295b49f143d..91c7181ebca41c090d7909392cd1ac884c70869b 100644 --- a/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch +++ b/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch @@ -1,4 +1,4 @@ -From d8e0b51447d8c64788cd7f9b0fa75c4ccb06f8eb Mon Sep 17 00:00:00 2001 +From 42072fd4b33125959d825a0c5cee0d1122072f71 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 10:17:27 +0800 Subject: [PATCH] arm/cpu: assign arm_get_arch_id handler to get_arch_id hook @@ -13,13 +13,13 @@ Signed-off-by: Salil Mehta 1 file changed, 8 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 39bbe7e2d7..1ccb30e5eb 100644 +index 65163f5135..f06ba29885 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -2575,6 +2575,13 @@ static gchar *arm_gdb_arch_name(CPUState *cs) - return g_strdup("arm"); - } - +@@ -2557,6 +2557,13 @@ static const struct TCGCPUOps arm_tcg_ops = { + }; + #endif /* CONFIG_TCG */ + +static int64_t arm_cpu_get_arch_id(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); @@ -30,13 +30,14 @@ index 39bbe7e2d7..1ccb30e5eb 100644 static void arm_cpu_class_init(ObjectClass *oc, void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); -@@ -2596,6 +2603,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) - cc->synchronize_from_tb = arm_cpu_synchronize_from_tb; +@@ -2575,6 +2582,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + cc->set_pc = arm_cpu_set_pc; cc->gdb_read_register = arm_cpu_gdb_read_register; cc->gdb_write_register = arm_cpu_gdb_write_register; + cc->get_arch_id = arm_cpu_get_arch_id; #ifndef CONFIG_USER_ONLY - cc->do_interrupt = arm_cpu_do_interrupt; - cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug; --- -2.19.1 + cc->sysemu_ops = &arm_sysemu_ops; + #endif +-- +2.27.0 + diff --git a/arm-translate-a64-fix-uninitialized-variable-warning.patch b/arm-translate-a64-fix-uninitialized-variable-warning.patch deleted file mode 100644 index 8e31bbf51e12d63818e74aca17f94020301c7855..0000000000000000000000000000000000000000 --- a/arm-translate-a64-fix-uninitialized-variable-warning.patch +++ /dev/null @@ -1,36 +0,0 @@ -From b4bab3bf6a75d97d2f1098c4dc52d35ced003c70 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Mon, 13 Jan 2020 17:01:11 +0800 -Subject: [PATCH] arm/translate-a64: fix uninitialized variable warning - -Fixes: -target/arm/translate-a64.c: In function 'disas_crypto_three_reg_sha512': -target/arm/translate-a64.c:13625:9: error: 'genfn' may be used uninitialized in this function [-Werror=maybe-uninitialized] - genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -qemu/target/arm/translate-a64.c:13609:8: error: 'feature' may be used uninitialized in this function [-Werror=maybe-uninitialized] - if (!feature) { - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - target/arm/translate-a64.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c -index dcdeb801..5f423d5d 100644 ---- a/target/arm/translate-a64.c -+++ b/target/arm/translate-a64.c -@@ -13767,6 +13767,8 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) - feature = dc_isar_feature(aa64_sha3, s); - genfn = NULL; - break; -+ default: -+ g_assert_not_reached(); - } - } else { - switch (opcode) { --- -2.18.1 - - diff --git a/arm-virt-Add-CPU-hotplug-framework.patch b/arm-virt-Add-CPU-hotplug-framework.patch index 5de672afeab55fe5af5da3d2ce58aa2e9ae1435d..4fdcf9f088e9c309a8b5b935978ef389d3af5aee 100644 --- a/arm-virt-Add-CPU-hotplug-framework.patch +++ b/arm-virt-Add-CPU-hotplug-framework.patch @@ -1,4 +1,4 @@ -From 6d287b3f1d961cc4adda1c6a452f41db84466f5a Mon Sep 17 00:00:00 2001 +From 209b3e4e522b8f7f41e495feaade96ee9a91e46a Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 3 Apr 2020 16:16:18 +0800 Subject: [PATCH] arm/virt: Add CPU hotplug framework @@ -14,13 +14,13 @@ Signed-off-by: Salil Mehta 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index d09a5773df..0bd37af26c 100644 +index 9b73c479c4..11155fcb70 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -2077,11 +2077,25 @@ out: - error_propagate(errp, local_err); +@@ -2586,6 +2586,18 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, + dev, &error_abort); } - + +static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ @@ -36,31 +36,34 @@ index d09a5773df..0bd37af26c 100644 static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - virt_memory_pre_plug(hotplug_dev, dev, errp); +@@ -2619,6 +2631,8 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + qdev_prop_set_uint32(dev, "len-reserved-regions", 1); + qdev_prop_set_string(dev, "reserved-regions[0]", resv_prop_str); + g_free(resv_prop_str); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + virt_cpu_pre_plug(hotplug_dev, dev, errp); } } - -@@ -2098,6 +2112,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + +@@ -2637,6 +2651,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, } if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { virt_memory_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + virt_cpu_plug(hotplug_dev, dev, errp); } - } - -@@ -2112,7 +2128,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, - DeviceState *dev) - { - if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) || + if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { + PCIDevice *pdev = PCI_DEVICE(dev); +@@ -2717,7 +2733,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || - (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || -+ object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) || ++ (object_dynamic_cast(OBJECT(dev), TYPE_CPU))) { return HOTPLUG_HANDLER(machine); } + if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { +-- +2.27.0 --- -2.19.1 diff --git a/arm-virt-Add-CPU-topology-support.patch b/arm-virt-Add-CPU-topology-support.patch index c7813c637449328c5fecf7575d27a06fa1fa0700..016b3ed684491491637525b2edad0b24d099d0d2 100644 --- a/arm-virt-Add-CPU-topology-support.patch +++ b/arm-virt-Add-CPU-topology-support.patch @@ -1,4 +1,4 @@ -From cde57fcae2ed16a10e1ef7f2da0ec368883988ba Mon Sep 17 00:00:00 2001 +From 5454c00908236dcabcbf9ae246ccb69e1fcea72e Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 6 Apr 2020 10:54:35 +0800 Subject: [PATCH] arm/virt: Add CPU topology support @@ -10,18 +10,19 @@ plug or unplug. Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/arm/virt.c | 68 +++++++++++++++++++++++++++++++++++++-- - include/hw/arm/topology.h | 61 +++++++++++++++++++++++++++++++++++ - target/arm/cpu.c | 3 ++ - target/arm/cpu.h | 3 ++ - 4 files changed, 133 insertions(+), 2 deletions(-) + hw/arm/virt.c | 87 ++++++++++++++++++++++++++++++++++++++- + include/hw/arm/topology.h | 68 ++++++++++++++++++++++++++++++ + qapi/machine.json | 2 + + target/arm/cpu.c | 4 ++ + target/arm/cpu.h | 4 ++ + 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 include/hw/arm/topology.h diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 0bd37af26c..64532b61b2 100644 +index 11155fcb70..a12e718686 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -36,6 +36,7 @@ +@@ -39,6 +39,7 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/arm/primecell.h" @@ -29,15 +30,15 @@ index 0bd37af26c..64532b61b2 100644 #include "hw/arm/virt.h" #include "hw/block/flash.h" #include "hw/vfio/vfio-calxeda-xgmac.h" -@@ -2020,6 +2021,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) +@@ -2524,6 +2525,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) int n; unsigned int max_cpus = ms->smp.max_cpus; VirtMachineState *vms = VIRT_MACHINE(ms); + ARMCPUTopoInfo topo; - + if (ms->possible_cpus) { assert(ms->possible_cpus->len == max_cpus); -@@ -2031,10 +2033,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) +@@ -2535,10 +2537,19 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) ms->possible_cpus->len = max_cpus; for (n = 0; n < ms->possible_cpus->len; n++) { ms->possible_cpus->cpus[n].type = ms->cpu_type; @@ -45,9 +46,11 @@ index 0bd37af26c..64532b61b2 100644 ms->possible_cpus->cpus[n].arch_id = virt_cpu_mp_affinity(vms, n); + -+ topo_ids_from_idx(n, ms->smp.cores, ms->smp.threads, &topo); ++ topo_ids_from_idx(n, ms->smp.clusters, ms->smp.cores, ms->smp.threads, &topo); + ms->possible_cpus->cpus[n].props.has_socket_id = true; + ms->possible_cpus->cpus[n].props.socket_id = topo.pkg_id; ++ ms->possible_cpus->cpus[n].props.has_cluster_id = true; ++ ms->possible_cpus->cpus[n].props.cluster_id = topo.cluster_id; + ms->possible_cpus->cpus[n].props.has_core_id = true; + ms->possible_cpus->cpus[n].props.core_id = topo.core_id; ms->possible_cpus->cpus[n].props.has_thread_id = true; @@ -56,7 +59,7 @@ index 0bd37af26c..64532b61b2 100644 } return ms->possible_cpus; } -@@ -2080,7 +2089,62 @@ out: +@@ -2589,7 +2600,79 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -65,17 +68,25 @@ index 0bd37af26c..64532b61b2 100644 + ARMCPUTopoInfo topo; + ARMCPU *cpu = ARM_CPU(dev); + MachineState *ms = MACHINE(hotplug_dev); ++ int smp_clusters = ms->smp.clusters; + int smp_cores = ms->smp.cores; + int smp_threads = ms->smp.threads; + -+ /* if cpu idx is not set, set it based on socket/core/thread properties */ ++ /* if cpu idx is not set, set it based on socket/cluster/core/thread ++ * properties ++ */ + if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { -+ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; ++ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores / smp_clusters; + if (cpu->socket_id < 0 || cpu->socket_id >= max_socket) { + error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", + cpu->socket_id, max_socket - 1); + return; + } ++ if (cpu->cluster_id < 0 || cpu->cluster_id >= smp_clusters) { ++ error_setg(errp, "Invalid CPU cluster-id: %u must be in range 0:%u", ++ cpu->cluster_id, smp_clusters - 1); ++ return; ++ } + if (cpu->core_id < 0 || cpu->core_id >= smp_cores) { + error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", + cpu->core_id, smp_cores - 1); @@ -88,15 +99,17 @@ index 0bd37af26c..64532b61b2 100644 + } + + topo.pkg_id = cpu->socket_id; ++ topo.cluster_id = cpu->cluster_id; + topo.core_id = cpu->core_id; + topo.smt_id = cpu->thread_id; -+ cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo); ++ cs->cpu_index = idx_from_topo_ids(smp_clusters, smp_cores, smp_threads, &topo); + } + -+ /* if 'address' properties socket-id/core-id/thread-id are not set, set them -+ * so that machine_query_hotpluggable_cpus would show correct values ++ /* if 'address' properties socket-id/cluster-id/core-id/thread-id are not ++ * set, set them so that machine_query_hotpluggable_cpus would show correct ++ * values + */ -+ topo_ids_from_idx(cs->cpu_index, smp_cores, smp_threads, &topo); ++ topo_ids_from_idx(cs->cpu_index, smp_clusters, smp_cores, smp_threads, &topo); + if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) { + error_setg(errp, "property socket-id: %u doesn't match set idx:" + " 0x%x (socket-id: %u)", cpu->socket_id, cs->cpu_index, topo.pkg_id); @@ -104,6 +117,13 @@ index 0bd37af26c..64532b61b2 100644 + } + cpu->socket_id = topo.pkg_id; + ++ if (cpu->cluster_id != -1 && cpu->cluster_id != topo.cluster_id) { ++ error_setg(errp, "property cluster-id: %u doesn't match set idx:" ++ " 0x%x (cluster-id: %u)", cpu->cluster_id, cs->cpu_index, topo.cluster_id); ++ return; ++ } ++ cpu->cluster_id = topo.cluster_id; ++ + if (cpu->core_id != -1 && cpu->core_id != topo.core_id) { + error_setg(errp, "property core-id: %u doesn't match set idx:" + " 0x%x (core-id: %u)", cpu->core_id, cs->cpu_index, topo.core_id); @@ -118,14 +138,14 @@ index 0bd37af26c..64532b61b2 100644 + } + cpu->thread_id = topo.smt_id; } - + static void virt_cpu_plug(HotplugHandler *hotplug_dev, diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h new file mode 100644 -index 0000000000..a3e5f436c5 +index 0000000000..d0dad1a9a3 --- /dev/null +++ b/include/hw/arm/topology.h -@@ -0,0 +1,61 @@ +@@ -0,0 +1,68 @@ +/* + * ARM CPU topology data structures and functions + * @@ -150,70 +170,100 @@ index 0000000000..a3e5f436c5 + +typedef struct ARMCPUTopoInfo { + unsigned pkg_id; ++ unsigned cluster_id; + unsigned core_id; + unsigned smt_id; +} ARMCPUTopoInfo; + +/* Calculate (contiguous) CPU index based on topology */ -+static inline unsigned idx_from_topo_ids(unsigned nr_cores, ++static inline unsigned idx_from_topo_ids(unsigned nr_clusters, ++ unsigned nr_cores, + unsigned nr_threads, + const ARMCPUTopoInfo *topo) +{ ++ assert(nr_clusters > 0); + assert(nr_cores > 0); + assert(nr_threads > 0); + assert(topo != NULL); + -+ return topo->pkg_id * nr_cores * nr_threads + ++ return topo->pkg_id * nr_clusters * nr_cores * nr_threads + ++ topo->cluster_id * nr_cores + + topo->core_id * nr_threads + + topo->smt_id; +} + -+/* Calculate thread/core/package topology ++/* Calculate thread/core/cluster/package topology + * based on (contiguous) CPU index + */ +static inline void topo_ids_from_idx(unsigned cpu_index, ++ unsigned nr_clusters, + unsigned nr_cores, + unsigned nr_threads, + ARMCPUTopoInfo *topo) +{ ++ assert(nr_clusters > 0); + assert(nr_cores > 0); + assert(nr_threads > 0); + assert(topo != NULL); + + topo->smt_id = cpu_index % nr_threads; + topo->core_id = cpu_index / nr_threads % nr_cores; -+ topo->pkg_id = cpu_index / nr_threads / nr_cores; ++ topo->cluster_id = cpu_index / nr_threads / nr_cores % nr_clusters; ++ topo->pkg_id = cpu_index / nr_threads / nr_cores / nr_clusters; +} + +#endif /* HW_ARM_TOPOLOGY_H */ + +diff --git a/qapi/machine.json b/qapi/machine.json +index 8faa51074e..6822cafe2e 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -868,6 +868,7 @@ + # @node-id: NUMA node ID the CPU belongs to + # @socket-id: socket number within node/board the CPU belongs to + # @die-id: die number within socket the CPU belongs to (since 4.1) ++# @cluster-id: cluster number within die the CPU belongs to (since 6.2) + # @core-id: core number within die the CPU belongs to + # @thread-id: thread number within core the CPU belongs to + # +@@ -883,6 +884,7 @@ + 'data': { '*node-id': 'int', + '*socket-id': 'int', + '*die-id': 'int', ++ '*cluster-id': 'int', + '*core-id': 'int', + '*thread-id': 'int' + } diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 1ccb30e5eb..91f1e36cd8 100644 +index f06ba29885..9fd8e57971 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -2560,6 +2560,9 @@ static Property arm_cpu_properties[] = { +@@ -2507,6 +2507,10 @@ static Property arm_cpu_properties[] = { DEFINE_PROP_UINT64("mp-affinity", ARMCPU, mp_affinity, ARM64_AFFINITY_INVALID), DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID), + DEFINE_PROP_INT32("socket-id", ARMCPU, socket_id, -1), ++ DEFINE_PROP_INT32("cluster-id", ARMCPU, cluster_id, -1), + DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1), + DEFINE_PROP_INT32("thread-id", ARMCPU, thread_id, -1), DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1), DEFINE_PROP_END_OF_LIST() }; diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index e19531a77b..219c222b89 100644 +index 947897d5ac..eb804dffaa 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h -@@ -916,6 +916,9 @@ struct ARMCPU { +@@ -1006,6 +1006,10 @@ struct ARMCPU { QLIST_HEAD(, ARMELChangeHook) el_change_hooks; - + int32_t node_id; /* NUMA node this CPU belongs to */ + int32_t socket_id; ++ int32_t cluster_id; + int32_t core_id; + int32_t thread_id; - + /* Used to synchronize KVM and QEMU in-kernel device levels */ uint8_t device_irq_level; --- -2.19.1 +-- +2.27.0 + diff --git a/arm-virt-Add-cpu_hotplug_enabled-field.patch b/arm-virt-Add-cpu_hotplug_enabled-field.patch index 0b8bc47f6d31dba63e1148c22cc803204ce82e70..0ae840c7cdae03104a7bb317f98c872399e4eafb 100644 --- a/arm-virt-Add-cpu_hotplug_enabled-field.patch +++ b/arm-virt-Add-cpu_hotplug_enabled-field.patch @@ -1,4 +1,4 @@ -From 31873c4c0454fb17654f57adece2bc396415f8bf Mon Sep 17 00:00:00 2001 +From 965eb25b03f6977a7656dce3ac5cdb4c95bfe003 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 13:50:40 +0800 Subject: [PATCH] arm/virt: Add cpu_hotplug_enabled field @@ -14,10 +14,10 @@ Signed-off-by: Salil Mehta 2 files changed, 8 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index dda22194b5..304a4c2d31 100644 +index b1224fb1e4..45a0a045b1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -1645,6 +1645,7 @@ static void machvirt_init(MachineState *machine) +@@ -2008,6 +2008,7 @@ static void machvirt_init(MachineState *machine) { VirtMachineState *vms = VIRT_MACHINE(machine); VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); @@ -25,37 +25,38 @@ index dda22194b5..304a4c2d31 100644 MachineClass *mc = MACHINE_GET_CLASS(machine); const CPUArchIdList *possible_cpus; MemoryRegion *sysmem = get_system_memory(); -@@ -1655,6 +1656,7 @@ static void machvirt_init(MachineState *machine) +@@ -2017,6 +2018,7 @@ static void machvirt_init(MachineState *machine) bool has_ged = !vmc->no_ged; unsigned int smp_cpus = machine->smp.cpus; unsigned int max_cpus = machine->smp.max_cpus; + ObjectClass *cpu_class; - + /* * In accelerated mode, the memory map is computed earlier in kvm_type() -@@ -1760,6 +1762,11 @@ static void machvirt_init(MachineState *machine) - +@@ -2106,6 +2108,11 @@ static void machvirt_init(MachineState *machine) create_fdt(vms); - + qemu_log("cpu init start\n"); + + cpu_class = object_class_by_name(ms->cpu_type); + vms->cpu_hotplug_enabled = has_ged && firmware_loaded && -+ acpi_enabled && vms->gic_version == 3 && ++ virt_is_acpi_enabled(vms) && vms->gic_version == 3 && + !!object_class_dynamic_cast(cpu_class, TYPE_AARCH64_CPU); + possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len == max_cpus); for (n = 0; n < possible_cpus->len; n++) { - Object *cpuobj; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index beef4c8002..b4c53d920e 100644 +index 947d41f767..c371d377e0 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -126,6 +126,7 @@ typedef struct { - bool highmem_ecam; +@@ -149,6 +149,7 @@ struct VirtMachineState { bool its; + bool tcg_its; bool virt; + bool cpu_hotplug_enabled; - int32_t gic_version; - VirtIOMMUType iommu; - struct arm_boot_info bootinfo; --- -2.19.1 + bool ras; + bool mte; + OnOffAuto acpi; +-- +2.27.0 + diff --git a/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch b/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch deleted file mode 100644 index c81227d8a3ef4ff3ffc74f7b848b42e8cc79c762..0000000000000000000000000000000000000000 --- a/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 7cfb37c50209208f853c6fbd0df6673a95e03ef9 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Fri, 10 Apr 2020 14:16:40 +0800 -Subject: [PATCH] arm/virt: Add some sanity checks in cpu_pre_plug hook - -For that user will try to hotplug a CPU when preconditions -are not satisfied, check these CPU hotplug preconditions in -pre_plug hook. - -Signed-off-by: Keqian Zhu -Signed-off-by: Salil Mehta ---- - hw/arm/virt.c | 27 +++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 983084c459..c6a99e683a 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -2086,10 +2086,30 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, - VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); - VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev); - const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); -+ const CPUArchId *cpu_slot = NULL; - MemoryRegion *sysmem = get_system_memory(); - int smp_cores = ms->smp.cores; - int smp_threads = ms->smp.threads; - -+ /* Some hotplug capability checks */ -+ -+ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { -+ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", -+ ms->cpu_type); -+ return; -+ } -+ -+ if (dev->hotplugged && !vms->acpi_dev) { -+ error_setg(errp, "CPU hotplug is disabled: missing acpi device."); -+ return; -+ } -+ -+ if (dev->hotplugged && !vms->cpu_hotplug_enabled) { -+ error_setg(errp, "CPU hotplug is disabled: " -+ "should use AArch64 CPU and GICv3."); -+ return; -+ } -+ - /* if cpu idx is not set, set it based on socket/core/thread properties */ - if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { - int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; -@@ -2145,6 +2165,13 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, - object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id, - "mp-affinity", NULL); - -+ cpu_slot = &possible_cpus->cpus[cs->cpu_index]; -+ if (cpu_slot->cpu) { -+ error_setg(errp, "CPU[%d] with mp_affinity %" PRIu64 " exists", -+ cs->cpu_index, cpu->mp_affinity); -+ return; -+ } -+ - numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), - &error_fatal); - --- -2.19.1 diff --git a/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch b/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch index ade3ccfd9fe50a78c8ef33ded3463e52b5f6d6c3..174c3de0ee3cd29515413a2316c8ad0cd70441a9 100644 --- a/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch +++ b/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch @@ -1,4 +1,4 @@ -From d38d1d4e859450535ddc6bf0c7a59f6217b1403c Mon Sep 17 00:00:00 2001 +From 6b0f94aee82c7558d79e5ec28437483c4873dc65 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sun, 5 Apr 2020 16:03:15 +0800 Subject: [PATCH] arm/virt: Attach ACPI CPU hotplug support to virt @@ -16,26 +16,26 @@ Signed-off-by: Salil Mehta 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 8b68a15d76..dbe9acb148 100644 +index a93d223879..7cb320d9f2 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -806,6 +806,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - MachineState *ms = MACHINE(vms); - const MemMapEntry *memmap = vms->memmap; +@@ -937,6 +937,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) const int *irqmap = vms->irqmap; + AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + bool cpu_aml_built = false; - + + acpi_table_begin(&table, table_data); dsdt = init_aml_allocator(); - /* Reserve space for header */ -@@ -817,7 +818,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -947,7 +948,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); -- acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); +- acpi_dsdt_add_cpus(scope, vms); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); -@@ -845,6 +845,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + if (vmc->acpi_expose_flash) { +@@ -977,6 +977,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AML_SYSTEM_MEMORY, memmap[VIRT_PCDIMM_ACPI].base); } @@ -51,50 +51,53 @@ index 8b68a15d76..dbe9acb148 100644 + } + + if (!cpu_aml_built) { -+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); ++ acpi_dsdt_add_cpus(scope, vms); } - + acpi_dsdt_add_power_button(scope); diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 8638aeedb7..d09a5773df 100644 +index 3299d674c8..9b73c479c4 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -140,6 +140,7 @@ static const MemMapEntry base_memmap[] = { - [VIRT_SMMU] = { 0x09050000, 0x00020000 }, - [VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN }, - [VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN }, -+ [VIRT_CPU_ACPI] = { 0x09090000, ACPI_CPU_HOTPLUG_REG_LEN }, +@@ -154,6 +154,7 @@ static const MemMapEntry base_memmap[] = { + [VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN}, + [VIRT_PVTIME] = { 0x090a0000, 0x00010000 }, + [VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 }, ++ [VIRT_CPU_ACPI] = { 0x090c0000, ACPI_CPU_HOTPLUG_REG_LEN }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, - [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, + [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ -@@ -645,11 +646,16 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) - event |= ACPI_GED_MEM_HOTPLUG_EVT; +@@ -697,6 +698,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + event |= ACPI_GED_NVDIMM_HOTPLUG_EVT; } - + + /* event |= ACPI_GED_CPU_HOTPLUG_EVT; + * Currently CPU hotplug is not enabled. + */ + - dev = qdev_create(NULL, TYPE_ACPI_GED); + dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); - + +@@ -706,6 +711,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); -+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, vms->memmap[VIRT_CPU_ACPI].base); ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 3, vms->memmap[VIRT_CPU_ACPI].base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - - qdev_init_nofail(dev); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index cbdea7ff32..6880ebe07c 100644 +index fe26709e1a..2a838620d8 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -81,6 +81,7 @@ enum { - VIRT_SECURE_MEM, - VIRT_PCDIMM_ACPI, +@@ -88,6 +88,7 @@ enum { VIRT_ACPI_GED, + VIRT_NVDIMM_ACPI, + VIRT_PVTIME, + VIRT_CPU_ACPI, VIRT_LOWMEMMAP_LAST, }; + +-- +2.27.0 --- -2.19.1 diff --git a/arm-virt-Correct-timing-of-executing-cpu_synchronize.patch b/arm-virt-Correct-timing-of-executing-cpu_synchronize.patch new file mode 100644 index 0000000000000000000000000000000000000000..b89aadb240dcadbbe7429e4488c802d262d18634 --- /dev/null +++ b/arm-virt-Correct-timing-of-executing-cpu_synchronize.patch @@ -0,0 +1,52 @@ +From c3f86c199885506cfddde0dfc235c04e0897d591 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Tue, 14 Feb 2023 20:33:40 +0800 +Subject: [PATCH] arm/virt: Correct timing of executing + cpu_synchronize_post_init for hot-plugged cpus + +When the CPU starts normally, cpu_synchronize_post_init is executed +after GICv3 is implemented. This order should be followed when dealing +with hot-plugged CPUs. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/virt.c | 1 + + hw/core/cpu-common.c | 6 ++---- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 4716f9baaa..7d5b332594 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2798,6 +2798,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + } + + /* Register CPU reset and trigger it manually */ ++ cpu_synchronize_post_init(cs); + cpu_synchronize_state(cs); + cpu_hotplug_register_reset(ncpu); + cpu_hotplug_reset_manually(ncpu); +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index b8d1d820cb..2213840260 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -206,14 +206,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) + } + } + ++#ifdef __aarch64__ + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); +- +-#ifdef __aarch64__ +- if (!kvm_enabled()) +-#endif + cpu_resume(cpu); + } ++#endif + + /* NOTE: latest generic point where the cpu is fully realized */ + trace_init_vcpu(cpu); +-- +2.27.0 + diff --git a/arm-virt-Correct-timing-of-pause-all-vcpus-for-hot-p.patch b/arm-virt-Correct-timing-of-pause-all-vcpus-for-hot-p.patch new file mode 100644 index 0000000000000000000000000000000000000000..817c1250d43df826828be38f1a3aa2d27d30b476 --- /dev/null +++ b/arm-virt-Correct-timing-of-pause-all-vcpus-for-hot-p.patch @@ -0,0 +1,58 @@ +From 41f30679648676d4d62b1ae9026dde77fa9895d5 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Tue, 14 Feb 2023 20:39:07 +0800 +Subject: [PATCH] arm/virt: Correct timing of pause all vcpus for hot-plugged + CPUs + +When dealing with hot-plugging cpus, it may fail when realize cpu. +Such a failure would make paused vcpus unrecoverable. So we only +pause all vcpus when needed. Add removed some unnecessary checks. + +Signed-off-by: Kunkun Jiang +--- + hw/arm/virt.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 7d5b332594..4c876fcf16 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2747,13 +2747,6 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + &error_abort); + } + } +- +- /* If we use KVM accel, we should pause all vcpus to +- * allow hot access of vcpu registers. +- */ +- if (dev->hotplugged && kvm_enabled()) { +- pause_all_vcpus(); +- } + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, +@@ -2773,6 +2766,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + + /* For CPU that is cold/hot plugged */ + if (ncpu >= ms->smp.cpus) { ++ if (dev->hotplugged) { ++ pause_all_vcpus(); ++ } ++ + /* Realize GIC related parts of CPU */ + assert(vms->gic_version == 3); + gicv3 = ARM_GICV3_COMMON(vms->gic); +@@ -2803,6 +2800,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + cpu_hotplug_register_reset(ncpu); + cpu_hotplug_reset_manually(ncpu); + cpu_synchronize_post_reset(cs); ++ ++ if (dev->hotplugged) { ++ resume_all_vcpus(); ++ } + } + + if (dev->hotplugged && kvm_enabled()) { +-- +2.27.0 + diff --git a/arm-virt-Fix-vcpu-hotplug-idx_from_topo_ids.patch b/arm-virt-Fix-vcpu-hotplug-idx_from_topo_ids.patch new file mode 100644 index 0000000000000000000000000000000000000000..4562e47afef277358290e1bf15664e42db143d5f --- /dev/null +++ b/arm-virt-Fix-vcpu-hotplug-idx_from_topo_ids.patch @@ -0,0 +1,29 @@ +From add7ed9bb57490e29371a542d47891b7c9210c43 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Sun, 6 Nov 2022 06:36:15 +0800 +Subject: [PATCH 1/3] arm/virt: Fix vcpu hotplug idx_from_topo_ids + +Add missing "nr_threads" when compute cpu index. + +Fixes: 5454c0090823 ("arm/virt: Add CPU topology support") +Signed-off-by: Keqian Zhu +--- + include/hw/arm/topology.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h +index d0dad1a9a3..33e4a0d552 100644 +--- a/include/hw/arm/topology.h ++++ b/include/hw/arm/topology.h +@@ -39,7 +39,7 @@ static inline unsigned idx_from_topo_ids(unsigned nr_clusters, + assert(topo != NULL); + + return topo->pkg_id * nr_clusters * nr_cores * nr_threads + +- topo->cluster_id * nr_cores + ++ topo->cluster_id * nr_cores * nr_threads + + topo->core_id * nr_threads + + topo->smt_id; + } +-- +2.27.0 + diff --git a/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch b/arm-virt-Pre-sizing-MADT-GICC-GICv3-and-Pre-park-KVM.patch similarity index 46% rename from arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch rename to arm-virt-Pre-sizing-MADT-GICC-GICv3-and-Pre-park-KVM.patch index c2d9a3cb0a48436433a30670e8517d7dafb9bca4..134cdbe252c59ee6cad7494c9635e8436acbdd7f 100644 --- a/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch +++ b/arm-virt-Pre-sizing-MADT-GICC-GICv3-and-Pre-park-KVM.patch @@ -1,78 +1,54 @@ -From bf47ef282bfe8b0a98e1f87d8708051ffa7192a1 Mon Sep 17 00:00:00 2001 +From 3063d421cd68937ece290bc02151cc15b7ec33d0 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 13:55:11 +0800 -Subject: [PATCH] arm/virt: Pre-sizing MADT-GICC PPTT GICv3 and Pre-park KVM - vCPU +Subject: [PATCH] arm/virt: Pre-sizing MADT-GICC GICv3 and Pre-park KVM vCPU Establish all pre-sizing facilities based on cpu_hotplug_enabled field. +Note: PPTT is constructed for possible_cpus, so it does not need +to pre-sizing it. + Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/arm/virt-acpi-build.c | 12 +++++++++++- + hw/arm/virt-acpi-build.c | 3 +++ hw/arm/virt.c | 14 ++++++++++++-- - target/arm/kvm.c | 6 +++--- - 3 files changed, 26 insertions(+), 6 deletions(-) + target/arm/kvm.c | 4 ++-- + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index efac788ba1..2cfac7b84f 100644 +index a16b54086e..1101161d70 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -736,6 +736,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); - gicd->version = vms->gic_version; - +@@ -859,6 +859,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + build_append_int_noprefix(table_data, vms->gic_version, 1); + build_append_int_noprefix(table_data, 0, 3); /* Reserved */ + + if (vms->cpu_hotplug_enabled) { + num_cpu = ms->smp.max_cpus; + } for (i = 0; i < num_cpu; i++) { - virt_madt_cpu_entry(NULL, i, possible_cpus, table_data); + virt_madt_cpu_entry(NULL, i, possible_cpus, table_data, false); } -@@ -902,9 +905,11 @@ static - void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) - { - VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); -+ MachineState *ms = MACHINE(vms); - GArray *table_offsets; - unsigned dsdt, xsdt; - GArray *tables_blob = tables->table_data; -+ int num_cpus; - - table_offsets = g_array_new(false, true /* clear */, - sizeof(uint32_t)); -@@ -923,7 +928,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) - - acpi_add_table(table_offsets, tables_blob); - -- build_pptt(tables_blob, tables->linker, vms->smp_cpus); -+ if (vms->cpu_hotplug_enabled) { -+ num_cpus = ms->smp.max_cpus; -+ } else { -+ num_cpus = ms->smp.cpus; -+ } -+ build_pptt(tables_blob, tables->linker, num_cpus); - - acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, vms); diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 304a4c2d31..983084c459 100644 +index 45a0a045b1..4eb1b44729 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -767,6 +767,9 @@ static void create_gic(VirtMachineState *vms) +@@ -833,6 +833,9 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) unsigned int smp_cpus = ms->smp.cpus; uint32_t nb_redist_regions = 0; - + + if (vms->cpu_hotplug_enabled) { + num_cpus = ms->smp.max_cpus; + } assert(num_cpus >= smp_cpus); - + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); -@@ -1772,8 +1775,15 @@ static void machvirt_init(MachineState *machine) +@@ -2119,8 +2122,15 @@ static void machvirt_init(MachineState *machine) Object *cpuobj; CPUState *cs; - + + if (kvm_enabled() && vms->cpu_hotplug_enabled) { + if (kvm_create_parked_vcpu(n) < 0) { + error_report("mach-virt: Create KVM parked vCPU failed"); @@ -84,41 +60,33 @@ index 304a4c2d31..983084c459 100644 - break; + continue; } - + cpuobj = object_new(possible_cpus->cpus[n].type); -@@ -1857,7 +1867,7 @@ static void machvirt_init(MachineState *machine) - vms->bootinfo.kernel_filename = machine->kernel_filename; - vms->bootinfo.kernel_cmdline = machine->kernel_cmdline; - vms->bootinfo.initrd_filename = machine->initrd_filename; +@@ -2208,7 +2218,7 @@ static void machvirt_init(MachineState *machine) + } + + vms->bootinfo.ram_size = machine->ram_size; - vms->bootinfo.nb_cpus = smp_cpus; + vms->bootinfo.nb_cpus = vms->cpu_hotplug_enabled ? max_cpus : smp_cpus; vms->bootinfo.board_id = -1; vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; vms->bootinfo.get_dtb = machvirt_dtb; diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index 327b3bc338..4f131f687d 100644 +index 59d556724f..29ac3f40e0 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c -@@ -202,7 +202,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - int kvm_arch_init(MachineState *ms, KVMState *s) - { - int ret = 0; -- unsigned int smp_cpus = ms->smp.cpus; -+ unsigned int max_cpus = ms->smp.max_cpus; - /* For ARM interrupt delivery is always asynchronous, - * whether we are using an in-kernel VGIC or not. - */ -@@ -216,9 +216,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - +@@ -262,9 +262,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); - -- if (smp_cpus > 256 && -+ if (max_cpus > 256 && + +- if (ms->smp.cpus > 256 && ++ if (ms->smp.max_cpus > 256 && !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) { - error_report("Using more than 256 vcpus requires a host kernel " + error_report("Using more than max 256 vcpus requires a host kernel " "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2"); ret = -EINVAL; } --- -2.19.1 +-- +2.27.0 + diff --git a/arm-virt-Start-up-CPU-hot-plug.patch b/arm-virt-Start-up-CPU-hot-plug-and-cold-plug.patch similarity index 42% rename from arm-virt-Start-up-CPU-hot-plug.patch rename to arm-virt-Start-up-CPU-hot-plug-and-cold-plug.patch index 5ba620a2215710682afa4ccdfd0d5cad53556680..d4970f16b93686535d83709d379356dd68a4e14c 100644 --- a/arm-virt-Start-up-CPU-hot-plug.patch +++ b/arm-virt-Start-up-CPU-hot-plug-and-cold-plug.patch @@ -1,49 +1,107 @@ -From 11f9628ceff019259ff12ce469deafbf50eb3075 Mon Sep 17 00:00:00 2001 +From a2d8cf86a379bb161cdae850824c9e80fb370599 Mon Sep 17 00:00:00 2001 From: Keqian Zhu -Date: Fri, 10 Apr 2020 14:20:59 +0800 -Subject: [PATCH] arm/virt: Start up CPU hot-plug +Date: Fri, 10 Apr 2020 14:16:40 +0800 +Subject: [PATCH] arm/virt: Start up CPU hot-plug and cold-plug All the CPU hotplug facilities are ready. Assemble them to start up CPU hot-plug capability for arm/virt. -Signed-off-by: Keqian Zhu +This also adds CPU cold plug support to arm virt machine +board. CPU cold plug means adding CPU by using "-device +xx-arm-cpu" when we bring up Qemu. + Signed-off-by: Salil Mehta +Signed-off-by: Keqian Zhu --- - hw/arm/virt.c | 61 ++++++++++++++++++++++++++++++++++++++++--- - include/hw/arm/virt.h | 1 + - qom/cpu.c | 5 ++++ - target/arm/cpu.c | 2 ++ - 4 files changed, 65 insertions(+), 4 deletions(-) + hw/arm/virt.c | 110 ++++++++++++++++++++++++++++++++++++++++-- + hw/core/cpu-common.c | 4 ++ + include/hw/arm/virt.h | 1 + + target/arm/cpu.c | 2 + + 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index c6a99e683a..112a6ae7cb 100644 +index 4eb1b44729..b81d22d68f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -48,6 +48,8 @@ - #include "sysemu/cpus.h" - #include "sysemu/sysemu.h" +@@ -52,6 +52,8 @@ + #include "sysemu/tpm.h" #include "sysemu/kvm.h" + #include "sysemu/hvf.h" +#include "sysemu/cpus.h" +#include "sysemu/hw_accel.h" #include "hw/loader.h" - #include "exec/address-spaces.h" + #include "qapi/error.h" #include "qemu/bitops.h" -@@ -649,9 +651,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) - event |= ACPI_GED_MEM_HOTPLUG_EVT; +@@ -703,9 +705,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + event |= ACPI_GED_NVDIMM_HOTPLUG_EVT; } - + - /* event |= ACPI_GED_CPU_HOTPLUG_EVT; - * Currently CPU hotplug is not enabled. - */ + if (vms->cpu_hotplug_enabled) { + event |= ACPI_GED_CPU_HOTPLUG_EVT; + } - - dev = qdev_create(NULL, TYPE_ACPI_GED); + + dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); -@@ -2214,12 +2216,62 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, - object_property_set_link(cpuobj, OBJECT(secure_sysmem), - "secure-memory", &error_abort); +@@ -2555,11 +2557,18 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ const CPUArchId *cpu_slot = NULL; + MemoryRegion *sysmem = get_system_memory(); + int smp_clusters = ms->smp.clusters; + int smp_cores = ms->smp.cores; + int smp_threads = ms->smp.threads; + ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ return; ++ } ++ + /* if cpu idx is not set, set it based on socket/cluster/core/thread + * properties + */ +@@ -2593,6 +2602,20 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + cs->cpu_index = idx_from_topo_ids(smp_clusters, smp_cores, smp_threads, &topo); + } + ++ /* Some hotplug capability checks */ ++ if (cs->cpu_index >= ms->smp.cpus) { ++ if (!vms->acpi_dev) { ++ error_setg(errp, "CPU cold/hot plug is disabled: " ++ "missing acpi device."); ++ return; ++ } ++ if (!vms->cpu_hotplug_enabled) { ++ error_setg(errp, "CPU cold/hot plug is disabled: " ++ "should use AArch64 CPU and GICv3."); ++ return; ++ } ++ } ++ + /* if 'address' properties socket-id/cluster-id/core-id/thread-id are not + * set, set them so that machine_query_hotpluggable_cpus would show correct + * values +@@ -2631,6 +2654,13 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + object_property_set_int(cpuobj, "mp-affinity", + possible_cpus->cpus[cs->cpu_index].arch_id, NULL); + ++ cpu_slot = &possible_cpus->cpus[cs->cpu_index]; ++ if (cpu_slot->cpu) { ++ error_setg(errp, "CPU[%d] with mp_affinity %" PRIu64 " exists", ++ cs->cpu_index, cpu->mp_affinity); ++ return; ++ } ++ + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), + &error_fatal); + +@@ -2716,12 +2746,83 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + &error_abort); + } } + + /* If we use KVM accel, we should pause all vcpus to @@ -53,7 +111,7 @@ index c6a99e683a..112a6ae7cb 100644 + pause_all_vcpus(); + } } - + static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -63,11 +121,15 @@ index c6a99e683a..112a6ae7cb 100644 + int ncpu = cs->cpu_index; + MachineState *ms = MACHINE(hotplug_dev); + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL); ++ bool steal_time = object_property_get_bool(OBJECT(first_cpu), ++ "kvm-steal-time", NULL); + GICv3State *gicv3; + ARMGICv3CommonClass *agcc; + Error *local_err = NULL; + -+ if (dev->hotplugged) { ++ /* For CPU that is cold/hot plugged */ ++ if (ncpu >= ms->smp.cpus) { + /* Realize GIC related parts of CPU */ + assert(vms->gic_version == 3); + gicv3 = ARM_GICV3_COMMON(vms->gic); @@ -75,15 +137,32 @@ index c6a99e683a..112a6ae7cb 100644 + agcc->cpu_hotplug_realize(gicv3, ncpu); + connect_gic_cpu_irqs(vms, ncpu); + ++ /* Init PMU and steal_time part */ ++ if (kvm_enabled()) { ++ hwaddr pvtime_reg_base = vms->memmap[VIRT_PVTIME].base; ++ ++ if (pmu) { ++ assert(arm_feature(&ARM_CPU(cs)->env, ARM_FEATURE_PMU)); ++ if (kvm_irqchip_in_kernel()) { ++ kvm_arm_pmu_set_irq(cs, PPI(VIRTUAL_PMU_IRQ)); ++ } ++ kvm_arm_pmu_init(cs); ++ } ++ if (steal_time) { ++ kvm_arm_pvtime_init(cs, pvtime_reg_base + ++ ncpu * PVTIME_SIZE_PER_CPU); ++ } ++ } ++ + /* Register CPU reset and trigger it manually */ + cpu_synchronize_state(cs); + cpu_hotplug_register_reset(ncpu); + cpu_hotplug_reset_manually(ncpu); + cpu_synchronize_post_reset(cs); ++ } + -+ if (kvm_enabled()) { -+ resume_all_vcpus(); -+ } ++ if (dev->hotplugged && kvm_enabled()) { ++ resume_all_vcpus(); + } + + if (vms->acpi_dev) { @@ -103,9 +182,9 @@ index c6a99e683a..112a6ae7cb 100644 +out: + error_propagate(errp, local_err); } - + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, -@@ -2324,6 +2376,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) +@@ -2940,6 +3041,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; mc->kvm_type = virt_kvm_type; @@ -113,11 +192,26 @@ index c6a99e683a..112a6ae7cb 100644 assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = virt_machine_get_hotplug_handler; hc->pre_plug = virt_machine_device_pre_plug_cb; +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index 9e3241b430..b8d1d820cb 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -208,6 +208,10 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) + + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); ++ ++#ifdef __aarch64__ ++ if (!kvm_enabled()) ++#endif + cpu_resume(cpu); + } + diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index b4c53d920e..a9429bed25 100644 +index c371d377e0..4ddee19b18 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -140,6 +140,7 @@ typedef struct { +@@ -168,6 +168,7 @@ struct VirtMachineState { uint32_t msi_phandle; uint32_t iommu_phandle; int psci_conduit; @@ -125,35 +219,19 @@ index b4c53d920e..a9429bed25 100644 hwaddr highest_gpa; DeviceState *gic; DeviceState *acpi_dev; -diff --git a/qom/cpu.c b/qom/cpu.c -index f376f782d8..58cd9d5bbc 100644 ---- a/qom/cpu.c -+++ b/qom/cpu.c -@@ -342,7 +342,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) - - if (dev->hotplugged) { - cpu_synchronize_post_init(cpu); -+ -+#ifdef __aarch64__ -+ if (!kvm_enabled()) -+#endif - cpu_resume(cpu); -+ - } - - /* NOTE: latest generic point where the cpu is fully realized */ diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 91f1e36cd8..811e5c6365 100644 +index 9fd8e57971..d550022f18 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -2598,6 +2598,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) - acc->parent_reset = cc->reset; - cc->reset = arm_cpu_reset; - +@@ -2580,6 +2580,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + device_class_set_props(dc, arm_cpu_properties); + device_class_set_parent_reset(dc, arm_cpu_reset, &acc->parent_reset); + + dc->user_creatable = true; + cc->class_by_name = arm_cpu_class_by_name; cc->has_work = arm_cpu_has_work; - cc->cpu_exec_interrupt = arm_cpu_exec_interrupt; --- -2.19.1 + cc->dump_state = arm_cpu_dump_state; +-- +2.27.0 + diff --git a/arm-virt-Support-CPU-cold-plug.patch b/arm-virt-Support-CPU-cold-plug.patch deleted file mode 100644 index 3f96fede24c1e4f18d0f05c1987b20cc5a883b93..0000000000000000000000000000000000000000 --- a/arm-virt-Support-CPU-cold-plug.patch +++ /dev/null @@ -1,92 +0,0 @@ -From e3a1af72fca5bbcc840fba44d512bbe69ec55ca9 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Tue, 12 May 2020 15:05:06 +0800 -Subject: [PATCH] arm/virt: Support CPU cold plug - -This adds CPU cold plug support to arm virt machine board. -CPU cold plug means adding CPU by using "-device xx-arm-cpu" -when we bring up Qemu. - -Signed-off-by: Keqian Zhu ---- - hw/arm/virt.c | 36 +++++++++++++++++++----------------- - 1 file changed, 19 insertions(+), 17 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 112a6ae7cb..4c7279392f 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -2093,25 +2093,12 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, - int smp_cores = ms->smp.cores; - int smp_threads = ms->smp.threads; - -- /* Some hotplug capability checks */ -- - if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { - error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", - ms->cpu_type); - return; - } - -- if (dev->hotplugged && !vms->acpi_dev) { -- error_setg(errp, "CPU hotplug is disabled: missing acpi device."); -- return; -- } -- -- if (dev->hotplugged && !vms->cpu_hotplug_enabled) { -- error_setg(errp, "CPU hotplug is disabled: " -- "should use AArch64 CPU and GICv3."); -- return; -- } -- - /* if cpu idx is not set, set it based on socket/core/thread properties */ - if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { - int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; -@@ -2137,6 +2124,20 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, - cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo); - } - -+ /* Some hotplug capability checks */ -+ if (cs->cpu_index >= ms->smp.cpus) { -+ if (!vms->acpi_dev) { -+ error_setg(errp, "CPU cold/hot plug is disabled: " -+ "missing acpi device."); -+ return; -+ } -+ if (!vms->cpu_hotplug_enabled) { -+ error_setg(errp, "CPU cold/hot plug is disabled: " -+ "should use AArch64 CPU and GICv3."); -+ return; -+ } -+ } -+ - /* if 'address' properties socket-id/core-id/thread-id are not set, set them - * so that machine_query_hotpluggable_cpus would show correct values - */ -@@ -2237,7 +2238,8 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, - ARMGICv3CommonClass *agcc; - Error *local_err = NULL; - -- if (dev->hotplugged) { -+ /* For CPU that is cold/hot plugged */ -+ if (ncpu >= ms->smp.cpus) { - /* Realize GIC related parts of CPU */ - assert(vms->gic_version == 3); - gicv3 = ARM_GICV3_COMMON(vms->gic); -@@ -2250,10 +2252,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, - cpu_hotplug_register_reset(ncpu); - cpu_hotplug_reset_manually(ncpu); - cpu_synchronize_post_reset(cs); -+ } - -- if (kvm_enabled()) { -- resume_all_vcpus(); -- } -+ if (dev->hotplugged && kvm_enabled()) { -+ resume_all_vcpus(); - } - - if (vms->acpi_dev) { --- -2.19.1 - diff --git a/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch b/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch index 297ccf633fe69840b863f10109ee4271f16c11a1..501573c5e2cd6e783537befb38024aa6d17b24bd 100644 --- a/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch +++ b/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch @@ -1,4 +1,4 @@ -From 91fed8840b004ec7bc91969afa10f03e13f311c4 Mon Sep 17 00:00:00 2001 +From e3522e63a2f14c3c7d8cd603099b6bb51087f43b Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Wed, 22 Apr 2020 19:52:58 +0800 Subject: [PATCH] arm/virt/acpi: Extend cpufreq to support max_cpus @@ -12,21 +12,21 @@ Signed-off-by: Keqian Zhu 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c -index d02a25a6de..38dcab5683 100644 +index a84db490b3..a76f7b8fa2 100644 --- a/hw/acpi/cpufreq.c +++ b/hw/acpi/cpufreq.c -@@ -84,6 +84,7 @@ typedef struct CpuhzState { +@@ -83,6 +83,7 @@ typedef struct CpuhzState { uint32_t PerformanceLimited; uint32_t LowestFreq; uint32_t NominalFreq; + uint32_t num_cpu; uint32_t reg_size; } CpuhzState; - -@@ -95,10 +96,7 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, + +@@ -93,10 +94,7 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, unsigned size) uint64_t r; uint64_t n; - + - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; - @@ -35,7 +35,7 @@ index d02a25a6de..38dcab5683 100644 warn_report("cpufreq_read: offset 0x%lx out of range", offset); return 0; } -@@ -166,11 +164,10 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, +@@ -163,11 +161,10 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, unsigned size) static void cpufreq_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { @@ -43,23 +43,24 @@ index d02a25a6de..38dcab5683 100644 uint64_t n; - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; - + - if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { + if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) { error_printf("cpufreq_write: offset 0x%lx out of range", offset); return; } -@@ -251,9 +248,9 @@ static void cpufreq_init(Object *obj) +@@ -248,9 +245,9 @@ static void cpufreq_init(Object *obj) CpuhzState *s = CPUFREQ(obj); - + MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; + s->num_cpu = ms->smp.max_cpus; - + - s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE; + s->reg_size = s->num_cpu * CPPC_REG_PER_CPU_STRIDE; if (s->reg_size > MAX_SUPPORT_SPACE) { error_report("Required space 0x%x excesses the max support 0x%x", s->reg_size, MAX_SUPPORT_SPACE); --- -2.19.1 +-- +2.27.0 + diff --git a/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch b/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch index f08f83de6505d7810cb7b6753bd00034e3921862..fe171fe867386edc37f5ae7a84868623699549f4 100644 --- a/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch +++ b/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch @@ -1,4 +1,4 @@ -From 2fdece10dac6161cb6c1f0f05247391aa3269eed Mon Sep 17 00:00:00 2001 +From 06837491e2ece2fdd6fe6cc8572aaab52fbdcb3e Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Wed, 22 Apr 2020 15:58:27 +0800 Subject: [PATCH] arm/virt/acpi: Factor out CPPC building from DSDT CPU aml @@ -9,33 +9,21 @@ in build_cpus_aml. Signed-off-by: Keqian Zhu --- - hw/acpi/generic_event_device.c | 1 + hw/arm/virt-acpi-build.c | 33 +++++++++++++++++----------- + hw/arm/virt.c | 1 + include/hw/acpi/acpi_dev_interface.h | 2 ++ include/hw/arm/virt.h | 2 ++ 4 files changed, 25 insertions(+), 13 deletions(-) -diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c -index b834ae3ff6..82139b4314 100644 ---- a/hw/acpi/generic_event_device.c -+++ b/hw/acpi/generic_event_device.c -@@ -289,6 +289,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) - - adevc->send_event = acpi_ged_send_event; - adevc->madt_cpu = virt_madt_cpu_entry; -+ adevc->cpu_cppc = virt_acpi_dsdt_cpu_cppc; - } - - static const TypeInfo acpi_ged_info = { diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 4b6aace433..8b68a15d76 100644 +index 64b1ed8672..a93d223879 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -111,8 +111,24 @@ static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset) +@@ -120,8 +120,24 @@ static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset) aml_append(dev, aml_name_decl("_CPC", cpc)); } - --static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, + +-static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms, - const MemMapEntry *cppc_memmap) +void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int ncpu, int num_cpu, Aml *dev) +{ @@ -54,14 +42,14 @@ index 4b6aace433..8b68a15d76 100644 + } +} + -+static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, VirtMachineState *vms) ++static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) { + MachineState *ms = MACHINE(vms); uint16_t i; - -@@ -121,16 +137,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, +@@ -131,16 +147,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms, aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); aml_append(dev, aml_name_decl("_UID", aml_int(i))); - + - /* - * Append _CPC and _PSD to support CPU frequence show - * Check CPPC available by DESIRED_PERF register @@ -70,52 +58,65 @@ index 4b6aace433..8b68a15d76 100644 - acpi_dsdt_add_cppc(dev, - cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE, - cppc_regs_offset); -- acpi_dsdt_add_psd(dev, smp_cpus); +- acpi_dsdt_add_psd(dev, ms->smp.cpus); - } -+ virt_acpi_dsdt_cpu_cppc(NULL, i, smp_cpus, dev); - ++ virt_acpi_dsdt_cpu_cppc(NULL, i, ms->smp.cpus, dev); + aml_append(scope, dev); } -@@ -810,7 +817,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -940,7 +947,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); -- acpi_dsdt_add_cpus(scope, vms->smp_cpus, &memmap[VIRT_CPUFREQ]); -+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); +- acpi_dsdt_add_cpus(scope, vms, &memmap[VIRT_CPUFREQ]); ++ acpi_dsdt_add_cpus(scope, vms); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + if (vmc->acpi_expose_flash) { +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 44c29070c4..3299d674c8 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -702,6 +702,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + + adevc = ACPI_DEVICE_IF_GET_CLASS(dev); + adevc->madt_cpu = virt_madt_cpu_entry; ++ adevc->cpu_cppc = virt_acpi_dsdt_cpu_cppc; + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h -index adcb3a816c..2952914569 100644 +index ea6056ab92..601931433a 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h -@@ -3,6 +3,7 @@ - +@@ -5,6 +5,7 @@ #include "qom/object.h" #include "hw/boards.h" + #include "hw/qdev-core.h" +#include "hw/acpi/aml-build.h" - + /* These values are part of guest ABI, and can not be changed */ typedef enum { -@@ -55,5 +56,6 @@ typedef struct AcpiDeviceIfClass { - void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev); +@@ -55,5 +56,6 @@ struct AcpiDeviceIfClass { void (*madt_cpu)(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry); + const CPUArchIdList *apic_ids, GArray *entry, + bool force_enabled); + void (*cpu_cppc)(AcpiDeviceIf *adev, int uid, int num_cpu, Aml *dev); - } AcpiDeviceIfClass; + }; #endif diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 6b1f10b231..cbdea7ff32 100644 +index 36639e8d3e..fe26709e1a 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -157,6 +157,8 @@ typedef struct { - void virt_acpi_setup(VirtMachineState *vms); +@@ -185,6 +185,8 @@ bool virt_is_acpi_enabled(VirtMachineState *vms); void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *cpu_list, GArray *entry); + const CPUArchIdList *cpu_list, GArray *entry, + bool force_enabled); +void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int uid, + int num_cpu, Aml *dev); - + /* Return the number of used redistributor regions */ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) --- -2.19.1 +-- +2.27.0 + diff --git a/arm-virt-gic-Construct-irqs-connection-from-create_g.patch b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch index 7e9506425f1de938d2ba70a3fb31a83561a4154e..c16cb0ecacb898a5348c2fe50f12b5ba79ff3f6e 100644 --- a/arm-virt-gic-Construct-irqs-connection-from-create_g.patch +++ b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch @@ -1,4 +1,4 @@ -From 92124743f4560c490780a229f53ea5881f706383 Mon Sep 17 00:00:00 2001 +From 03e050611d6dc9909166fd31dd11abf6fd5012ea Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sun, 5 Apr 2020 15:29:16 +0800 Subject: [PATCH] arm/virt/gic: Construct irqs connection from create_gic @@ -12,13 +12,13 @@ Signed-off-by: Salil Mehta 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 83f4887e57..55d403bad6 100644 +index 149e0245d7..0af0a996a1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -706,6 +706,54 @@ static void create_v2m(VirtMachineState *vms) - fdt_add_v2m_gic_node(vms); +@@ -772,6 +772,54 @@ static void create_v2m(VirtMachineState *vms) + vms->msi_controller = VIRT_MSI_CTRL_GICV2M; } - + +static void connect_gic_cpu_irqs(VirtMachineState *vms, int i) +{ + DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); @@ -67,10 +67,10 @@ index 83f4887e57..55d403bad6 100644 + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); +} + - static void create_gic(VirtMachineState *vms) + static void create_gic(VirtMachineState *vms, MemoryRegion *mem) { MachineState *ms = MACHINE(vms); -@@ -775,47 +823,7 @@ static void create_gic(VirtMachineState *vms) +@@ -849,47 +897,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. */ for (i = 0; i < smp_cpus; i++) { @@ -117,7 +117,8 @@ index 83f4887e57..55d403bad6 100644 - qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + connect_gic_cpu_irqs(vms, i); } - + fdt_add_gic_node(vms); --- -2.19.1 +-- +2.27.0 + diff --git a/hw-arm-expose-host-CPU-frequency-info-to-guest.patch b/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch similarity index 77% rename from hw-arm-expose-host-CPU-frequency-info-to-guest.patch rename to arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch index f0093812ed61e769afec350993e0298a4c5f9e10..005ac1e8d8ba2b927c4a4e5644d26cb83a3e50d6 100644 --- a/hw-arm-expose-host-CPU-frequency-info-to-guest.patch +++ b/arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch @@ -1,7 +1,8 @@ -From b70d020dba72283d7b16a77c377512c84aab5f81 Mon Sep 17 00:00:00 2001 +From e7e28e79988eb671051d0d2af0eb010314c83d41 Mon Sep 17 00:00:00 2001 From: Ying Fang -Date: Mon, 20 Apr 2020 10:38:12 +0800 -Subject: [PATCH] arm64: Add the cpufreq device to show cpufreq info to guest +Date: Tue, 8 Feb 2022 21:01:09 +0800 +Subject: [PATCH 24/24] arm64: Add the cpufreq device to show cpufreq info to + guest On ARM64 platform, cpu frequency is retrieved via ACPI CPPC. A virtual cpufreq device based on ACPI CPPC is created to @@ -22,46 +23,39 @@ This series is backported from: https://patchwork.kernel.org/cover/11379943/ Signed-off-by: Ying Fang +Signed-off-by: Yanan Wang --- - default-configs/aarch64-softmmu.mak | 1 + - hw/acpi/Makefile.objs | 1 + - hw/acpi/aml-build.c | 22 +++ - hw/acpi/cpufreq.c | 287 ++++++++++++++++++++++++++++ - hw/arm/virt-acpi-build.c | 78 +++++++- - hw/arm/virt.c | 13 ++ - hw/char/Kconfig | 4 + - include/hw/acpi/acpi-defs.h | 38 ++++ - include/hw/acpi/aml-build.h | 3 + - include/hw/arm/virt.h | 1 + - 10 files changed, 446 insertions(+), 2 deletions(-) + configs/devices/aarch64-softmmu/default.mak | 1 + + hw/acpi/aml-build.c | 22 ++ + hw/acpi/cpufreq.c | 283 ++++++++++++++++++++ + hw/acpi/meson.build | 1 + + hw/arm/virt-acpi-build.c | 77 +++++- + hw/arm/virt.c | 13 + + hw/char/Kconfig | 4 + + include/hw/acpi/acpi-defs.h | 38 +++ + include/hw/acpi/aml-build.h | 3 + + include/hw/arm/virt.h | 1 + + tests/data/acpi/virt/DSDT | Bin 5196 -> 5669 bytes + tests/data/acpi/virt/DSDT.memhp | Bin 6557 -> 7030 bytes + tests/data/acpi/virt/DSDT.numamem | Bin 5196 -> 5669 bytes + tests/data/acpi/virt/DSDT.pxb | Bin 7679 -> 8152 bytes + 14 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 hw/acpi/cpufreq.c -diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak -index 958b1e08..0a030e85 100644 ---- a/default-configs/aarch64-softmmu.mak -+++ b/default-configs/aarch64-softmmu.mak -@@ -6,3 +6,4 @@ include arm-softmmu.mak +diff --git a/configs/devices/aarch64-softmmu/default.mak b/configs/devices/aarch64-softmmu/default.mak +index cf43ac8da1..c7a710a0f1 100644 +--- a/configs/devices/aarch64-softmmu/default.mak ++++ b/configs/devices/aarch64-softmmu/default.mak +@@ -6,3 +6,4 @@ include ../arm-softmmu/default.mak CONFIG_XLNX_ZYNQMP_ARM=y CONFIG_XLNX_VERSAL=y CONFIG_SBSA_REF=y +CONFIG_CPUFREQ=y -diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs -index 9bb2101e..1a720c38 100644 ---- a/hw/acpi/Makefile.objs -+++ b/hw/acpi/Makefile.objs -@@ -13,6 +13,7 @@ common-obj-y += bios-linker-loader.o - common-obj-y += aml-build.o utils.o - common-obj-$(CONFIG_ACPI_PCI) += pci.o - common-obj-$(CONFIG_TPM) += tpm.o -+common-obj-$(CONFIG_CPUFREQ) += cpufreq.o - - common-obj-$(CONFIG_IPMI) += ipmi.o - common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 555c24f2..73f97751 100644 +index bebf49622b..c4edaafa4a 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c -@@ -1369,6 +1369,28 @@ Aml *aml_sleep(uint64_t msec) +@@ -1554,6 +1554,28 @@ Aml *aml_sleep(uint64_t msec) return var; } @@ -92,10 +86,10 @@ index 555c24f2..73f97751 100644 int hi, lo; diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c new file mode 100644 -index 00000000..d02a25a6 +index 0000000000..a84db490b3 --- /dev/null +++ b/hw/acpi/cpufreq.c -@@ -0,0 +1,287 @@ +@@ -0,0 +1,283 @@ +/* + * ACPI CPPC register device + * @@ -142,7 +136,6 @@ index 00000000..d02a25a6 + */ +#define DEFAULT_HZ 2400 + -+ +int cppc_regs_offset[CPPC_REG_COUNT] = { + [HIGHEST_PERF] = 0, + [NOMINAL_PERF] = 4, @@ -186,8 +179,7 @@ index 00000000..d02a25a6 +} CpuhzState; + + -+static uint64_t cpufreq_read(void *opaque, hwaddr offset, -+ unsigned size) ++static uint64_t cpufreq_read(void *opaque, hwaddr offset, unsigned size) +{ + CpuhzState *s = (CpuhzState *)opaque; + uint64_t r; @@ -231,7 +223,7 @@ index 00000000..d02a25a6 + break; + /* + * Guest may still access the register by 32bit; add the process to -+ * eliminate unnecessary warnings ++ * eliminate unnecessary warnings. + */ + case 28: + r = s->ReferencePerformanceCounter >> 32; @@ -260,7 +252,6 @@ index 00000000..d02a25a6 + return r; +} + -+ +static void cpufreq_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ @@ -292,7 +283,7 @@ index 00000000..d02a25a6 + const char *endptr = NULL; + int ret; + -+ fd = qemu_open(hostpath, O_RDONLY); ++ fd = qemu_open_old(hostpath, O_RDONLY); + if (fd < 0) { + return 0; + } @@ -382,21 +373,27 @@ index 00000000..d02a25a6 +} + +type_init(cpufreq_register_types) -+ +diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build +index adf6347bc4..448ea6afb4 100644 +--- a/hw/acpi/meson.build ++++ b/hw/acpi/meson.build +@@ -25,6 +25,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) + acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) + acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) + acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c')) ++acpi_ss.add(when: 'CONFIG_CPUFREQ', if_true: files('cpufreq.c')) + softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c')) + softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 0afb3727..29494ebd 100644 +index 674f902652..1ca705654b 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -45,11 +45,73 @@ - #include "hw/arm/virt.h" - #include "sysemu/numa.h" - #include "kvm_arm.h" -+#include "hw/acpi/acpi-defs.h" +@@ -60,7 +60,68 @@ - #define ARM_SPI_BASE 32 - #define ACPI_POWER_BUTTON_DEVICE "PWRB" + #define ACPI_BUILD_TABLE_SIZE 0x20000 --static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) +-static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) +static void acpi_dsdt_add_psd(Aml *dev, int cpus) +{ + Aml *pkg; @@ -457,12 +454,12 @@ index 0afb3727..29494ebd 100644 + aml_append(dev, aml_name_decl("_CPC", cpc)); +} + -+static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, ++static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms, + const MemMapEntry *cppc_memmap) { + MachineState *ms = MACHINE(vms); uint16_t i; - -@@ -57,6 +119,18 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) +@@ -69,6 +130,18 @@ static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) Aml *dev = aml_device("C%.03X", i); aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); aml_append(dev, aml_name_decl("_UID", aml_int(i))); @@ -475,78 +472,78 @@ index 0afb3727..29494ebd 100644 + acpi_dsdt_add_cppc(dev, + cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE, + cppc_regs_offset); -+ acpi_dsdt_add_psd(dev, smp_cpus); ++ acpi_dsdt_add_psd(dev, ms->smp.cpus); + } + aml_append(scope, dev); } } -@@ -718,7 +792,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -858,7 +931,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); -- acpi_dsdt_add_cpus(scope, vms->smp_cpus); -+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, &memmap[VIRT_CPUFREQ]); +- acpi_dsdt_add_cpus(scope, vms); ++ acpi_dsdt_add_cpus(scope, vms, &memmap[VIRT_CPUFREQ]); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + if (vmc->acpi_expose_flash) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index d9496c93..0fa355ba 100644 +index 529c0d38b6..0538d258fa 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -135,6 +135,7 @@ static const MemMapEntry base_memmap[] = { - [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, - [VIRT_SMMU] = { 0x09050000, 0x00020000 }, +@@ -154,6 +154,7 @@ static const MemMapEntry base_memmap[] = { + [VIRT_PVTIME] = { 0x090a0000, 0x00010000 }, + [VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, -+ [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, ++ [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, -@@ -731,6 +732,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, +@@ -931,6 +932,16 @@ static void create_uart(const VirtMachineState *vms, int uart, g_free(nodename); } +static void create_cpufreq(const VirtMachineState *vms, MemoryRegion *mem) +{ + hwaddr base = vms->memmap[VIRT_CPUFREQ].base; -+ DeviceState *dev = qdev_create(NULL, "cpufreq"); ++ DeviceState *dev = qdev_new("cpufreq"); + SysBusDevice *s = SYS_BUS_DEVICE(dev); + -+ qdev_init_nofail(dev); ++ sysbus_realize_and_unref(s, &error_fatal); + memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); +} + - static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) + static void create_rtc(const VirtMachineState *vms) { char *nodename; -@@ -1682,6 +1693,8 @@ static void machvirt_init(MachineState *machine) +@@ -2190,6 +2201,8 @@ static void machvirt_init(MachineState *machine) - create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); + create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); + create_cpufreq(vms, sysmem); + if (vms->secure) { - create_secure_ram(vms, secure_sysmem); - create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); + create_secure_ram(vms, secure_sysmem, secure_tag_sysmem); + create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); diff --git a/hw/char/Kconfig b/hw/char/Kconfig -index 40e7a8b8..2f61bf53 100644 +index 6b6cf2fc1d..335a60c2c1 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig -@@ -46,3 +46,7 @@ config SCLPCONSOLE +@@ -71,3 +71,7 @@ config GOLDFISH_TTY - config TERMINAL3270 + config SHAKTI_UART bool + +config CPUFREQ -+ bool -+ default y ++ bool ++ default y diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h -index 57a3f58b..39ae91d3 100644 +index c97e8633ad..ab86583228 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h -@@ -634,4 +634,42 @@ struct AcpiIortRC { - } QEMU_PACKED; - typedef struct AcpiIortRC AcpiIortRC; +@@ -92,4 +92,42 @@ typedef struct AcpiFadtData { + #define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0) + #define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1) +/* + * CPPC register definition from kernel header @@ -588,13 +585,13 @@ index 57a3f58b..39ae91d3 100644 + #endif diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h -index 1a563ad7..375335ab 100644 +index 8e8ad8029e..2e00d2e208 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h -@@ -347,6 +347,9 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed, - Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, +@@ -429,6 +429,9 @@ Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, uint8_t channel); Aml *aml_sleep(uint64_t msec); + Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source); +Aml *aml_generic_register(AmlRegionSpace rs, uint8_t reg_width, + uint8_t reg_offset, AmlAccessType type, + uint64_t addr); @@ -602,10 +599,10 @@ index 1a563ad7..375335ab 100644 /* Block AML object primitives */ Aml *aml_scope(const char *name_format, ...) GCC_FMT_ATTR(1, 2); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index a7209420..43a6ce91 100644 +index dc6b66ffc8..a4356cf736 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -66,6 +66,7 @@ enum { +@@ -70,6 +70,7 @@ enum { VIRT_GIC_REDIST, VIRT_SMMU, VIRT_UART, @@ -613,6 +610,7 @@ index a7209420..43a6ce91 100644 VIRT_MMIO, VIRT_RTC, VIRT_FW_CFG, + -- -2.23.0 +2.27.0 diff --git a/artist-set-memory-region-owners-for-buffers-to-the-a.patch b/artist-set-memory-region-owners-for-buffers-to-the-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..4513e1e242c3ee0789b7c1facf98726a4d105285 --- /dev/null +++ b/artist-set-memory-region-owners-for-buffers-to-the-a.patch @@ -0,0 +1,37 @@ +From db2e1d340763e23180e4709e4ddf33390f2e49ea Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:00:01 +0000 +Subject: [PATCH] artist: set memory region owners for buffers to the artist + device mainline inclusion commit 39fbaeca096a9bf6cbe2af88572c1cb2aa62aa8c + category: bugfix + +--------------------------------------------------------------- + +This fixes the output of "info qom-tree" so that the buffers appear as children +of the artist device, rather than underneath the "unattached" container. + +Signed-off-by: Mark Cave-Ayland +Message-Id: <20220624160839.886649-1-mark.cave-ayland@ilande.co.uk> +Reviewed-by: Helge Deller + +Signed-off-by: tangbinzy +--- + hw/display/artist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/artist.c b/hw/display/artist.c +index 21b7fd1b44..1767203477 100644 +--- a/hw/display/artist.c ++++ b/hw/display/artist.c +@@ -1359,7 +1359,7 @@ static void artist_create_buffer(ARTISTState *s, const char *name, + { + struct vram_buffer *buf = s->vram_buffer + idx; + +- memory_region_init_ram(&buf->mr, NULL, name, width * height, ++ memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height, + &error_fatal); + memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0); + +-- +2.27.0 + diff --git a/async-use-explicit-memory-barriers.patch b/async-use-explicit-memory-barriers.patch deleted file mode 100644 index 7fb68c949ad4e95cc0f908c44042096b69cf9295..0000000000000000000000000000000000000000 --- a/async-use-explicit-memory-barriers.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 787af8ed2bc86dc8688727d62a251965d9c42e00 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Fri, 10 Apr 2020 16:19:50 +0000 -Subject: [PATCH 2/2] async: use explicit memory barriers - -When using C11 atomics, non-seqcst reads and writes do not participate -in the total order of seqcst operations. In util/async.c and util/aio-posix.c, -in particular, the pattern that we use - - write ctx->notify_me write bh->scheduled - read bh->scheduled read ctx->notify_me - if !bh->scheduled, sleep if ctx->notify_me, notify - -needs to use seqcst operations for both the write and the read. In -general this is something that we do not want, because there can be -many sources that are polled in addition to bottom halves. The -alternative is to place a seqcst memory barrier between the write -and the read. This also comes with a disadvantage, in that the -memory barrier is implicit on strongly-ordered architectures and -it wastes a few dozen clock cycles. - -Fortunately, ctx->notify_me is never written concurrently by two -threads, so we can assert that and relax the writes to ctx->notify_me. -The resulting solution works and performs well on both aarch64 and x86. - -Note that the atomic_set/atomic_read combination is not an atomic -read-modify-write, and therefore it is even weaker than C11 ATOMIC_RELAXED; -on x86, ATOMIC_RELAXED compiles to a locked operation. - -upstream_url: https://patchwork.kernel.org/patch/11482103/ - -Analyzed-by: Ying Fang -Signed-off-by: Paolo Bonzini -Tested-by: Ying Fang -Message-Id: <20200407140746.8041-6-pbonzini@redhat.com> -Signed-off-by: Stefan Hajnoczi ---- - util/aio-posix.c | 16 ++++++++++++++-- - util/aio-win32.c | 17 ++++++++++++++--- - util/async.c | 16 ++++++++++++---- - 3 files changed, 40 insertions(+), 9 deletions(-) - -diff --git a/util/aio-posix.c b/util/aio-posix.c -index 6fbfa792..ca58b9a4 100644 ---- a/util/aio-posix.c -+++ b/util/aio-posix.c -@@ -613,6 +613,11 @@ bool aio_poll(AioContext *ctx, bool blocking) - int64_t timeout; - int64_t start = 0; - -+ /* -+ * There cannot be two concurrent aio_poll calls for the same AioContext (or -+ * an aio_poll concurrent with a GSource prepare/check/dispatch callback). -+ * We rely on this below to avoid slow locked accesses to ctx->notify_me. -+ */ - assert(in_aio_context_home_thread(ctx)); - - /* aio_notify can avoid the expensive event_notifier_set if -@@ -623,7 +628,13 @@ bool aio_poll(AioContext *ctx, bool blocking) - * so disable the optimization now. - */ - if (blocking) { -- atomic_add(&ctx->notify_me, 2); -+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); -+ /* -+ * Write ctx->notify_me before computing the timeout -+ * (reading bottom half flags, etc.). Pairs with -+ * smp_mb in aio_notify(). -+ */ -+ smp_mb(); - } - - qemu_lockcnt_inc(&ctx->list_lock); -@@ -668,7 +679,8 @@ bool aio_poll(AioContext *ctx, bool blocking) - } - - if (blocking) { -- atomic_sub(&ctx->notify_me, 2); -+ /* Finish the poll before clearing the flag. */ -+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2); - aio_notify_accept(ctx); - } - -diff --git a/util/aio-win32.c b/util/aio-win32.c -index a23b9c36..729d533f 100644 ---- a/util/aio-win32.c -+++ b/util/aio-win32.c -@@ -321,6 +321,12 @@ bool aio_poll(AioContext *ctx, bool blocking) - int count; - int timeout; - -+ /* -+ * There cannot be two concurrent aio_poll calls for the same AioContext (or -+ * an aio_poll concurrent with a GSource prepare/check/dispatch callback). -+ * We rely on this below to avoid slow locked accesses to ctx->notify_me. -+ */ -+ assert(in_aio_context_home_thread(ctx)); - progress = false; - - /* aio_notify can avoid the expensive event_notifier_set if -@@ -331,7 +337,13 @@ bool aio_poll(AioContext *ctx, bool blocking) - * so disable the optimization now. - */ - if (blocking) { -- atomic_add(&ctx->notify_me, 2); -+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); -+ /* -+ * Write ctx->notify_me before computing the timeout -+ * (reading bottom half flags, etc.). Pairs with -+ * smp_mb in aio_notify(). -+ */ -+ smp_mb(); - } - - qemu_lockcnt_inc(&ctx->list_lock); -@@ -364,8 +376,7 @@ bool aio_poll(AioContext *ctx, bool blocking) - ret = WaitForMultipleObjects(count, events, FALSE, timeout); - if (blocking) { - assert(first); -- assert(in_aio_context_home_thread(ctx)); -- atomic_sub(&ctx->notify_me, 2); -+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2); - aio_notify_accept(ctx); - } - -diff --git a/util/async.c b/util/async.c -index afc17fb3..12b33204 100644 ---- a/util/async.c -+++ b/util/async.c -@@ -221,7 +221,14 @@ aio_ctx_prepare(GSource *source, gint *timeout) - { - AioContext *ctx = (AioContext *) source; - -- atomic_or(&ctx->notify_me, 1); -+ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) | 1); -+ -+ /* -+ * Write ctx->notify_me before computing the timeout -+ * (reading bottom half flags, etc.). Pairs with -+ * smp_mb in aio_notify(). -+ */ -+ smp_mb(); - - /* We assume there is no timeout already supplied */ - *timeout = qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)); -@@ -239,7 +246,8 @@ aio_ctx_check(GSource *source) - AioContext *ctx = (AioContext *) source; - QEMUBH *bh; - -- atomic_and(&ctx->notify_me, ~1); -+ /* Finish computing the timeout before clearing the flag. */ -+ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) & ~1); - aio_notify_accept(ctx); - - for (bh = ctx->first_bh; bh; bh = bh->next) { -@@ -344,10 +352,10 @@ LinuxAioState *aio_get_linux_aio(AioContext *ctx) - void aio_notify(AioContext *ctx) - { - /* Write e.g. bh->scheduled before reading ctx->notify_me. Pairs -- * with atomic_or in aio_ctx_prepare or atomic_add in aio_poll. -+ * with smp_mb in aio_ctx_prepare or aio_poll. - */ - smp_mb(); -- if (ctx->notify_me) { -+ if (atomic_read(&ctx->notify_me)) { - event_notifier_set(&ctx->notifier); - atomic_mb_set(&ctx->notified, true); - } --- -2.25.2 - diff --git a/ati-check-x-y-display-parameter-values.patch b/ati-check-x-y-display-parameter-values.patch deleted file mode 100644 index 22a38b28067a612f181c4fc0a2cf1b9f6d049493..0000000000000000000000000000000000000000 --- a/ati-check-x-y-display-parameter-values.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 9557ba506470517668ffecb4d5ef4804eca4fd88 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Wed, 18 Nov 2020 10:22:32 +0800 -Subject: [PATCH] ati: check x y display parameter values - -fix CVE-2020-24352 - -The source and destination x,y display parameters in ati_2d_blt() -may run off the vga limits if either of s->regs.[src|dst]_[xy] is -zero. Check the parameter values to avoid potential crash. - -Reported-by: Gaoning Pan -Signed-off-by: Prasad J Pandit -Message-id: 20201021103818.1704030-1-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann - -cherry-pick from commit ca1f9cbfdce4d63b10d57de80fef89a89d92a540 -Signed-off-by: Jiajie Li ---- - hw/display/ati_2d.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c -index 23a8ae0cd8..4dc10ea795 100644 ---- a/hw/display/ati_2d.c -+++ b/hw/display/ati_2d.c -@@ -75,8 +75,9 @@ void ati_2d_blt(ATIVGAState *s) - dst_stride *= bpp; - } - uint8_t *end = s->vga.vram_ptr + s->vga.vram_size; -- if (dst_bits >= end || dst_bits + dst_x + (dst_y + s->regs.dst_height) * -- dst_stride >= end) { -+ if (dst_x > 0x3fff || dst_y > 0x3fff || dst_bits >= end -+ || dst_bits + dst_x -+ + (dst_y + s->regs.dst_height) * dst_stride >= end) { - qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n"); - return; - } -@@ -107,8 +108,9 @@ void ati_2d_blt(ATIVGAState *s) - src_bits += s->regs.crtc_offset & 0x07ffffff; - src_stride *= bpp; - } -- if (src_bits >= end || src_bits + src_x + -- (src_y + s->regs.dst_height) * src_stride >= end) { -+ if (src_x > 0x3fff || src_y > 0x3fff || src_bits >= end -+ || src_bits + src_x -+ + (src_y + s->regs.dst_height) * src_stride >= end) { - qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n"); - return; - } --- -2.27.0 - diff --git a/ati-use-vga_read_byte-in-ati_cursor_define.patch b/ati-use-vga_read_byte-in-ati_cursor_define.patch deleted file mode 100644 index a4b7e806600c341d865ca6acaf75ed4ce6b9c9b8..0000000000000000000000000000000000000000 --- a/ati-use-vga_read_byte-in-ati_cursor_define.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 1ebe0e71d04bfdc76777a3a672e873f006d207e2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 5 Feb 2021 10:38:24 +0800 -Subject: [PATCH] ati: use vga_read_byte in ati_cursor_define -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -fix CVE-2019-20808 - -This makes sure reads are confined to vga video memory. - -v3: use uint32_t, fix cut+paste bug. -v2: fix ati_cursor_draw_line too. - -Reported-by: xu hang -Signed-off-by: Gerd Hoffmann -Reviewed-by: BALATON Zoltan -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 20190917111441.27405-3-kraxel@redhat.com - -cherry-pick from aab0e2a661b2b6bf7915c0aefe807fb60d6d9d13 -Signed-off-by: Jiajie Li ---- - hw/display/ati.c | 21 ++++++++--------- - hw/display/vga-access.h | 49 ++++++++++++++++++++++++++++++++++++++++ - hw/display/vga-helpers.h | 27 +--------------------- - 3 files changed, 60 insertions(+), 37 deletions(-) - create mode 100644 hw/display/vga-access.h - -diff --git a/hw/display/ati.c b/hw/display/ati.c -index 5943040416..b17569874e 100644 ---- a/hw/display/ati.c -+++ b/hw/display/ati.c -@@ -19,6 +19,7 @@ - #include "qemu/osdep.h" - #include "ati_int.h" - #include "ati_regs.h" -+#include "vga-access.h" - #include "vga_regs.h" - #include "qemu/log.h" - #include "qemu/module.h" -@@ -125,20 +126,19 @@ static void ati_vga_switch_mode(ATIVGAState *s) - static void ati_cursor_define(ATIVGAState *s) - { - uint8_t data[1024]; -- uint8_t *src; -+ uint32_t srcoff; - int i, j, idx = 0; - - if ((s->regs.cur_offset & BIT(31)) || s->cursor_guest_mode) { - return; /* Do not update cursor if locked or rendered by guest */ - } - /* FIXME handle cur_hv_offs correctly */ -- src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + -- s->regs.cur_offset - (s->regs.cur_hv_offs >> 16) - -- (s->regs.cur_hv_offs & 0xffff) * 16; -+ srcoff = s->regs.cur_offset - -+ (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16; - for (i = 0; i < 64; i++) { - for (j = 0; j < 8; j++, idx++) { -- data[idx] = src[i * 16 + j]; -- data[512 + idx] = src[i * 16 + j + 8]; -+ data[idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j); -+ data[512 + idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j + 8); - } - } - if (!s->cursor) { -@@ -180,7 +180,7 @@ static void ati_cursor_invalidate(VGACommonState *vga) - static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) - { - ATIVGAState *s = container_of(vga, ATIVGAState, vga); -- uint8_t *src; -+ uint32_t srcoff; - uint32_t *dp = (uint32_t *)d; - int i, j, h; - -@@ -190,14 +190,13 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) - return; - } - /* FIXME handle cur_hv_offs correctly */ -- src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + -- s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; -+ srcoff = s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; - dp = &dp[vga->hw_cursor_x]; - h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8; - for (i = 0; i < 8; i++) { - uint32_t color; -- uint8_t abits = src[i]; -- uint8_t xbits = src[i + 8]; -+ uint8_t abits = vga_read_byte(vga, srcoff + i); -+ uint8_t xbits = vga_read_byte(vga, srcoff + i + 8); - for (j = 0; j < 8; j++, abits <<= 1, xbits <<= 1) { - if (abits & BIT(7)) { - if (xbits & BIT(7)) { -diff --git a/hw/display/vga-access.h b/hw/display/vga-access.h -new file mode 100644 -index 0000000000..c0fbd9958b ---- /dev/null -+++ b/hw/display/vga-access.h -@@ -0,0 +1,49 @@ -+/* -+ * QEMU VGA Emulator templates -+ * -+ * Copyright (c) 2003 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr) -+{ -+ return vga->vram_ptr[addr & vga->vbe_size_mask]; -+} -+ -+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~1; -+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -+ return lduw_le_p(ptr); -+} -+ -+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~1; -+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -+ return lduw_be_p(ptr); -+} -+ -+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~3; -+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset); -+ return ldl_le_p(ptr); -+} -diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h -index 5a752b3f9e..5b6c02faa6 100644 ---- a/hw/display/vga-helpers.h -+++ b/hw/display/vga-helpers.h -@@ -21,6 +21,7 @@ - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -+#include "vga-access.h" - - static inline void vga_draw_glyph_line(uint8_t *d, uint32_t font_data, - uint32_t xorcol, uint32_t bgcol) -@@ -95,32 +96,6 @@ static void vga_draw_glyph9(uint8_t *d, int linesize, - } while (--h); - } - --static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr) --{ -- return vga->vram_ptr[addr & vga->vbe_size_mask]; --} -- --static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr) --{ -- uint32_t offset = addr & vga->vbe_size_mask & ~1; -- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -- return lduw_le_p(ptr); --} -- --static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr) --{ -- uint32_t offset = addr & vga->vbe_size_mask & ~1; -- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -- return lduw_be_p(ptr); --} -- --static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr) --{ -- uint32_t offset = addr & vga->vbe_size_mask & ~3; -- uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset); -- return ldl_le_p(ptr); --} -- - /* - * 4 color mode - */ --- -2.27.0 - diff --git a/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch b/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch deleted file mode 100644 index ef1d8b646c607a5afb6278ab229efc4a5a15965f..0000000000000000000000000000000000000000 --- a/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch +++ /dev/null @@ -1,91 +0,0 @@ -From ac2071c3791b67fc7af78b8ceb320c01ca1b5df7 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Mon, 6 Apr 2020 22:34:26 +0200 -Subject: [PATCH] ati-vga: Fix checks in ati_2d_blt() to avoid crash - -In some corner cases (that never happen during normal operation but a -malicious guest could program wrong values) pixman functions were -called with parameters that result in a crash. Fix this and add more -checks to disallow such cases. - -Reported-by: Ziming Zhang -Signed-off-by: BALATON Zoltan -Message-id: 20200406204029.19559747D5D@zero.eik.bme.hu -Signed-off-by: Gerd Hoffmann - -diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c -index 42e82311eb..23a8ae0cd8 100644 ---- a/hw/display/ati_2d.c -+++ b/hw/display/ati_2d.c -@@ -53,12 +53,20 @@ void ati_2d_blt(ATIVGAState *s) - s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds), - surface_bits_per_pixel(ds), - (s->regs.dp_mix & GMC_ROP3_MASK) >> 16); -- int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? -- s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); -- int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -- s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); -+ unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? -+ s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); -+ unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -+ s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); - int bpp = ati_bpp_from_datatype(s); -+ if (!bpp) { -+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n"); -+ return; -+ } - int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch; -+ if (!dst_stride) { -+ qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n"); -+ return; -+ } - uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? - s->regs.dst_offset : s->regs.default_offset); - -@@ -82,12 +90,16 @@ void ati_2d_blt(ATIVGAState *s) - switch (s->regs.dp_mix & GMC_ROP3_MASK) { - case ROP3_SRCCOPY: - { -- int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? -- s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); -- int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -- s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); -+ unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? -+ s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); -+ unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -+ s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); - int src_stride = DEFAULT_CNTL ? - s->regs.src_pitch : s->regs.default_pitch; -+ if (!src_stride) { -+ qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n"); -+ return; -+ } - uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? - s->regs.src_offset : s->regs.default_offset); - -@@ -137,8 +149,10 @@ void ati_2d_blt(ATIVGAState *s) - dst_y * surface_stride(ds), - s->regs.dst_height * surface_stride(ds)); - } -- s->regs.dst_x += s->regs.dst_width; -- s->regs.dst_y += s->regs.dst_height; -+ s->regs.dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? -+ dst_x + s->regs.dst_width : dst_x); -+ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -+ dst_y + s->regs.dst_height : dst_y); - break; - } - case ROP3_PATCOPY: -@@ -179,7 +193,8 @@ void ati_2d_blt(ATIVGAState *s) - dst_y * surface_stride(ds), - s->regs.dst_height * surface_stride(ds)); - } -- s->regs.dst_y += s->regs.dst_height; -+ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? -+ dst_y + s->regs.dst_height : dst_y); - break; - } - default: --- -2.23.0 - diff --git a/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch b/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch deleted file mode 100644 index b80c9dc973015dd83e3d9c0c000dd0b15b303608..0000000000000000000000000000000000000000 --- a/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 89554d2f71d4c79c5d8e804d90d74f3985d7ded5 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 4 Jun 2020 14:38:30 +0530 -Subject: [PATCH 3/9] ati-vga: check mm_index before recursive call - (CVE-2020-13800) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While accessing VGA registers via ati_mm_read/write routines, -a guest may set 's->regs.mm_index' such that it leads to infinite -recursion. Check mm_index value to avoid such recursion. Log an -error message for wrong values. - -Reported-by: Ren Ding -Reported-by: Hanqing Zhao -Reported-by: Yi Ren -Message-id: 20200604090830.33885-1-ppandit@redhat.com -Suggested-by: BALATON Zoltan -Suggested-by: Philippe Mathieu-Daudé -Signed-off-by: Prasad J Pandit -Signed-off-by: Gerd Hoffmann ---- - hw/display/ati.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/hw/display/ati.c b/hw/display/ati.c -index a747c4cc98..5943040416 100644 ---- a/hw/display/ati.c -+++ b/hw/display/ati.c -@@ -261,8 +261,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) - if (idx <= s->vga.vram_size - size) { - val = ldn_le_p(s->vga.vram_ptr + idx, size); - } -- } else { -+ } else if (s->regs.mm_index > MM_DATA + 3) { - val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size); -+ } else { -+ qemu_log_mask(LOG_GUEST_ERROR, -+ "ati_mm_read: mm_index too small: %u\n", s->regs.mm_index); - } - break; - case BIOS_0_SCRATCH ... BUS_CNTL - 1: -@@ -472,8 +475,11 @@ static void ati_mm_write(void *opaque, hwaddr addr, - if (idx <= s->vga.vram_size - size) { - stn_le_p(s->vga.vram_ptr + idx, size, data); - } -- } else { -+ } else if (s->regs.mm_index > MM_DATA + 3) { - ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size); -+ } else { -+ qemu_log_mask(LOG_GUEST_ERROR, -+ "ati_mm_write: mm_index too small: %u\n", s->regs.mm_index); - } - break; - case BIOS_0_SCRATCH ... BUS_CNTL - 1: --- -2.25.1 - diff --git a/audio-fix-integer-overflow.patch b/audio-fix-integer-overflow.patch deleted file mode 100644 index 91f5280f1854634460e43b48ae98a4f5eb57b26c..0000000000000000000000000000000000000000 --- a/audio-fix-integer-overflow.patch +++ /dev/null @@ -1,37 +0,0 @@ -From d0c4e8cc25dc3bfed1659c35fb59b2f0418ba1d5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Volker=20R=C3=BCmelin?= -Date: Thu, 19 Dec 2019 21:34:05 +0100 -Subject: [PATCH 2/8] audio: fix integer overflow -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Tell the compiler to do a 32bit * 32bit -> 64bit multiplication -because period_ticks is a 64bit variable. The overflow occurs -for audio timer periods larger than 4294967us. - -Fixes: be1092afa0 "audio: fix audio timer rate conversion bug" - -Signed-off-by: Volker Rümelin -Message-id: 8893a235-66a8-8fbe-7d95-862e29da90b1@t-online.de -Signed-off-by: Gerd Hoffmann ---- - audio/audio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/audio/audio.c b/audio/audio.c -index 05adf7f..efcb5d4 100644 ---- a/audio/audio.c -+++ b/audio/audio.c -@@ -1473,7 +1473,7 @@ static int audio_init(Audiodev *dev) - if (dev->timer_period <= 0) { - s->period_ticks = 1; - } else { -- s->period_ticks = dev->timer_period * SCALE_US; -+ s->period_ticks = dev->timer_period * (int64_t)SCALE_US; - } - - e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); --- -1.8.3.1 - diff --git a/backup-Improve-error-for-bdrv_getlength-failure.patch b/backup-Improve-error-for-bdrv_getlength-failure.patch deleted file mode 100644 index df188942c913062b499c1d6579556784661b2985..0000000000000000000000000000000000000000 --- a/backup-Improve-error-for-bdrv_getlength-failure.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0b66aef5389d622434128fc7db9abd2cd4724b51 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Wed, 3 Jun 2020 16:03:19 +0100 -Subject: [PATCH] backup: Improve error for bdrv_getlength() failure - -RH-Author: Kevin Wolf -Message-id: <20200603160325.67506-6-kwolf@redhat.com> -Patchwork-id: 97103 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH v2 05/11] backup: Improve error for bdrv_getlength() failure -Bugzilla: 1778593 -RH-Acked-by: Eric Blake -RH-Acked-by: Max Reitz -RH-Acked-by: Stefano Garzarella - -bdrv_get_device_name() will be an empty string with modern management -tools that don't use -drive. Use bdrv_get_device_or_node_name() instead -so that the node name is used if the BlockBackend is anonymous. - -While at it, start with upper case to make the message consistent with -the rest of the function. - -Signed-off-by: Kevin Wolf -Reviewed-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Alberto Garcia -Message-Id: <20200430142755.315494-3-kwolf@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 58226634c4b02af7b10862f7fbd3610a344bfb7f) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - block/backup.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index 8761f1f9a7..88354dcb32 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -613,8 +613,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - - len = bdrv_getlength(bs); - if (len < 0) { -- error_setg_errno(errp, -len, "unable to get length for '%s'", -- bdrv_get_device_name(bs)); -+ error_setg_errno(errp, -len, "Unable to get length for '%s'", -+ bdrv_get_device_or_node_name(bs)); - goto error; - } - --- -2.27.0 - diff --git a/balloon-Fix-a-misleading-error-message.patch b/balloon-Fix-a-misleading-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0f7cdc81da2c8af25954d5783b00a6eb8a5093d --- /dev/null +++ b/balloon-Fix-a-misleading-error-message.patch @@ -0,0 +1,60 @@ +From 0c24a55d582e8219b64f2090cbdd21027d496bb1 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 10:44:31 +0800 +Subject: [PATCH] balloon: Fix a misleading error message + +cherry picked from eeef44b3a583637265f602882a0d058a52e3a33b + +The error message + + {"execute": "balloon", "arguments":{"value": -1}} + {"error": {"class": "GenericError", "desc": "Parameter 'target' expects a size"}} + +points to 'target' instead of 'value'. Fix: + + {"error": {"class": "GenericError", "desc": "Parameter 'value' expects a size"}} + +Root cause: qmp_balloon()'s parameter is named @target. Rename it to +@value to match the QAPI schema. + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-7-armbru@redhat.com> +Reviewed-by: David Hildenbrand +Reviewed-by: Michael S. Tsirkin +Tested-by: Mario Casquero + +Signed-off-by: boringandboring +--- + softmmu/balloon.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/softmmu/balloon.c b/softmmu/balloon.c +index e0e8969a4b..fda7af832e 100644 +--- a/softmmu/balloon.c ++++ b/softmmu/balloon.c +@@ -90,17 +90,17 @@ BalloonInfo *qmp_query_balloon(Error **errp) + return info; + } + +-void qmp_balloon(int64_t target, Error **errp) ++void qmp_balloon(int64_t value, Error **errp) + { + if (!have_balloon(errp)) { + return; + } + +- if (target <= 0) { +- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "target", "a size"); ++ if (value <= 0) { ++ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "value", "a size"); + return; + } + +- trace_balloon_event(balloon_opaque, target); +- balloon_event_fn(balloon_opaque, target); ++ trace_balloon_event(balloon_opaque, value); ++ balloon_event_fn(balloon_opaque, value); + } +-- +2.27.0 + diff --git a/bios-tables-test-Allow-changes-to-q35-SSDT.dimmpxm-f.patch b/bios-tables-test-Allow-changes-to-q35-SSDT.dimmpxm-f.patch new file mode 100644 index 0000000000000000000000000000000000000000..8228abcd539d2ad17cd911cfc7a5281b7beda939 --- /dev/null +++ b/bios-tables-test-Allow-changes-to-q35-SSDT.dimmpxm-f.patch @@ -0,0 +1,23 @@ +From 00c4115a1388ee72295b99fce1f6ad49bf761134 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 17:08:08 +0800 +Subject: [PATCH] bios-tables-test: Allow changes to q35/SSDT.dimmpxm file + +List test/data/acpi/q35/SSDT.dimmpxm as the expected files allowed to +be changed in tests/qtest/bios-tables-test-allowed-diff.h + +Signed-off-by: Yan Wang +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523c8b..81148a604f 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/q35/SSDT.dimmpxm", +-- +2.27.0 + diff --git a/bios-tables-test-Update-expected-q35-SSDT.dimmpxm-fi.patch b/bios-tables-test-Update-expected-q35-SSDT.dimmpxm-fi.patch new file mode 100644 index 0000000000000000000000000000000000000000..6cfa1f203d183536ae36b3eed2255310e0e4e50d --- /dev/null +++ b/bios-tables-test-Update-expected-q35-SSDT.dimmpxm-fi.patch @@ -0,0 +1,79 @@ +From 8940f11a055da0a744d10b53cf999dea7967be25 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 17:12:35 +0800 +Subject: [PATCH] bios-tables-test: Update expected q35/SSDT.dimmpxm file + +Run ./tests/data/acpi/rebuild-expected-aml.sh from build directory +to update q35/SSDT.dimmpxm file. Also empty bios-tables-test-allowed-diff.h. + +The disassembled differences between actual and expected SSDT.dimmpxm: + + /* + * Intel ACPI Component Architecture + * AML/ASL+ Disassembler version 20210604 (64-bit version) + * Copyright (c) 2000 - 2021 Intel Corporation + * + * Disassembling to symbolic ASL+ operators + * +- * Disassembly of tests/data/acpi/q35/SSDT.dimmpxm, Thu Feb 10 15:03:52 2022 ++ * Disassembly of /tmp/aml-CK68G1, Thu Feb 10 15:03:52 2022 + * + * Original Table Header: + * Signature "SSDT" + * Length 0x000002DE (734) + * Revision 0x01 +- * Checksum 0x06 ++ * Checksum 0x16 + * OEM ID "BOCHS " + * OEM Table ID "NVDIMM " + * OEM Revision 0x00000001 (1) + * Compiler ID "BXPC" + * Compiler Version 0x00000001 (1) + */ + DefinitionBlock ("", "SSDT", 1, "BOCHS ", "NVDIMM ", 0x00000001) + { + Scope (\_SB) + { + Device (NVDR) + { + Name (_HID, "ACPI0012" /* NVDIMM Root Device */) // _HID: Hardware ID + Method (NCAL, 5, Serialized) + { + Local6 = MEMA /* \MEMA */ +@@ -187,19 +187,19 @@ + { + Return (NCAL (Arg0, Arg1, Arg2, Arg3, 0x02)) + } + } + + Device (NV02) + { + Name (_ADR, 0x03) // _ADR: Address + Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method + { + Return (NCAL (Arg0, Arg1, Arg2, Arg3, 0x03)) + } + } + } + } + +- Name (MEMA, 0x07FFF000) ++ Name (MEMA, 0x07FFE000) + } + +Signed-off-by: Yan Wang +--- + tests/data/acpi/q35/SSDT.dimmpxm | Bin 734 -> 734 bytes + tests/qtest/bios-tables-test-allowed-diff.h | 1 - + 2 files changed, 1 deletion(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index 81148a604f..dfb8523c8b 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,2 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/q35/SSDT.dimmpxm", +-- +2.27.0 + diff --git a/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch b/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch deleted file mode 100644 index 1dc656892b5f124d3ad732aed9c31b0f71a3363b..0000000000000000000000000000000000000000 --- a/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2892a4b1f7dfc75e06d0ce770d44a062b6334eb0 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 15 Apr 2020 17:03:54 +0800 -Subject: [PATCH] bios-tables-test: prepare to change ARM virt ACPI DSDT - -We will change ARM virt ACPI DSDT table in order to add the cpufreq device, -which use ACPI CPPC to show CPU frequency info to guest. - -Signed-off-by: Ying Fang ---- - tests/bios-tables-test-allowed-diff.h | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h -index dfb8523c..32a401ae 100644 ---- a/tests/bios-tables-test-allowed-diff.h -+++ b/tests/bios-tables-test-allowed-diff.h -@@ -1 +1,4 @@ - /* List of comma-separated changed AML files to ignore */ -+"tests/data/acpi/virt/DSDT", -+"tests/data/acpi/virt/DSDT.memhp", -+"tests/data/acpi/virt/DSDT.numamem", --- -2.23.0 diff --git a/block-Add-bdrv_co_get_self_request.patch b/block-Add-bdrv_co_get_self_request.patch deleted file mode 100644 index 4972f084649f70253978ad8fb1d3842bbf741d81..0000000000000000000000000000000000000000 --- a/block-Add-bdrv_co_get_self_request.patch +++ /dev/null @@ -1,59 +0,0 @@ -From d9b88f7e0d56feb4d7daa2506e2756fc48e975a1 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Fri, 1 Nov 2019 16:25:09 +0100 -Subject: [PATCH] block: Add bdrv_co_get_self_request() - -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Message-id: 20191101152510.11719-3-mreitz@redhat.com -Signed-off-by: Max Reitz -(cherry picked from commit c28107e9e55b11cd35cf3dc2505e3e69d10dcf13) -Signed-off-by: Michael Roth ---- - block/io.c | 18 ++++++++++++++++++ - include/block/block_int.h | 1 + - 2 files changed, 19 insertions(+) - -diff --git a/block/io.c b/block/io.c -index d4ceaaa2ce..65b5102714 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -721,6 +721,24 @@ static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req) - (req->bytes == req->overlap_bytes); - } - -+/** -+ * Return the tracked request on @bs for the current coroutine, or -+ * NULL if there is none. -+ */ -+BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) -+{ -+ BdrvTrackedRequest *req; -+ Coroutine *self = qemu_coroutine_self(); -+ -+ QLIST_FOREACH(req, &bs->tracked_requests, list) { -+ if (req->co == self) { -+ return req; -+ } -+ } -+ -+ return NULL; -+} -+ - /** - * Round a region to cluster boundaries - */ -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 4465b02242..05ee6b4866 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -964,6 +964,7 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); - - bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self); - void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align); -+BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); - - int get_tmp_filename(char *filename, int size); - BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, --- -2.23.0 diff --git a/block-Add-error-retry-param-setting.patch b/block-Add-error-retry-param-setting.patch index 72f214b1283635a32308e67ba095ff981368ea2e..4facb3f8c1fca5e941ee5154bd2459ae8309b8f8 100644 --- a/block-Add-error-retry-param-setting.patch +++ b/block-Add-error-retry-param-setting.patch @@ -1,7 +1,7 @@ -From 3464a135565d718d0fedadd67081a0f76d81a9c6 Mon Sep 17 00:00:00 2001 +From a58fda7b158441c645e143bf658d12914ffbc7b8 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:50 +0800 -Subject: [PATCH] block: Add error retry param setting +Subject: [PATCH 6/7] block: Add error retry param setting Add "retry_interval" and "retry_timeout" parameter for drive and device option. These parameter are valid only when werror/rerror=retry. @@ -10,6 +10,7 @@ eg. --drive file=image,rerror=retry,retry_interval=1000,retry_timeout=5000 Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 13 +++++++-- blockdev.c | 50 ++++++++++++++++++++++++++++++++++ @@ -19,10 +20,10 @@ Signed-off-by: Ying Fang 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c -index 0fe99ffe52..2d812e2254 100644 +index 37e21c473e..d3d90a95a5 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -31,9 +31,6 @@ +@@ -35,9 +35,6 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); @@ -32,7 +33,7 @@ index 0fe99ffe52..2d812e2254 100644 typedef struct BlockBackendAioNotifier { void (*attached_aio_context)(AioContext *new_context, void *opaque); void (*detach_aio_context)(void *opaque); -@@ -1633,6 +1630,16 @@ void blk_drain_all(void) +@@ -1766,6 +1763,16 @@ void blk_drain_all(void) bdrv_drain_all_end(); } @@ -50,10 +51,10 @@ index 0fe99ffe52..2d812e2254 100644 { /* No timeout set, infinite retries. */ diff --git a/blockdev.c b/blockdev.c -index 0f49fd290e..99c92b96d2 100644 +index 6f1981635b..10a73fa423 100644 --- a/blockdev.c +++ b/blockdev.c -@@ -470,6 +470,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, +@@ -480,6 +480,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, const char *buf; int bdrv_flags = 0; int on_read_error, on_write_error; @@ -61,7 +62,7 @@ index 0f49fd290e..99c92b96d2 100644 bool account_invalid, account_failed; bool writethrough, read_only; BlockBackend *blk; -@@ -565,6 +566,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, +@@ -572,6 +573,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, } } @@ -72,7 +73,7 @@ index 0f49fd290e..99c92b96d2 100644 if (snapshot) { bdrv_flags |= BDRV_O_SNAPSHOT; } -@@ -629,6 +634,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, +@@ -635,6 +640,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, blk_set_enable_write_cache(blk, !writethrough); blk_set_on_error(blk, on_read_error, on_write_error); @@ -84,7 +85,7 @@ index 0f49fd290e..99c92b96d2 100644 if (!monitor_add_blk(blk, id, errp)) { blk_unref(blk); -@@ -754,6 +764,14 @@ QemuOptsList qemu_legacy_drive_opts = { +@@ -761,6 +771,14 @@ QemuOptsList qemu_legacy_drive_opts = { .name = "werror", .type = QEMU_OPT_STRING, .help = "write error action", @@ -99,7 +100,7 @@ index 0f49fd290e..99c92b96d2 100644 },{ .name = "copy-on-read", .type = QEMU_OPT_BOOL, -@@ -776,6 +794,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, +@@ -783,6 +801,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, BlockInterfaceType type; int max_devs, bus_id, unit_id, index; const char *werror, *rerror; @@ -107,7 +108,7 @@ index 0f49fd290e..99c92b96d2 100644 bool read_only = false; bool copy_on_read; const char *filename; -@@ -992,6 +1011,29 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, +@@ -990,6 +1009,29 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, qdict_put_str(bs_opts, "rerror", rerror); } @@ -135,9 +136,9 @@ index 0f49fd290e..99c92b96d2 100644 + } + /* Actual block device init: Functionality shared with blockdev-add */ - blk = blockdev_init(filename, bs_opts, &local_err); + blk = blockdev_init(filename, bs_opts, errp); bs_opts = NULL; -@@ -4593,6 +4635,14 @@ QemuOptsList qemu_common_drive_opts = { +@@ -3806,6 +3848,14 @@ QemuOptsList qemu_common_drive_opts = { .name = "werror", .type = QEMU_OPT_STRING, .help = "write error action", @@ -153,10 +154,10 @@ index 0f49fd290e..99c92b96d2 100644 .name = BDRV_OPT_READ_ONLY, .type = QEMU_OPT_BOOL, diff --git a/hw/block/block.c b/hw/block/block.c -index bf56c7612b..56141940ca 100644 +index d47ebf005a..26c0767552 100644 --- a/hw/block/block.c +++ b/hw/block/block.c -@@ -134,6 +134,16 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, +@@ -206,6 +206,16 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, blk_set_enable_write_cache(blk, wce); blk_set_on_error(blk, rerror, werror); @@ -174,10 +175,10 @@ index bf56c7612b..56141940ca 100644 } diff --git a/include/hw/block/block.h b/include/hw/block/block.h -index 607539057a..d12603aabd 100644 +index 5902c0440a..24fb7d77af 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h -@@ -30,6 +30,8 @@ typedef struct BlockConf { +@@ -33,6 +33,8 @@ typedef struct BlockConf { bool share_rw; BlockdevOnError rerror; BlockdevOnError werror; @@ -186,7 +187,7 @@ index 607539057a..d12603aabd 100644 } BlockConf; static inline unsigned int get_physical_block_exp(BlockConf *conf) -@@ -71,7 +73,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) +@@ -79,7 +81,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) DEFINE_PROP_BLOCKDEV_ON_ERROR("rerror", _state, _conf.rerror, \ BLOCKDEV_ON_ERROR_AUTO), \ DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \ @@ -199,7 +200,7 @@ index 607539057a..d12603aabd 100644 /* Backend access helpers */ diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h -index 58dde446ca..dc10e507ae 100644 +index 56a403883d..887c19ff5d 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -25,6 +25,9 @@ @@ -212,7 +213,7 @@ index 58dde446ca..dc10e507ae 100644 /* Callbacks for block device models */ typedef struct BlockDevOps { /* -@@ -184,6 +187,8 @@ void blk_inc_in_flight(BlockBackend *blk); +@@ -198,6 +201,8 @@ void blk_inc_in_flight(BlockBackend *blk); void blk_dec_in_flight(BlockBackend *blk); void blk_drain(BlockBackend *blk); void blk_drain_all(void); diff --git a/block-Add-sanity-check-when-setting-retry-parameters.patch b/block-Add-sanity-check-when-setting-retry-parameters.patch index 0af7b6e14e2be698821105d386c4c39893c67a83..d48fa5d654a4d5eb2e50b2336715bbeff40242a5 100644 --- a/block-Add-sanity-check-when-setting-retry-parameters.patch +++ b/block-Add-sanity-check-when-setting-retry-parameters.patch @@ -1,24 +1,40 @@ -From 6642b2c6fcad2e1099c61b56f4fe78f3180d005e Mon Sep 17 00:00:00 2001 +From f329ec9bd971ba7776cadb57e7311bfb6da41060 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 18 Mar 2021 19:45:11 +0800 -Subject: [PATCH] block: Add sanity check when setting retry parameters +Subject: [PATCH 9/9] block: Add sanity check when setting retry parameters Add sanity check when setting retry parameters to avoid invalid retry configuration. Signed-off-by: Jiahui Cen +Signed-off-by: Alex Chen --- - hw/core/qdev-properties.c | 45 ++++++++++++++++++++++++++++++++++++ - include/hw/block/block.h | 7 +++--- - include/hw/qdev-properties.h | 8 +++++++ - 3 files changed, 57 insertions(+), 3 deletions(-) + hw/core/qdev-prop-internal.h | 2 ++ + hw/core/qdev-properties-system.c | 45 +++++++++++++++++++++++++++++ + hw/core/qdev-properties.c | 4 +-- + include/hw/block/block.h | 7 +++-- + include/hw/qdev-properties-system.h | 8 +++++ + 5 files changed, 61 insertions(+), 5 deletions(-) -diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c -index 709f9e0f9d..2601091f8f 100644 ---- a/hw/core/qdev-properties.c -+++ b/hw/core/qdev-properties.c -@@ -628,6 +628,51 @@ const PropertyInfo qdev_prop_blockdev_on_error = { - .set_default_value = set_default_value_enum, +diff --git a/hw/core/qdev-prop-internal.h b/hw/core/qdev-prop-internal.h +index d7b77844fe..68b1b9d10c 100644 +--- a/hw/core/qdev-prop-internal.h ++++ b/hw/core/qdev-prop-internal.h +@@ -22,6 +22,8 @@ void qdev_propinfo_set_default_value_uint(ObjectProperty *op, + + void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp); ++void qdev_propinfo_get_int64(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp); + void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp); + +diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c +index 6a6ff03be7..b93ed9b4dd 100644 +--- a/hw/core/qdev-properties-system.c ++++ b/hw/core/qdev-properties-system.c +@@ -612,6 +612,51 @@ const PropertyInfo qdev_prop_blockdev_on_error = { + .set_default_value = qdev_propinfo_set_default_value_enum, }; +static void set_retry_time(Object *obj, Visitor *v, const char *name, @@ -26,7 +42,7 @@ index 709f9e0f9d..2601091f8f 100644 +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; -+ int64_t value, *ptr = qdev_get_prop_ptr(dev, prop); ++ int64_t value, *ptr = object_field_prop_ptr(obj, prop); + Error *local_err = NULL; + + if (dev->realized) { @@ -53,27 +69,49 @@ index 709f9e0f9d..2601091f8f 100644 +const PropertyInfo qdev_prop_blockdev_retry_interval = { + .name = "BlockdevRetryInterval", + .description = "Interval for retry error handling policy", -+ .get = get_int64, ++ .get = qdev_propinfo_get_int64, + .set = set_retry_time, -+ .set_default_value = set_default_value_int, ++ .set_default_value = qdev_propinfo_set_default_value_int, +}; + +const PropertyInfo qdev_prop_blockdev_retry_timeout = { + .name = "BlockdevRetryTimeout", + .description = "Timeout for retry error handling policy", -+ .get = get_int64, ++ .get = qdev_propinfo_get_int64, + .set = set_retry_time, -+ .set_default_value = set_default_value_int, ++ .set_default_value = qdev_propinfo_set_default_value_int, +}; + /* --- BIOS CHS translation */ QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int)); +diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c +index c34aac6ebc..2d5f662663 100644 +--- a/hw/core/qdev-properties.c ++++ b/hw/core/qdev-properties.c +@@ -396,7 +396,7 @@ static void set_uint64(Object *obj, Visitor *v, const char *name, + visit_type_uint64(v, name, ptr, errp); + } + +-static void get_int64(Object *obj, Visitor *v, const char *name, ++void qdev_propinfo_get_int64(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { + Property *prop = opaque; +@@ -423,7 +423,7 @@ const PropertyInfo qdev_prop_uint64 = { + + const PropertyInfo qdev_prop_int64 = { + .name = "int64", +- .get = get_int64, ++ .get = qdev_propinfo_get_int64, + .set = set_int64, + .set_default_value = qdev_propinfo_set_default_value_int, + }; diff --git a/include/hw/block/block.h b/include/hw/block/block.h -index d12603aabd..c5276fec0d 100644 +index 24fb7d77af..282929e8f0 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h -@@ -74,9 +74,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) +@@ -82,9 +82,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) BLOCKDEV_ON_ERROR_AUTO), \ DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \ BLOCKDEV_ON_ERROR_AUTO), \ @@ -87,12 +125,12 @@ index d12603aabd..c5276fec0d 100644 /* Backend access helpers */ -diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h -index a22a532eb8..d7742be3bc 100644 ---- a/include/hw/qdev-properties.h -+++ b/include/hw/qdev-properties.h -@@ -26,6 +26,8 @@ extern const PropertyInfo qdev_prop_on_off_auto; - extern const PropertyInfo qdev_prop_compress_method; +diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h +index 0ac327ae60..906a027676 100644 +--- a/include/hw/qdev-properties-system.h ++++ b/include/hw/qdev-properties-system.h +@@ -9,6 +9,8 @@ extern const PropertyInfo qdev_prop_reserved_region; + extern const PropertyInfo qdev_prop_multifd_compression; extern const PropertyInfo qdev_prop_losttickpolicy; extern const PropertyInfo qdev_prop_blockdev_on_error; +extern const PropertyInfo qdev_prop_blockdev_retry_interval; @@ -100,7 +138,7 @@ index a22a532eb8..d7742be3bc 100644 extern const PropertyInfo qdev_prop_bios_chs_trans; extern const PropertyInfo qdev_prop_fdc_drive_type; extern const PropertyInfo qdev_prop_drive; -@@ -215,6 +217,12 @@ extern const PropertyInfo qdev_prop_pcie_link_width; +@@ -47,6 +49,12 @@ extern const PropertyInfo qdev_prop_pcie_link_width; #define DEFINE_PROP_BLOCKDEV_ON_ERROR(_n, _s, _f, _d) \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_on_error, \ BlockdevOnError) diff --git a/block-Avoid-memleak-on-qcow2-image-info-failure.patch b/block-Avoid-memleak-on-qcow2-image-info-failure.patch deleted file mode 100644 index 13917f5b61ed267f584feac9041450e6fe9bbca6..0000000000000000000000000000000000000000 --- a/block-Avoid-memleak-on-qcow2-image-info-failure.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 6a39af8880c18fb3bcbfb715aef909c64286524e Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 20 Mar 2020 13:36:20 -0500 -Subject: [PATCH 04/14] block: Avoid memleak on qcow2 image info failure - -If we fail to get bitmap info, we must not leak the encryption info. - -Fixes: b8968c875f403 -Fixes: Coverity CID 1421894 -Signed-off-by: Eric Blake -Message-Id: <20200320183620.1112123-1-eblake@redhat.com> -Reviewed-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Andrey Shinkevich -Tested-by: Andrey Shinkevich -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - block/qcow2.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block/qcow2.c b/block/qcow2.c -index 27c54b9905aa..0f4b0940d457 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -4588,6 +4588,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, - if (local_err) { - error_propagate(errp, local_err); - qapi_free_ImageInfoSpecific(spec_info); -+ qapi_free_QCryptoBlockInfo(encrypt_info); - return NULL; - } - *spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){ --- -2.26.2 - diff --git a/block-Call-attention-to-truncation-of-long-NBD-expor.patch b/block-Call-attention-to-truncation-of-long-NBD-expor.patch deleted file mode 100644 index 91745acf1dd03b8186fd70e5a538014727c7099a..0000000000000000000000000000000000000000 --- a/block-Call-attention-to-truncation-of-long-NBD-expor.patch +++ /dev/null @@ -1,105 +0,0 @@ -From e94c1625c0f8155740b1bb7b2c749df759e04526 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 10 Jun 2020 18:32:02 -0400 -Subject: [PATCH] block: Call attention to truncation of long NBD exports - -RH-Author: Eric Blake -Message-id: <20200610183202.3780750-3-eblake@redhat.com> -Patchwork-id: 97495 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 2/2] block: Call attention to truncation of long NBD exports -Bugzilla: 1845384 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Max Reitz -RH-Acked-by: Stefan Hajnoczi - -Commit 93676c88 relaxed our NBD client code to request export names up -to the NBD protocol maximum of 4096 bytes without NUL terminator, even -though the block layer can't store anything longer than 4096 bytes -including NUL terminator for display to the user. Since this means -there are some export names where we have to truncate things, we can -at least try to make the truncation a bit more obvious for the user. -Note that in spite of the truncated display name, we can still -communicate with an NBD server using such a long export name; this was -deemed nicer than refusing to even connect to such a server (since the -server may not be under our control, and since determining our actual -length limits gets tricky when nbd://host:port/export and -nbd+unix:///export?socket=/path are themselves variable-length -expansions beyond the export name but count towards the block layer -name length). - -Reported-by: Xueqiang Wei -Fixes: https://bugzilla.redhat.com/1843684 -Signed-off-by: Eric Blake -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200610163741.3745251-3-eblake@redhat.com> -(cherry picked from commit 5c86bdf1208916ece0b87e1151c9b48ee54faa3e) -Signed-off-by: Eric Blake -Signed-off-by: Eduardo Lima (Etrunko) ---- - block.c | 7 +++++-- - block/nbd.c | 21 +++++++++++++-------- - 2 files changed, 18 insertions(+), 10 deletions(-) - -diff --git a/block.c b/block.c -index 38880eabf8..ba36b53a00 100644 ---- a/block.c -+++ b/block.c -@@ -6444,8 +6444,11 @@ void bdrv_refresh_filename(BlockDriverState *bs) - pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename); - } else { - QString *json = qobject_to_json(QOBJECT(bs->full_open_options)); -- snprintf(bs->filename, sizeof(bs->filename), "json:%s", -- qstring_get_str(json)); -+ if (snprintf(bs->filename, sizeof(bs->filename), "json:%s", -+ qstring_get_str(json)) >= sizeof(bs->filename)) { -+ /* Give user a hint if we truncated things. */ -+ strcpy(bs->filename + sizeof(bs->filename) - 4, "..."); -+ } - qobject_unref(json); - } - } -diff --git a/block/nbd.c b/block/nbd.c -index 3977b1efc7..63cdd051ab 100644 ---- a/block/nbd.c -+++ b/block/nbd.c -@@ -1714,6 +1714,7 @@ static void nbd_refresh_filename(BlockDriverState *bs) - { - BDRVNBDState *s = bs->opaque; - const char *host = NULL, *port = NULL, *path = NULL; -+ size_t len = 0; - - if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) { - const InetSocketAddress *inet = &s->saddr->u.inet; -@@ -1726,17 +1727,21 @@ static void nbd_refresh_filename(BlockDriverState *bs) - } /* else can't represent as pseudo-filename */ - - if (path && s->export) { -- snprintf(bs->exact_filename, sizeof(bs->exact_filename), -- "nbd+unix:///%s?socket=%s", s->export, path); -+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), -+ "nbd+unix:///%s?socket=%s", s->export, path); - } else if (path && !s->export) { -- snprintf(bs->exact_filename, sizeof(bs->exact_filename), -- "nbd+unix://?socket=%s", path); -+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), -+ "nbd+unix://?socket=%s", path); - } else if (host && s->export) { -- snprintf(bs->exact_filename, sizeof(bs->exact_filename), -- "nbd://%s:%s/%s", host, port, s->export); -+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), -+ "nbd://%s:%s/%s", host, port, s->export); - } else if (host && !s->export) { -- snprintf(bs->exact_filename, sizeof(bs->exact_filename), -- "nbd://%s:%s", host, port); -+ len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), -+ "nbd://%s:%s", host, port); -+ } -+ if (len > sizeof(bs->exact_filename)) { -+ /* Name is too long to represent exactly, so leave it empty. */ -+ bs->exact_filename[0] = '\0'; - } - } - --- -2.27.0 - diff --git a/block-Fix-cross-AioContext-blockdev-snapshot.patch b/block-Fix-cross-AioContext-blockdev-snapshot.patch deleted file mode 100644 index a4a4d9dbb4c51b74a8258b6368bd9a9ca88b71c6..0000000000000000000000000000000000000000 --- a/block-Fix-cross-AioContext-blockdev-snapshot.patch +++ /dev/null @@ -1,78 +0,0 @@ -From ec96b9f64c239736003413d70dc3999ad0b8271c Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 10 Mar 2020 12:38:29 +0100 -Subject: [PATCH] block: Fix cross-AioContext blockdev-snapshot - -external_snapshot_prepare() tries to move the overlay to the AioContext -of the backing file (the snapshotted node). However, it's possible that -this doesn't work, but the backing file can instead be moved to the -overlay's AioContext (e.g. opening the backing chain for a mirror -target). - -bdrv_append() already indirectly uses bdrv_attach_node(), which takes -care to move nodes to make sure they use the same AioContext and which -tries both directions. - -So the problem has a simple fix: Just delete the unnecessary extra -bdrv_try_set_aio_context() call in external_snapshot_prepare() and -instead assert in bdrv_append() that both nodes were indeed moved to the -same AioContext. - -Signed-off-by: Kevin Wolf -Message-Id: <20200310113831.27293-6-kwolf@redhat.com> -Tested-by: Peter Krempa -Signed-off-by: Kevin Wolf ---- - block.c | 1 + - blockdev.c | 16 ---------------- - 2 files changed, 1 insertion(+), 16 deletions(-) - -diff --git a/block.c b/block.c -index ba36b53a00..824025f781 100644 ---- a/block.c -+++ b/block.c -@@ -4165,6 +4165,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, - bdrv_ref(from); - - assert(qemu_get_current_aio_context() == qemu_get_aio_context()); -+ assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to)); - bdrv_drained_begin(from); - - /* Put all parents into @list and calculate their cumulative permissions */ -diff --git a/blockdev.c b/blockdev.c -index 79112be2e6..d1a3b6a630 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1578,8 +1578,6 @@ static void external_snapshot_prepare(BlkActionState *common, - DO_UPCAST(ExternalSnapshotState, common, common); - TransactionAction *action = common->action; - AioContext *aio_context; -- AioContext *old_context; -- int ret; - - /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar - * purpose but a different set of parameters */ -@@ -1719,20 +1717,6 @@ static void external_snapshot_prepare(BlkActionState *common, - goto out; - } - -- /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ -- old_context = bdrv_get_aio_context(state->new_bs); -- aio_context_release(aio_context); -- aio_context_acquire(old_context); -- -- ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp); -- -- aio_context_release(old_context); -- aio_context_acquire(aio_context); -- -- if (ret < 0) { -- goto out; -- } -- - /* This removes our old bs and adds the new bs. This is an operation that - * can fail, so we need to do it in .prepare; undoing it for abort is - * always possible. */ --- -2.27.0 - diff --git a/block-Fix-misleading-hexadecimal-format.patch b/block-Fix-misleading-hexadecimal-format.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fa36720c955991662dc1aa34ecaf5dec27f81df --- /dev/null +++ b/block-Fix-misleading-hexadecimal-format.patch @@ -0,0 +1,46 @@ +From 23ba08631691242000e60f85a9d0a67a42dcca3b Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 4 Aug 2023 08:26:16 +0000 +Subject: [PATCH] block: Fix misleading hexadecimal format mainline inclusion + commit 3f1db95917bf0b4accaf8f56d43f795fed1fb733 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +"0x%u" format is very misleading, replace by "0x%x". + +Found running: + + $ git grep -E '0x%[0-9]*([lL]*|" ?PRI)[dDuU]' block/ + +Inspired-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Hanna Reitz +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Denis V. Lunev +Message-id: 20220323114718.58714-2-philippe.mathieu.daude@gmail.com +Signed-off-by: Stefan Hajnoczi + +Signed-off-by: tangbinzy +--- + block/parallels-ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/parallels-ext.c b/block/parallels-ext.c +index e0dd0975c6..b0e1c1aa47 100644 +--- a/block/parallels-ext.c ++++ b/block/parallels-ext.c +@@ -260,7 +260,7 @@ static int parallels_parse_format_extension(BlockDriverState *bs, + break; + + default: +- error_setg(errp, "Unknown feature: 0x%" PRIu64, fh.magic); ++ error_setg(errp, "Unknown feature: 0x%" PRIx64, fh.magic); + goto fail; + } + +-- +2.41.0.windows.1 + diff --git a/block-Make-wait-mark-serialising-requests-public.patch b/block-Make-wait-mark-serialising-requests-public.patch deleted file mode 100644 index 162463c7769093014562846d9d7c0da4e131b5e3..0000000000000000000000000000000000000000 --- a/block-Make-wait-mark-serialising-requests-public.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 590cff8230749794ba09b38f3ea4eb6b0f2f73b5 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Fri, 1 Nov 2019 16:25:08 +0100 -Subject: [PATCH] block: Make wait/mark serialising requests public - -Make both bdrv_mark_request_serialising() and -bdrv_wait_serialising_requests() public so they can be used from block -drivers. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Message-id: 20191101152510.11719-2-mreitz@redhat.com -Signed-off-by: Max Reitz -(cherry picked from commit 304d9d7f034ff7f5e1e66a65b7f720f63a72c57e) - Conflicts: - block/io.c -*drop context dependency on 1acc3466a2 -Signed-off-by: Michael Roth ---- - block/io.c | 24 ++++++++++++------------ - include/block/block_int.h | 3 +++ - 2 files changed, 15 insertions(+), 12 deletions(-) - -diff --git a/block/io.c b/block/io.c -index 07d2d825c3..d4ceaaa2ce 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -694,7 +694,7 @@ static void tracked_request_begin(BdrvTrackedRequest *req, - qemu_co_mutex_unlock(&bs->reqs_lock); - } - --static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) -+void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) - { - int64_t overlap_offset = req->offset & ~(align - 1); - uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align) -@@ -784,7 +784,7 @@ void bdrv_dec_in_flight(BlockDriverState *bs) - bdrv_wakeup(bs); - } - --static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self) -+bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self) - { - BlockDriverState *bs = self->bs; - BdrvTrackedRequest *req; -@@ -1340,14 +1340,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, - * with each other for the same cluster. For example, in copy-on-read - * it ensures that the CoR read and write operations are atomic and - * guest writes cannot interleave between them. */ -- mark_request_serialising(req, bdrv_get_cluster_size(bs)); -+ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); - } - - /* BDRV_REQ_SERIALISING is only for write operation */ - assert(!(flags & BDRV_REQ_SERIALISING)); - - if (!(flags & BDRV_REQ_NO_SERIALISING)) { -- wait_serialising_requests(req); -+ bdrv_wait_serialising_requests(req); - } - - if (flags & BDRV_REQ_COPY_ON_READ) { -@@ -1736,10 +1736,10 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes, - assert(!(flags & ~BDRV_REQ_MASK)); - - if (flags & BDRV_REQ_SERIALISING) { -- mark_request_serialising(req, bdrv_get_cluster_size(bs)); -+ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); - } - -- waited = wait_serialising_requests(req); -+ waited = bdrv_wait_serialising_requests(req); - - assert(!waited || !req->serialising || - is_request_serialising_and_aligned(req)); -@@ -1905,8 +1905,8 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, - - padding = bdrv_init_padding(bs, offset, bytes, &pad); - if (padding) { -- mark_request_serialising(req, align); -- wait_serialising_requests(req); -+ bdrv_mark_request_serialising(req, align); -+ bdrv_wait_serialising_requests(req); - - bdrv_padding_rmw_read(child, req, &pad, true); - -@@ -1993,8 +1993,8 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, - } - - if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) { -- mark_request_serialising(&req, align); -- wait_serialising_requests(&req); -+ bdrv_mark_request_serialising(&req, align); -+ bdrv_wait_serialising_requests(&req); - bdrv_padding_rmw_read(child, &req, &pad, false); - } - -@@ -3078,7 +3078,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( - /* BDRV_REQ_SERIALISING is only for write operation */ - assert(!(read_flags & BDRV_REQ_SERIALISING)); - if (!(read_flags & BDRV_REQ_NO_SERIALISING)) { -- wait_serialising_requests(&req); -+ bdrv_wait_serialising_requests(&req); - } - - ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, -@@ -3205,7 +3205,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, - * new area, we need to make sure that no write requests are made to it - * concurrently or they might be overwritten by preallocation. */ - if (new_bytes) { -- mark_request_serialising(&req, 1); -+ bdrv_mark_request_serialising(&req, 1); - } - if (bs->read_only) { - error_setg(errp, "Image is read-only"); -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 3aa1e832a8..4465b02242 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -962,6 +962,9 @@ extern unsigned int bdrv_drain_all_count; - void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); - void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); - -+bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self); -+void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align); -+ - int get_tmp_filename(char *filename, int size); - BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, - const char *filename); --- -2.23.0 diff --git a/block-Remove-unused-include.patch b/block-Remove-unused-include.patch deleted file mode 100644 index f643ebc66f0f631e949412b706c3210e9d3aead1..0000000000000000000000000000000000000000 --- a/block-Remove-unused-include.patch +++ /dev/null @@ -1,31 +0,0 @@ -From b353d059bddf4b211c2560e7c123f874ed5c8cf6 Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Wed, 21 Oct 2020 17:12:52 +0800 -Subject: [PATCH] block: Remove unused include - -The "qemu-common.h" include is not used, remove it. - -Reported-by: Euler Robot -Signed-off-by: AlexChen -Message-Id: <5F8FFB94.3030209@huawei.com> -Signed-off-by: Max Reitz -(cherry-picked from commit 3d86af858e) ---- - block/dmg-lzfse.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/block/dmg-lzfse.c b/block/dmg-lzfse.c -index 19d25bc646..6798cf4fbf 100644 ---- a/block/dmg-lzfse.c -+++ b/block/dmg-lzfse.c -@@ -22,7 +22,6 @@ - * THE SOFTWARE. - */ - #include "qemu/osdep.h" --#include "qemu-common.h" - #include "dmg.h" - #include - --- -2.27.0 - diff --git a/block-backend-Add-device-specific-retry-callback.patch b/block-backend-Add-device-specific-retry-callback.patch index d50d6bc99cdd87e74838b3b2b61a2eabd1df3ed1..04465292d66e8652846ffb8683a6c19c1a2ba701 100644 --- a/block-backend-Add-device-specific-retry-callback.patch +++ b/block-backend-Add-device-specific-retry-callback.patch @@ -1,7 +1,7 @@ -From f74edc7c8c85874691daf8801c159874ef45aae0 Mon Sep 17 00:00:00 2001 +From dfda8c57de71f2f10b57cf21b1e36f18d4ed37a3 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:47 +0800 -Subject: [PATCH] block-backend: Add device specific retry callback +Subject: [PATCH 3/7] block-backend: Add device specific retry callback Add retry_request_cb in BlockDevOps to do device specific retry action. Backend's timer would be registered only when the backend is set 'retry' @@ -9,16 +9,17 @@ on errors and the device supports retry action. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 8 ++++++++ include/sysemu/block-backend.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c -index a9a43b1440..b8f535a5fd 100644 +index 257cd775c0..24003adf0b 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -958,6 +958,14 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, +@@ -1018,6 +1018,14 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, blk->dev_ops = ops; blk->dev_opaque = opaque; @@ -34,13 +35,13 @@ index a9a43b1440..b8f535a5fd 100644 if (blk->quiesce_counter && ops->drained_begin) { ops->drained_begin(opaque); diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h -index 733c4957eb..b58dc6bde8 100644 +index e5e1524f06..a7a13d47de 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h -@@ -66,6 +66,10 @@ typedef struct BlockDevOps { - * Runs when the backend's last drain request ends. +@@ -70,6 +70,10 @@ typedef struct BlockDevOps { + * Is the device still busy? */ - void (*drained_end)(void *opaque); + bool (*drained_poll)(void *opaque); + /* + * Runs when retrying failed requests. + */ diff --git a/block-backend-Add-timeout-support-for-retry.patch b/block-backend-Add-timeout-support-for-retry.patch index ac1bc66230f533b542e0f0a31d0035f868f3c06b..a3b79e2e9aaea6752caec1f652acd9957a0574bd 100644 --- a/block-backend-Add-timeout-support-for-retry.patch +++ b/block-backend-Add-timeout-support-for-retry.patch @@ -1,7 +1,7 @@ -From c58269c64af18bc2a22bbef8b92e489214272429 Mon Sep 17 00:00:00 2001 +From 953590f4854d75e6051237f668c9fb393235f471 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:49 +0800 -Subject: [PATCH] block-backend: Add timeout support for retry +Subject: [PATCH 5/7] block-backend: Add timeout support for retry Retry should only be triggered when timeout is not reached, so let's check timeout before retry. Device should also reset retry_start_time after @@ -9,16 +9,17 @@ successful retry. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 25 ++++++++++++++++++++++++- include/sysemu/block-backend.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/block/block-backend.c b/block/block-backend.c -index 11f8ff4301..0fe99ffe52 100644 +index 5a016d32fa..37e21c473e 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -1633,6 +1633,29 @@ void blk_drain_all(void) +@@ -1766,6 +1766,29 @@ void blk_drain_all(void) bdrv_drain_all_end(); } @@ -48,7 +49,7 @@ index 11f8ff4301..0fe99ffe52 100644 void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, BlockdevOnError on_write_error) { -@@ -1661,7 +1684,7 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, +@@ -1794,7 +1817,7 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, case BLOCKDEV_ON_ERROR_IGNORE: return BLOCK_ERROR_ACTION_IGNORE; case BLOCKDEV_ON_ERROR_RETRY: @@ -58,10 +59,10 @@ index 11f8ff4301..0fe99ffe52 100644 case BLOCKDEV_ON_ERROR_AUTO: default: diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h -index b58dc6bde8..58dde446ca 100644 +index a7a13d47de..56a403883d 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h -@@ -184,6 +184,7 @@ void blk_inc_in_flight(BlockBackend *blk); +@@ -198,6 +198,7 @@ void blk_inc_in_flight(BlockBackend *blk); void blk_dec_in_flight(BlockBackend *blk); void blk_drain(BlockBackend *blk); void blk_drain_all(void); diff --git a/block-backend-Enable-retry-action-on-errors.patch b/block-backend-Enable-retry-action-on-errors.patch index 241f945cff9edae0f464177226b2b3ef33d98ca0..ee56c455009a3946459efa1313b43452efcd3262 100644 --- a/block-backend-Enable-retry-action-on-errors.patch +++ b/block-backend-Enable-retry-action-on-errors.patch @@ -1,22 +1,23 @@ -From 8df36cddd1e5e2b3c3598c83a70e8cbb81c26cec Mon Sep 17 00:00:00 2001 +From 2e1c75e5a0339d2bf417e5a4437d8e627a303286 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:48 +0800 -Subject: [PATCH] block-backend: Enable retry action on errors +Subject: [PATCH 4/7] block-backend: Enable retry action on errors Enable retry action when backend's retry timer is available. It would trigger the timer to do device specific retry action. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c -index b8f535a5fd..11f8ff4301 100644 +index 24003adf0b..5a016d32fa 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -1660,6 +1660,9 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, +@@ -1793,6 +1793,9 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, return BLOCK_ERROR_ACTION_REPORT; case BLOCKDEV_ON_ERROR_IGNORE: return BLOCK_ERROR_ACTION_IGNORE; @@ -26,7 +27,7 @@ index b8f535a5fd..11f8ff4301 100644 case BLOCKDEV_ON_ERROR_AUTO: default: abort(); -@@ -1707,6 +1710,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, +@@ -1840,6 +1843,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, qemu_system_vmstop_request_prepare(); send_qmp_error_event(blk, action, is_read, error); qemu_system_vmstop_request(RUN_STATE_IO_ERROR); diff --git a/block-backend-Introduce-retry-timer.patch b/block-backend-Introduce-retry-timer.patch index e45aacc149860baf2951e34a5b964cae7cc9aea3..5a0bc334c48ee597ca35b3da2771c258e9ee26e8 100644 --- a/block-backend-Introduce-retry-timer.patch +++ b/block-backend-Introduce-retry-timer.patch @@ -1,21 +1,22 @@ -From 805c2e121e1ad612f63bafec458284554e76d034 Mon Sep 17 00:00:00 2001 +From 4dc180e87fb641f64fce7be3a0807488d0cc0a51 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:46 +0800 -Subject: [PATCH] block-backend: Introduce retry timer +Subject: [PATCH 2/7] block-backend: Introduce retry timer Add a timer to regularly trigger retry on errors. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c -index 0056b526b8..a9a43b1440 100644 +index 12ef80ea17..257cd775c0 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -31,6 +31,9 @@ +@@ -35,6 +35,9 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); @@ -25,7 +26,7 @@ index 0056b526b8..a9a43b1440 100644 typedef struct BlockBackendAioNotifier { void (*attached_aio_context)(AioContext *new_context, void *opaque); void (*detach_aio_context)(void *opaque); -@@ -88,6 +91,15 @@ struct BlockBackend { +@@ -95,6 +98,15 @@ struct BlockBackend { * Accessed with atomic ops. */ unsigned int in_flight; @@ -41,7 +42,7 @@ index 0056b526b8..a9a43b1440 100644 }; typedef struct BlockBackendAIOCB { -@@ -337,6 +349,11 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) +@@ -353,6 +365,11 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) blk->on_read_error = BLOCKDEV_ON_ERROR_REPORT; blk->on_write_error = BLOCKDEV_ON_ERROR_ENOSPC; @@ -52,8 +53,8 @@ index 0056b526b8..a9a43b1440 100644 + block_acct_init(&blk->stats); - notifier_list_init(&blk->remove_bs_notifiers); -@@ -423,6 +440,10 @@ static void blk_delete(BlockBackend *blk) + qemu_co_queue_init(&blk->queued_requests); +@@ -471,6 +488,10 @@ static void blk_delete(BlockBackend *blk) QTAILQ_REMOVE(&block_backends, blk, link); drive_info_del(blk->legacy_dinfo); block_acct_cleanup(&blk->stats); diff --git a/block-backend-Stop-retrying-when-draining.patch b/block-backend-Stop-retrying-when-draining.patch index 13f3ad64d1c2d2db02d830ca67ee3f90e893e46a..baf5c6c35333786da98e82334cf8b84eb59eaa38 100644 --- a/block-backend-Stop-retrying-when-draining.patch +++ b/block-backend-Stop-retrying-when-draining.patch @@ -1,7 +1,7 @@ -From da64af4b1e92c345296d937e66136f86027d1ca2 Mon Sep 17 00:00:00 2001 +From 06db37983cfd20d7e92001ac3cb06867a281f1c9 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 25 Feb 2021 18:03:57 +0800 -Subject: [PATCH] block-backend: Stop retrying when draining +Subject: [PATCH 8/9] block-backend: Stop retrying when draining Retrying failed requests when draining would make the draining hung. So it is better not to trigger the retry timer when draining. And after the @@ -9,15 +9,16 @@ virtual devices go back to work, they would retry those queued requests. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- block/block-backend.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c -index 2d812e2254..f6c918f1d9 100644 +index d3d90a95a5..49d236b2a4 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -1741,9 +1741,11 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, +@@ -1874,9 +1874,11 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, send_qmp_error_event(blk, action, is_read, error); qemu_system_vmstop_request(RUN_STATE_IO_ERROR); } else if (action == BLOCK_ERROR_ACTION_RETRY) { diff --git a/block-backend-prevent-dangling-BDS-pointers-across-a.patch b/block-backend-prevent-dangling-BDS-pointers-across-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..9ffabfd42982e99e1d105a42ec425085c371b322 --- /dev/null +++ b/block-backend-prevent-dangling-BDS-pointers-across-a.patch @@ -0,0 +1,124 @@ +From 6363172843fd756c61d6a3725ad5b3a385eddc87 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Mar 2023 03:02:58 +0000 +Subject: [PATCH] block-backend: prevent dangling BDS pointers across + aio_poll() mainline inclusion commit 1e3552dbd28359d35967b7c28dc86cde1bc29205 + category: bugfix + +--------------------------------------------------------------- + +The BlockBackend root child can change when aio_poll() is invoked. This +happens when a temporary filter node is removed upon blockjob +completion, for example. + +Functions in block/block-backend.c must be aware of this when using a +blk_bs() pointer across aio_poll() because the BlockDriverState refcnt +may reach 0, resulting in a stale pointer. + +One example is scsi_device_purge_requests(), which calls blk_drain() to +wait for in-flight requests to cancel. If the backup blockjob is active, +then the BlockBackend root child is a temporary filter BDS owned by the +blockjob. The blockjob can complete during bdrv_drained_begin() and the +last reference to the BDS is released when the temporary filter node is +removed. This results in a use-after-free when blk_drain() calls +bdrv_drained_end(bs) on the dangling pointer. + +Explicitly hold a reference to bs across block APIs that invoke +aio_poll(). + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2021778 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178 +Signed-off-by: Stefan Hajnoczi +Message-Id: <20220111153613.25453-2-stefanha@redhat.com> +Signed-off-by: Kevin Wolf + +Signed-off-by: tangbinzy +--- + block/block-backend.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 49d236b2a4..3a757fb746 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -840,16 +840,22 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) + void blk_remove_bs(BlockBackend *blk) + { + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; +- BlockDriverState *bs; + BdrvChild *root; + + notifier_list_notify(&blk->remove_bs_notifiers, blk); + if (tgm->throttle_state) { +- bs = blk_bs(blk); ++ BlockDriverState *bs = blk_bs(blk); ++ ++ /* ++ * Take a ref in case blk_bs() changes across bdrv_drained_begin(), for ++ * example, if a temporary filter node is removed by a blockjob. ++ */ ++ bdrv_ref(bs); + bdrv_drained_begin(bs); + throttle_group_detach_aio_context(tgm); + throttle_group_attach_aio_context(tgm, qemu_get_aio_context()); + bdrv_drained_end(bs); ++ bdrv_unref(bs); + } + + blk_update_root_state(blk); +@@ -1731,6 +1737,7 @@ void blk_drain(BlockBackend *blk) + BlockDriverState *bs = blk_bs(blk); + + if (bs) { ++ bdrv_ref(bs); + bdrv_drained_begin(bs); + } + +@@ -1740,6 +1747,7 @@ void blk_drain(BlockBackend *blk) + + if (bs) { + bdrv_drained_end(bs); ++ bdrv_unref(bs); + } + } + +@@ -2112,10 +2120,13 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, + int ret; + + if (bs) { ++ bdrv_ref(bs); ++ + if (update_root_node) { + ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root, + errp); + if (ret < 0) { ++ bdrv_unref(bs); + return ret; + } + } +@@ -2125,6 +2136,8 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, + throttle_group_attach_aio_context(tgm, new_context); + bdrv_drained_end(bs); + } ++ ++ bdrv_unref(bs); + } + + blk->ctx = new_context; +@@ -2394,11 +2407,13 @@ void blk_io_limits_disable(BlockBackend *blk) + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; + assert(tgm->throttle_state); + if (bs) { ++ bdrv_ref(bs); + bdrv_drained_begin(bs); + } + throttle_group_unregister_tgm(tgm); + if (bs) { + bdrv_drained_end(bs); ++ bdrv_unref(bs); + } + } + +-- +2.27.0 + diff --git a/block-backup-Add-mirror-sync-mode-bitmap.patch b/block-backup-Add-mirror-sync-mode-bitmap.patch deleted file mode 100644 index fb111206baa228ef558d0a567f7d88421a66ad84..0000000000000000000000000000000000000000 --- a/block-backup-Add-mirror-sync-mode-bitmap.patch +++ /dev/null @@ -1,252 +0,0 @@ -From e0a0150e671e8129f11aa3df907e444e91711f53 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:52 -0400 -Subject: [PATCH] block/backup: Add mirror sync mode 'bitmap' - -We don't need or want a new sync mode for simple differences in -semantics. Create a new mode simply named "BITMAP" that is designed to -make use of the new Bitmap Sync Mode field. - -Because the only bitmap sync mode is 'on-success', this adds no new -functionality to the backup job (yet). The old incremental backup mode -is maintained as a syntactic sugar for sync=bitmap, mode=on-success. - -Add all of the plumbing necessary to support this new instruction. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190709232550.10724-6-jsnow@redhat.com -Signed-off-by: John Snow ---- - block/backup.c | 20 ++++++++++++-------- - block/mirror.c | 6 ++++-- - block/replication.c | 2 +- - blockdev.c | 25 +++++++++++++++++++++++-- - include/block/block_int.h | 4 +++- - qapi/block-core.json | 21 +++++++++++++++------ - 6 files changed, 58 insertions(+), 20 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index 88354dcb32..e37eda80cd 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -38,9 +38,9 @@ typedef struct CowRequest { - typedef struct BackupBlockJob { - BlockJob common; - BlockBackend *target; -- /* bitmap for sync=incremental */ - BdrvDirtyBitmap *sync_bitmap; - MirrorSyncMode sync_mode; -+ BitmapSyncMode bitmap_mode; - BlockdevOnError on_source_error; - BlockdevOnError on_target_error; - CoRwlock flush_rwlock; -@@ -461,7 +461,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp) - - job_progress_set_remaining(job, s->len); - -- if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { -+ if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { - backup_incremental_init_copy_bitmap(s); - } else { - hbitmap_set(s->copy_bitmap, 0, s->len); -@@ -545,6 +545,7 @@ static int64_t backup_calculate_cluster_size(BlockDriverState *target, - BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockDriverState *target, int64_t speed, - MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, -+ BitmapSyncMode bitmap_mode, - bool compress, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, -@@ -592,10 +593,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - return NULL; - } - -- if (sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { -+ /* QMP interface should have handled translating this to bitmap mode */ -+ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); -+ -+ if (sync_mode == MIRROR_SYNC_MODE_BITMAP) { - if (!sync_bitmap) { - error_setg(errp, "must provide a valid bitmap name for " -- "\"incremental\" sync mode"); -+ "'%s' sync mode", MirrorSyncMode_str(sync_mode)); - return NULL; - } - -@@ -605,8 +609,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - } - } else if (sync_bitmap) { - error_setg(errp, -- "a sync_bitmap was provided to backup_run, " -- "but received an incompatible sync_mode (%s)", -+ "a bitmap was given to backup_job_create, " -+ "but it received an incompatible sync_mode (%s)", - MirrorSyncMode_str(sync_mode)); - return NULL; - } -@@ -648,8 +652,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - job->on_source_error = on_source_error; - job->on_target_error = on_target_error; - job->sync_mode = sync_mode; -- job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ? -- sync_bitmap : NULL; -+ job->sync_bitmap = sync_bitmap; -+ job->bitmap_mode = bitmap_mode; - job->compress = compress; - - /* Detect image-fleecing (and similar) schemes */ -diff --git a/block/mirror.c b/block/mirror.c -index abcf60a961..ccae49a28e 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -1770,8 +1770,10 @@ void mirror_start(const char *job_id, BlockDriverState *bs, - bool is_none_mode; - BlockDriverState *base; - -- if (mode == MIRROR_SYNC_MODE_INCREMENTAL) { -- error_setg(errp, "Sync mode 'incremental' not supported"); -+ if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) || -+ (mode == MIRROR_SYNC_MODE_BITMAP)) { -+ error_setg(errp, "Sync mode '%s' not supported", -+ MirrorSyncMode_str(mode)); - return; - } - is_none_mode = mode == MIRROR_SYNC_MODE_NONE; -diff --git a/block/replication.c b/block/replication.c -index 23b2993d74..936b2f8b5a 100644 ---- a/block/replication.c -+++ b/block/replication.c -@@ -543,7 +543,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, - - s->backup_job = backup_job_create( - NULL, s->secondary_disk->bs, s->hidden_disk->bs, -- 0, MIRROR_SYNC_MODE_NONE, NULL, false, -+ 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, - BLOCKDEV_ON_ERROR_REPORT, - BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, - backup_job_completed, bs, NULL, &local_err); -diff --git a/blockdev.c b/blockdev.c -index aa15ed1f00..34c8b651e1 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3508,12 +3508,31 @@ static BlockJob *do_backup_common(BackupCommon *backup, - return NULL; - } - -+ if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) { -+ if (backup->has_bitmap_mode && -+ backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) { -+ error_setg(errp, "Bitmap sync mode must be '%s' " -+ "when using sync mode '%s'", -+ BitmapSyncMode_str(BITMAP_SYNC_MODE_ON_SUCCESS), -+ MirrorSyncMode_str(backup->sync)); -+ return NULL; -+ } -+ backup->has_bitmap_mode = true; -+ backup->sync = MIRROR_SYNC_MODE_BITMAP; -+ backup->bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS; -+ } -+ - if (backup->has_bitmap) { - bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); - if (!bmap) { - error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); - return NULL; - } -+ if (!backup->has_bitmap_mode) { -+ error_setg(errp, "Bitmap sync mode must be given " -+ "when providing a bitmap"); -+ return NULL; -+ } - if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { - return NULL; - } -@@ -3527,8 +3546,10 @@ static BlockJob *do_backup_common(BackupCommon *backup, - } - - job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, -- backup->sync, bmap, backup->compress, -- backup->on_source_error, backup->on_target_error, -+ backup->sync, bmap, backup->bitmap_mode, -+ backup->compress, -+ backup->on_source_error, -+ backup->on_target_error, - job_flags, NULL, NULL, txn, errp); - return job; - } -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 05ee6b4866..76117a761a 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -1152,7 +1152,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs, - * @target: Block device to write to. - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @sync_mode: What parts of the disk image should be copied to the destination. -- * @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_INCREMENTAL. -+ * @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental' -+ * @bitmap_mode: The bitmap synchronization policy to use. - * @on_source_error: The action to take upon error reading from the source. - * @on_target_error: The action to take upon error writing to the target. - * @creation_flags: Flags that control the behavior of the Job lifetime. -@@ -1168,6 +1169,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockDriverState *target, int64_t speed, - MirrorSyncMode sync_mode, - BdrvDirtyBitmap *sync_bitmap, -+ BitmapSyncMode bitmap_mode, - bool compress, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, -diff --git a/qapi/block-core.json b/qapi/block-core.json -index b8d12a4951..97baff3a8c 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -1127,12 +1127,15 @@ - # - # @none: only copy data written from now on - # --# @incremental: only copy data described by the dirty bitmap. Since: 2.4 -+# @incremental: only copy data described by the dirty bitmap. (since: 2.4) -+# -+# @bitmap: only copy data described by the dirty bitmap. (since: 4.2) -+# Behavior on completion is determined by the BitmapSyncMode. - # - # Since: 1.3 - ## - { 'enum': 'MirrorSyncMode', -- 'data': ['top', 'full', 'none', 'incremental'] } -+ 'data': ['top', 'full', 'none', 'incremental', 'bitmap'] } - - ## - # @BitmapSyncMode: -@@ -1343,9 +1346,14 @@ - # @speed: the maximum speed, in bytes per second. The default is 0, - # for unlimited. - # --# @bitmap: the name of dirty bitmap if sync is "incremental". --# Must be present if sync is "incremental", must NOT be present --# otherwise. (Since 2.4 (drive-backup), 3.1 (blockdev-backup)) -+# @bitmap: the name of a dirty bitmap if sync is "bitmap" or "incremental". -+# Must be present if sync is "bitmap" or "incremental". -+# Must not be present otherwise. -+# (Since 2.4 (drive-backup), 3.1 (blockdev-backup)) -+# -+# @bitmap-mode: Specifies the type of data the bitmap should contain after -+# the operation concludes. Must be present if sync is "bitmap". -+# Must NOT be present otherwise. (Since 4.2) - # - # @compress: true to compress data, if the target format supports it. - # (default: false) (since 2.8) -@@ -1380,7 +1388,8 @@ - { 'struct': 'BackupCommon', - 'data': { '*job-id': 'str', 'device': 'str', - 'sync': 'MirrorSyncMode', '*speed': 'int', -- '*bitmap': 'str', '*compress': 'bool', -+ '*bitmap': 'str', '*bitmap-mode': 'BitmapSyncMode', -+ '*compress': 'bool', - '*on-source-error': 'BlockdevOnError', - '*on-target-error': 'BlockdevOnError', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } --- -2.27.0 - diff --git a/block-backup-add-never-policy-to-bitmap-sync-mode.patch b/block-backup-add-never-policy-to-bitmap-sync-mode.patch deleted file mode 100644 index e7a3dc356084623f89f89f9421467233e82b7dbb..0000000000000000000000000000000000000000 --- a/block-backup-add-never-policy-to-bitmap-sync-mode.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 98ed0f915cf3335768ed84ee5dfa54f4e99aaf00 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:53 -0400 -Subject: [PATCH] block/backup: add 'never' policy to bitmap sync mode - -This adds a "never" policy for bitmap synchronization. Regardless of if -the job succeeds or fails, we never update the bitmap. This can be used -to perform differential backups, or simply to avoid the job modifying a -bitmap. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190709232550.10724-7-jsnow@redhat.com -Signed-off-by: John Snow ---- - block/backup.c | 7 +++++-- - qapi/block-core.json | 5 ++++- - 2 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index e37eda80cd..84a56337ac 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -274,8 +274,11 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) - BdrvDirtyBitmap *bm; - BlockDriverState *bs = blk_bs(job->common.blk); - -- if (ret < 0) { -- /* Merge the successor back into the parent, delete nothing. */ -+ if (ret < 0 || job->bitmap_mode == BITMAP_SYNC_MODE_NEVER) { -+ /* -+ * Failure, or we don't want to synchronize the bitmap. -+ * Merge the successor back into the parent, delete nothing. -+ */ - bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL); - assert(bm); - } else { -diff --git a/qapi/block-core.json b/qapi/block-core.json -index 97baff3a8c..48a0bfab63 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -1146,10 +1146,13 @@ - # @on-success: The bitmap is only synced when the operation is successful. - # This is the behavior always used for 'INCREMENTAL' backups. - # -+# @never: The bitmap is never synchronized with the operation, and is -+# treated solely as a read-only manifest of blocks to copy. -+# - # Since: 4.2 - ## - { 'enum': 'BitmapSyncMode', -- 'data': ['on-success'] } -+ 'data': ['on-success', 'never'] } - - ## - # @MirrorCopyMode: --- -2.27.0 - diff --git a/block-backup-deal-with-zero-detection.patch b/block-backup-deal-with-zero-detection.patch deleted file mode 100644 index 9f111e58efff5bb63808d91441f4028bb743fce9..0000000000000000000000000000000000000000 --- a/block-backup-deal-with-zero-detection.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 3cf14b9a7daf0a40eb2af7a86e67cb05f6d2bea6 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 30 Jul 2019 19:32:49 +0300 -Subject: [PATCH] block/backup: deal with zero detection - -We have detect_zeroes option, so at least for blockdev-backup user -should define it if zero-detection is needed. For drive-backup leave -detection enabled by default but do it through existing option instead -of open-coding. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190730163251.755248-2-vsementsov@virtuozzo.com -Signed-off-by: John Snow ---- - block/backup.c | 15 ++++++--------- - blockdev.c | 8 ++++---- - 2 files changed, 10 insertions(+), 13 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index cc19643b47..6023573299 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -110,7 +110,10 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, - BlockBackend *blk = job->common.blk; - int nbytes; - int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0; -- int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0; -+ int write_flags = -+ (job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0) | -+ (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); -+ - - assert(QEMU_IS_ALIGNED(start, job->cluster_size)); - hbitmap_reset(job->copy_bitmap, start, job->cluster_size); -@@ -128,14 +131,8 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, - goto fail; - } - -- if (buffer_is_zero(*bounce_buffer, nbytes)) { -- ret = blk_co_pwrite_zeroes(job->target, start, -- nbytes, write_flags | BDRV_REQ_MAY_UNMAP); -- } else { -- ret = blk_co_pwrite(job->target, start, -- nbytes, *bounce_buffer, write_flags | -- (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0)); -- } -+ ret = blk_co_pwrite(job->target, start, nbytes, *bounce_buffer, -+ write_flags); - if (ret < 0) { - trace_backup_do_cow_write_fail(job, start, ret); - if (error_is_read) { -diff --git a/blockdev.c b/blockdev.c -index 0a71a15fa2..94e5aee30b 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3572,7 +3572,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - BlockDriverState *source = NULL; - BlockJob *job = NULL; - AioContext *aio_context; -- QDict *options = NULL; -+ QDict *options; - Error *local_err = NULL; - int flags; - int64_t size; -@@ -3645,10 +3645,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - goto out; - } - -+ options = qdict_new(); -+ qdict_put_str(options, "discard", "unmap"); -+ qdict_put_str(options, "detect-zeroes", "unmap"); - if (backup->format) { -- if (!options) { -- options = qdict_new(); -- } - qdict_put_str(options, "driver", backup->format); - } - --- -2.27.0 - diff --git a/block-backup-fix-backup_cow_with_offload-for-last-cl.patch b/block-backup-fix-backup_cow_with_offload-for-last-cl.patch deleted file mode 100644 index 1dfccaca1200b02b9ff0225bf488804f0e7790ae..0000000000000000000000000000000000000000 --- a/block-backup-fix-backup_cow_with_offload-for-last-cl.patch +++ /dev/null @@ -1,35 +0,0 @@ -From adb934c8d2cfd8b920e69712f07a8fb9399fdc2d Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Fri, 20 Sep 2019 17:20:43 +0300 -Subject: [PATCH] block/backup: fix backup_cow_with_offload for last cluster - -We shouldn't try to copy bytes beyond EOF. Fix it. - -Fixes: 9ded4a0114968e -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Max Reitz -Reviewed-by: John Snow -Message-id: 20190920142056.12778-3-vsementsov@virtuozzo.com -Signed-off-by: Max Reitz -(cherry picked from commit 1048ddf0a32dcdaa952e581bd503d49adad527cc) -Signed-off-by: Michael Roth ---- - block/backup.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block/backup.c b/block/backup.c -index 8119d3c..55736ea 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -169,7 +169,7 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job, - - assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size)); - assert(QEMU_IS_ALIGNED(start, job->cluster_size)); -- nbytes = MIN(job->copy_range_size, end - start); -+ nbytes = MIN(job->copy_range_size, MIN(end, job->len) - start); - nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size); - hbitmap_reset(job->copy_bitmap, start, job->cluster_size * nr_clusters); - ret = blk_co_copy_range(blk, start, job->target, start, nbytes, --- -1.8.3.1 - diff --git a/block-backup-fix-max_transfer-handling-for-copy_rang.patch b/block-backup-fix-max_transfer-handling-for-copy_rang.patch deleted file mode 100644 index 2303b5faf858182f9820d6b3497150d481b4879b..0000000000000000000000000000000000000000 --- a/block-backup-fix-max_transfer-handling-for-copy_rang.patch +++ /dev/null @@ -1,51 +0,0 @@ -From bad8a640a29f16b4d333673577b06880894766e1 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Fri, 20 Sep 2019 17:20:42 +0300 -Subject: [PATCH] block/backup: fix max_transfer handling for copy_range - -Of course, QEMU_ALIGN_UP is a typo, it should be QEMU_ALIGN_DOWN, as we -are trying to find aligned size which satisfy both source and target. -Also, don't ignore too small max_transfer. In this case seems safer to -disable copy_range. - -Fixes: 9ded4a0114968e -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-id: 20190920142056.12778-2-vsementsov@virtuozzo.com -Signed-off-by: Max Reitz -(cherry picked from commit 981fb5810aa3f68797ee6e261db338bd78857614) -Signed-off-by: Michael Roth ---- - block/backup.c | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index 381659d..8119d3c 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -666,12 +666,19 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - job->cluster_size = cluster_size; - job->copy_bitmap = copy_bitmap; - copy_bitmap = NULL; -- job->use_copy_range = !compress; /* compression isn't supported for it */ - job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk), - blk_get_max_transfer(job->target)); -- job->copy_range_size = MAX(job->cluster_size, -- QEMU_ALIGN_UP(job->copy_range_size, -- job->cluster_size)); -+ job->copy_range_size = QEMU_ALIGN_DOWN(job->copy_range_size, -+ job->cluster_size); -+ /* -+ * Set use_copy_range, consider the following: -+ * 1. Compression is not supported for copy_range. -+ * 2. copy_range does not respect max_transfer (it's a TODO), so we factor -+ * that in here. If max_transfer is smaller than the job->cluster_size, -+ * we do not use copy_range (in that case it's zero after aligning down -+ * above). -+ */ -+ job->use_copy_range = !compress && job->copy_range_size > 0; - - /* Required permissions are already taken with target's blk_new() */ - block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, --- -1.8.3.1 - diff --git a/block-backup-hoist-bitmap-check-into-QMP-interface.patch b/block-backup-hoist-bitmap-check-into-QMP-interface.patch deleted file mode 100644 index 51dc67ccbcd131c09200963de192185c0aa97671..0000000000000000000000000000000000000000 --- a/block-backup-hoist-bitmap-check-into-QMP-interface.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 9cc9e9657aad126502183fa4ceb9b962b55471cb Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:55 -0400 -Subject: [PATCH] block/backup: hoist bitmap check into QMP interface - -This is nicer to do in the unified QMP interface that we have now, -because it lets us use the right terminology back at the user. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190716000117.25219-5-jsnow@redhat.com -Signed-off-by: John Snow ---- - block/backup.c | 13 ++++--------- - blockdev.c | 10 ++++++++++ - 2 files changed, 14 insertions(+), 9 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index 59ac2c0396..cc19643b47 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -565,6 +565,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - assert(bs); - assert(target); - -+ /* QMP interface protects us from these cases */ -+ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); -+ assert(sync_bitmap || sync_mode != MIRROR_SYNC_MODE_BITMAP); -+ - if (bs == target) { - error_setg(errp, "Source and target cannot be the same"); - return NULL; -@@ -596,16 +600,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - return NULL; - } - -- /* QMP interface should have handled translating this to bitmap mode */ -- assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); -- - if (sync_mode == MIRROR_SYNC_MODE_BITMAP) { -- if (!sync_bitmap) { -- error_setg(errp, "must provide a valid bitmap name for " -- "'%s' sync mode", MirrorSyncMode_str(sync_mode)); -- return NULL; -- } -- - /* If we need to write to this bitmap, check that we can: */ - if (bitmap_mode != BITMAP_SYNC_MODE_NEVER && - bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) { -diff --git a/blockdev.c b/blockdev.c -index efb69d343a..0a71a15fa2 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3508,6 +3508,16 @@ static BlockJob *do_backup_common(BackupCommon *backup, - return NULL; - } - -+ if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) || -+ (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) { -+ /* done before desugaring 'incremental' to print the right message */ -+ if (!backup->has_bitmap) { -+ error_setg(errp, "must provide a valid bitmap name for " -+ "'%s' sync mode", MirrorSyncMode_str(backup->sync)); -+ return NULL; -+ } -+ } -+ - if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) { - if (backup->has_bitmap_mode && - backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) { --- -2.27.0 - diff --git a/block-backup-loosen-restriction-on-readonly-bitmaps.patch b/block-backup-loosen-restriction-on-readonly-bitmaps.patch deleted file mode 100644 index ab0617c2b580040a460aad2bd4eb16f3e4687141..0000000000000000000000000000000000000000 --- a/block-backup-loosen-restriction-on-readonly-bitmaps.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 801e9452bc80a38ee26fe12ba42356851acd6a9e Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:54 -0400 -Subject: [PATCH] block/backup: loosen restriction on readonly bitmaps - -With the "never" sync policy, we actually can utilize readonly bitmaps -now. Loosen the check at the QMP level, and tighten it based on -provided arguments down at the job creation level instead. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190709232550.10724-19-jsnow@redhat.com -Signed-off-by: John Snow ---- - block/backup.c | 6 ++++++ - blockdev.c | 2 +- - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/block/backup.c b/block/backup.c -index 84a56337ac..59ac2c0396 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -606,6 +606,12 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - return NULL; - } - -+ /* If we need to write to this bitmap, check that we can: */ -+ if (bitmap_mode != BITMAP_SYNC_MODE_NEVER && -+ bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) { -+ return NULL; -+ } -+ - /* Create a new bitmap, and freeze/disable this one. */ - if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) { - return NULL; -diff --git a/blockdev.c b/blockdev.c -index 34c8b651e1..efb69d343a 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3533,7 +3533,7 @@ static BlockJob *do_backup_common(BackupCommon *backup, - "when providing a bitmap"); - return NULL; - } -- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { -+ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) { - return NULL; - } - } --- -2.27.0 - diff --git a/block-bdrv_set_backing_bs-fix-use-after-free.patch b/block-bdrv_set_backing_bs-fix-use-after-free.patch deleted file mode 100644 index 93ac72169d8518a8fcadc82c7ee01fcfdfcf94fc..0000000000000000000000000000000000000000 --- a/block-bdrv_set_backing_bs-fix-use-after-free.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 3754525eb383f91869634766ccd041cfe40bbf17 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Mon, 16 Mar 2020 09:06:30 +0300 -Subject: [PATCH 05/14] block: bdrv_set_backing_bs: fix use-after-free -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There is a use-after-free possible: bdrv_unref_child() leaves -bs->backing freed but not NULL. bdrv_attach_child may produce nested -polling loop due to drain, than access of freed pointer is possible. - -I've produced the following crash on 30 iotest with modified code. It -does not reproduce on master, but still seems possible: - - #0 __strcmp_avx2 () at /lib64/libc.so.6 - #1 bdrv_backing_overridden (bs=0x55c9d3cc2060) at block.c:6350 - #2 bdrv_refresh_filename (bs=0x55c9d3cc2060) at block.c:6404 - #3 bdrv_backing_attach (c=0x55c9d48e5520) at block.c:1063 - #4 bdrv_replace_child_noperm - (child=child@entry=0x55c9d48e5520, - new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2290 - #5 bdrv_replace_child - (child=child@entry=0x55c9d48e5520, - new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2320 - #6 bdrv_root_attach_child - (child_bs=child_bs@entry=0x55c9d3cc2060, - child_name=child_name@entry=0x55c9d241d478 "backing", - child_role=child_role@entry=0x55c9d26ecee0 , - ctx=, perm=, shared_perm=21, - opaque=0x55c9d3c5a3d0, errp=0x7ffd117108e0) at block.c:2424 - #7 bdrv_attach_child - (parent_bs=parent_bs@entry=0x55c9d3c5a3d0, - child_bs=child_bs@entry=0x55c9d3cc2060, - child_name=child_name@entry=0x55c9d241d478 "backing", - child_role=child_role@entry=0x55c9d26ecee0 , - errp=errp@entry=0x7ffd117108e0) at block.c:5876 - #8 in bdrv_set_backing_hd - (bs=bs@entry=0x55c9d3c5a3d0, - backing_hd=backing_hd@entry=0x55c9d3cc2060, - errp=errp@entry=0x7ffd117108e0) - at block.c:2576 - #9 stream_prepare (job=0x55c9d49d84a0) at block/stream.c:150 - #10 job_prepare (job=0x55c9d49d84a0) at job.c:761 - #11 job_txn_apply (txn=, fn=) at - job.c:145 - #12 job_do_finalize (job=0x55c9d49d84a0) at job.c:778 - #13 job_completed_txn_success (job=0x55c9d49d84a0) at job.c:832 - #14 job_completed (job=0x55c9d49d84a0) at job.c:845 - #15 job_completed (job=0x55c9d49d84a0) at job.c:836 - #16 job_exit (opaque=0x55c9d49d84a0) at job.c:864 - #17 aio_bh_call (bh=0x55c9d471a160) at util/async.c:117 - #18 aio_bh_poll (ctx=ctx@entry=0x55c9d3c46720) at util/async.c:117 - #19 aio_poll (ctx=ctx@entry=0x55c9d3c46720, - blocking=blocking@entry=true) - at util/aio-posix.c:728 - #20 bdrv_parent_drained_begin_single (poll=true, c=0x55c9d3d558f0) - at block/io.c:121 - #21 bdrv_parent_drained_begin_single (c=c@entry=0x55c9d3d558f0, - poll=poll@entry=true) - at block/io.c:114 - #22 bdrv_replace_child_noperm - (child=child@entry=0x55c9d3d558f0, - new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2258 - #23 bdrv_replace_child - (child=child@entry=0x55c9d3d558f0, - new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2320 - #24 bdrv_root_attach_child - (child_bs=child_bs@entry=0x55c9d3d27300, - child_name=child_name@entry=0x55c9d241d478 "backing", - child_role=child_role@entry=0x55c9d26ecee0 , - ctx=, perm=, shared_perm=21, - opaque=0x55c9d3cc2060, errp=0x7ffd11710c60) at block.c:2424 - #25 bdrv_attach_child - (parent_bs=parent_bs@entry=0x55c9d3cc2060, - child_bs=child_bs@entry=0x55c9d3d27300, - child_name=child_name@entry=0x55c9d241d478 "backing", - child_role=child_role@entry=0x55c9d26ecee0 , - errp=errp@entry=0x7ffd11710c60) at block.c:5876 - #26 bdrv_set_backing_hd - (bs=bs@entry=0x55c9d3cc2060, - backing_hd=backing_hd@entry=0x55c9d3d27300, - errp=errp@entry=0x7ffd11710c60) - at block.c:2576 - #27 stream_prepare (job=0x55c9d495ead0) at block/stream.c:150 - ... - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200316060631.30052-2-vsementsov@virtuozzo.com> -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: John Snow -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - block.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index 29e504b86aff..e834102c87f7 100644 ---- a/block.c -+++ b/block.c -@@ -2549,10 +2549,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, - - if (bs->backing) { - bdrv_unref_child(bs, bs->backing); -+ bs->backing = NULL; - } - - if (!backing_hd) { -- bs->backing = NULL; - goto out; - } - --- -2.26.2 - diff --git a/block-bugfix-Don-t-pause-vm-when-NOSPACE-EIO-happene.patch b/block-bugfix-Don-t-pause-vm-when-NOSPACE-EIO-happene.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d454ecc4935d6ff4206b8b47d76962cfc4ee673 --- /dev/null +++ b/block-bugfix-Don-t-pause-vm-when-NOSPACE-EIO-happene.patch @@ -0,0 +1,33 @@ +From d0586db311e8b78732923ce46f149fdf8251a59c Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 16:10:22 +0800 +Subject: [PATCH] block: bugfix: Don't pause vm when NOSPACE EIO happened + +When backend disk is FULL and disk IO type is 'dataplane', +QEMU will pause the vm, and this may cause endless-loop in +QEMU main thread if we do the snapshot merge now. + +When backend disk is FULL, only reporting an error rather +than pausing the virtual machine. + +Signed-off-by: wangjian161 +--- + blockdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index 37e3ee6f26..3ce294ec4a 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -556,7 +556,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + qdict_put_str(bs_opts, "driver", buf); + } + +- on_write_error = BLOCKDEV_ON_ERROR_ENOSPC; ++ on_write_error = BLOCKDEV_ON_ERROR_REPORT; + if ((buf = qemu_opt_get(opts, "werror")) != NULL) { + on_write_error = parse_block_error_action(buf, 0, &error); + if (error) { +-- +2.27.0 + diff --git a/block-bugfix-disable-process-AIO-when-attach-scsi-di.patch b/block-bugfix-disable-process-AIO-when-attach-scsi-di.patch new file mode 100644 index 0000000000000000000000000000000000000000..30a1bacb258e52e0203d081f1aee0b6093735f5f --- /dev/null +++ b/block-bugfix-disable-process-AIO-when-attach-scsi-di.patch @@ -0,0 +1,43 @@ +From 87d8b7dcd880e0cef0c043dfef5ae649652cfe21 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 11:51:43 +0800 +Subject: [PATCH] block: bugfix: disable process AIO when attach scsi disk + +When initializing the virtio-scsi disk, hd_geometry_guess() will +be called to process AIO. At this time, the scsi disk has not +been fully initialized, and some fields in struct SCSIDiskState, +such as vendor and version, are NULL. If processing AIO at this +time, qemu may crash down. + +Add aio_disable_external() before hd_geometry_guess() to disable +processing AIO at that time. + +Signed-off-by: wangjian161 +--- + hw/block/block.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/block/block.c b/hw/block/block.c +index 26c0767552..2cfc93a68e 100644 +--- a/hw/block/block.c ++++ b/hw/block/block.c +@@ -224,9 +224,16 @@ bool blkconf_geometry(BlockConf *conf, int *ptrans, + Error **errp) + { + if (!conf->cyls && !conf->heads && !conf->secs) { ++ AioContext *ctx = blk_get_aio_context(conf->blk); ++ ++ /* Callers may not expect this function to dispatch aio handlers, so ++ * disable external aio such as guest device emulation. ++ */ ++ aio_disable_external(ctx); + hd_geometry_guess(conf->blk, + &conf->cyls, &conf->heads, &conf->secs, + ptrans); ++ aio_enable_external(ctx); + } else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) { + *ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs); + } +-- +2.27.0 + diff --git a/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch b/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch deleted file mode 100644 index 73d2b9d0e5e490c3f855304e692ed68fd4029468..0000000000000000000000000000000000000000 --- a/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 088f1e8fd9e790bc5766bd43af134230abcff6dd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Thu, 12 Sep 2019 00:08:49 +0200 -Subject: [PATCH] block/create: Do not abort if a block driver is not available -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The 'blockdev-create' QMP command was introduced as experimental -feature in commit b0292b851b8, using the assert() debug call. -It got promoted to 'stable' command in 3fb588a0f2c, but the -assert call was not removed. - -Some block drivers are optional, and bdrv_find_format() might -return a NULL value, triggering the assertion. - -Stable code is not expected to abort, so return an error instead. - -This is easily reproducible when libnfs is not installed: - - ./configure - [...] - module support no - Block whitelist (rw) - Block whitelist (ro) - libiscsi support yes - libnfs support no - [...] - -Start QEMU: - - $ qemu-system-x86_64 -S -qmp unix:/tmp/qemu.qmp,server,nowait - -Send the 'blockdev-create' with the 'nfs' driver: - - $ ( cat << 'EOF' - {'execute': 'qmp_capabilities'} - {'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'} - EOF - ) | socat STDIO UNIX:/tmp/qemu.qmp - {"QMP": {"version": {"qemu": {"micro": 50, "minor": 1, "major": 4}, "package": "v4.1.0-733-g89ea03a7dc"}, "capabilities": ["oob"]}} - {"return": {}} - -QEMU crashes: - - $ gdb qemu-system-x86_64 core - Program received signal SIGSEGV, Segmentation fault. - (gdb) bt - #0 0x00007ffff510957f in raise () at /lib64/libc.so.6 - #1 0x00007ffff50f3895 in abort () at /lib64/libc.so.6 - #2 0x00007ffff50f3769 in _nl_load_domain.cold.0 () at /lib64/libc.so.6 - #3 0x00007ffff5101a26 in .annobin_assert.c_end () at /lib64/libc.so.6 - #4 0x0000555555d7e1f1 in qmp_blockdev_create (job_id=0x555556baee40 "x", options=0x555557666610, errp=0x7fffffffc770) at block/create.c:69 - #5 0x0000555555c96b52 in qmp_marshal_blockdev_create (args=0x7fffdc003830, ret=0x7fffffffc7f8, errp=0x7fffffffc7f0) at qapi/qapi-commands-block-core.c:1314 - #6 0x0000555555deb0a0 in do_qmp_dispatch (cmds=0x55555645de70 , request=0x7fffdc005c70, allow_oob=false, errp=0x7fffffffc898) at qapi/qmp-dispatch.c:131 - #7 0x0000555555deb2a1 in qmp_dispatch (cmds=0x55555645de70 , request=0x7fffdc005c70, allow_oob=false) at qapi/qmp-dispatch.c:174 - -With this patch applied, QEMU returns a QMP error: - - {'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'} - {"id": "x", "error": {"class": "GenericError", "desc": "Block driver 'nfs' not found or not supported"}} - -Cc: qemu-stable@nongnu.org -Reported-by: Xu Tian -Signed-off-by: Philippe Mathieu-Daudé -Reviewed-by: Eric Blake -Reviewed-by: John Snow -Signed-off-by: Kevin Wolf -(cherry picked from commit d90d5cae2b10efc0e8d0b3cc91ff16201853d3ba) -Signed-off-by: Michael Roth ---- - block/create.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/block/create.c b/block/create.c -index 95341219ef..de5e97bb18 100644 ---- a/block/create.c -+++ b/block/create.c -@@ -63,9 +63,13 @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, - const char *fmt = BlockdevDriver_str(options->driver); - BlockDriver *drv = bdrv_find_format(fmt); - -+ if (!drv) { -+ error_setg(errp, "Block driver '%s' not found or not supported", fmt); -+ return; -+ } -+ - /* If the driver is in the schema, we know that it exists. But it may not - * be whitelisted. */ -- assert(drv); - if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) { - error_setg(errp, "Driver is not whitelisted"); - return; --- -2.23.0 diff --git a/block-curl-HTTP-header-field-names-are-case-insensit.patch b/block-curl-HTTP-header-field-names-are-case-insensit.patch deleted file mode 100644 index 8f1028d75bbb4db6b16eca9718c90d5fe2e5795e..0000000000000000000000000000000000000000 --- a/block-curl-HTTP-header-field-names-are-case-insensit.patch +++ /dev/null @@ -1,54 +0,0 @@ -From ae2c6d13c4ac625a2c6b217a7f6a17506a2b26e5 Mon Sep 17 00:00:00 2001 -From: Richard Jones -Date: Thu, 28 May 2020 14:27:37 +0100 -Subject: [PATCH] block/curl: HTTP header field names are case insensitive -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Richard Jones -Message-id: <20200528142737.17318-3-rjones@redhat.com> -Patchwork-id: 96895 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 2/2] block/curl: HTTP header field names are case insensitive -Bugzilla: 1841038 -RH-Acked-by: Eric Blake -RH-Acked-by: Max Reitz -RH-Acked-by: Philippe Mathieu-Daudé - -From: David Edmondson - -RFC 7230 section 3.2 indicates that HTTP header field names are case -insensitive. - -Signed-off-by: David Edmondson -Message-Id: <20200224101310.101169-3-david.edmondson@oracle.com> -Reviewed-by: Max Reitz -Signed-off-by: Max Reitz -(cherry picked from commit 69032253c33ae1774233c63cedf36d32242a85fc) -Signed-off-by: Danilo C. L. de Paula ---- - block/curl.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/block/curl.c b/block/curl.c -index bfabe7eabd..a298fcc591 100644 ---- a/block/curl.c -+++ b/block/curl.c -@@ -214,11 +214,12 @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque) - size_t realsize = size * nmemb; - const char *header = (char *)ptr; - const char *end = header + realsize; -- const char *accept_ranges = "Accept-Ranges:"; -+ const char *accept_ranges = "accept-ranges:"; - const char *bytes = "bytes"; - - if (realsize >= strlen(accept_ranges) -- && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) { -+ && g_ascii_strncasecmp(header, accept_ranges, -+ strlen(accept_ranges)) == 0) { - - char *p = strchr(header, ':') + 1; - --- -2.27.0 - diff --git a/block-curl-HTTP-header-fields-allow-whitespace-aroun.patch b/block-curl-HTTP-header-fields-allow-whitespace-aroun.patch deleted file mode 100644 index 6f3aade47ce62e588e7ce490a7a3fc8f873c49de..0000000000000000000000000000000000000000 --- a/block-curl-HTTP-header-fields-allow-whitespace-aroun.patch +++ /dev/null @@ -1,75 +0,0 @@ -From c8fd37c06fd24d1242629dda329dd16bea20f319 Mon Sep 17 00:00:00 2001 -From: Richard Jones -Date: Thu, 28 May 2020 14:27:36 +0100 -Subject: [PATCH] block/curl: HTTP header fields allow whitespace around values - -RH-Author: Richard Jones -Message-id: <20200528142737.17318-2-rjones@redhat.com> -Patchwork-id: 96894 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 1/2] block/curl: HTTP header fields allow whitespace around values -Bugzilla: 1841038 -RH-Acked-by: Eric Blake -RH-Acked-by: Max Reitz -RH-Acked-by: Danilo de Paula - -From: David Edmondson - -RFC 7230 section 3.2 indicates that whitespace is permitted between -the field name and field value and after the field value. - -Signed-off-by: David Edmondson -Message-Id: <20200224101310.101169-2-david.edmondson@oracle.com> -Reviewed-by: Max Reitz -Signed-off-by: Max Reitz -(cherry picked from commit 7788a319399f17476ff1dd43164c869e320820a2) -Signed-off-by: Danilo C. L. de Paula ---- - block/curl.c | 31 +++++++++++++++++++++++++++---- - 1 file changed, 27 insertions(+), 4 deletions(-) - -diff --git a/block/curl.c b/block/curl.c -index d4c8e94f3e..bfabe7eabd 100644 ---- a/block/curl.c -+++ b/block/curl.c -@@ -212,11 +212,34 @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque) - { - BDRVCURLState *s = opaque; - size_t realsize = size * nmemb; -- const char *accept_line = "Accept-Ranges: bytes"; -+ const char *header = (char *)ptr; -+ const char *end = header + realsize; -+ const char *accept_ranges = "Accept-Ranges:"; -+ const char *bytes = "bytes"; - -- if (realsize >= strlen(accept_line) -- && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) { -- s->accept_range = true; -+ if (realsize >= strlen(accept_ranges) -+ && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) { -+ -+ char *p = strchr(header, ':') + 1; -+ -+ /* Skip whitespace between the header name and value. */ -+ while (p < end && *p && g_ascii_isspace(*p)) { -+ p++; -+ } -+ -+ if (end - p >= strlen(bytes) -+ && strncmp(p, bytes, strlen(bytes)) == 0) { -+ -+ /* Check that there is nothing but whitespace after the value. */ -+ p += strlen(bytes); -+ while (p < end && *p && g_ascii_isspace(*p)) { -+ p++; -+ } -+ -+ if (p == end || !*p) { -+ s->accept_range = true; -+ } -+ } - } - - return realsize; --- -2.27.0 - diff --git a/block-disallow-block-jobs-when-there-is-a-BDRV_O_INA.patch b/block-disallow-block-jobs-when-there-is-a-BDRV_O_INA.patch new file mode 100644 index 0000000000000000000000000000000000000000..f243df9947f7acea06bb5ca06ebbbf53fb95968c --- /dev/null +++ b/block-disallow-block-jobs-when-there-is-a-BDRV_O_INA.patch @@ -0,0 +1,47 @@ +From 0a2c96ee5a3463e82397afb9cb36f340a93264c2 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 11:29:15 +0800 +Subject: [PATCH] block: disallow block jobs when there is a BDRV_O_INACTIVE + flag + +Currently, migration will put a BDRV_O_INACTIVE flag +on bs's open_flags until another resume being called. In that case, +any IO from vm or block jobs will cause a qemu crash with an assert +'assert(!(bs->open_flags & BDRV_O_INACTIVE))' failure in bdrv_co_pwritev +function. we hereby disallow block jobs by faking a blocker. + +Signed-off-by: wangjian161 +--- + block.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/block.c b/block.c +index 0ac5b163d2..26c3982567 100644 +--- a/block.c ++++ b/block.c +@@ -6692,6 +6692,22 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) + bdrv_get_device_or_node_name(bs)); + return true; + } ++ ++ /* ++ * When migration puts a BDRV_O_INACTIVE flag on driver's open_flags, ++ * we fake a blocker that doesn't exist. From now on, block jobs ++ * will not be permitted. ++ */ ++ if ((op == BLOCK_OP_TYPE_RESIZE || op == BLOCK_OP_TYPE_COMMIT_SOURCE || ++ op == BLOCK_OP_TYPE_MIRROR_SOURCE || op == BLOCK_OP_TYPE_MIRROR_TARGET) && ++ (bs->open_flags & BDRV_O_INACTIVE)) { ++ if (errp) { ++ error_setg(errp, "block device is in use by migration with" ++ " a driver BDRV_O_INACTIVE flag setted"); ++ } ++ return true; ++ } ++ + return false; + } + +-- +2.27.0 + diff --git a/block-enable-cache-mode-of-empty-cdrom.patch b/block-enable-cache-mode-of-empty-cdrom.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a5c0b1dcdb858aef4653fbb6155e7fff28deec3 --- /dev/null +++ b/block-enable-cache-mode-of-empty-cdrom.patch @@ -0,0 +1,49 @@ +From 21b172a3ce13c3b499e4265628f7d7c7e1189749 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 11:18:21 +0800 +Subject: [PATCH] block: enable cache mode of empty cdrom + +enable cache mode even if cdrom is empty + +Signed-off-by: wangjian161 +--- + blockdev.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/blockdev.c b/blockdev.c +index 10a73fa423..37e3ee6f26 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -492,6 +492,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + QDict *interval_dict = NULL; + QList *interval_list = NULL; + const char *id; ++ const char *cache; + BlockdevDetectZeroesOptions detect_zeroes = + BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; + const char *throttling_group = NULL; +@@ -583,6 +584,21 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + + read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false); + ++ if (!file || !*file) { ++ cache = qdict_get_try_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH); ++ if (cache && !strcmp(cache, "on")) { ++ bdrv_flags |= BDRV_O_NO_FLUSH; ++ } ++ ++ cache = qdict_get_try_str(bs_opts, BDRV_OPT_CACHE_DIRECT); ++ if (cache && !strcmp(cache, "on")) { ++ bdrv_flags |= BDRV_O_NOCACHE; ++ } ++ ++ qdict_del(bs_opts, BDRV_OPT_CACHE_NO_FLUSH); ++ qdict_del(bs_opts, BDRV_OPT_CACHE_DIRECT); ++ } ++ + /* init */ + if ((!file || !*file) && !qdict_size(bs_opts)) { + BlockBackendRootState *blk_rs; +-- +2.27.0 + diff --git a/block-file-posix-Let-post-EOF-fallocate-serialize.patch b/block-file-posix-Let-post-EOF-fallocate-serialize.patch deleted file mode 100644 index bf7d34a3e54ffe24356a16185d1dfcaef603c455..0000000000000000000000000000000000000000 --- a/block-file-posix-Let-post-EOF-fallocate-serialize.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 7db05c8a732fbdc986a40aadf0de6dd23057d044 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Fri, 1 Nov 2019 16:25:10 +0100 -Subject: [PATCH] block/file-posix: Let post-EOF fallocate serialize - -The XFS kernel driver has a bug that may cause data corruption for qcow2 -images as of qemu commit c8bb23cbdbe32f. We can work around it by -treating post-EOF fallocates as serializing up until infinity (INT64_MAX -in practice). - -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Message-id: 20191101152510.11719-4-mreitz@redhat.com -Signed-off-by: Max Reitz -(cherry picked from commit 292d06b925b2787ee6f2430996b95651cae42fce) -Signed-off-by: Michael Roth ---- - block/file-posix.c | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/block/file-posix.c b/block/file-posix.c -index 992eb4a798..c5df61b477 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -2623,6 +2623,42 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, - RawPosixAIOData acb; - ThreadPoolFunc *handler; - -+#ifdef CONFIG_FALLOCATE -+ if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) { -+ BdrvTrackedRequest *req; -+ uint64_t end; -+ -+ /* -+ * This is a workaround for a bug in the Linux XFS driver, -+ * where writes submitted through the AIO interface will be -+ * discarded if they happen beyond a concurrently running -+ * fallocate() that increases the file length (i.e., both the -+ * write and the fallocate() happen beyond the EOF). -+ * -+ * To work around it, we extend the tracked request for this -+ * zero write until INT64_MAX (effectively infinity), and mark -+ * it as serializing. -+ * -+ * We have to enable this workaround for all filesystems and -+ * AIO modes (not just XFS with aio=native), because for -+ * remote filesystems we do not know the host configuration. -+ */ -+ -+ req = bdrv_co_get_self_request(bs); -+ assert(req); -+ assert(req->type == BDRV_TRACKED_WRITE); -+ assert(req->offset <= offset); -+ assert(req->offset + req->bytes >= offset + bytes); -+ -+ end = INT64_MAX & -(uint64_t)bs->bl.request_alignment; -+ req->bytes = end - req->offset; -+ req->overlap_bytes = req->bytes; -+ -+ bdrv_mark_request_serialising(req, bs->bl.request_alignment); -+ bdrv_wait_serialising_requests(req); -+ } -+#endif -+ - acb = (RawPosixAIOData) { - .bs = bs, - .aio_fildes = s->fd, --- -2.23.0 diff --git a/block-file-posix-Reduce-xfsctl-use.patch b/block-file-posix-Reduce-xfsctl-use.patch deleted file mode 100644 index 69ceb453efac39a1fcfcc26488e04a7bb8eee0df..0000000000000000000000000000000000000000 --- a/block-file-posix-Reduce-xfsctl-use.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 6f1a94035b02d3676a897ea5fa4cda4c62128228 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Fri, 23 Aug 2019 15:03:40 +0200 -Subject: [PATCH] block/file-posix: Reduce xfsctl() use -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch removes xfs_write_zeroes() and xfs_discard(). Both functions -have been added just before the same feature was present through -fallocate(): - -- fallocate() has supported PUNCH_HOLE for XFS since Linux 2.6.38 (March - 2011); xfs_discard() was added in December 2010. - -- fallocate() has supported ZERO_RANGE for XFS since Linux 3.15 (June - 2014); xfs_write_zeroes() was added in November 2013. - -Nowadays, all systems that qemu runs on should support both fallocate() -features (RHEL 7's kernel does). - -xfsctl() is still useful for getting the request alignment for O_DIRECT, -so this patch does not remove our dependency on it completely. - -Note that xfs_write_zeroes() had a bug: It calls ftruncate() when the -file is shorter than the specified range (because ZERO_RANGE does not -increase the file length). ftruncate() may yield and then discard data -that parallel write requests have written past the EOF in the meantime. -Dropping the function altogether fixes the bug. - -Suggested-by: Paolo Bonzini -Fixes: 50ba5b2d994853b38fed10e0841b119da0f8b8e5 -Reported-by: Lukáš Doktor -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Reviewed-by: Stefano Garzarella -Reviewed-by: John Snow -Tested-by: Stefano Garzarella -Tested-by: John Snow -Signed-off-by: Kevin Wolf -(cherry picked from commit b2c6f23f4a9f6d8f1b648705cd46d3713b78d6a2) -Signed-off-by: Michael Roth ---- - block/file-posix.c | 77 +--------------------------------------------- - 1 file changed, 1 insertion(+), 76 deletions(-) - -diff --git a/block/file-posix.c b/block/file-posix.c -index 4479cc7ab4..992eb4a798 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -1445,59 +1445,6 @@ out: - } - } - --#ifdef CONFIG_XFS --static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes) --{ -- int64_t len; -- struct xfs_flock64 fl; -- int err; -- -- len = lseek(s->fd, 0, SEEK_END); -- if (len < 0) { -- return -errno; -- } -- -- if (offset + bytes > len) { -- /* XFS_IOC_ZERO_RANGE does not increase the file length */ -- if (ftruncate(s->fd, offset + bytes) < 0) { -- return -errno; -- } -- } -- -- memset(&fl, 0, sizeof(fl)); -- fl.l_whence = SEEK_SET; -- fl.l_start = offset; -- fl.l_len = bytes; -- -- if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) { -- err = errno; -- trace_file_xfs_write_zeroes(strerror(errno)); -- return -err; -- } -- -- return 0; --} -- --static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) --{ -- struct xfs_flock64 fl; -- int err; -- -- memset(&fl, 0, sizeof(fl)); -- fl.l_whence = SEEK_SET; -- fl.l_start = offset; -- fl.l_len = bytes; -- -- if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { -- err = errno; -- trace_file_xfs_discard(strerror(errno)); -- return -err; -- } -- -- return 0; --} --#endif -- - static int translate_err(int err) - { - if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP || -@@ -1553,10 +1500,8 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb) - static int handle_aiocb_write_zeroes(void *opaque) - { - RawPosixAIOData *aiocb = opaque; --#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS) -- BDRVRawState *s = aiocb->bs->opaque; --#endif - #ifdef CONFIG_FALLOCATE -+ BDRVRawState *s = aiocb->bs->opaque; - int64_t len; - #endif - -@@ -1564,12 +1509,6 @@ static int handle_aiocb_write_zeroes(void *opaque) - return handle_aiocb_write_zeroes_block(aiocb); - } - --#ifdef CONFIG_XFS -- if (s->is_xfs) { -- return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes); -- } --#endif -- - #ifdef CONFIG_FALLOCATE_ZERO_RANGE - if (s->has_write_zeroes) { - int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE, -@@ -1632,14 +1571,6 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) - } - #endif - --#ifdef CONFIG_XFS -- if (s->is_xfs) { -- /* xfs_discard() guarantees that the discarded area reads as all-zero -- * afterwards, so we can use it here. */ -- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); -- } --#endif -- - /* If we couldn't manage to unmap while guaranteed that the area reads as - * all-zero afterwards, just write zeroes without unmapping */ - ret = handle_aiocb_write_zeroes(aiocb); -@@ -1716,12 +1647,6 @@ static int handle_aiocb_discard(void *opaque) - ret = -errno; - #endif - } else { --#ifdef CONFIG_XFS -- if (s->is_xfs) { -- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); -- } --#endif -- - #ifdef CONFIG_FALLOCATE_PUNCH_HOLE - ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, - aiocb->aio_offset, aiocb->aio_nbytes); --- -2.23.0 diff --git a/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch b/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch deleted file mode 100644 index d901f1062659223d2899ab5520759a6a5065545a..0000000000000000000000000000000000000000 --- a/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 5060ef71fa4621061101a30fa9e0d1690696c5c1 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 24 Mar 2020 18:59:21 +0300 -Subject: [PATCH 10/14] block: fix bdrv_root_attach_child forget to unref - child_bs - -bdrv_root_attach_child promises to drop child_bs reference on failure. -It does it on first handled failure path, but not on the second. Fix -that. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200324155921.23822-1-vsementsov@virtuozzo.com> -Signed-off-by: Kevin Wolf -Signed-off-by: Peng Liang ---- - block.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block.c b/block.c -index e834102c87f7..38880eabf801 100644 ---- a/block.c -+++ b/block.c -@@ -2399,6 +2399,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, - error_propagate(errp, local_err); - g_free(child); - bdrv_abort_perm_update(child_bs); -+ bdrv_unref(child_bs); - return NULL; - } - } --- -2.26.2 - diff --git a/block-fix-memleaks-in-bdrv_refresh_filename.patch b/block-fix-memleaks-in-bdrv_refresh_filename.patch deleted file mode 100644 index 48682054e6d7db02048c7538f8f1963447020c85..0000000000000000000000000000000000000000 --- a/block-fix-memleaks-in-bdrv_refresh_filename.patch +++ /dev/null @@ -1,56 +0,0 @@ -From d09b8364d9f89c9d5f36dc983c4d4a36bb7388b9 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Thu, 16 Jan 2020 17:29:29 +0800 -Subject: [PATCH] block: fix memleaks in bdrv_refresh_filename - -If we call the qmp 'query-block' while qemu is working on 'block-commit', -it will cause memleaks. The memory leak stack is as follow: - -Indirect leak of 12360 byte(s) in 3 object(s) allocated from: - #0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) - #1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) - #2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu/qobject/qdict.c - #3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #6 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #7 0x55ea958818ea in bdrv_block_device_info /mnt/sdb/qemu/block/qapi.c - #8 0x55ea958879de in bdrv_query_info /mnt/sdb/qemu/block/qapi.c - #9 0x55ea9588b58f in qmp_query_block /mnt/sdb/qemu/block/qapi.c - #10 0x55ea95567392 in qmp_marshal_query_block qapi/qapi-commands-block-core.c - -Indirect leak of 4120 byte(s) in 1 object(s) allocated from: - #0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) - #1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) - #2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu/qobject/qdict.c - #3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu/block.c - #6 0x55ea9569f301 in bdrv_backing_attach /mnt/sdb/qemu/block.c - #7 0x55ea956a99dd in bdrv_replace_child_noperm /mnt/sdb/qemu/block.c - #8 0x55ea956b9b53 in bdrv_replace_node /mnt/sdb/qemu/block.c - #9 0x55ea956b9e49 in bdrv_append /mnt/sdb/qemu/block.c - #10 0x55ea958c3472 in commit_start /mnt/sdb/qemu/block/commit.c - #11 0x55ea94b68ab0 in qmp_block_commit /mnt/sdb/qemu/blockdev.c - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - block.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block.c b/block.c -index 9ae5c0e..52bad05 100644 ---- a/block.c -+++ b/block.c -@@ -6048,6 +6048,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) - child->bs->exact_filename); - pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename); - -+ qobject_unref(bs->full_open_options); - bs->full_open_options = qobject_ref(child->bs->full_open_options); - - return; --- -1.8.3.1 - diff --git a/block-io-refactor-padding.patch b/block-io-refactor-padding.patch deleted file mode 100644 index 7a267147f5b5fbfa908edf342c02bd17481b3d70..0000000000000000000000000000000000000000 --- a/block-io-refactor-padding.patch +++ /dev/null @@ -1,481 +0,0 @@ -From 2e2ad02f2cecf419eaad0df982ceb5b41170cc7e Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 4 Jun 2019 19:15:05 +0300 -Subject: [PATCH] block/io: refactor padding - -We have similar padding code in bdrv_co_pwritev, -bdrv_co_do_pwrite_zeroes and bdrv_co_preadv. Let's combine and unify -it. - -[Squashed in Vladimir's qemu-iotests 077 fix ---Stefan] - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Acked-by: Stefan Hajnoczi -Message-id: 20190604161514.262241-4-vsementsov@virtuozzo.com -Message-Id: <20190604161514.262241-4-vsementsov@virtuozzo.com> -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 7a3f542fbdfd799be4fa6f8b96dc8c1e6933fce4) -*prereq for 292d06b9 -Signed-off-by: Michael Roth ---- - block/io.c | 365 +++++++++++++++++++++++++++++------------------------ - 1 file changed, 200 insertions(+), 165 deletions(-) - -diff --git a/block/io.c b/block/io.c -index dccf687acc..07d2d825c3 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -1408,28 +1408,177 @@ out: - } - - /* -- * Handle a read request in coroutine context -+ * Request padding -+ * -+ * |<---- align ----->| |<----- align ---->| -+ * |<- head ->|<------------- bytes ------------->|<-- tail -->| -+ * | | | | | | -+ * -*----------$-------*-------- ... --------*-----$------------*--- -+ * | | | | | | -+ * | offset | | end | -+ * ALIGN_DOWN(offset) ALIGN_UP(offset) ALIGN_DOWN(end) ALIGN_UP(end) -+ * [buf ... ) [tail_buf ) -+ * -+ * @buf is an aligned allocation needed to store @head and @tail paddings. @head -+ * is placed at the beginning of @buf and @tail at the @end. -+ * -+ * @tail_buf is a pointer to sub-buffer, corresponding to align-sized chunk -+ * around tail, if tail exists. -+ * -+ * @merge_reads is true for small requests, -+ * if @buf_len == @head + bytes + @tail. In this case it is possible that both -+ * head and tail exist but @buf_len == align and @tail_buf == @buf. -+ */ -+typedef struct BdrvRequestPadding { -+ uint8_t *buf; -+ size_t buf_len; -+ uint8_t *tail_buf; -+ size_t head; -+ size_t tail; -+ bool merge_reads; -+ QEMUIOVector local_qiov; -+} BdrvRequestPadding; -+ -+static bool bdrv_init_padding(BlockDriverState *bs, -+ int64_t offset, int64_t bytes, -+ BdrvRequestPadding *pad) -+{ -+ uint64_t align = bs->bl.request_alignment; -+ size_t sum; -+ -+ memset(pad, 0, sizeof(*pad)); -+ -+ pad->head = offset & (align - 1); -+ pad->tail = ((offset + bytes) & (align - 1)); -+ if (pad->tail) { -+ pad->tail = align - pad->tail; -+ } -+ -+ if ((!pad->head && !pad->tail) || !bytes) { -+ return false; -+ } -+ -+ sum = pad->head + bytes + pad->tail; -+ pad->buf_len = (sum > align && pad->head && pad->tail) ? 2 * align : align; -+ pad->buf = qemu_blockalign(bs, pad->buf_len); -+ pad->merge_reads = sum == pad->buf_len; -+ if (pad->tail) { -+ pad->tail_buf = pad->buf + pad->buf_len - align; -+ } -+ -+ return true; -+} -+ -+static int bdrv_padding_rmw_read(BdrvChild *child, -+ BdrvTrackedRequest *req, -+ BdrvRequestPadding *pad, -+ bool zero_middle) -+{ -+ QEMUIOVector local_qiov; -+ BlockDriverState *bs = child->bs; -+ uint64_t align = bs->bl.request_alignment; -+ int ret; -+ -+ assert(req->serialising && pad->buf); -+ -+ if (pad->head || pad->merge_reads) { -+ uint64_t bytes = pad->merge_reads ? pad->buf_len : align; -+ -+ qemu_iovec_init_buf(&local_qiov, pad->buf, bytes); -+ -+ if (pad->head) { -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); -+ } -+ if (pad->merge_reads && pad->tail) { -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); -+ } -+ ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes, -+ align, &local_qiov, 0); -+ if (ret < 0) { -+ return ret; -+ } -+ if (pad->head) { -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); -+ } -+ if (pad->merge_reads && pad->tail) { -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); -+ } -+ -+ if (pad->merge_reads) { -+ goto zero_mem; -+ } -+ } -+ -+ if (pad->tail) { -+ qemu_iovec_init_buf(&local_qiov, pad->tail_buf, align); -+ -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); -+ ret = bdrv_aligned_preadv( -+ child, req, -+ req->overlap_offset + req->overlap_bytes - align, -+ align, align, &local_qiov, 0); -+ if (ret < 0) { -+ return ret; -+ } -+ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); -+ } -+ -+zero_mem: -+ if (zero_middle) { -+ memset(pad->buf + pad->head, 0, pad->buf_len - pad->head - pad->tail); -+ } -+ -+ return 0; -+} -+ -+static void bdrv_padding_destroy(BdrvRequestPadding *pad) -+{ -+ if (pad->buf) { -+ qemu_vfree(pad->buf); -+ qemu_iovec_destroy(&pad->local_qiov); -+ } -+} -+ -+/* -+ * bdrv_pad_request -+ * -+ * Exchange request parameters with padded request if needed. Don't include RMW -+ * read of padding, bdrv_padding_rmw_read() should be called separately if -+ * needed. -+ * -+ * All parameters except @bs are in-out: they represent original request at -+ * function call and padded (if padding needed) at function finish. -+ * -+ * Function always succeeds. - */ -+static bool bdrv_pad_request(BlockDriverState *bs, QEMUIOVector **qiov, -+ int64_t *offset, unsigned int *bytes, -+ BdrvRequestPadding *pad) -+{ -+ if (!bdrv_init_padding(bs, *offset, *bytes, pad)) { -+ return false; -+ } -+ -+ qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head, -+ *qiov, 0, *bytes, -+ pad->buf + pad->buf_len - pad->tail, pad->tail); -+ *bytes += pad->head + pad->tail; -+ *offset -= pad->head; -+ *qiov = &pad->local_qiov; -+ -+ return true; -+} -+ - int coroutine_fn bdrv_co_preadv(BdrvChild *child, - int64_t offset, unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) - { - BlockDriverState *bs = child->bs; -- BlockDriver *drv = bs->drv; - BdrvTrackedRequest req; -- -- uint64_t align = bs->bl.request_alignment; -- uint8_t *head_buf = NULL; -- uint8_t *tail_buf = NULL; -- QEMUIOVector local_qiov; -- bool use_local_qiov = false; -+ BdrvRequestPadding pad; - int ret; - -- trace_bdrv_co_preadv(child->bs, offset, bytes, flags); -- -- if (!drv) { -- return -ENOMEDIUM; -- } -+ trace_bdrv_co_preadv(bs, offset, bytes, flags); - - ret = bdrv_check_byte_request(bs, offset, bytes); - if (ret < 0) { -@@ -1443,43 +1592,16 @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child, - flags |= BDRV_REQ_COPY_ON_READ; - } - -- /* Align read if necessary by padding qiov */ -- if (offset & (align - 1)) { -- head_buf = qemu_blockalign(bs, align); -- qemu_iovec_init(&local_qiov, qiov->niov + 2); -- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1)); -- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); -- use_local_qiov = true; -- -- bytes += offset & (align - 1); -- offset = offset & ~(align - 1); -- } -- -- if ((offset + bytes) & (align - 1)) { -- if (!use_local_qiov) { -- qemu_iovec_init(&local_qiov, qiov->niov + 1); -- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); -- use_local_qiov = true; -- } -- tail_buf = qemu_blockalign(bs, align); -- qemu_iovec_add(&local_qiov, tail_buf, -- align - ((offset + bytes) & (align - 1))); -- -- bytes = ROUND_UP(bytes, align); -- } -+ bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad); - - tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ); -- ret = bdrv_aligned_preadv(child, &req, offset, bytes, align, -- use_local_qiov ? &local_qiov : qiov, -- flags); -+ ret = bdrv_aligned_preadv(child, &req, offset, bytes, -+ bs->bl.request_alignment, -+ qiov, flags); - tracked_request_end(&req); - bdrv_dec_in_flight(bs); - -- if (use_local_qiov) { -- qemu_iovec_destroy(&local_qiov); -- qemu_vfree(head_buf); -- qemu_vfree(tail_buf); -- } -+ bdrv_padding_destroy(&pad); - - return ret; - } -@@ -1775,44 +1897,34 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, - BdrvTrackedRequest *req) - { - BlockDriverState *bs = child->bs; -- uint8_t *buf = NULL; - QEMUIOVector local_qiov; - uint64_t align = bs->bl.request_alignment; -- unsigned int head_padding_bytes, tail_padding_bytes; - int ret = 0; -+ bool padding; -+ BdrvRequestPadding pad; - -- head_padding_bytes = offset & (align - 1); -- tail_padding_bytes = (align - (offset + bytes)) & (align - 1); -- -- -- assert(flags & BDRV_REQ_ZERO_WRITE); -- if (head_padding_bytes || tail_padding_bytes) { -- buf = qemu_blockalign(bs, align); -- qemu_iovec_init_buf(&local_qiov, buf, align); -- } -- if (head_padding_bytes) { -- uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes); -- -- /* RMW the unaligned part before head. */ -+ padding = bdrv_init_padding(bs, offset, bytes, &pad); -+ if (padding) { - mark_request_serialising(req, align); - wait_serialising_requests(req); -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); -- ret = bdrv_aligned_preadv(child, req, offset & ~(align - 1), align, -- align, &local_qiov, 0); -- if (ret < 0) { -- goto fail; -- } -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); - -- memset(buf + head_padding_bytes, 0, zero_bytes); -- ret = bdrv_aligned_pwritev(child, req, offset & ~(align - 1), align, -- align, &local_qiov, -- flags & ~BDRV_REQ_ZERO_WRITE); -- if (ret < 0) { -- goto fail; -+ bdrv_padding_rmw_read(child, req, &pad, true); -+ -+ if (pad.head || pad.merge_reads) { -+ int64_t aligned_offset = offset & ~(align - 1); -+ int64_t write_bytes = pad.merge_reads ? pad.buf_len : align; -+ -+ qemu_iovec_init_buf(&local_qiov, pad.buf, write_bytes); -+ ret = bdrv_aligned_pwritev(child, req, aligned_offset, write_bytes, -+ align, &local_qiov, -+ flags & ~BDRV_REQ_ZERO_WRITE); -+ if (ret < 0 || pad.merge_reads) { -+ /* Error or all work is done */ -+ goto out; -+ } -+ offset += write_bytes - pad.head; -+ bytes -= write_bytes - pad.head; - } -- offset += zero_bytes; -- bytes -= zero_bytes; - } - - assert(!bytes || (offset & (align - 1)) == 0); -@@ -1822,7 +1934,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, - ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align, - NULL, flags); - if (ret < 0) { -- goto fail; -+ goto out; - } - bytes -= aligned_bytes; - offset += aligned_bytes; -@@ -1830,26 +1942,17 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, - - assert(!bytes || (offset & (align - 1)) == 0); - if (bytes) { -- assert(align == tail_padding_bytes + bytes); -- /* RMW the unaligned part after tail. */ -- mark_request_serialising(req, align); -- wait_serialising_requests(req); -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); -- ret = bdrv_aligned_preadv(child, req, offset, align, -- align, &local_qiov, 0); -- if (ret < 0) { -- goto fail; -- } -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); -+ assert(align == pad.tail + bytes); - -- memset(buf, 0, bytes); -+ qemu_iovec_init_buf(&local_qiov, pad.tail_buf, align); - ret = bdrv_aligned_pwritev(child, req, offset, align, align, - &local_qiov, flags & ~BDRV_REQ_ZERO_WRITE); - } --fail: -- qemu_vfree(buf); -- return ret; - -+out: -+ bdrv_padding_destroy(&pad); -+ -+ return ret; - } - - /* -@@ -1862,10 +1965,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, - BlockDriverState *bs = child->bs; - BdrvTrackedRequest req; - uint64_t align = bs->bl.request_alignment; -- uint8_t *head_buf = NULL; -- uint8_t *tail_buf = NULL; -- QEMUIOVector local_qiov; -- bool use_local_qiov = false; -+ BdrvRequestPadding pad; - int ret; - - trace_bdrv_co_pwritev(child->bs, offset, bytes, flags); -@@ -1892,86 +1992,21 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, - goto out; - } - -- if (offset & (align - 1)) { -- QEMUIOVector head_qiov; -- -+ if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) { - mark_request_serialising(&req, align); - wait_serialising_requests(&req); -- -- head_buf = qemu_blockalign(bs, align); -- qemu_iovec_init_buf(&head_qiov, head_buf, align); -- -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); -- ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align, -- align, &head_qiov, 0); -- if (ret < 0) { -- goto fail; -- } -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); -- -- qemu_iovec_init(&local_qiov, qiov->niov + 2); -- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1)); -- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); -- use_local_qiov = true; -- -- bytes += offset & (align - 1); -- offset = offset & ~(align - 1); -- -- /* We have read the tail already if the request is smaller -- * than one aligned block. -- */ -- if (bytes < align) { -- qemu_iovec_add(&local_qiov, head_buf + bytes, align - bytes); -- bytes = align; -- } -- } -- -- if ((offset + bytes) & (align - 1)) { -- QEMUIOVector tail_qiov; -- size_t tail_bytes; -- bool waited; -- -- mark_request_serialising(&req, align); -- waited = wait_serialising_requests(&req); -- assert(!waited || !use_local_qiov); -- -- tail_buf = qemu_blockalign(bs, align); -- qemu_iovec_init_buf(&tail_qiov, tail_buf, align); -- -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); -- ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1), -- align, align, &tail_qiov, 0); -- if (ret < 0) { -- goto fail; -- } -- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); -- -- if (!use_local_qiov) { -- qemu_iovec_init(&local_qiov, qiov->niov + 1); -- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); -- use_local_qiov = true; -- } -- -- tail_bytes = (offset + bytes) & (align - 1); -- qemu_iovec_add(&local_qiov, tail_buf + tail_bytes, align - tail_bytes); -- -- bytes = ROUND_UP(bytes, align); -+ bdrv_padding_rmw_read(child, &req, &pad, false); - } - - ret = bdrv_aligned_pwritev(child, &req, offset, bytes, align, -- use_local_qiov ? &local_qiov : qiov, -- flags); -+ qiov, flags); - --fail: -+ bdrv_padding_destroy(&pad); - -- if (use_local_qiov) { -- qemu_iovec_destroy(&local_qiov); -- } -- qemu_vfree(head_buf); -- qemu_vfree(tail_buf); - out: - tracked_request_end(&req); - bdrv_dec_in_flight(bs); -+ - return ret; - } - --- -2.23.0 diff --git a/block-iscsi-fix-double-free-on-BUSY-or-similar-statu.patch b/block-iscsi-fix-double-free-on-BUSY-or-similar-statu.patch new file mode 100644 index 0000000000000000000000000000000000000000..61ca0571f2638052ff454c2586a5bbb57bd514fe --- /dev/null +++ b/block-iscsi-fix-double-free-on-BUSY-or-similar-statu.patch @@ -0,0 +1,36 @@ +From 2d37c08cc6f274c48a4a65a446788e946f0363c0 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 28 Jun 2023 10:58:55 +0800 +Subject: [PATCH] block/iscsi: fix double-free on BUSY or similar statuses + +cheery-pick from 5080152e2ef6cde7aa692e29880c62bd54acb750 + +Commit 8c460269aa77 ("iscsi: base all handling of check condition on +scsi_sense_to_errno", 2019-07-15) removed a "goto out" so that the +same coroutine is re-entered twice; once from iscsi_co_generic_cb, +once from the timer callback iscsi_retry_timer_expired. This can +cause a crash. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1378 +Reported-by: Grzegorz Zdanowski +Signed-off-by: Paolo Bonzini +Signed-off-by: qihao_yewu +--- + block/iscsi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 57aa07a40d..61ccb58fc8 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -268,6 +268,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, + timer_mod(&iTask->retry_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); + iTask->do_retry = 1; ++ return; + } else if (status == SCSI_STATUS_CHECK_CONDITION) { + int error = iscsi_translate_sense(&task->sense); + if (error == EAGAIN) { +-- +2.41.0.windows.1 + diff --git a/block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch b/block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch deleted file mode 100644 index ba53c1ddb4381562aa1fe486ad7f0ce56923d1d7..0000000000000000000000000000000000000000 --- a/block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 547b06bb04287eb97ffb02e213aa8466c15cce65 Mon Sep 17 00:00:00 2001 -From: Chen Qun -Date: Mon, 16 Mar 2020 14:35:34 +0800 -Subject: [PATCH] block/iscsi: use MIN() between mx_sb_len and sb_len_wr - -Use MIN() macro between mx_sb_len and sb_len_wr the len for sbp copy data. - -Reported-by: Euler Robot -Signed-off-by: Chen Qun ---- - block/iscsi.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/block/iscsi.c b/block/iscsi.c -index 3f86aaf..5c3c598 100644 ---- a/block/iscsi.c -+++ b/block/iscsi.c -@@ -989,8 +989,7 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status, - acb->ioh->driver_status |= SG_ERR_DRIVER_SENSE; - - acb->ioh->sb_len_wr = acb->task->datain.size - 2; -- ss = (acb->ioh->mx_sb_len >= acb->ioh->sb_len_wr) ? -- acb->ioh->mx_sb_len : acb->ioh->sb_len_wr; -+ ss = MIN(acb->ioh->mx_sb_len, acb->ioh->sb_len_wr); - memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss); - } - --- -1.8.3.1 - diff --git a/block-mirror-fix-file-system-went-to-read-only-after.patch b/block-mirror-fix-file-system-went-to-read-only-after.patch new file mode 100644 index 0000000000000000000000000000000000000000..2126e83278425742c52f2cbd5f391fee7a70c3a0 --- /dev/null +++ b/block-mirror-fix-file-system-went-to-read-only-after.patch @@ -0,0 +1,32 @@ +From 7448eb87ee59856aa0f0853f2aa5b803c832fccf Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 21:37:49 +0800 +Subject: [PATCH] block/mirror: fix file-system went to read-only after + block-mirror + +config vm disk with prdm, keep the disk writing data continuously +during block-mirror, the file-system will went to read-only after +block-mirror, fix it. + +Signed-off-by: caojinhua +Signed-off-by: jiangdongxu +--- + block/mirror.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/mirror.c b/block/mirror.c +index efec2c7674..b7f0cba9b9 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1640,7 +1640,7 @@ static BlockJob *mirror_start_job( + * reads on the top, while disabling it in the intermediate nodes, and make + * the backing chain writable. */ + mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name, +- BDRV_O_RDWR, errp); ++ BDRV_O_RDWR | BDRV_O_NOCACHE, errp); + if (mirror_top_bs == NULL) { + return NULL; + } +-- +2.27.0 + diff --git a/block-mirror-fix-use-after-free-of-local_err.patch b/block-mirror-fix-use-after-free-of-local_err.patch deleted file mode 100644 index ea2f739410164f7df43f020192cd60653a3b8cf0..0000000000000000000000000000000000000000 --- a/block-mirror-fix-use-after-free-of-local_err.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 682d23829adf0a872d5a3ca6eb4b31c424f558fc Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 24 Mar 2020 18:36:26 +0300 -Subject: [PATCH 09/14] block/mirror: fix use after free of local_err - -local_err is used again in mirror_exit_common() after -bdrv_set_backing_hd(), so we must zero it. Otherwise try to set -non-NULL local_err will crash. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200324153630.11882-3-vsementsov@virtuozzo.com> -Reviewed-by: Eric Blake -Reviewed-by: John Snow -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - block/mirror.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block/mirror.c b/block/mirror.c -index 681b305de650..ef6c958ff9b3 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -674,6 +674,7 @@ static int mirror_exit_common(Job *job) - bdrv_set_backing_hd(target_bs, backing, &local_err); - if (local_err) { - error_report_err(local_err); -+ local_err = NULL; - ret = -EPERM; - } - } --- -2.26.2 - diff --git a/block-monitor-Fix-crash-when-executing-HMP-commit.patch b/block-monitor-Fix-crash-when-executing-HMP-commit.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f57f31d8f29e3dde2ed4b4f0bee8fcfb89cc01d --- /dev/null +++ b/block-monitor-Fix-crash-when-executing-HMP-commit.patch @@ -0,0 +1,54 @@ +From 33dfb9d81a8cfe17aaa3f0804cbd491b06d38cd6 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 27 Jun 2023 14:40:13 +0800 +Subject: [PATCH] block/monitor: Fix crash when executing HMP commit + +cheery-pick from b7b814cd87a5fbe9f0fb5732dd28932699317bda + +hmp_commit() calls blk_is_available() from a non-coroutine context (and +in the main loop). blk_is_available() is a co_wrapper_mixed_bdrv_rdlock +function, and in the non-coroutine context it calls AIO_WAIT_WHILE(), +which crashes if the aio_context lock is not taken before. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1615 +Signed-off-by: Wang Liang +Message-Id: <20230424103902.45265-1-wangliangzz@126.com> +Reviewed-by: Emanuele Giuseppe Esposito +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 8c1e8fb2e7fc2cbeb57703e143965a4cd3ad301a) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + block/monitor/block-hmp-cmds.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c +index 2ac4aedfff..44f0af3430 100644 +--- a/block/monitor/block-hmp-cmds.c ++++ b/block/monitor/block-hmp-cmds.c +@@ -213,15 +213,17 @@ void hmp_commit(Monitor *mon, const QDict *qdict) + error_report("Device '%s' not found", device); + return; + } +- if (!blk_is_available(blk)) { +- error_report("Device '%s' has no medium", device); +- return; +- } + + bs = bdrv_skip_implicit_filters(blk_bs(blk)); + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + ++ if (!blk_is_available(blk)) { ++ error_report("Device '%s' has no medium", device); ++ aio_context_release(aio_context); ++ return; ++ } ++ + ret = bdrv_commit(bs); + + aio_context_release(aio_context); +-- +2.41.0.windows.1 + diff --git a/block-nbd-Assert-there-are-no-timers-when-closed.patch b/block-nbd-Assert-there-are-no-timers-when-closed.patch new file mode 100644 index 0000000000000000000000000000000000000000..da3badd97ae37bc26297c8a7de35e5fa022a3d9a --- /dev/null +++ b/block-nbd-Assert-there-are-no-timers-when-closed.patch @@ -0,0 +1,38 @@ +From 8353d0d6a31042ba7c54696ef1ec59eb883d647f Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Mon, 29 Aug 2022 15:37:08 +0800 +Subject: [PATCH 4/5] block/nbd: Assert there are no timers when closed + +Our two timers must not remain armed beyond nbd_clear_bdrvstate(), or +they will access freed data when they fire. + +This patch is separate from the patches that actually fix the issue +(HEAD^^ and HEAD^) so that you can run the associated regression iotest +(281) on a configuration that reproducibly exposes the bug. + +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Hanna Reitz +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Zhang Bo +--- + block/nbd.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/block/nbd.c b/block/nbd.c +index 5ff8a57314..dc6c3f3bbc 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -110,6 +110,10 @@ static void nbd_clear_bdrvstate(BlockDriverState *bs) + + yank_unregister_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name)); + ++ /* Must not leave timers behind that would access freed data */ ++ assert(!s->reconnect_delay_timer); ++ assert(!s->open_timer); ++ + object_unref(OBJECT(s->tlscreds)); + qapi_free_SocketAddress(s->saddr); + s->saddr = NULL; +-- +2.27.0 + diff --git a/block-nbd-Delete-open-timer-when-done.patch b/block-nbd-Delete-open-timer-when-done.patch new file mode 100644 index 0000000000000000000000000000000000000000..f8cebada722ac193250137c90c6691f7136f4b22 --- /dev/null +++ b/block-nbd-Delete-open-timer-when-done.patch @@ -0,0 +1,48 @@ +From 6a49e752439f02ef9ccaac30d14acf185e31a261 Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Mon, 29 Aug 2022 15:35:36 +0800 +Subject: [PATCH 3/5] block/nbd: Delete open timer when done + +We start the open timer to cancel the connection attempt after a while. +Once nbd_do_establish_connection() has returned, the attempt is over, +and we no longer need the timer. + +Delete it before returning from nbd_open(), so that it does not persist +for longer. It has no use after nbd_open(), and just like the reconnect +delay timer, it might well be dangerous if it were to fire afterwards. + +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Hanna Reitz +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Zhang Bo +--- + block/nbd.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/block/nbd.c b/block/nbd.c +index 16cd7fef77..5ff8a57314 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -1885,11 +1885,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + ++ /* ++ * The connect attempt is done, so we no longer need this timer. ++ * Delete it, because we do not want it to be around when this node ++ * is drained or closed. ++ */ ++ open_timer_del(s); ++ + nbd_client_connection_enable_retry(s->conn); + + return 0; + + fail: ++ open_timer_del(s); + nbd_clear_bdrvstate(bs); + return ret; + } +-- +2.27.0 + diff --git a/block-nbd-Delete-reconnect-delay-timer-when-done.patch b/block-nbd-Delete-reconnect-delay-timer-when-done.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7ca363f09737b48f723b99af7ac0f39fc043e60 --- /dev/null +++ b/block-nbd-Delete-reconnect-delay-timer-when-done.patch @@ -0,0 +1,45 @@ +From a4d001a08ce1279b121cb870c378ddeb0825f2bc Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Mon, 29 Aug 2022 15:34:07 +0800 +Subject: [PATCH 2/5] block/nbd: Delete reconnect delay timer when done + +We start the reconnect delay timer to cancel the reconnection attempt +after a while. Once nbd_co_do_establish_connection() has returned, this +attempt is over, and we no longer need the timer. + +Delete it before returning from nbd_reconnect_attempt(), so that it does +not persist beyond the I/O request that was paused for reconnecting; we +do not want it to fire in a drained section, because all sort of things +can happen in such a section (e.g. the AioContext might be changed, and +we do not want the timer to fire in the wrong context; or the BDS might +even be deleted, and so the timer CB would access already-freed data). + +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Hanna Reitz +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Zhang Bo +--- + block/nbd.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/block/nbd.c b/block/nbd.c +index 63dbfa807d..16cd7fef77 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -381,6 +381,13 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) + } + + nbd_co_do_establish_connection(s->bs, NULL); ++ ++ /* ++ * The reconnect attempt is done (maybe successfully, maybe not), so ++ * we no longer need this timer. Delete it so it will not outlive ++ * this I/O request (so draining removes all timers). ++ */ ++ reconnect_delay_timer_del(s); + } + + static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle) +-- +2.27.0 + diff --git a/block-nbd-Move-s-ioc-on-AioContext-change.patch b/block-nbd-Move-s-ioc-on-AioContext-change.patch new file mode 100644 index 0000000000000000000000000000000000000000..f39430e46062687ee2f3c125d2d3d953fa95ed19 --- /dev/null +++ b/block-nbd-Move-s-ioc-on-AioContext-change.patch @@ -0,0 +1,97 @@ +From ba810e3b3800f0d084a2dd324a9dea89c9320548 Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Mon, 29 Aug 2022 15:38:19 +0800 +Subject: [PATCH 5/5] block/nbd: Move s->ioc on AioContext change + +s->ioc must always be attached to the NBD node's AioContext. If that +context changes, s->ioc must be attached to the new context. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2033626 +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Hanna Reitz +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Zhang Bo +--- + block/nbd.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/block/nbd.c b/block/nbd.c +index dc6c3f3bbc..5853d85d60 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -2055,6 +2055,42 @@ static void nbd_cancel_in_flight(BlockDriverState *bs) + nbd_co_establish_connection_cancel(s->conn); + } + ++static void nbd_attach_aio_context(BlockDriverState *bs, ++ AioContext *new_context) ++{ ++ BDRVNBDState *s = bs->opaque; ++ ++ /* The open_timer is used only during nbd_open() */ ++ assert(!s->open_timer); ++ ++ /* ++ * The reconnect_delay_timer is scheduled in I/O paths when the ++ * connection is lost, to cancel the reconnection attempt after a ++ * given time. Once this attempt is done (successfully or not), ++ * nbd_reconnect_attempt() ensures the timer is deleted before the ++ * respective I/O request is resumed. ++ * Since the AioContext can only be changed when a node is drained, ++ * the reconnect_delay_timer cannot be active here. ++ */ ++ assert(!s->reconnect_delay_timer); ++ ++ if (s->ioc) { ++ qio_channel_attach_aio_context(s->ioc, new_context); ++ } ++} ++ ++static void nbd_detach_aio_context(BlockDriverState *bs) ++{ ++ BDRVNBDState *s = bs->opaque; ++ ++ assert(!s->open_timer); ++ assert(!s->reconnect_delay_timer); ++ ++ if (s->ioc) { ++ qio_channel_detach_aio_context(s->ioc); ++ } ++} ++ + static BlockDriver bdrv_nbd = { + .format_name = "nbd", + .protocol_name = "nbd", +@@ -2078,6 +2114,9 @@ static BlockDriver bdrv_nbd = { + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, + .bdrv_cancel_in_flight = nbd_cancel_in_flight, ++ ++ .bdrv_attach_aio_context = nbd_attach_aio_context, ++ .bdrv_detach_aio_context = nbd_detach_aio_context, + }; + + static BlockDriver bdrv_nbd_tcp = { +@@ -2103,6 +2142,9 @@ static BlockDriver bdrv_nbd_tcp = { + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, + .bdrv_cancel_in_flight = nbd_cancel_in_flight, ++ ++ .bdrv_attach_aio_context = nbd_attach_aio_context, ++ .bdrv_detach_aio_context = nbd_detach_aio_context, + }; + + static BlockDriver bdrv_nbd_unix = { +@@ -2128,6 +2170,9 @@ static BlockDriver bdrv_nbd_unix = { + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, + .bdrv_cancel_in_flight = nbd_cancel_in_flight, ++ ++ .bdrv_attach_aio_context = nbd_attach_aio_context, ++ .bdrv_detach_aio_context = nbd_detach_aio_context, + }; + + static void bdrv_nbd_init(void) +-- +2.27.0 + diff --git a/block-nbd-extract-the-common-cleanup-code.patch b/block-nbd-extract-the-common-cleanup-code.patch deleted file mode 100644 index 4cc24818b7c96cc8c85a0c8ac97dc2452c234610..0000000000000000000000000000000000000000 --- a/block-nbd-extract-the-common-cleanup-code.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 1196a2079a558cbb673e06142fa67a401c5e6c30 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Thu, 5 Dec 2019 11:45:27 +0800 -Subject: [PATCH 6/9] block/nbd: extract the common cleanup code - -The BDRVNBDState cleanup code is common in two places, add -nbd_clear_bdrvstate() function to do these cleanups. - -Suggested-by: Stefano Garzarella -Signed-off-by: Pan Nengyuan -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-Id: <1575517528-44312-2-git-send-email-pannengyuan@huawei.com> -Reviewed-by: Eric Blake -[eblake: fix compilation error and commit message] -Signed-off-by: Eric Blake -Signed-off-by: AlexChen ---- - block/nbd.c | 19 ++++++++++++------- - 1 file changed, 12 insertions(+), 7 deletions(-) - -diff --git a/block/nbd.c b/block/nbd.c -index 57c1a20..3977b1e 100644 ---- a/block/nbd.c -+++ b/block/nbd.c -@@ -73,6 +73,16 @@ typedef struct BDRVNBDState { - char *export, *tlscredsid; - } BDRVNBDState; - -+static void nbd_clear_bdrvstate(BDRVNBDState *s) -+{ -+ qapi_free_SocketAddress(s->saddr); -+ s->saddr = NULL; -+ g_free(s->export); -+ s->export = NULL; -+ g_free(s->tlscredsid); -+ s->tlscredsid = NULL; -+} -+ - static void nbd_recv_coroutines_wake_all(BDRVNBDState *s) - { - int i; -@@ -1640,9 +1650,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, - object_unref(OBJECT(tlscreds)); - } - if (ret < 0) { -- qapi_free_SocketAddress(s->saddr); -- g_free(s->export); -- g_free(s->tlscredsid); -+ nbd_clear_bdrvstate(s); - } - qemu_opts_del(opts); - return ret; -@@ -1692,10 +1700,7 @@ static void nbd_close(BlockDriverState *bs) - BDRVNBDState *s = bs->opaque; - - nbd_client_close(bs); -- -- qapi_free_SocketAddress(s->saddr); -- g_free(s->export); -- g_free(s->tlscredsid); -+ nbd_clear_bdrvstate(s); - } - - static int64_t nbd_getlength(BlockDriverState *bs) --- -1.8.3.1 - diff --git a/block-nbd.c-Fixed-IO-request-coroutine-not-being-wak.patch b/block-nbd.c-Fixed-IO-request-coroutine-not-being-wak.patch new file mode 100644 index 0000000000000000000000000000000000000000..99bbf55ac5026d120c2c492e2e3079bd41657b53 --- /dev/null +++ b/block-nbd.c-Fixed-IO-request-coroutine-not-being-wak.patch @@ -0,0 +1,100 @@ +From 09f03d6bd8842b58e6a1e50cf9c44a788b8d2693 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 4 Aug 2023 07:40:46 +0000 +Subject: [PATCH] block/nbd.c: Fixed IO request coroutine not being wakeup + when kill NBD server mainline inclusion commit + 6690302b848e5b55e3e3da34f0ee7fd9f8602e23 category: bugfix + +--------------------------------------------------------------- + +During the IO stress test, the IO request coroutine has a probability that is +can't be awakened when the NBD server is killed. + +The GDB stack is as follows: +(gdb) bt +0 0x00007f2ff990cbf6 in __ppoll (fds=0x55575de85000, nfds=1, timeout=, sigmask=0x0) at ../sysdeps/unix/sysv/linux/ppoll.c:44 +1 0x000055575c302e7c in qemu_poll_ns (fds=0x55575de85000, nfds=1, timeout=599999603140) at ../util/qemu-timer.c:348 +2 0x000055575c2d3c34 in fdmon_poll_wait (ctx=0x55575dc480f0, ready_list=0x7ffd9dd1dae0, timeout=599999603140) at ../util/fdmon-poll.c:80 +3 0x000055575c2d350d in aio_poll (ctx=0x55575dc480f0, blocking=true) at ../util/aio-posix.c:655 +4 0x000055575c16eabd in bdrv_do_drained_begin(bs=0x55575dee7fe0, recursive=false, parent=0x0, ignore_bds_parents=false, poll=true)at ../block/io.c:474 +5 0x000055575c16eba6 in bdrv_drained_begin (bs=0x55575dee7fe0) at ../block/io.c:480 +6 0x000055575c1aff33 in quorum_del_child (bs=0x55575dee7fe0, child=0x55575dcea690, errp=0x7ffd9dd1dd08) at ../block/quorum.c:1130 +7 0x000055575c14239b in bdrv_del_child (parent_bs=0x55575dee7fe0, child=0x55575dcea690, errp=0x7ffd9dd1dd08) at ../block.c:7705 +8 0x000055575c12da28 in qmp_x_blockdev_change(parent=0x55575df404c0 "colo-disk0", has_child=true, child=0x55575de867f0 "children.1", has_node=false, no de=0x0, errp=0x7ffd9dd1dd08) at ../blockdev.c:3676 +9 0x000055575c258435 in qmp_marshal_x_blockdev_change (args=0x7f2fec008190, ret=0x7f2ff7b0bd98, errp=0x7f2ff7b0bd90) at qapi/qapi-commands-block-core.c :1675 +10 0x000055575c2c6201 in do_qmp_dispatch_bh (opaque=0x7f2ff7b0be30) at ../qapi/qmp-dispatch.c:129 +11 0x000055575c2ebb1c in aio_bh_call (bh=0x55575dc429c0) at ../util/async.c:141 +12 0x000055575c2ebc2a in aio_bh_poll (ctx=0x55575dc480f0) at ../util/async.c:169 +13 0x000055575c2d2d96 in aio_dispatch (ctx=0x55575dc480f0) at ../util/aio-posix.c:415 +14 0x000055575c2ec07f in aio_ctx_dispatch (source=0x55575dc480f0, callback=0x0, user_data=0x0) at ../util/async.c:311 +15 0x00007f2ff9e7cfbd in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 +16 0x000055575c2fd581 in glib_pollfds_poll () at ../util/main-loop.c:232 +17 0x000055575c2fd5ff in os_host_main_loop_wait (timeout=0) at ../util/main-loop.c:255 +18 0x000055575c2fd710 in main_loop_wait (nonblocking=0) at ../util/main-loop.c:531 +19 0x000055575bfa7588 in qemu_main_loop () at ../softmmu/runstate.c:726 +20 0x000055575bbee57a in main (argc=60, argv=0x7ffd9dd1e0e8, envp=0x7ffd9dd1e2d0) at ../softmmu/main.c:50 + +(gdb) qemu coroutine 0x55575e16aac0 +0 0x000055575c2ee7dc in qemu_coroutine_switch (from_=0x55575e16aac0, to_=0x7f2ff830fba0, action=COROUTINE_YIELD) at ../util/coroutine-ucontext.c:302 +1 0x000055575c2fe2a9 in qemu_coroutine_yield () at ../util/qemu-coroutine.c:195 +2 0x000055575c2fe93c in qemu_co_queue_wait_impl (queue=0x55575dc46170, lock=0x7f2b32ad9850) at ../util/qemu-coroutine-lock.c:56 +3 0x000055575c17ddfb in nbd_co_send_request (bs=0x55575ebfaf20, request=0x7f2b32ad9920, qiov=0x55575dfc15d8) at ../block/nbd.c:478 +4 0x000055575c17f931 in nbd_co_request (bs=0x55575ebfaf20, request=0x7f2b32ad9920, write_qiov=0x55575dfc15d8) at ../block/nbd.c:1182 +5 0x000055575c17fe14 in nbd_client_co_pwritev (bs=0x55575ebfaf20, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, flags=0) at ../block/nbd.c:1284 +6 0x000055575c170d25 in bdrv_driver_pwritev (bs=0x55575ebfaf20, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) + at ../block/io.c:1264 +7 0x000055575c1733b4 in bdrv_aligned_pwritev + (child=0x55575dff6890, req=0x7f2b32ad9ad0, offset=403487858688, bytes=4538368, align=1, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) at ../block/io.c:2126 +8 0x000055575c173c67 in bdrv_co_pwritev_part (child=0x55575dff6890, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) + at ../block/io.c:2314 +9 0x000055575c17391b in bdrv_co_pwritev (child=0x55575dff6890, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, flags=0) at ../block/io.c:2233 +10 0x000055575c1ee506 in replication_co_writev (bs=0x55575e9824f0, sector_num=788062224, remaining_sectors=8864, qiov=0x55575dfc15d8, flags=0) + at ../block/replication.c:270 +11 0x000055575c170eed in bdrv_driver_pwritev (bs=0x55575e9824f0, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) + at ../block/io.c:1297 +12 0x000055575c1733b4 in bdrv_aligned_pwritev + (child=0x55575dcea690, req=0x7f2b32ad9e00, offset=403487858688, bytes=4538368, align=512, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) + at ../block/io.c:2126 +13 0x000055575c173c67 in bdrv_co_pwritev_part (child=0x55575dcea690, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, qiov_offset=0, flags=0) + at ../block/io.c:2314 +14 0x000055575c17391b in bdrv_co_pwritev (child=0x55575dcea690, offset=403487858688, bytes=4538368, qiov=0x55575dfc15d8, flags=0) at ../block/io.c:2233 +15 0x000055575c1aeffa in write_quorum_entry (opaque=0x7f2fddaf8c50) at ../block/quorum.c:699 +16 0x000055575c2ee4db in coroutine_trampoline (i0=1578543808, i1=21847) at ../util/coroutine-ucontext.c:173 +17 0x00007f2ff9855660 in __start_context () at ../sysdeps/unix/sysv/linux/x86_64/__start_context.S:91 + +When we do failover in COLO mode, QEMU will hang while it is waiting for +the in-flight IO. From the call trace, we can see the IO request coroutine +has yielded in nbd_co_send_request(). When we kill the NBD server, it will never +be wake up. Actually, when we do IO stress test, it will have a lot of +requests in free_sema queue. When the NBD server is killed, current +MAX_NBD_REQUESTS finishes with errors but they wake up at most +MAX_NBD_REQEUSTS from the queue. So, let's move qemu_co_queue_next out +to fix this issue. + +Signed-off-by: Lei Rao +Message-Id: <20220309074844.275450-1-lei.rao@intel.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake + +Signed-off-by: tangbinzy +--- + block/nbd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/nbd.c b/block/nbd.c +index 5853d85d60..33adfddc41 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -529,8 +529,8 @@ err: + if (i != -1) { + s->requests[i].coroutine = NULL; + s->in_flight--; +- qemu_co_queue_next(&s->free_sema); + } ++ qemu_co_queue_next(&s->free_sema); + } + qemu_co_mutex_unlock(&s->send_mutex); + return rc; +-- +2.41.0.windows.1 + diff --git a/block-nfs-Fix-32-bit-Windows-build.patch b/block-nfs-Fix-32-bit-Windows-build.patch new file mode 100644 index 0000000000000000000000000000000000000000..257ed1be0cc3c02cea69a64f143a64148197c239 --- /dev/null +++ b/block-nfs-Fix-32-bit-Windows-build.patch @@ -0,0 +1,58 @@ +From 5969f357385914e29a847c030d195cb8476f38c4 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 3 Aug 2023 19:19:26 +0800 +Subject: [PATCH] block/nfs: Fix 32-bit Windows build + +cheery-pick from 588fec8a4c3fe9e0d1cb3f7ea6fdd46221e42814 + +libnfs.h declares nfs_fstat() as the following for win32: + +int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, +struct __stat64 *st); + +The 'st' parameter should be of type 'struct __stat64'. The +codes happen to build successfully for 64-bit Windows, but it +does not build for 32-bit Windows. + +Fixes: 6542aa9c75bc ("block: add native support for NFS") +Fixes: 18a8056e0bc7 ("block/nfs: cache allocated filesize for read-only files") +Signed-off-by: Bin Meng +Message-Id: <20220908132817.1831008-6-bmeng.cn@gmail.com> +Reviewed-by: Stefan Weil +Signed-off-by: Stefan Weil +Signed-off-by: qihao_yewu +--- + block/nfs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/block/nfs.c b/block/nfs.c +index 577aea1d22..56b25829cf 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -418,7 +418,11 @@ static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts, + int flags, int open_flags, Error **errp) + { + int64_t ret = -EINVAL; ++#ifdef _WIN32 ++ struct __stat64 st; ++#else + struct stat st; ++#endif + char *file = NULL, *strp = NULL; + + qemu_mutex_init(&client->mutex); +@@ -781,7 +785,11 @@ static int nfs_reopen_prepare(BDRVReopenState *state, + BlockReopenQueue *queue, Error **errp) + { + NFSClient *client = state->bs->opaque; ++#ifdef _WIN32 ++ struct __stat64 st; ++#else + struct stat st; ++#endif + int ret = 0; + + if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) { +-- +2.41.0.windows.1 + diff --git a/block-nfs-tear-down-aio-before-nfs_close.patch b/block-nfs-tear-down-aio-before-nfs_close.patch deleted file mode 100644 index ea116d0a381c18521da88b94d3ea914f0357939d..0000000000000000000000000000000000000000 --- a/block-nfs-tear-down-aio-before-nfs_close.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0694c489cd240620fee5675e8d24c7ce02d1d67d Mon Sep 17 00:00:00 2001 -From: Peter Lieven -Date: Tue, 10 Sep 2019 17:41:09 +0200 -Subject: [PATCH] block/nfs: tear down aio before nfs_close - -nfs_close is a sync call from libnfs and has its own event -handler polling on the nfs FD. Avoid that both QEMU and libnfs -are intefering here. - -CC: qemu-stable@nongnu.org -Signed-off-by: Peter Lieven -Signed-off-by: Kevin Wolf -(cherry picked from commit 601dc6559725f7a614b6f893611e17ff0908e914) -Signed-off-by: Michael Roth ---- - block/nfs.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/block/nfs.c b/block/nfs.c -index d93241b3bb..2b7a078241 100644 ---- a/block/nfs.c -+++ b/block/nfs.c -@@ -390,12 +390,14 @@ static void nfs_attach_aio_context(BlockDriverState *bs, - static void nfs_client_close(NFSClient *client) - { - if (client->context) { -+ qemu_mutex_lock(&client->mutex); -+ aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), -+ false, NULL, NULL, NULL, NULL); -+ qemu_mutex_unlock(&client->mutex); - if (client->fh) { - nfs_close(client->context, client->fh); - client->fh = NULL; - } -- aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), -- false, NULL, NULL, NULL, NULL); - nfs_destroy_context(client->context); - client->context = NULL; - } --- -2.23.0 diff --git a/block-nvme-fix-infinite-loop-in-nvme_free_req_queue_.patch b/block-nvme-fix-infinite-loop-in-nvme_free_req_queue_.patch new file mode 100644 index 0000000000000000000000000000000000000000..eb0595fa8c37155f12a61a658046482cb34f1b88 --- /dev/null +++ b/block-nvme-fix-infinite-loop-in-nvme_free_req_queue_.patch @@ -0,0 +1,64 @@ +From ba31baabf9ad582c8a256a58123c036b6a70ba15 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Fri, 1 Dec 2023 10:00:41 +0800 +Subject: [PATCH] block/nvme: fix infinite loop in nvme_free_req_queue_cb() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit cf4fbc3030c974fff726756a7ceef8386cdf500b + +When the request free list is exhausted the coroutine waits on +q->free_req_queue for the next free request. Whenever a request is +completed a BH is scheduled to invoke nvme_free_req_queue_cb() and wake +up waiting coroutines. + +1. nvme_get_free_req() waits for a free request: + + while (q->free_req_head == -1) { + ... + trace_nvme_free_req_queue_wait(q->s, q->index); + qemu_co_queue_wait(&q->free_req_queue, &q->lock); + ... + } + +2. nvme_free_req_queue_cb() wakes up the coroutine: + + while (qemu_co_enter_next(&q->free_req_queue, &q->lock)) { + ^--- infinite loop when free_req_head == -1 + } + +nvme_free_req_queue_cb() and the coroutine form an infinite loop when +q->free_req_head == -1. Fix this by checking q->free_req_head in +nvme_free_req_queue_cb(). If the free request list is exhausted, don't +wake waiting coroutines. Eventually an in-flight request will complete +and the BH will be scheduled again, guaranteeing forward progress. + +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20211208152246.244585-1-stefanha@redhat.com +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Luo Yifan +--- + block/nvme.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/nvme.c b/block/nvme.c +index e4f336d79c..fa360b9b3c 100644 +--- a/block/nvme.c ++++ b/block/nvme.c +@@ -206,8 +206,9 @@ static void nvme_free_req_queue_cb(void *opaque) + NVMeQueuePair *q = opaque; + + qemu_mutex_lock(&q->lock); +- while (qemu_co_enter_next(&q->free_req_queue, &q->lock)) { +- /* Retry all pending requests */ ++ while (q->free_req_head != -1 && ++ qemu_co_enter_next(&q->free_req_queue, &q->lock)) { ++ /* Retry waiting requests */ + } + qemu_mutex_unlock(&q->lock); + } +-- +2.27.0 + diff --git a/block-posix-Always-allocate-the-first-block.patch b/block-posix-Always-allocate-the-first-block.patch deleted file mode 100644 index 166d73957ce0569929276d446a1934be17cad612..0000000000000000000000000000000000000000 --- a/block-posix-Always-allocate-the-first-block.patch +++ /dev/null @@ -1,343 +0,0 @@ -From 3d018ff3bdd8aec260254036b600cfa8d694ced4 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Tue, 27 Aug 2019 04:05:27 +0300 -Subject: [PATCH] block: posix: Always allocate the first block - -When creating an image with preallocation "off" or "falloc", the first -block of the image is typically not allocated. When using Gluster -storage backed by XFS filesystem, reading this block using direct I/O -succeeds regardless of request length, fooling alignment detection. - -In this case we fallback to a safe value (4096) instead of the optimal -value (512), which may lead to unneeded data copying when aligning -requests. Allocating the first block avoids the fallback. - -Since we allocate the first block even with preallocation=off, we no -longer create images with zero disk size: - - $ ./qemu-img create -f raw test.raw 1g - Formatting 'test.raw', fmt=raw size=1073741824 - - $ ls -lhs test.raw - 4.0K -rw-r--r--. 1 nsoffer nsoffer 1.0G Aug 16 23:48 test.raw - -And converting the image requires additional cluster: - - $ ./qemu-img measure -f raw -O qcow2 test.raw - required size: 458752 - fully allocated size: 1074135040 - -When using format like vmdk with multiple files per image, we allocate -one block per file: - - $ ./qemu-img create -f vmdk -o subformat=twoGbMaxExtentFlat test.vmdk 4g - Formatting 'test.vmdk', fmt=vmdk size=4294967296 compat6=off hwversion=undefined subformat=twoGbMaxExtentFlat - - $ ls -lhs test*.vmdk - 4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f001.vmdk - 4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f002.vmdk - 4.0K -rw-r--r--. 1 nsoffer nsoffer 353 Aug 27 03:23 test.vmdk - -I did quick performance test for copying disks with qemu-img convert to -new raw target image to Gluster storage with sector size of 512 bytes: - - for i in $(seq 10); do - rm -f dst.raw - sleep 10 - time ./qemu-img convert -f raw -O raw -t none -T none src.raw dst.raw - done - -Here is a table comparing the total time spent: - -Type Before(s) After(s) Diff(%) ---------------------------------------- -real 530.028 469.123 -11.4 -user 17.204 10.768 -37.4 -sys 17.881 7.011 -60.7 - -We can see very clear improvement in CPU usage. - -Signed-off-by: Nir Soffer -Message-id: 20190827010528.8818-2-nsoffer@redhat.com -Reviewed-by: Max Reitz -Signed-off-by: Max Reitz - -(cherry picked from commit 3a20013fbb26d2a1bd11ef148eefdb1508783787) - -Signed-off-by: Michael Roth ---- - block/file-posix.c | 51 +++++++++++++++++++ - tests/qemu-iotests/059.out | 2 +- - tests/qemu-iotests/{150.out => 150.out.qcow2} | 0 - tests/qemu-iotests/150.out.raw | 12 +++++ - tests/qemu-iotests/175 | 19 ++++--- - tests/qemu-iotests/175.out | 8 +-- - tests/qemu-iotests/178.out.qcow2 | 4 +- - tests/qemu-iotests/221.out | 12 +++-- - tests/qemu-iotests/253.out | 12 +++-- - 9 files changed, 99 insertions(+), 21 deletions(-) - rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%) - create mode 100644 tests/qemu-iotests/150.out.raw - -diff --git a/block/file-posix.c b/block/file-posix.c -index be32dd8c51..2184aa980c 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -1674,6 +1674,43 @@ static int handle_aiocb_discard(void *opaque) - return ret; - } - -+/* -+ * Help alignment probing by allocating the first block. -+ * -+ * When reading with direct I/O from unallocated area on Gluster backed by XFS, -+ * reading succeeds regardless of request length. In this case we fallback to -+ * safe alignment which is not optimal. Allocating the first block avoids this -+ * fallback. -+ * -+ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or -+ * request alignment, so we use safe values. -+ * -+ * Returns: 0 on success, -errno on failure. Since this is an optimization, -+ * caller may ignore failures. -+ */ -+static int allocate_first_block(int fd, size_t max_size) -+{ -+ size_t write_size = (max_size < MAX_BLOCKSIZE) -+ ? BDRV_SECTOR_SIZE -+ : MAX_BLOCKSIZE; -+ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); -+ void *buf; -+ ssize_t n; -+ int ret; -+ -+ buf = qemu_memalign(max_align, write_size); -+ memset(buf, 0, write_size); -+ -+ do { -+ n = pwrite(fd, buf, write_size, 0); -+ } while (n == -1 && errno == EINTR); -+ -+ ret = (n == -1) ? -errno : 0; -+ -+ qemu_vfree(buf); -+ return ret; -+} -+ - static int handle_aiocb_truncate(void *opaque) - { - RawPosixAIOData *aiocb = opaque; -@@ -1713,6 +1750,17 @@ static int handle_aiocb_truncate(void *opaque) - /* posix_fallocate() doesn't set errno. */ - error_setg_errno(errp, -result, - "Could not preallocate new data"); -+ } else if (current_length == 0) { -+ /* -+ * posix_fallocate() uses fallocate() if the filesystem -+ * supports it, or fallback to manually writing zeroes. If -+ * fallocate() was used, unaligned reads from the fallocated -+ * area in raw_probe_alignment() will succeed, hence we need to -+ * allocate the first block. -+ * -+ * Optimize future alignment probing; ignore failures. -+ */ -+ allocate_first_block(fd, offset); - } - } else { - result = 0; -@@ -1774,6 +1822,9 @@ static int handle_aiocb_truncate(void *opaque) - if (ftruncate(fd, offset) != 0) { - result = -errno; - error_setg_errno(errp, -result, "Could not resize file"); -+ } else if (current_length == 0 && offset > current_length) { -+ /* Optimize future alignment probing; ignore failures. */ -+ allocate_first_block(fd, offset); - } - return result; - default: -diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out -index 4fab42a28c..fe3f861f3c 100644 ---- a/tests/qemu-iotests/059.out -+++ b/tests/qemu-iotests/059.out -@@ -27,7 +27,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMax - image: TEST_DIR/t.vmdk - file format: vmdk - virtual size: 0.977 TiB (1073741824000 bytes) --disk size: 16 KiB -+disk size: 1.97 MiB - Format specific information: - cid: XXXXXXXX - parent cid: XXXXXXXX -diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2 -similarity index 100% -rename from tests/qemu-iotests/150.out -rename to tests/qemu-iotests/150.out.qcow2 -diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw -new file mode 100644 -index 0000000000..3cdc7727a5 ---- /dev/null -+++ b/tests/qemu-iotests/150.out.raw -@@ -0,0 +1,12 @@ -+QA output created by 150 -+ -+=== Mapping sparse conversion === -+ -+Offset Length File -+0 0x1000 TEST_DIR/t.IMGFMT -+ -+=== Mapping non-sparse conversion === -+ -+Offset Length File -+0 0x100000 TEST_DIR/t.IMGFMT -+*** done -diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 -index 51e62c8276..7ba28b3c1b 100755 ---- a/tests/qemu-iotests/175 -+++ b/tests/qemu-iotests/175 -@@ -37,14 +37,16 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 - # the file size. This function hides the resulting difference in the - # stat -c '%b' output. - # Parameter 1: Number of blocks an empty file occupies --# Parameter 2: Image size in bytes -+# Parameter 2: Minimal number of blocks in an image -+# Parameter 3: Image size in bytes - _filter_blocks() - { - extra_blocks=$1 -- img_size=$2 -+ min_blocks=$2 -+ img_size=$3 - -- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \ -- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/" -+ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \ -+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/" - } - - # get standard environment, filters and checks -@@ -60,16 +62,21 @@ size=$((1 * 1024 * 1024)) - touch "$TEST_DIR/empty" - extra_blocks=$(stat -c '%b' "$TEST_DIR/empty") - -+# We always write the first byte; check how many blocks this filesystem -+# allocates to match empty image alloation. -+printf "\0" > "$TEST_DIR/empty" -+min_blocks=$(stat -c '%b' "$TEST_DIR/empty") -+ - echo - echo "== creating image with default preallocation ==" - _make_test_img $size | _filter_imgfmt --stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size -+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size - - for mode in off full falloc; do - echo - echo "== creating image with preallocation $mode ==" - IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt -- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size -+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size - done - - # success, all done -diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out -index 6d9a5ed84e..263e521262 100644 ---- a/tests/qemu-iotests/175.out -+++ b/tests/qemu-iotests/175.out -@@ -2,17 +2,17 @@ QA output created by 175 - - == creating image with default preallocation == - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 --size=1048576, nothing allocated -+size=1048576, min allocation - - == creating image with preallocation off == - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off --size=1048576, nothing allocated -+size=1048576, min allocation - - == creating image with preallocation full == - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full --size=1048576, everything allocated -+size=1048576, max allocation - - == creating image with preallocation falloc == - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc --size=1048576, everything allocated -+size=1048576, max allocation - *** done -diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 -index 55a8dc926f..9e7d8c44df 100644 ---- a/tests/qemu-iotests/178.out.qcow2 -+++ b/tests/qemu-iotests/178.out.qcow2 -@@ -101,7 +101,7 @@ converted image file size in bytes: 196608 - == raw input image with data (human) == - - Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 --required size: 393216 -+required size: 458752 - fully allocated size: 1074135040 - wrote 512/512 bytes at offset 512 - 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -@@ -257,7 +257,7 @@ converted image file size in bytes: 196608 - - Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 - { -- "required": 393216, -+ "required": 458752, - "fully-allocated": 1074135040 - } - wrote 512/512 bytes at offset 512 -diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out -index 9f9dd52bb0..dca024a0c3 100644 ---- a/tests/qemu-iotests/221.out -+++ b/tests/qemu-iotests/221.out -@@ -3,14 +3,18 @@ QA output created by 221 - === Check mapping of unaligned raw image === - - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537 --[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] --[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] - wrote 1/1 bytes at offset 65536 - 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) --[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, - { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, - { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] --[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, - { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, - { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] - *** done -diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out -index 607c0baa0b..3d08b305d7 100644 ---- a/tests/qemu-iotests/253.out -+++ b/tests/qemu-iotests/253.out -@@ -3,12 +3,16 @@ QA output created by 253 - === Check mapping of unaligned raw image === - - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575 --[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] --[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] - wrote 65535/65535 bytes at offset 983040 - 63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) --[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, - { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] --[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, -+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, -+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, - { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] - *** done --- -2.23.0 diff --git a/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch b/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch deleted file mode 100644 index f77cc06c60dd36ccd84a5ad5c5e9748bb2126c08..0000000000000000000000000000000000000000 --- a/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 84f22c728520792f1010074e0d5ac2ec8e2e372c Mon Sep 17 00:00:00 2001 -From: Maxim Levitsky -Date: Sun, 15 Sep 2019 23:36:53 +0300 -Subject: [PATCH] block/qcow2: Fix corruption introduced by commit 8ac0f15f335 - -This fixes subtle corruption introduced by luks threaded encryption -in commit 8ac0f15f335 - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1745922 - -The corruption happens when we do a write that - * writes to two or more unallocated clusters at once - * doesn't fully cover the first sector - * doesn't fully cover the last sector - * uses luks encryption - -In this case, when allocating the new clusters we COW both areas -prior to the write and after the write, and we encrypt them. - -The above mentioned commit accidentally made it so we encrypt the -second COW area using the physical cluster offset of the first area. - -The problem is that offset_in_cluster in do_perform_cow_encrypt -can be larger that the cluster size, thus cluster_offset -will no longer point to the start of the cluster at which encrypted -area starts. - -Next patch in this series will refactor the code to avoid all these -assumptions. - -In the bugreport that was triggered by rebasing a luks image to new, -zero filled base, which lot of such writes, and causes some files -with zero areas to contain garbage there instead. -But as described above it can happen elsewhere as well - -Signed-off-by: Maxim Levitsky -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-id: 20190915203655.21638-2-mlevitsk@redhat.com -Reviewed-by: Max Reitz -Signed-off-by: Max Reitz -(cherry picked from commit 38e7d54bdc518b5a05a922467304bcace2396945) -Signed-off-by: Michael Roth ---- - block/qcow2-cluster.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c -index cc5609e27a..760564c8fb 100644 ---- a/block/qcow2-cluster.c -+++ b/block/qcow2-cluster.c -@@ -473,9 +473,10 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, - assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); - assert((bytes & ~BDRV_SECTOR_MASK) == 0); - assert(s->crypto); -- if (qcow2_co_encrypt(bs, cluster_offset, -- src_cluster_offset + offset_in_cluster, -- buffer, bytes) < 0) { -+ if (qcow2_co_encrypt(bs, -+ start_of_cluster(s, cluster_offset + offset_in_cluster), -+ src_cluster_offset + offset_in_cluster, -+ buffer, bytes) < 0) { - return false; - } - } --- -2.23.0 diff --git a/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch b/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch deleted file mode 100644 index 44b0ea19e95b95bbd583034e9c830e3dd6d647e6..0000000000000000000000000000000000000000 --- a/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 88ef4e1862987227f8b87228cff94be3af66d054 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Thu, 27 Feb 2020 09:29:49 +0800 -Subject: [PATCH 01/14] block/qcow2: do free crypto_opts in qcow2_close() - -'crypto_opts' forgot to free in qcow2_close(), this patch fix the bellow leak stack: - -Direct leak of 24 byte(s) in 1 object(s) allocated from: - #0 0x7f0edd81f970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) - #1 0x7f0edc6d149d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) - #2 0x55d7eaede63d in qobject_input_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qobject-input-visitor.c:295 - #3 0x55d7eaed78b8 in visit_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qapi-visit-core.c:49 - #4 0x55d7eaf5140b in visit_type_QCryptoBlockOpenOptions qapi/qapi-visit-crypto.c:290 - #5 0x55d7eae43af3 in block_crypto_open_opts_init /mnt/sdb/qemu-new/qemu_test/qemu/block/crypto.c:163 - #6 0x55d7eacd2924 in qcow2_update_options_prepare /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1148 - #7 0x55d7eacd33f7 in qcow2_update_options /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1232 - #8 0x55d7eacd9680 in qcow2_do_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1512 - #9 0x55d7eacdc55e in qcow2_open_entry /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1792 - #10 0x55d7eacdc8fe in qcow2_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1819 - #11 0x55d7eac3742d in bdrv_open_driver /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1317 - #12 0x55d7eac3e990 in bdrv_open_common /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1575 - #13 0x55d7eac4442c in bdrv_open_inherit /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3126 - #14 0x55d7eac45c3f in bdrv_open /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3219 - #15 0x55d7ead8e8a4 in blk_new_open /mnt/sdb/qemu-new/qemu_test/qemu/block/block-backend.c:397 - #16 0x55d7eacde74c in qcow2_co_create /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3534 - #17 0x55d7eacdfa6d in qcow2_co_create_opts /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3668 - #18 0x55d7eac1c678 in bdrv_create_co_entry /mnt/sdb/qemu-new/qemu_test/qemu/block.c:485 - #19 0x55d7eb0024d2 in coroutine_trampoline /mnt/sdb/qemu-new/qemu_test/qemu/util/coroutine-ucontext.c:115 - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Reviewed-by: Max Reitz -Message-Id: <20200227012950.12256-2-pannengyuan@huawei.com> -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - block/qcow2.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block/qcow2.c b/block/qcow2.c -index 1909df6e1d24..27c54b9905aa 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -2408,6 +2408,7 @@ static void qcow2_close(BlockDriverState *bs) - - qcrypto_block_free(s->crypto); - s->crypto = NULL; -+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); - - g_free(s->unknown_header_fields); - cleanup_unknown_header_ext(bs); --- -2.26.2 - diff --git a/block-qcow2-threads-fix-qcow2_decompress.patch b/block-qcow2-threads-fix-qcow2_decompress.patch deleted file mode 100644 index d2fd9ee74fc5b57fb57ee1f655763895f1fe4356..0000000000000000000000000000000000000000 --- a/block-qcow2-threads-fix-qcow2_decompress.patch +++ /dev/null @@ -1,75 +0,0 @@ -From a583b6b616b086d3fdce93e255d24ab2c865efd3 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Mon, 2 Mar 2020 18:09:30 +0300 -Subject: [PATCH 03/14] block/qcow2-threads: fix qcow2_decompress -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -On success path we return what inflate() returns instead of 0. And it -most probably works for Z_STREAM_END as it is positive, but is -definitely broken for Z_BUF_ERROR. - -While being here, switch to errno return code, to be closer to -qcow2_compress API (and usual expectations). - -Revert condition in if to be more positive. Drop dead initialization of -ret. - -Cc: qemu-stable@nongnu.org # v4.0 -Fixes: 341926ab83e2b -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200302150930.16218-1-vsementsov@virtuozzo.com> -Reviewed-by: Alberto Garcia -Reviewed-by: Ján Tomko -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - block/qcow2-threads.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c -index 3b1e63fe414d..449cd3c0a1f4 100644 ---- a/block/qcow2-threads.c -+++ b/block/qcow2-threads.c -@@ -128,12 +128,12 @@ static ssize_t qcow2_compress(void *dest, size_t dest_size, - * @src - source buffer, @src_size bytes - * - * Returns: 0 on success -- * -1 on fail -+ * -EIO on fail - */ - static ssize_t qcow2_decompress(void *dest, size_t dest_size, - const void *src, size_t src_size) - { -- int ret = 0; -+ int ret; - z_stream strm; - - memset(&strm, 0, sizeof(strm)); -@@ -144,17 +144,19 @@ static ssize_t qcow2_decompress(void *dest, size_t dest_size, - - ret = inflateInit2(&strm, -12); - if (ret != Z_OK) { -- return -1; -+ return -EIO; - } - - ret = inflate(&strm, Z_FINISH); -- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) { -+ if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) { - /* - * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but - * @src buffer may be processed partly (because in qcow2 we know size of - * compressed data with precision of one sector) - */ -- ret = -1; -+ ret = 0; -+ } else { -+ ret = -EIO; - } - - inflateEnd(&strm); --- -2.26.2 - diff --git a/block-rbd-fix-write-zeroes-with-growing-images.patch b/block-rbd-fix-write-zeroes-with-growing-images.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce19d29193c4016e57532bc5da852c7e844eb63f --- /dev/null +++ b/block-rbd-fix-write-zeroes-with-growing-images.patch @@ -0,0 +1,76 @@ +From c0caaf3367912df00107e6cd49809a48ccc566fb Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 4 Aug 2023 08:03:35 +0000 +Subject: [PATCH] block/rbd: fix write zeroes with growing images mainline + inclusion commit cc5387a544325c26dcf124ac7d3999389c24e5c6 category: bugfix + +--------------------------------------------------------------- + +Commit d24f80234b ("block/rbd: increase dynamically the image size") +added a workaround to support growing images (eg. qcow2), resizing +the image before write operations that exceed the current size. + +We recently added support for write zeroes and without the +workaround we can have problems with qcow2. + +So let's move the resize into qemu_rbd_start_co() and do it when +the command is RBD_AIO_WRITE or RBD_AIO_WRITE_ZEROES. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2020993 +Fixes: c56ac27d2a ("block/rbd: add write zeroes support") +Signed-off-by: Stefano Garzarella +Message-Id: <20220317162638.41192-1-sgarzare@redhat.com> +Signed-off-by: Hanna Reitz + +Signed-off-by: tangbinzy +--- + block/rbd.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index 92dfb6083b..ccb14efd55 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -1107,6 +1107,20 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs, + + assert(!qiov || qiov->size == bytes); + ++ if (cmd == RBD_AIO_WRITE || cmd == RBD_AIO_WRITE_ZEROES) { ++ /* ++ * RBD APIs don't allow us to write more than actual size, so in order ++ * to support growing images, we resize the image before write ++ * operations that exceed the current size. ++ */ ++ if (offset + bytes > s->image_size) { ++ int r = qemu_rbd_resize(bs, offset + bytes); ++ if (r < 0) { ++ return r; ++ } ++ } ++ } ++ + r = rbd_aio_create_completion(&task, + (rbd_callback_t) qemu_rbd_completion_cb, &c); + if (r < 0) { +@@ -1182,18 +1196,6 @@ coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) + { +- BDRVRBDState *s = bs->opaque; +- /* +- * RBD APIs don't allow us to write more than actual size, so in order +- * to support growing images, we resize the image before write +- * operations that exceed the current size. +- */ +- if (offset + bytes > s->image_size) { +- int r = qemu_rbd_resize(bs, offset + bytes); +- if (r < 0) { +- return r; +- } +- } + return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_WRITE); + } + +-- +2.41.0.windows.1 + diff --git a/block-rbd-workaround-for-ceph-issue-53784.patch b/block-rbd-workaround-for-ceph-issue-53784.patch new file mode 100644 index 0000000000000000000000000000000000000000..efd6225bffa6eee217ab61383e3f940298861ffe --- /dev/null +++ b/block-rbd-workaround-for-ceph-issue-53784.patch @@ -0,0 +1,93 @@ +From 43302c8f56518cd467578fa084d64fd42c59348c Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Thu, 13 Jan 2022 15:44:26 +0100 +Subject: [PATCH] block/rbd: workaround for ceph issue #53784 + +librbd had a bug until early 2022 that affected all versions of ceph that +supported fast-diff. This bug results in reporting of incorrect offsets +if the offset parameter to rbd_diff_iterate2 is not object aligned. + +This patch works around this bug for pre Quincy versions of librbd. + +Fixes: 0347a8fd4c3faaedf119be04c197804be40a384b +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Lieven +Message-Id: <20220113144426.4036493-3-pl@kamp.de> +Reviewed-by: Ilya Dryomov +Reviewed-by: Stefano Garzarella +Tested-by: Stefano Garzarella +Signed-off-by: Kevin Wolf +--- + block/rbd.c | 42 ++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 40 insertions(+), 2 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index def96292e0..92dfb6083b 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -1320,6 +1320,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, + int status, r; + RBDDiffIterateReq req = { .offs = offset }; + uint64_t features, flags; ++ uint64_t head = 0; + + assert(offset + bytes <= s->image_size); + +@@ -1347,7 +1348,43 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, + return status; + } + +- r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true, ++#if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 17, 0) ++ /* ++ * librbd had a bug until early 2022 that affected all versions of ceph that ++ * supported fast-diff. This bug results in reporting of incorrect offsets ++ * if the offset parameter to rbd_diff_iterate2 is not object aligned. ++ * Work around this bug by rounding down the offset to object boundaries. ++ * This is OK because we call rbd_diff_iterate2 with whole_object = true. ++ * However, this workaround only works for non cloned images with default ++ * striping. ++ * ++ * See: https://tracker.ceph.com/issues/53784 ++ */ ++ ++ /* check if RBD image has non-default striping enabled */ ++ if (features & RBD_FEATURE_STRIPINGV2) { ++ return status; ++ } ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wdeprecated-declarations" ++ /* ++ * check if RBD image is a clone (= has a parent). ++ * ++ * rbd_get_parent_info is deprecated from Nautilus onwards, but the ++ * replacement rbd_get_parent is not present in Luminous and Mimic. ++ */ ++ if (rbd_get_parent_info(s->image, NULL, 0, NULL, 0, NULL, 0) != -ENOENT) { ++ return status; ++ } ++#pragma GCC diagnostic pop ++ ++ head = req.offs & (s->object_size - 1); ++ req.offs -= head; ++ bytes += head; ++#endif ++ ++ r = rbd_diff_iterate2(s->image, NULL, req.offs, bytes, true, true, + qemu_rbd_diff_iterate_cb, &req); + if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) { + return status; +@@ -1366,7 +1403,8 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, + status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID; + } + +- *pnum = req.bytes; ++ assert(req.bytes > head); ++ *pnum = req.bytes - head; + return status; + } + +-- +2.27.0 + diff --git a/block-snapshot-Restrict-set-of-snapshot-nodes.patch b/block-snapshot-Restrict-set-of-snapshot-nodes.patch deleted file mode 100644 index c29f30adc897f5b60bf8004b7f317b6e6257bf3a..0000000000000000000000000000000000000000 --- a/block-snapshot-Restrict-set-of-snapshot-nodes.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 7a8aa6c734bb1c2927ad0cc1d10bcacb53cf4ae3 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 17 Sep 2019 12:26:23 +0200 -Subject: [PATCH] block/snapshot: Restrict set of snapshot nodes - -Nodes involved in internal snapshots were those that were returned by -bdrv_next(), inserted and not read-only. bdrv_next() in turn returns all -nodes that are either the root node of a BlockBackend or monitor-owned -nodes. - -With the typical -drive use, this worked well enough. However, in the -typical -blockdev case, the user defines one node per option, making all -nodes monitor-owned nodes. This includes protocol nodes etc. which often -are not snapshottable, so "savevm" only returns an error. - -Change the conditions so that internal snapshot still include all nodes -that have a BlockBackend attached (we definitely want to snapshot -anything attached to a guest device and probably also the built-in NBD -server; snapshotting block job BlockBackends is more of an accident, but -a preexisting one), but other monitor-owned nodes are only included if -they have no parents. - -This makes internal snapshots usable again with typical -blockdev -configurations. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -Reviewed-by: Peter Krempa -Tested-by: Peter Krempa -(cherry picked from commit 05f4aced658a02b02d3e89a6c7a2281008fcf26c) -Signed-off-by: Michael Roth ---- - block/snapshot.c | 26 +++++++++++++++++++------- - 1 file changed, 19 insertions(+), 7 deletions(-) - -diff --git a/block/snapshot.c b/block/snapshot.c -index f2f48f926a..8081616ae9 100644 ---- a/block/snapshot.c -+++ b/block/snapshot.c -@@ -31,6 +31,7 @@ - #include "qapi/qmp/qerror.h" - #include "qapi/qmp/qstring.h" - #include "qemu/option.h" -+#include "sysemu/block-backend.h" - - QemuOptsList internal_snapshot_opts = { - .name = "snapshot", -@@ -384,6 +385,16 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, - return ret; - } - -+static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs) -+{ -+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { -+ return false; -+ } -+ -+ /* Include all nodes that are either in use by a BlockBackend, or that -+ * aren't attached to any node, but owned by the monitor. */ -+ return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents); -+} - - /* Group operations. All block drivers are involved. - * These functions will properly handle dataplane (take aio_context_acquire -@@ -399,7 +410,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_context_acquire(ctx); -- if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) { -+ if (bdrv_all_snapshots_includes_bs(bs)) { - ok = bdrv_can_snapshot(bs); - } - aio_context_release(ctx); -@@ -426,8 +437,9 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_context_acquire(ctx); -- if (bdrv_can_snapshot(bs) && -- bdrv_snapshot_find(bs, snapshot, name) >= 0) { -+ if (bdrv_all_snapshots_includes_bs(bs) && -+ bdrv_snapshot_find(bs, snapshot, name) >= 0) -+ { - ret = bdrv_snapshot_delete(bs, snapshot->id_str, - snapshot->name, err); - } -@@ -455,7 +467,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs, - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_context_acquire(ctx); -- if (bdrv_can_snapshot(bs)) { -+ if (bdrv_all_snapshots_includes_bs(bs)) { - ret = bdrv_snapshot_goto(bs, name, errp); - } - aio_context_release(ctx); -@@ -481,7 +493,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_context_acquire(ctx); -- if (bdrv_can_snapshot(bs)) { -+ if (bdrv_all_snapshots_includes_bs(bs)) { - err = bdrv_snapshot_find(bs, &sn, name); - } - aio_context_release(ctx); -@@ -512,7 +524,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, - if (bs == vm_state_bs) { - sn->vm_state_size = vm_state_size; - err = bdrv_snapshot_create(bs, sn); -- } else if (bdrv_can_snapshot(bs)) { -+ } else if (bdrv_all_snapshots_includes_bs(bs)) { - sn->vm_state_size = 0; - err = bdrv_snapshot_create(bs, sn); - } -@@ -538,7 +550,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void) - bool found; - - aio_context_acquire(ctx); -- found = bdrv_can_snapshot(bs); -+ found = bdrv_all_snapshots_includes_bs(bs) && bdrv_can_snapshot(bs); - aio_context_release(ctx); - - if (found) { --- -2.23.0 diff --git a/block-use-unsigned-for-in_flight-field-on-driver-sta.patch b/block-use-unsigned-for-in_flight-field-on-driver-sta.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ff052c60e6eb12a718b004a0f19de951ec3ee14 --- /dev/null +++ b/block-use-unsigned-for-in_flight-field-on-driver-sta.patch @@ -0,0 +1,54 @@ +From d82b2052d61cd57fb2ebf53f633cb0ff272d16c3 Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:53:08 -0800 +Subject: [PATCH] block: use 'unsigned' for in_flight field on driver state + +cherry picked from commit 1b8f777673985af366de099ad4e41d334b36fb12 + +This patch makes in_flight field 'unsigned' for BDRVNBDState and +MirrorBlockJob. This matches the definition of this field on BDS +and is generically correct - we should never get negative value here. + +Signed-off-by: Denis V. Lunev +CC: John Snow +CC: Vladimir Sementsov-Ogievskiy +CC: Kevin Wolf +CC: Hanna Reitz +CC: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Wanghe Xiao +--- + block/mirror.c | 2 +- + block/nbd.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index b7f0cba9b9..d1863565c4 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -72,7 +72,7 @@ typedef struct MirrorBlockJob { + + uint64_t last_pause_ns; + unsigned long *in_flight_bitmap; +- int in_flight; ++ unsigned in_flight; + int64_t bytes_in_flight; + QTAILQ_HEAD(, MirrorOp) ops_in_flight; + int ret; +diff --git a/block/nbd.c b/block/nbd.c +index 33adfddc41..a543e68d2f 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -76,7 +76,7 @@ typedef struct BDRVNBDState { + CoQueue free_sema; + + CoMutex receive_mutex; +- int in_flight; ++ unsigned in_flight; + NBDClientState state; + + QEMUTimer *reconnect_delay_timer; +-- +2.27.0 + diff --git a/block-vvfat-Fix-bad-printf-format-specifiers.patch b/block-vvfat-Fix-bad-printf-format-specifiers.patch deleted file mode 100644 index 597b9782683778c799e3192fd66d27eb230eee8e..0000000000000000000000000000000000000000 --- a/block-vvfat-Fix-bad-printf-format-specifiers.patch +++ /dev/null @@ -1,77 +0,0 @@ -From c9a4e85610bffe1803648c431e4cff4539a42323 Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Tue, 3 Nov 2020 17:42:56 +0800 -Subject: [PATCH] block/vvfat: Fix bad printf format specifiers - -We should use printf format specifier "%u" instead of "%d" for -argument of type "unsigned int". -In addition, fix two error format problems found by checkpatch.pl: -ERROR: space required after that ',' (ctx:VxV) -+ fprintf(stderr,"%s attributes=0x%02x begin=%u size=%d\n", - ^ -ERROR: line over 90 characters -+ fprintf(stderr, "%d, %s (%u, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action); - -Reported-by: Euler Robot -Signed-off-by: Alex Chen -Message-Id: <5FA12620.6030705@huawei.com> -Signed-off-by: Kevin Wolf -(cherry-picked from commit c9eb2f3e38) ---- - block/vvfat.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/block/vvfat.c b/block/vvfat.c -index f6c28805dd..5dc8d6eb4c 100644 ---- a/block/vvfat.c -+++ b/block/vvfat.c -@@ -1453,7 +1453,7 @@ static void print_direntry(const direntry_t* direntry) - for(i=0;i<11;i++) - ADD_CHAR(direntry->name[i]); - buffer[j] = 0; -- fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n", -+ fprintf(stderr, "%s attributes=0x%02x begin=%u size=%u\n", - buffer, - direntry->attributes, - begin_of_direntry(direntry),le32_to_cpu(direntry->size)); -@@ -1462,7 +1462,7 @@ static void print_direntry(const direntry_t* direntry) - - static void print_mapping(const mapping_t* mapping) - { -- fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, " -+ fprintf(stderr, "mapping (%p): begin, end = %u, %u, dir_index = %u, " - "first_mapping_index = %d, name = %s, mode = 0x%x, " , - mapping, mapping->begin, mapping->end, mapping->dir_index, - mapping->first_mapping_index, mapping->path, mapping->mode); -@@ -1470,7 +1470,7 @@ static void print_mapping(const mapping_t* mapping) - if (mapping->mode & MODE_DIRECTORY) - fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index); - else -- fprintf(stderr, "offset = %d\n", mapping->info.file.offset); -+ fprintf(stderr, "offset = %u\n", mapping->info.file.offset); - } - #endif - -@@ -1604,7 +1604,7 @@ typedef struct commit_t { - static void clear_commits(BDRVVVFATState* s) - { - int i; --DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next)); -+DLOG(fprintf(stderr, "clear_commits (%u commits)\n", s->commits.next)); - for (i = 0; i < s->commits.next; i++) { - commit_t* commit = array_get(&(s->commits), i); - assert(commit->path || commit->action == ACTION_WRITEOUT); -@@ -2660,7 +2660,9 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) - fprintf(stderr, "handle_renames\n"); - for (i = 0; i < s->commits.next; i++) { - commit_t* commit = array_get(&(s->commits), i); -- fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action); -+ fprintf(stderr, "%d, %s (%u, %d)\n", i, -+ commit->path ? commit->path : "(null)", -+ commit->param.rename.cluster, commit->action); - } - #endif - --- -2.27.0 - diff --git a/blockdev-Return-bs-to-the-proper-context-on-snapshot.patch b/blockdev-Return-bs-to-the-proper-context-on-snapshot.patch deleted file mode 100644 index a232c7450689ae13c12e215803a7d1a2bca4c158..0000000000000000000000000000000000000000 --- a/blockdev-Return-bs-to-the-proper-context-on-snapshot.patch +++ /dev/null @@ -1,93 +0,0 @@ -From dc6b61f12750b3ab5a3965af2ec758750389233d Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 8 Jan 2020 15:31:37 +0100 -Subject: [PATCH] blockdev: Return bs to the proper context on snapshot abort - -external_snapshot_abort() calls to bdrv_set_backing_hd(), which -returns state->old_bs to the main AioContext, as it's intended to be -used then the BDS is going to be released. As that's not the case when -aborting an external snapshot, return it to the AioContext it was -before the call. - -This issue can be triggered by issuing a transaction with two actions, -a proper blockdev-snapshot-sync and a bogus one, so the second will -trigger a transaction abort. This results in a crash with an stack -trace like this one: - - #0 0x00007fa1048b28df in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 - #1 0x00007fa10489ccf5 in __GI_abort () at abort.c:79 - #2 0x00007fa10489cbc9 in __assert_fail_base - (fmt=0x7fa104a03300 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x5572240b44d8 "bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)", file=0x557224014d30 "block.c", line=2240, function=) at assert.c:92 - #3 0x00007fa1048aae96 in __GI___assert_fail - (assertion=assertion@entry=0x5572240b44d8 "bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)", file=file@entry=0x557224014d30 "block.c", line=line@entry=2240, function=function@entry=0x5572240b5d60 <__PRETTY_FUNCTION__.31620> "bdrv_replace_child_noperm") at assert.c:101 - #4 0x0000557223e631f8 in bdrv_replace_child_noperm (child=0x557225b9c980, new_bs=new_bs@entry=0x557225c42e40) at block.c:2240 - #5 0x0000557223e68be7 in bdrv_replace_node (from=0x557226951a60, to=0x557225c42e40, errp=0x5572247d6138 ) at block.c:4196 - #6 0x0000557223d069c4 in external_snapshot_abort (common=0x557225d7e170) at blockdev.c:1731 - #7 0x0000557223d069c4 in external_snapshot_abort (common=0x557225d7e170) at blockdev.c:1717 - #8 0x0000557223d09013 in qmp_transaction (dev_list=, has_props=, props=0x557225cc7d70, errp=errp@entry=0x7ffe704c0c98) at blockdev.c:2360 - #9 0x0000557223e32085 in qmp_marshal_transaction (args=, ret=, errp=0x7ffe704c0d08) at qapi/qapi-commands-transaction.c:44 - #10 0x0000557223ee798c in do_qmp_dispatch (errp=0x7ffe704c0d00, allow_oob=, request=, cmds=0x5572247d3cc0 ) at qapi/qmp-dispatch.c:132 - #11 0x0000557223ee798c in qmp_dispatch (cmds=0x5572247d3cc0 , request=, allow_oob=) at qapi/qmp-dispatch.c:175 - #12 0x0000557223e06141 in monitor_qmp_dispatch (mon=0x557225c69ff0, req=) at monitor/qmp.c:120 - #13 0x0000557223e0678a in monitor_qmp_bh_dispatcher (data=) at monitor/qmp.c:209 - #14 0x0000557223f2f366 in aio_bh_call (bh=0x557225b9dc60) at util/async.c:117 - #15 0x0000557223f2f366 in aio_bh_poll (ctx=ctx@entry=0x557225b9c840) at util/async.c:117 - #16 0x0000557223f32754 in aio_dispatch (ctx=0x557225b9c840) at util/aio-posix.c:459 - #17 0x0000557223f2f242 in aio_ctx_dispatch (source=, callback=, user_data=) at util/async.c:260 - #18 0x00007fa10913467d in g_main_dispatch (context=0x557225c28e80) at gmain.c:3176 - #19 0x00007fa10913467d in g_main_context_dispatch (context=context@entry=0x557225c28e80) at gmain.c:3829 - #20 0x0000557223f31808 in glib_pollfds_poll () at util/main-loop.c:219 - #21 0x0000557223f31808 in os_host_main_loop_wait (timeout=) at util/main-loop.c:242 - #22 0x0000557223f31808 in main_loop_wait (nonblocking=) at util/main-loop.c:518 - #23 0x0000557223d13201 in main_loop () at vl.c:1828 - #24 0x0000557223bbfb82 in main (argc=, argv=, envp=) at vl.c:4504 - -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1779036 -Signed-off-by: Sergio Lopez -Signed-off-by: Kevin Wolf ---- - blockdev.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/blockdev.c b/blockdev.c -index 5088541591..79112be2e6 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1774,6 +1774,8 @@ static void external_snapshot_abort(BlkActionState *common) - if (state->new_bs) { - if (state->overlay_appended) { - AioContext *aio_context; -+ AioContext *tmp_context; -+ int ret; - - aio_context = bdrv_get_aio_context(state->old_bs); - aio_context_acquire(aio_context); -@@ -1781,6 +1783,25 @@ static void external_snapshot_abort(BlkActionState *common) - bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd() - close state->old_bs; we need it */ - bdrv_set_backing_hd(state->new_bs, NULL, &error_abort); -+ -+ /* -+ * The call to bdrv_set_backing_hd() above returns state->old_bs to -+ * the main AioContext. As we're still going to be using it, return -+ * it to the AioContext it was before. -+ */ -+ tmp_context = bdrv_get_aio_context(state->old_bs); -+ if (aio_context != tmp_context) { -+ aio_context_release(aio_context); -+ aio_context_acquire(tmp_context); -+ -+ ret = bdrv_try_set_aio_context(state->old_bs, -+ aio_context, NULL); -+ assert(ret == 0); -+ -+ aio_context_release(tmp_context); -+ aio_context_acquire(aio_context); -+ } -+ - bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); - bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */ - --- -2.27.0 - diff --git a/blockdev-backup-utilize-do_backup_common.patch b/blockdev-backup-utilize-do_backup_common.patch deleted file mode 100644 index 6827b221978c2646d97f15e62b42b8eb34282bea..0000000000000000000000000000000000000000 --- a/blockdev-backup-utilize-do_backup_common.patch +++ /dev/null @@ -1,105 +0,0 @@ -From e5456acf2332efd0ed6106eb13cf24e6bca1ee64 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:52 -0400 -Subject: [PATCH] blockdev-backup: utilize do_backup_common - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190709232550.10724-4-jsnow@redhat.com -Signed-off-by: John Snow ---- - blockdev.c | 65 +++++------------------------------------------------- - 1 file changed, 6 insertions(+), 59 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index a29838a1c8..aa15ed1f00 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3668,78 +3668,25 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, - { - BlockDriverState *bs; - BlockDriverState *target_bs; -- Error *local_err = NULL; -- BdrvDirtyBitmap *bmap = NULL; - AioContext *aio_context; -- BlockJob *job = NULL; -- int job_flags = JOB_DEFAULT; -- int ret; -- -- if (!backup->has_speed) { -- backup->speed = 0; -- } -- if (!backup->has_on_source_error) { -- backup->on_source_error = BLOCKDEV_ON_ERROR_REPORT; -- } -- if (!backup->has_on_target_error) { -- backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT; -- } -- if (!backup->has_job_id) { -- backup->job_id = NULL; -- } -- if (!backup->has_auto_finalize) { -- backup->auto_finalize = true; -- } -- if (!backup->has_auto_dismiss) { -- backup->auto_dismiss = true; -- } -- if (!backup->has_compress) { -- backup->compress = false; -- } -+ BlockJob *job; - - bs = bdrv_lookup_bs(backup->device, backup->device, errp); - if (!bs) { - return NULL; - } - -- aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(aio_context); -- - target_bs = bdrv_lookup_bs(backup->target, backup->target, errp); - if (!target_bs) { -- goto out; -+ return NULL; - } - -- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -- if (ret < 0) { -- goto out; -- } -+ aio_context = bdrv_get_aio_context(bs); -+ aio_context_acquire(aio_context); - -- if (backup->has_bitmap) { -- bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); -- if (!bmap) { -- error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); -- goto out; -- } -- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { -- goto out; -- } -- } -+ job = do_backup_common(qapi_BlockdevBackup_base(backup), -+ bs, target_bs, aio_context, txn, errp); - -- if (!backup->auto_finalize) { -- job_flags |= JOB_MANUAL_FINALIZE; -- } -- if (!backup->auto_dismiss) { -- job_flags |= JOB_MANUAL_DISMISS; -- } -- job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, -- backup->sync, bmap, backup->compress, -- backup->on_source_error, backup->on_target_error, -- job_flags, NULL, NULL, txn, &local_err); -- if (local_err != NULL) { -- error_propagate(errp, local_err); -- } --out: - aio_context_release(aio_context); - return job; - } --- -2.27.0 - diff --git a/blockdev-fix-coding-style-issues-in-drive_backup_pre.patch b/blockdev-fix-coding-style-issues-in-drive_backup_pre.patch deleted file mode 100644 index e915b05a415c2e2fc76ac0e58be7cc819f457533..0000000000000000000000000000000000000000 --- a/blockdev-fix-coding-style-issues-in-drive_backup_pre.patch +++ /dev/null @@ -1,44 +0,0 @@ -From ffbf1e237d0311512c411e195278e69d710fb9cf Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 8 Jan 2020 15:31:31 +0100 -Subject: [PATCH] blockdev: fix coding style issues in drive_backup_prepare - -Fix a couple of minor coding style issues in drive_backup_prepare. - -Signed-off-by: Sergio Lopez -Reviewed-by: Max Reitz -Reviewed-by: Kevin Wolf -Signed-off-by: Kevin Wolf ---- - blockdev.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 4435795b6d..99b1cafb8f 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3597,7 +3597,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - - if (!backup->has_format) { - backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ? -- NULL : (char*) bs->drv->format_name; -+ NULL : (char *) bs->drv->format_name; - } - - /* Early check to avoid creating target */ -@@ -3607,8 +3607,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - - flags = bs->open_flags | BDRV_O_RDWR; - -- /* See if we have a backing HD we can use to create our new image -- * on top of. */ -+ /* -+ * See if we have a backing HD we can use to create our new image -+ * on top of. -+ */ - if (backup->sync == MIRROR_SYNC_MODE_TOP) { - source = backing_bs(bs); - if (!source) { --- -2.27.0 - diff --git a/blockdev-honor-bdrv_try_set_aio_context-context-requ.patch b/blockdev-honor-bdrv_try_set_aio_context-context-requ.patch deleted file mode 100644 index 970057179e504e1961c766d0a68107816c750721..0000000000000000000000000000000000000000 --- a/blockdev-honor-bdrv_try_set_aio_context-context-requ.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 64c6b3b911f65c19f3a235c8394f5db894c1ee6a Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 8 Jan 2020 15:31:34 +0100 -Subject: [PATCH] blockdev: honor bdrv_try_set_aio_context() context - requirements - -bdrv_try_set_aio_context() requires that the old context is held, and -the new context is not held. Fix all the occurrences where it's not -done this way. - -Suggested-by: Max Reitz -Signed-off-by: Sergio Lopez -Signed-off-by: Kevin Wolf ---- - blockdev.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++------- - 1 file changed, 60 insertions(+), 8 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index d3309c205a..5088541591 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1578,6 +1578,7 @@ static void external_snapshot_prepare(BlkActionState *common, - DO_UPCAST(ExternalSnapshotState, common, common); - TransactionAction *action = common->action; - AioContext *aio_context; -+ AioContext *old_context; - int ret; - - /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar -@@ -1718,7 +1719,16 @@ static void external_snapshot_prepare(BlkActionState *common, - goto out; - } - -+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ -+ old_context = bdrv_get_aio_context(state->new_bs); -+ aio_context_release(aio_context); -+ aio_context_acquire(old_context); -+ - ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp); -+ -+ aio_context_release(old_context); -+ aio_context_acquire(aio_context); -+ - if (ret < 0) { - goto out; - } -@@ -1818,11 +1828,13 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) - BlockDriverState *target_bs; - BlockDriverState *source = NULL; - AioContext *aio_context; -+ AioContext *old_context; - QDict *options; - Error *local_err = NULL; - int flags; - int64_t size; - bool set_backing_hd = false; -+ int ret; - - assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); - backup = common->action->u.drive_backup.data; -@@ -1911,6 +1923,21 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) - goto out; - } - -+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ -+ old_context = bdrv_get_aio_context(target_bs); -+ aio_context_release(aio_context); -+ aio_context_acquire(old_context); -+ -+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -+ if (ret < 0) { -+ bdrv_unref(target_bs); -+ aio_context_release(old_context); -+ return; -+ } -+ -+ aio_context_release(old_context); -+ aio_context_acquire(aio_context); -+ - if (set_backing_hd) { - bdrv_set_backing_hd(target_bs, source, &local_err); - if (local_err) { -@@ -1990,6 +2017,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - BlockDriverState *bs; - BlockDriverState *target_bs; - AioContext *aio_context; -+ AioContext *old_context; -+ int ret; - - assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); - backup = common->action->u.blockdev_backup.data; -@@ -2004,7 +2033,18 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - return; - } - -+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ - aio_context = bdrv_get_aio_context(bs); -+ old_context = bdrv_get_aio_context(target_bs); -+ aio_context_acquire(old_context); -+ -+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -+ if (ret < 0) { -+ aio_context_release(old_context); -+ return; -+ } -+ -+ aio_context_release(old_context); - aio_context_acquire(aio_context); - state->bs = bs; - -@@ -3562,7 +3602,6 @@ static BlockJob *do_backup_common(BackupCommon *backup, - BlockJob *job = NULL; - BdrvDirtyBitmap *bmap = NULL; - int job_flags = JOB_DEFAULT; -- int ret; - - if (!backup->has_speed) { - backup->speed = 0; -@@ -3586,11 +3625,6 @@ static BlockJob *do_backup_common(BackupCommon *backup, - backup->compress = false; - } - -- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -- if (ret < 0) { -- return NULL; -- } -- - if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) || - (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) { - /* done before desugaring 'incremental' to print the right message */ -@@ -3802,6 +3836,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) - BlockDriverState *bs; - BlockDriverState *source, *target_bs; - AioContext *aio_context; -+ AioContext *old_context; - BlockMirrorBackingMode backing_mode; - Error *local_err = NULL; - QDict *options = NULL; -@@ -3914,12 +3949,22 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) - (arg->mode == NEW_IMAGE_MODE_EXISTING || - !bdrv_has_zero_init(target_bs))); - -+ -+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ -+ old_context = bdrv_get_aio_context(target_bs); -+ aio_context_release(aio_context); -+ aio_context_acquire(old_context); -+ - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); - if (ret < 0) { - bdrv_unref(target_bs); -- goto out; -+ aio_context_release(old_context); -+ return; - } - -+ aio_context_release(old_context); -+ aio_context_acquire(aio_context); -+ - blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, - arg->has_replaces, arg->replaces, arg->sync, - backing_mode, zero_target, -@@ -3961,6 +4006,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, - BlockDriverState *bs; - BlockDriverState *target_bs; - AioContext *aio_context; -+ AioContext *old_context; - BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; - Error *local_err = NULL; - bool zero_target; -@@ -3978,10 +4024,16 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, - - zero_target = (sync == MIRROR_SYNC_MODE_FULL); - -+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ -+ old_context = bdrv_get_aio_context(target_bs); - aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(aio_context); -+ aio_context_acquire(old_context); - - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -+ -+ aio_context_release(old_context); -+ aio_context_acquire(aio_context); -+ - if (ret < 0) { - goto out; - } --- -2.27.0 - diff --git a/blockdev-unify-qmp_blockdev_backup-and-blockdev-back.patch b/blockdev-unify-qmp_blockdev_backup-and-blockdev-back.patch deleted file mode 100644 index 84e29fffabed38135f24a1e83cbe12538481dbac..0000000000000000000000000000000000000000 --- a/blockdev-unify-qmp_blockdev_backup-and-blockdev-back.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 6d89e4923e9c341975dbfdd2bae153ba367a1b79 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 8 Jan 2020 15:31:33 +0100 -Subject: [PATCH] blockdev: unify qmp_blockdev_backup and blockdev-backup - transaction paths - -Issuing a blockdev-backup from qmp_blockdev_backup takes a slightly -different path than when it's issued from a transaction. In the code, -this is manifested as some redundancy between do_blockdev_backup() and -blockdev_backup_prepare(). - -This change unifies both paths, merging do_blockdev_backup() and -blockdev_backup_prepare(), and changing qmp_blockdev_backup() to -create a transaction instead of calling do_backup_common() direcly. - -As a side-effect, now qmp_blockdev_backup() is executed inside a -drained section, as it happens when creating a blockdev-backup -transaction. This change is visible from the user's perspective, as -the job gets paused and immediately resumed before starting the actual -work. - -Signed-off-by: Sergio Lopez -Reviewed-by: Max Reitz -Reviewed-by: Kevin Wolf -Signed-off-by: Kevin Wolf ---- - blockdev.c | 60 ++++++++++++------------------------------------------ - 1 file changed, 13 insertions(+), 47 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 7016054688..d3309c205a 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1983,16 +1983,13 @@ typedef struct BlockdevBackupState { - BlockJob *job; - } BlockdevBackupState; - --static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, -- Error **errp); -- - static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - { - BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); - BlockdevBackup *backup; -- BlockDriverState *bs, *target; -+ BlockDriverState *bs; -+ BlockDriverState *target_bs; - AioContext *aio_context; -- Error *local_err = NULL; - - assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); - backup = common->action->u.blockdev_backup.data; -@@ -2002,8 +1999,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - return; - } - -- target = bdrv_lookup_bs(backup->target, backup->target, errp); -- if (!target) { -+ target_bs = bdrv_lookup_bs(backup->target, backup->target, errp); -+ if (!target_bs) { - return; - } - -@@ -2014,13 +2011,10 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - /* Paired with .clean() */ - bdrv_drained_begin(state->bs); - -- state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err); -- if (local_err) { -- error_propagate(errp, local_err); -- goto out; -- } -+ state->job = do_backup_common(qapi_BlockdevBackup_base(backup), -+ bs, target_bs, aio_context, -+ common->block_job_txn, errp); - --out: - aio_context_release(aio_context); - } - -@@ -3672,41 +3666,13 @@ XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp) - return bdrv_get_xdbg_block_graph(errp); - } - --BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, -- Error **errp) -+void qmp_blockdev_backup(BlockdevBackup *backup, Error **errp) - { -- BlockDriverState *bs; -- BlockDriverState *target_bs; -- AioContext *aio_context; -- BlockJob *job; -- -- bs = bdrv_lookup_bs(backup->device, backup->device, errp); -- if (!bs) { -- return NULL; -- } -- -- target_bs = bdrv_lookup_bs(backup->target, backup->target, errp); -- if (!target_bs) { -- return NULL; -- } -- -- aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(aio_context); -- -- job = do_backup_common(qapi_BlockdevBackup_base(backup), -- bs, target_bs, aio_context, txn, errp); -- -- aio_context_release(aio_context); -- return job; --} -- --void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp) --{ -- BlockJob *job; -- job = do_blockdev_backup(arg, NULL, errp); -- if (job) { -- job_start(&job->job); -- } -+ TransactionAction action = { -+ .type = TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP, -+ .u.blockdev_backup.data = backup, -+ }; -+ blockdev_do_action(&action, errp); - } - - /* Parameter check and block job starting for drive mirroring. --- -2.27.0 - diff --git a/blockdev-unify-qmp_drive_backup-and-drive-backup-tra.patch b/blockdev-unify-qmp_drive_backup-and-drive-backup-tra.patch deleted file mode 100644 index aefa05e921b7d66a09995716f8176367817d434c..0000000000000000000000000000000000000000 --- a/blockdev-unify-qmp_drive_backup-and-drive-backup-tra.patch +++ /dev/null @@ -1,406 +0,0 @@ -From 952f7f53cdd4320d1a0328481fa578dd199eb1ce Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 8 Jan 2020 15:31:32 +0100 -Subject: [PATCH] blockdev: unify qmp_drive_backup and drive-backup transaction - paths - -Issuing a drive-backup from qmp_drive_backup takes a slightly -different path than when it's issued from a transaction. In the code, -this is manifested as some redundancy between do_drive_backup() and -drive_backup_prepare(). - -This change unifies both paths, merging do_drive_backup() and -drive_backup_prepare(), and changing qmp_drive_backup() to create a -transaction instead of calling do_backup_common() direcly. - -As a side-effect, now qmp_drive_backup() is executed inside a drained -section, as it happens when creating a drive-backup transaction. This -change is visible from the user's perspective, as the job gets paused -and immediately resumed before starting the actual work. - -Also fix tests 141, 185 and 219 to cope with the extra -JOB_STATUS_CHANGE lines. - -Signed-off-by: Sergio Lopez -Reviewed-by: Kevin Wolf -Signed-off-by: Kevin Wolf ---- - blockdev.c | 224 +++++++++++++++++-------------------- - tests/qemu-iotests/141.out | 2 + - tests/qemu-iotests/185.out | 2 + - tests/qemu-iotests/219 | 7 +- - tests/qemu-iotests/219.out | 8 ++ - 5 files changed, 117 insertions(+), 126 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 99b1cafb8f..7016054688 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1804,39 +1804,128 @@ typedef struct DriveBackupState { - BlockJob *job; - } DriveBackupState; - --static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, -- Error **errp); -+static BlockJob *do_backup_common(BackupCommon *backup, -+ BlockDriverState *bs, -+ BlockDriverState *target_bs, -+ AioContext *aio_context, -+ JobTxn *txn, Error **errp); - - static void drive_backup_prepare(BlkActionState *common, Error **errp) - { - DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); -- BlockDriverState *bs; - DriveBackup *backup; -+ BlockDriverState *bs; -+ BlockDriverState *target_bs; -+ BlockDriverState *source = NULL; - AioContext *aio_context; -+ QDict *options; - Error *local_err = NULL; -+ int flags; -+ int64_t size; -+ bool set_backing_hd = false; - - assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); - backup = common->action->u.drive_backup.data; - -+ if (!backup->has_mode) { -+ backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; -+ } -+ - bs = bdrv_lookup_bs(backup->device, backup->device, errp); - if (!bs) { - return; - } - -+ if (!bs->drv) { -+ error_setg(errp, "Device has no medium"); -+ return; -+ } -+ - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - - /* Paired with .clean() */ - bdrv_drained_begin(bs); - -- state->bs = bs; -+ if (!backup->has_format) { -+ backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ? -+ NULL : (char *) bs->drv->format_name; -+ } -+ -+ /* Early check to avoid creating target */ -+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { -+ goto out; -+ } -+ -+ flags = bs->open_flags | BDRV_O_RDWR; -+ -+ /* -+ * See if we have a backing HD we can use to create our new image -+ * on top of. -+ */ -+ if (backup->sync == MIRROR_SYNC_MODE_TOP) { -+ source = backing_bs(bs); -+ if (!source) { -+ backup->sync = MIRROR_SYNC_MODE_FULL; -+ } -+ } -+ if (backup->sync == MIRROR_SYNC_MODE_NONE) { -+ source = bs; -+ flags |= BDRV_O_NO_BACKING; -+ set_backing_hd = true; -+ } -+ -+ size = bdrv_getlength(bs); -+ if (size < 0) { -+ error_setg_errno(errp, -size, "bdrv_getlength failed"); -+ goto out; -+ } -+ -+ if (backup->mode != NEW_IMAGE_MODE_EXISTING) { -+ assert(backup->format); -+ if (source) { -+ bdrv_refresh_filename(source); -+ bdrv_img_create(backup->target, backup->format, source->filename, -+ source->drv->format_name, NULL, -+ size, flags, false, &local_err); -+ } else { -+ bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL, -+ size, flags, false, &local_err); -+ } -+ } - -- state->job = do_drive_backup(backup, common->block_job_txn, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto out; - } - -+ options = qdict_new(); -+ qdict_put_str(options, "discard", "unmap"); -+ qdict_put_str(options, "detect-zeroes", "unmap"); -+ if (backup->format) { -+ qdict_put_str(options, "driver", backup->format); -+ } -+ -+ target_bs = bdrv_open(backup->target, NULL, options, flags, errp); -+ if (!target_bs) { -+ goto out; -+ } -+ -+ if (set_backing_hd) { -+ bdrv_set_backing_hd(target_bs, source, &local_err); -+ if (local_err) { -+ goto unref; -+ } -+ } -+ -+ state->bs = bs; -+ -+ state->job = do_backup_common(qapi_DriveBackup_base(backup), -+ bs, target_bs, aio_context, -+ common->block_job_txn, errp); -+ -+unref: -+ bdrv_unref(target_bs); - out: - aio_context_release(aio_context); - } -@@ -3564,126 +3653,13 @@ static BlockJob *do_backup_common(BackupCommon *backup, - return job; - } - --static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, -- Error **errp) --{ -- BlockDriverState *bs; -- BlockDriverState *target_bs; -- BlockDriverState *source = NULL; -- BlockJob *job = NULL; -- AioContext *aio_context; -- QDict *options; -- Error *local_err = NULL; -- int flags; -- int64_t size; -- bool set_backing_hd = false; -- -- if (!backup->has_mode) { -- backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; -- } -- -- bs = bdrv_lookup_bs(backup->device, backup->device, errp); -- if (!bs) { -- return NULL; -- } -- -- if (!bs->drv) { -- error_setg(errp, "Device has no medium"); -- return NULL; -- } -- -- aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(aio_context); -- -- if (!backup->has_format) { -- backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ? -- NULL : (char *) bs->drv->format_name; -- } -- -- /* Early check to avoid creating target */ -- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { -- goto out; -- } -- -- flags = bs->open_flags | BDRV_O_RDWR; -- -- /* -- * See if we have a backing HD we can use to create our new image -- * on top of. -- */ -- if (backup->sync == MIRROR_SYNC_MODE_TOP) { -- source = backing_bs(bs); -- if (!source) { -- backup->sync = MIRROR_SYNC_MODE_FULL; -- } -- } -- if (backup->sync == MIRROR_SYNC_MODE_NONE) { -- source = bs; -- flags |= BDRV_O_NO_BACKING; -- set_backing_hd = true; -- } -- -- size = bdrv_getlength(bs); -- if (size < 0) { -- error_setg_errno(errp, -size, "bdrv_getlength failed"); -- goto out; -- } -- -- if (backup->mode != NEW_IMAGE_MODE_EXISTING) { -- assert(backup->format); -- if (source) { -- bdrv_refresh_filename(source); -- bdrv_img_create(backup->target, backup->format, source->filename, -- source->drv->format_name, NULL, -- size, flags, false, &local_err); -- } else { -- bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL, -- size, flags, false, &local_err); -- } -- } -- -- if (local_err) { -- error_propagate(errp, local_err); -- goto out; -- } -- -- options = qdict_new(); -- qdict_put_str(options, "discard", "unmap"); -- qdict_put_str(options, "detect-zeroes", "unmap"); -- if (backup->format) { -- qdict_put_str(options, "driver", backup->format); -- } -- -- target_bs = bdrv_open(backup->target, NULL, options, flags, errp); -- if (!target_bs) { -- goto out; -- } -- -- if (set_backing_hd) { -- bdrv_set_backing_hd(target_bs, source, &local_err); -- if (local_err) { -- goto unref; -- } -- } -- -- job = do_backup_common(qapi_DriveBackup_base(backup), -- bs, target_bs, aio_context, txn, errp); -- --unref: -- bdrv_unref(target_bs); --out: -- aio_context_release(aio_context); -- return job; --} -- --void qmp_drive_backup(DriveBackup *arg, Error **errp) -+void qmp_drive_backup(DriveBackup *backup, Error **errp) - { -- -- BlockJob *job; -- job = do_drive_backup(arg, NULL, errp); -- if (job) { -- job_start(&job->job); -- } -+ TransactionAction action = { -+ .type = TRANSACTION_ACTION_KIND_DRIVE_BACKUP, -+ .u.drive_backup.data = backup, -+ }; -+ blockdev_do_action(&action, errp); - } - - BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp) -diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out -index 4d71d9dcae..07e0ec66d7 100644 ---- a/tests/qemu-iotests/141.out -+++ b/tests/qemu-iotests/141.out -@@ -10,6 +10,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m. - Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} -+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}} -+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} - {"return": {}} - {"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} - {"return": {}} -diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out -index ddfbf3c765..a233be7f58 100644 ---- a/tests/qemu-iotests/185.out -+++ b/tests/qemu-iotests/185.out -@@ -51,6 +51,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l - Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} -+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} -+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} - {"return": {}} - {"return": {}} - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219 -index e0c51662c0..655f54d881 100755 ---- a/tests/qemu-iotests/219 -+++ b/tests/qemu-iotests/219 -@@ -63,7 +63,7 @@ def test_pause_resume(vm): - # logged immediately - iotests.log(vm.qmp('query-jobs')) - --def test_job_lifecycle(vm, job, job_args, has_ready=False): -+def test_job_lifecycle(vm, job, job_args, has_ready=False, is_mirror=False): - global img_size - - iotests.log('') -@@ -135,6 +135,9 @@ def test_job_lifecycle(vm, job, job_args, has_ready=False): - iotests.log('Waiting for PENDING state...') - iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) - iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) -+ if is_mirror: -+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) -+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) - - if not job_args.get('auto-finalize', True): - # PENDING state: -@@ -218,7 +221,7 @@ with iotests.FilePath('disk.img') as disk_path, \ - - for auto_finalize in [True, False]: - for auto_dismiss in [True, False]: -- test_job_lifecycle(vm, 'drive-backup', job_args={ -+ test_job_lifecycle(vm, 'drive-backup', is_mirror=True, job_args={ - 'device': 'drive0-node', - 'target': copy_path, - 'sync': 'full', -diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out -index 8ebd3fee60..0ea5d0b9d5 100644 ---- a/tests/qemu-iotests/219.out -+++ b/tests/qemu-iotests/219.out -@@ -135,6 +135,8 @@ Pause/resume in RUNNING - {"return": {}} - - Waiting for PENDING state... -+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -@@ -186,6 +188,8 @@ Pause/resume in RUNNING - {"return": {}} - - Waiting for PENDING state... -+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -@@ -245,6 +249,8 @@ Pause/resume in RUNNING - {"return": {}} - - Waiting for PENDING state... -+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} -@@ -304,6 +310,8 @@ Pause/resume in RUNNING - {"return": {}} - - Waiting for PENDING state... -+{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -+{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} - {"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} --- -2.27.0 - diff --git a/blockjob-Fix-crash-with-IOthread-when-block-commit-a.patch b/blockjob-Fix-crash-with-IOthread-when-block-commit-a.patch deleted file mode 100644 index 2efef7276e0463b863265039dccdc0afd3aee834..0000000000000000000000000000000000000000 --- a/blockjob-Fix-crash-with-IOthread-when-block-commit-a.patch +++ /dev/null @@ -1,114 +0,0 @@ -From e37cda3452309d147f1f7aec3c74249001e3db0c Mon Sep 17 00:00:00 2001 -From: Michael Qiu -Date: Wed, 12 May 2021 21:54:37 +0800 -Subject: [PATCH] blockjob: Fix crash with IOthread when block commit after - snapshot - -Currently, if guest has workloads, IO thread will acquire aio_context -lock before do io_submit, it leads to segmentfault when do block commit -after snapshot. Just like below: - -Program received signal SIGSEGV, Segmentation fault. - -[Switching to Thread 0x7f7c7d91f700 (LWP 99907)] -0x00005576d0f65aab in bdrv_mirror_top_pwritev at ../block/mirror.c:1437 -1437 ../block/mirror.c: No such file or directory. -(gdb) p s->job -$17 = (MirrorBlockJob *) 0x0 -(gdb) p s->stop -$18 = false - -Call trace of IO thread: -0 0x00005576d0f65aab in bdrv_mirror_top_pwritev at ../block/mirror.c:1437 -1 0x00005576d0f7f3ab in bdrv_driver_pwritev at ../block/io.c:1174 -2 0x00005576d0f8139d in bdrv_aligned_pwritev at ../block/io.c:1988 -3 0x00005576d0f81b65 in bdrv_co_pwritev_part at ../block/io.c:2156 -4 0x00005576d0f8e6b7 in blk_do_pwritev_part at ../block/block-backend.c:1260 -5 0x00005576d0f8e84d in blk_aio_write_entry at ../block/block-backend.c:1476 -... - -Switch to qemu main thread: -0 0x00007f903be704ed in __lll_lock_wait at -/lib/../lib64/libpthread.so.0 -1 0x00007f903be6bde6 in _L_lock_941 at /lib/../lib64/libpthread.so.0 -2 0x00007f903be6bcdf in pthread_mutex_lock at -/lib/../lib64/libpthread.so.0 -3 0x0000564b21456889 in qemu_mutex_lock_impl at -../util/qemu-thread-posix.c:79 -4 0x0000564b213af8a5 in block_job_add_bdrv at ../blockjob.c:224 -5 0x0000564b213b00ad in block_job_create at ../blockjob.c:440 -6 0x0000564b21357c0a in mirror_start_job at ../block/mirror.c:1622 -7 0x0000564b2135a9af in commit_active_start at ../block/mirror.c:1867 -8 0x0000564b2133d132 in qmp_block_commit at ../blockdev.c:2768 -9 0x0000564b2141fef3 in qmp_marshal_block_commit at -qapi/qapi-commands-block-core.c:346 -10 0x0000564b214503c9 in do_qmp_dispatch_bh at -../qapi/qmp-dispatch.c:110 -11 0x0000564b21451996 in aio_bh_poll at ../util/async.c:164 -12 0x0000564b2146018e in aio_dispatch at ../util/aio-posix.c:381 -13 0x0000564b2145187e in aio_ctx_dispatch at ../util/async.c:306 -14 0x00007f9040239049 in g_main_context_dispatch at -/lib/../lib64/libglib-2.0.so.0 -15 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:232 -16 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:255 -17 0x0000564b21447368 in main_loop_wait at ../util/main-loop.c:531 -18 0x0000564b212304e1 in qemu_main_loop at ../softmmu/runstate.c:721 -19 0x0000564b20f7975e in main at ../softmmu/main.c:50 - -In IO thread when do bdrv_mirror_top_pwritev, the job is NULL, and stop field -is false, this means the MirrorBDSOpaque "s" object has not been initialized -yet, and this object is initialized by block_job_create(), but the initialize -process is stuck in acquiring the lock. - -In this situation, IO thread come to bdrv_mirror_top_pwritev(),which means that -mirror-top node is already inserted into block graph, but its bs->opaque->job -is not initialized. - -The root cause is that qemu main thread do release/acquire when hold the lock, -at the same time, IO thread get the lock after release stage, and the crash -occured. - -Actually, in this situation, job->job.aio_context will not equal to -qemu_get_aio_context(), and will be the same as bs->aio_context, -thus, no need to release the lock, becasue bdrv_root_attach_child() -will not change the context. - -This patch fix this issue. - -Fixes: 132ada80 "block: Adjust AioContexts when attaching nodes" - -Signed-off-by: Michael Qiu -Message-Id: <20210203024059.52683-1-08005325@163.com> -Signed-off-by: Kevin Wolf ---- - blockjob.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index 74abb97bfd..72865a4a6e 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -223,14 +223,18 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, - uint64_t perm, uint64_t shared_perm, Error **errp) - { - BdrvChild *c; -+ bool need_context_ops; - - bdrv_ref(bs); -- if (job->job.aio_context != qemu_get_aio_context()) { -+ -+ need_context_ops = bdrv_get_aio_context(bs) != job->job.aio_context; -+ -+ if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { - aio_context_release(job->job.aio_context); - } - c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context, - perm, shared_perm, job, errp); -- if (job->job.aio_context != qemu_get_aio_context()) { -+ if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { - aio_context_acquire(job->job.aio_context); - } - if (c == NULL) { --- -2.27.0 - diff --git a/blockjob-update-nodes-head-while-removing-all-bdrv.patch b/blockjob-update-nodes-head-while-removing-all-bdrv.patch deleted file mode 100644 index 36cedc77f7d38b124263a6f5d09e5f1dc97de5b8..0000000000000000000000000000000000000000 --- a/blockjob-update-nodes-head-while-removing-all-bdrv.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 86b0f4022bb43b16979ba5300e8d40a1e6d44b79 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Wed, 11 Sep 2019 12:03:16 +0200 -Subject: [PATCH] blockjob: update nodes head while removing all bdrv - -block_job_remove_all_bdrv() iterates through job->nodes, calling -bdrv_root_unref_child() for each entry. The call to the latter may -reach child_job_[can_]set_aio_ctx(), which will also attempt to -traverse job->nodes, potentially finding entries that where freed -on previous iterations. - -To avoid this situation, update job->nodes head on each iteration to -ensure that already freed entries are no longer linked to the list. - -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1746631 -Signed-off-by: Sergio Lopez -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Message-id: 20190911100316.32282-1-mreitz@redhat.com -Reviewed-by: Sergio Lopez -Signed-off-by: Max Reitz -(cherry picked from commit d876bf676f5e7c6aa9ac64555e48cba8734ecb2f) -Signed-off-by: Michael Roth ---- - blockjob.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index 20b7f557da..74abb97bfd 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -186,14 +186,23 @@ static const BdrvChildRole child_job = { - - void block_job_remove_all_bdrv(BlockJob *job) - { -- GSList *l; -- for (l = job->nodes; l; l = l->next) { -+ /* -+ * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(), -+ * which will also traverse job->nodes, so consume the list one by -+ * one to make sure that such a concurrent access does not attempt -+ * to process an already freed BdrvChild. -+ */ -+ while (job->nodes) { -+ GSList *l = job->nodes; - BdrvChild *c = l->data; -+ -+ job->nodes = l->next; -+ - bdrv_op_unblock_all(c->bs, job->blocker); - bdrv_root_unref_child(c); -+ -+ g_slist_free_1(l); - } -- g_slist_free(job->nodes); -- job->nodes = NULL; - } - - bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) --- -2.23.0 diff --git a/bt-use-size_t-type-for-length-parameters-instead-of-.patch b/bt-use-size_t-type-for-length-parameters-instead-of-.patch deleted file mode 100644 index 2005979aec4f4401b512bd0ea72d6c12493f5ea1..0000000000000000000000000000000000000000 --- a/bt-use-size_t-type-for-length-parameters-instead-of-.patch +++ /dev/null @@ -1,794 +0,0 @@ -From f9ab92373813cfccd31f29c0d963232f65cb5f88 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 22 May 2020 12:22:26 +0800 -Subject: [PATCH] bt: use size_t type for length parameters instead of int - -From: Prasad J Pandit - -The length parameter values are not negative, thus use an unsigned -type 'size_t' for them. Many routines pass 'len' values to memcpy(3) -calls. If it was negative, it could lead to memory corruption issues. -Add check to avoid it. - -Reported-by: Arash TC -Signed-off-by: Prasad J Pandit - -diff --git a/bt-host.c b/bt-host.c -index 2f8f631..b73a44d 100644 ---- a/bt-host.c -+++ b/bt-host.c -@@ -43,7 +43,7 @@ struct bt_host_hci_s { - }; - - static void bt_host_send(struct HCIInfo *hci, -- int type, const uint8_t *data, int len) -+ int type, const uint8_t *data, size_t len) - { - struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci; - uint8_t pkt = type; -@@ -63,17 +63,17 @@ static void bt_host_send(struct HCIInfo *hci, - } - } - --static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len) -+static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, size_t len) - { - bt_host_send(hci, HCI_COMMAND_PKT, data, len); - } - --static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len) -+static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, size_t len) - { - bt_host_send(hci, HCI_ACLDATA_PKT, data, len); - } - --static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len) -+static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, size_t len) - { - bt_host_send(hci, HCI_SCODATA_PKT, data, len); - } -diff --git a/bt-vhci.c b/bt-vhci.c -index 886e146..32ef1c5 100644 ---- a/bt-vhci.c -+++ b/bt-vhci.c -@@ -89,7 +89,7 @@ static void vhci_read(void *opaque) - } - - static void vhci_host_send(void *opaque, -- int type, const uint8_t *data, int len) -+ int type, const uint8_t *data, size_t len) - { - struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; - #if 0 -@@ -112,6 +112,7 @@ static void vhci_host_send(void *opaque, - static uint8_t buf[4096]; - - buf[0] = type; -+ assert(len < sizeof(buf)); - memcpy(buf + 1, data, len); - - while (write(s->fd, buf, len + 1) < 0) -@@ -124,13 +125,13 @@ static void vhci_host_send(void *opaque, - } - - static void vhci_out_hci_packet_event(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - vhci_host_send(opaque, HCI_EVENT_PKT, data, len); - } - - static void vhci_out_hci_packet_acl(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len); - } -diff --git a/hw/bt/core.c b/hw/bt/core.c -index dfb196e..f548b3d 100644 ---- a/hw/bt/core.c -+++ b/hw/bt/core.c -@@ -44,7 +44,7 @@ static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link) - } - - static void bt_dummy_lmp_acl_resp(struct bt_link_s *link, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - error_report("%s: stray ACL response PDU, fixme", __func__); - exit(-1); -diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c -index 3d60654..f7a74c0 100644 ---- a/hw/bt/hci-csr.c -+++ b/hw/bt/hci-csr.c -@@ -103,7 +103,7 @@ static inline void csrhci_fifo_wake(struct csrhci_s *s) - } - - #define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len) --static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) -+static uint8_t *csrhci_out_packet(struct csrhci_s *s, size_t len) - { - int off = s->out_start + s->out_len; - -@@ -112,14 +112,14 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) - - if (off < FIFO_LEN) { - if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) { -- error_report("%s: can't alloc %i bytes", __func__, len); -+ error_report("%s: can't alloc %zu bytes", __func__, len); - exit(-1); - } - return s->outfifo + off; - } - - if (s->out_len > s->out_size) { -- error_report("%s: can't alloc %i bytes", __func__, len); -+ error_report("%s: can't alloc %zu bytes", __func__, len); - exit(-1); - } - -@@ -127,7 +127,7 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) - } - - static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, -- int type, int len) -+ int type, size_t len) - { - uint8_t *ret = csrhci_out_packetz(s, len + 2); - -@@ -138,7 +138,7 @@ static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, - } - - static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, -- int evt, int len) -+ int evt, size_t len) - { - uint8_t *ret = csrhci_out_packetz(s, - len + 1 + sizeof(struct hci_event_hdr)); -@@ -151,7 +151,7 @@ static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, - } - - static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf, -- uint8_t *data, int len) -+ uint8_t *data, size_t len) - { - int offset; - uint8_t *rpkt; -@@ -320,18 +320,18 @@ static int csrhci_write(struct Chardev *chr, - struct csrhci_s *s = (struct csrhci_s *)chr; - int total = 0; - -- if (!s->enable) -+ if (!s->enable || len <= 0) - return 0; - - for (;;) { - int cnt = MIN(len, s->in_needed - s->in_len); -- if (cnt) { -- memcpy(s->inpkt + s->in_len, buf, cnt); -- s->in_len += cnt; -- buf += cnt; -- len -= cnt; -- total += cnt; -- } -+ assert(cnt > 0); -+ -+ memcpy(s->inpkt + s->in_len, buf, cnt); -+ s->in_len += cnt; -+ buf += cnt; -+ len -= cnt; -+ total += cnt; - - if (s->in_len < s->in_needed) { - break; -@@ -363,7 +363,7 @@ static int csrhci_write(struct Chardev *chr, - } - - static void csrhci_out_hci_packet_event(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - struct csrhci_s *s = (struct csrhci_s *) opaque; - uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ -@@ -375,7 +375,7 @@ static void csrhci_out_hci_packet_event(void *opaque, - } - - static void csrhci_out_hci_packet_acl(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - struct csrhci_s *s = (struct csrhci_s *) opaque; - uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ -diff --git a/hw/bt/hci.c b/hw/bt/hci.c -index c7958f6..9c4f957 100644 ---- a/hw/bt/hci.c -+++ b/hw/bt/hci.c -@@ -31,7 +31,7 @@ - - struct bt_hci_s { - uint8_t *(*evt_packet)(void *opaque); -- void (*evt_submit)(void *opaque, int len); -+ void (*evt_submit)(void *opaque, size_t len); - void *opaque; - uint8_t evt_buf[256]; - -@@ -61,7 +61,7 @@ struct bt_hci_s { - struct bt_hci_master_link_s { - struct bt_link_s *link; - void (*lmp_acl_data)(struct bt_link_s *link, -- const uint8_t *data, int start, int len); -+ const uint8_t *data, int start, size_t len); - QEMUTimer *acl_mode_timer; - } handle[HCI_HANDLES_MAX]; - uint32_t role_bmp; -@@ -433,7 +433,7 @@ static const uint8_t bt_event_reserved_mask[8] = { - }; - - --static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) -+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, size_t len) - { - } - -@@ -451,13 +451,13 @@ struct HCIInfo null_hci = { - - - static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, -- int evt, int len) -+ int evt, size_t len) - { - uint8_t *packet, mask; - int mask_byte; - - if (len > 255) { -- error_report("%s: HCI event params too long (%ib)", __func__, len); -+ error_report("%s: HCI event params too long (%zub)", __func__, len); - exit(-1); - } - -@@ -474,7 +474,7 @@ static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, - } - - static inline void bt_hci_event(struct bt_hci_s *hci, int evt, -- void *params, int len) -+ void *params, size_t len) - { - uint8_t *packet = bt_hci_event_start(hci, evt, len); - -@@ -499,7 +499,7 @@ static inline void bt_hci_event_status(struct bt_hci_s *hci, int status) - } - - static inline void bt_hci_event_complete(struct bt_hci_s *hci, -- void *ret, int len) -+ void *ret, size_t len) - { - uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE, - len + EVT_CMD_COMPLETE_SIZE); -@@ -1476,7 +1476,7 @@ static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci, - } - - static void bt_submit_hci(struct HCIInfo *info, -- const uint8_t *data, int length) -+ const uint8_t *data, size_t length) - { - struct bt_hci_s *hci = hci_from_info(info); - uint16_t cmd; -@@ -1970,7 +1970,7 @@ static void bt_submit_hci(struct HCIInfo *info, - break; - - short_hci: -- error_report("%s: HCI packet too short (%iB)", __func__, length); -+ error_report("%s: HCI packet too short (%zuB)", __func__, length); - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } -@@ -1981,7 +1981,7 @@ static void bt_submit_hci(struct HCIInfo *info, - * know that a packet contained the last fragment of the SDU when the next - * SDU starts. */ - static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - struct hci_acl_hdr *pkt = (void *) hci->acl_buf; - -@@ -1989,7 +1989,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, - /* TODO: avoid memcpy'ing */ - - if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) { -- error_report("%s: can't take ACL packets %i bytes long", -+ error_report("%s: can't take ACL packets %zu bytes long", - __func__, len); - return; - } -@@ -2003,7 +2003,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, - } - - static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; - -@@ -2012,14 +2012,14 @@ static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, - } - - static void bt_hci_lmp_acl_data_host(struct bt_link_s *link, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - bt_hci_lmp_acl_data(hci_from_device(link->host), - link->handle, data, start, len); - } - - static void bt_submit_acl(struct HCIInfo *info, -- const uint8_t *data, int length) -+ const uint8_t *data, size_t length) - { - struct bt_hci_s *hci = hci_from_info(info); - uint16_t handle; -@@ -2027,7 +2027,7 @@ static void bt_submit_acl(struct HCIInfo *info, - struct bt_link_s *link; - - if (length < HCI_ACL_HDR_SIZE) { -- error_report("%s: ACL packet too short (%iB)", __func__, length); -+ error_report("%s: ACL packet too short (%zuB)", __func__, length); - return; - } - -@@ -2045,7 +2045,7 @@ static void bt_submit_acl(struct HCIInfo *info, - handle &= ~HCI_HANDLE_OFFSET; - - if (datalen > length) { -- error_report("%s: ACL packet too short (%iB < %iB)", -+ error_report("%s: ACL packet too short (%zuB < %iB)", - __func__, length, datalen); - return; - } -@@ -2087,7 +2087,7 @@ static void bt_submit_acl(struct HCIInfo *info, - } - - static void bt_submit_sco(struct HCIInfo *info, -- const uint8_t *data, int length) -+ const uint8_t *data, size_t length) - { - struct bt_hci_s *hci = hci_from_info(info); - uint16_t handle; -@@ -2106,7 +2106,7 @@ static void bt_submit_sco(struct HCIInfo *info, - } - - if (datalen > length) { -- error_report("%s: SCO packet too short (%iB < %iB)", -+ error_report("%s: SCO packet too short (%zuB < %iB)", - __func__, length, datalen); - return; - } -@@ -2127,7 +2127,7 @@ static uint8_t *bt_hci_evt_packet(void *opaque) - return s->evt_buf; - } - --static void bt_hci_evt_submit(void *opaque, int len) -+static void bt_hci_evt_submit(void *opaque, size_t len) - { - /* TODO: notify upper layer */ - struct bt_hci_s *s = opaque; -diff --git a/hw/bt/hid.c b/hw/bt/hid.c -index 066ca99..fe15434 100644 ---- a/hw/bt/hid.c -+++ b/hw/bt/hid.c -@@ -95,7 +95,7 @@ struct bt_hid_device_s { - int data_type; - int intr_state; - struct { -- int len; -+ size_t len; - uint8_t buffer[1024]; - } dataother, datain, dataout, feature, intrdataout; - enum { -@@ -168,7 +168,7 @@ static void bt_hid_disconnect(struct bt_hid_device_s *s) - } - - static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - uint8_t *pkt, hdr = (BT_DATA << 4) | type; - int plen; -@@ -189,7 +189,7 @@ static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, - } - - static void bt_hid_control_transaction(struct bt_hid_device_s *s, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - uint8_t type, parameter; - int rlen, ret = -1; -@@ -361,7 +361,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, - bt_hid_send_handshake(s, ret); - } - --static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len) -+static void bt_hid_control_sdu(void *opaque, const uint8_t *data, size_t len) - { - struct bt_hid_device_s *hid = opaque; - -@@ -387,7 +387,7 @@ static void bt_hid_datain(HIDState *hs) - hid->datain.buffer, hid->datain.len); - } - --static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len) -+static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, size_t len) - { - struct bt_hid_device_s *hid = opaque; - -diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c -index d67098a..2f70a03 100644 ---- a/hw/bt/l2cap.c -+++ b/hw/bt/l2cap.c -@@ -31,10 +31,10 @@ struct l2cap_instance_s { - int role; - - uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); -- int frame_in_len; -+ uint32_t frame_in_len; - - uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); -- int frame_out_len; -+ uint32_t frame_out_len; - - /* Signalling channel timers. They exist per-request but we can make - * sure we have no more than one outstanding request at any time. */ -@@ -48,7 +48,7 @@ struct l2cap_instance_s { - struct bt_l2cap_conn_params_s params; - - void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid, -- const l2cap_hdr *hdr, int len); -+ const l2cap_hdr *hdr, size_t len); - int mps; - int min_mtu; - -@@ -67,7 +67,7 @@ struct l2cap_instance_s { - - /* Only flow-controlled, connection-oriented channels */ - uint8_t sdu[65536]; /* TODO: dynamically allocate */ -- int len_cur, len_total; -+ uint32_t len_cur, len_total; - int rexmit; - int monitor_timeout; - QEMUTimer *monitor_timer; -@@ -139,7 +139,7 @@ static const uint16_t l2cap_fcs16_table[256] = { - 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, - }; - --static uint16_t l2cap_fcs16(const uint8_t *message, int len) -+static uint16_t l2cap_fcs16(const uint8_t *message, size_t len) - { - uint16_t fcs = 0x0000; - -@@ -185,7 +185,7 @@ static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch) - } - - static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id, -- uint16_t reason, const void *data, int plen) -+ uint16_t reason, const void *data, size_t plen) - { - uint8_t *pkt; - l2cap_cmd_hdr *hdr; -@@ -246,7 +246,7 @@ static void l2cap_connection_response(struct l2cap_instance_s *l2cap, - } - - static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, -- int dcid, int flag, const uint8_t *data, int len) -+ int dcid, int flag, const uint8_t *data, size_t len) - { - uint8_t *pkt; - l2cap_cmd_hdr *hdr; -@@ -274,7 +274,7 @@ static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, - } - - static void l2cap_configuration_response(struct l2cap_instance_s *l2cap, -- int scid, int flag, int result, const uint8_t *data, int len) -+ int scid, int flag, int result, const uint8_t *data, size_t len) - { - uint8_t *pkt; - l2cap_cmd_hdr *hdr; -@@ -321,7 +321,7 @@ static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap, - } - - static void l2cap_echo_response(struct l2cap_instance_s *l2cap, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - uint8_t *pkt; - l2cap_cmd_hdr *hdr; -@@ -342,7 +342,7 @@ static void l2cap_echo_response(struct l2cap_instance_s *l2cap, - } - - static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, -- int result, const uint8_t *data, int len) -+ int result, const uint8_t *data, size_t len) - { - uint8_t *pkt; - l2cap_cmd_hdr *hdr; -@@ -365,16 +365,18 @@ static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); - } - --static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len); -+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, -+ size_t len); - static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms); - #if 0 --static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len); -+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, -+ size_t len); - static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm); - #endif - static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, -- const l2cap_hdr *hdr, int len); -+ const l2cap_hdr *hdr, size_t len); - static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, -- const l2cap_hdr *hdr, int len); -+ const l2cap_hdr *hdr, size_t len); - - static int l2cap_cid_new(struct l2cap_instance_s *l2cap) - { -@@ -498,7 +500,7 @@ static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap, - - static int l2cap_channel_config(struct l2cap_instance_s *l2cap, - struct l2cap_chan_s *ch, int flag, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - l2cap_conf_opt *opt; - l2cap_conf_opt_qos *qos; -@@ -683,7 +685,7 @@ static int l2cap_channel_config(struct l2cap_instance_s *l2cap, - } - - static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, -- int flag, int cid, const uint8_t *data, int len) -+ int flag, int cid, const uint8_t *data, size_t len) - { - struct l2cap_chan_s *ch; - -@@ -715,7 +717,7 @@ static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, - } - - static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap, -- int result, int flag, int cid, const uint8_t *data, int len) -+ int result, int flag, int cid, const uint8_t *data, size_t len) - { - struct l2cap_chan_s *ch; - -@@ -783,7 +785,7 @@ static void l2cap_info(struct l2cap_instance_s *l2cap, int type) - } - - static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id, -- const uint8_t *params, int len) -+ const uint8_t *params, size_t len) - { - int err; - -@@ -938,7 +940,7 @@ static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable) - } - - /* Command frame SDU */ --static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) -+static void l2cap_cframe_in(void *opaque, const uint8_t *data, size_t len) - { - struct l2cap_instance_s *l2cap = opaque; - const l2cap_cmd_hdr *hdr; -@@ -966,7 +968,7 @@ static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) - } - - /* Group frame SDU */ --static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len) -+static void l2cap_gframe_in(void *opaque, const uint8_t *data, size_t len) - { - } - -@@ -977,7 +979,7 @@ static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl) - - /* Basic L2CAP mode Information frame */ - static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, -- const l2cap_hdr *hdr, int len) -+ const l2cap_hdr *hdr, size_t len) - { - /* We have a full SDU, no further processing */ - ch->params.sdu_in(ch->params.opaque, hdr->data, len); -@@ -985,7 +987,7 @@ static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, - - /* Flow Control and Retransmission mode frame */ - static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, -- const l2cap_hdr *hdr, int len) -+ const l2cap_hdr *hdr, size_t len) - { - uint16_t fcs = lduw_le_p(hdr->data + len - 2); - -@@ -1076,7 +1078,7 @@ static void l2cap_frame_in(struct l2cap_instance_s *l2cap, - - /* "Recombination" */ - static void l2cap_pdu_in(struct l2cap_instance_s *l2cap, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - const l2cap_hdr *hdr = (void *) l2cap->frame_in; - -@@ -1123,7 +1125,7 @@ static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap) - (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len); - } - --static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len) -+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, size_t len) - { - struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; - -@@ -1146,7 +1148,7 @@ static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms) - - #if 0 - /* Stub: Only used if an emulated device requests outgoing flow control */ --static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len) -+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, size_t len) - { - struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; - -@@ -1291,7 +1293,7 @@ static void l2cap_lmp_disconnect_slave(struct bt_link_s *link) - } - - static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - struct slave_l2cap_instance_s *l2cap = - (struct slave_l2cap_instance_s *) link; -@@ -1304,7 +1306,7 @@ static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, - - /* Stub */ - static void l2cap_lmp_acl_data_host(struct bt_link_s *link, -- const uint8_t *data, int start, int len) -+ const uint8_t *data, int start, size_t len) - { - struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; - struct l2cap_instance_s *l2cap = -diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c -index 2860d76..6bfb174 100644 ---- a/hw/bt/sdp.c -+++ b/hw/bt/sdp.c -@@ -496,7 +496,7 @@ static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp, - return end + 2; - } - --static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) -+static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, size_t len) - { - struct bt_l2cap_sdp_state_s *sdp = opaque; - enum bt_sdp_cmd pdu_id; -@@ -506,7 +506,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) - int rsp_len = 0; - - if (len < 5) { -- error_report("%s: short SDP PDU (%iB).", __func__, len); -+ error_report("%s: short SDP PDU (%zuB).", __func__, len); - return; - } - -@@ -517,7 +517,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) - len -= 5; - - if (len != plen) { -- error_report("%s: wrong SDP PDU length (%iB != %iB).", -+ error_report("%s: wrong SDP PDU length (%iB != %zuB).", - __func__, plen, len); - err = SDP_INVALID_PDU_SIZE; - goto respond; -diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c -index 670ba32..240a901 100644 ---- a/hw/usb/dev-bluetooth.c -+++ b/hw/usb/dev-bluetooth.c -@@ -265,7 +265,7 @@ static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo) - } - - static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - int off = fifo->dstart + fifo->dlen; - uint8_t *buf; -@@ -274,13 +274,13 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, - if (off <= DFIFO_LEN_MASK) { - if (off + len > DFIFO_LEN_MASK + 1 && - (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) { -- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len); -+ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len); - exit(-1); - } - buf = fifo->data + off; - } else { - if (fifo->dlen > fifo->dsize) { -- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len); -+ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len); - exit(-1); - } - buf = fifo->data + off - fifo->dsize; -@@ -319,7 +319,7 @@ static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, - - static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s, - struct usb_hci_out_fifo_s *fifo, -- void (*send)(struct HCIInfo *, const uint8_t *, int), -+ void (*send)(struct HCIInfo *, const uint8_t *, size_t), - int (*complete)(const uint8_t *, int), - USBPacket *p) - { -@@ -478,7 +478,7 @@ static void usb_bt_handle_data(USBDevice *dev, USBPacket *p) - } - - static void usb_bt_out_hci_packet_event(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - struct USBBtState *s = (struct USBBtState *) opaque; - -@@ -489,7 +489,7 @@ static void usb_bt_out_hci_packet_event(void *opaque, - } - - static void usb_bt_out_hci_packet_acl(void *opaque, -- const uint8_t *data, int len) -+ const uint8_t *data, size_t len) - { - struct USBBtState *s = (struct USBBtState *) opaque; - -diff --git a/include/hw/bt.h b/include/hw/bt.h -index b5e11d4..bc362aa 100644 ---- a/include/hw/bt.h -+++ b/include/hw/bt.h -@@ -94,9 +94,9 @@ struct bt_device_s { - void (*lmp_disconnect_master)(struct bt_link_s *link); - void (*lmp_disconnect_slave)(struct bt_link_s *link); - void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data, -- int start, int len); -+ int start, size_t len); - void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data, -- int start, int len); -+ int start, size_t len); - void (*lmp_mode_change)(struct bt_link_s *link); - - void (*handle_destroy)(struct bt_device_s *device); -@@ -148,12 +148,12 @@ struct bt_l2cap_device_s { - - struct bt_l2cap_conn_params_s { - /* Input */ -- uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len); -+ uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, size_t len); - void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan); - int remote_mtu; - /* Output */ - void *opaque; -- void (*sdu_in)(void *opaque, const uint8_t *data, int len); -+ void (*sdu_in)(void *opaque, const uint8_t *data, size_t len); - void (*close)(void *opaque); - }; - -diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h -index 2fd8c0f..df8fb63 100644 ---- a/include/sysemu/bt.h -+++ b/include/sysemu/bt.h -@@ -5,12 +5,12 @@ - - typedef struct HCIInfo { - int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); -- void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); -- void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); -- void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len); -+ void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); -+ void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); -+ void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); - void *opaque; -- void (*evt_recv)(void *opaque, const uint8_t *data, int len); -- void (*acl_recv)(void *opaque, const uint8_t *data, int len); -+ void (*evt_recv)(void *opaque, const uint8_t *data, size_t len); -+ void (*acl_recv)(void *opaque, const uint8_t *data, size_t len); - } HCIInfo; - - /* bt-host.c */ --- -1.8.3.1 - diff --git a/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch b/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch deleted file mode 100644 index e714cb10bef351cd6ed6df71d08f3666df879ed5..0000000000000000000000000000000000000000 --- a/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch +++ /dev/null @@ -1,44 +0,0 @@ -From b9e4a4ff6f3292927adb1463777c86cd4063a6ef Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Sat, 18 Apr 2020 12:10:11 +0800 -Subject: [PATCH] bugfix: Use gicr_typer in arm_gicv3_icc_reset - -The KVM_VGIC_ATTR macro expect the second parameter as gicr_typer, -of which high 32bit is constructed by mp_affinity. For most case, -the high 32bit of mp_affinity is zero, so it will always access the -ICC_CTLR_EL1 of CPU0. - -Signed-off-by: Keqian Zhu ---- - hw/intc/arm_gicv3_kvm.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c -index d9c72f85be..b1e74147ba 100644 ---- a/hw/intc/arm_gicv3_kvm.c -+++ b/hw/intc/arm_gicv3_kvm.c -@@ -661,13 +661,11 @@ static void kvm_arm_gicv3_get(GICv3State *s) - - static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) - { -- ARMCPU *cpu; - GICv3State *s; - GICv3CPUState *c; - - c = (GICv3CPUState *)env->gicv3state; - s = c->gic; -- cpu = ARM_CPU(c->cpu); - - c->icc_pmr_el1 = 0; - c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; -@@ -684,7 +682,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) - - /* Initialize to actual HW supported configuration */ - kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, -- KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), -+ KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer), - &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); - - c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; --- -2.19.1 diff --git a/bugfix-fix-eventfds-may-double-free-when-vm_id-reuse.patch b/bugfix-fix-eventfds-may-double-free-when-vm_id-reuse.patch new file mode 100644 index 0000000000000000000000000000000000000000..5802835732b041606945c051bc2a5c5917ebb282 --- /dev/null +++ b/bugfix-fix-eventfds-may-double-free-when-vm_id-reuse.patch @@ -0,0 +1,48 @@ +From 02a17066ac3dfb5e53b72b15a80643154990191b Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 21:50:28 +0800 +Subject: [PATCH] bugfix: fix eventfds may double free when vm_id reused in + ivshmem + +As the ivshmem Server-Client Protol describes, when a +client disconnects from the server, server sends disconnect +notifications to the other clients. And the other clients +will free the eventfds of the disconnected client according +to the client ID. If the client ID is reused, the eventfds +may be double freed. + +It will be solved by setting eventfds to NULL after freeing +and allocating memory for it when it's used. + +Signed-off-by: Peng Liang +Signed-off-by: jiangdongxu +--- + hw/misc/ivshmem.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c +index 1ba4a98377..05f06ed6cf 100644 +--- a/hw/misc/ivshmem.c ++++ b/hw/misc/ivshmem.c +@@ -400,6 +400,7 @@ static void close_peer_eventfds(IVShmemState *s, int posn) + } + + g_free(s->peers[posn].eventfds); ++ s->peers[posn].eventfds = NULL; + s->peers[posn].nb_eventfds = 0; + } + +@@ -530,6 +531,10 @@ static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd, + close(fd); + return; + } ++ if (peer->eventfds == NULL) { ++ peer->eventfds = g_new0(EventNotifier, s->vectors); ++ peer->nb_eventfds = 0; ++ } + vector = peer->nb_eventfds++; + + IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd); +-- +2.27.0 + diff --git a/bugfix-fix-mmio-information-leak-and-ehci-vm-escape-.patch b/bugfix-fix-mmio-information-leak-and-ehci-vm-escape-.patch new file mode 100644 index 0000000000000000000000000000000000000000..f463c6b4b060133576134775c5c5c5ddcd400d92 --- /dev/null +++ b/bugfix-fix-mmio-information-leak-and-ehci-vm-escape-.patch @@ -0,0 +1,67 @@ +From f14ea0bd2596f94ad926009411b8ffda9c2c2cda Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 22:42:23 +0800 +Subject: [PATCH] bugfix: fix mmio information leak and ehci vm escape 0-day + vulnerability + +Signed-off-by: Yutao Ai +Signed-off-by: jiangdongxu +--- + hw/usb/core.c | 20 ++++++++++++++++++-- + hw/usb/hcd-ehci.c | 2 ++ + 2 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 51b36126ca..a62826e051 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -206,7 +206,15 @@ static void do_token_in(USBDevice *s, USBPacket *p) + + case SETUP_STATE_DATA: + if (s->setup_buf[0] & USB_DIR_IN) { +- int len = s->setup_len - s->setup_index; ++ int len; ++ if (s->setup_len > sizeof(s->data_buf)) { ++ fprintf(stderr, ++ "usb_generic_handle_packet: ctrl buffer too small do_token_in(%d > %zu)\n", ++ s->setup_len, sizeof(s->data_buf)); ++ p->status = USB_RET_STALL; ++ return; ++ } ++ len = s->setup_len - s->setup_index; + if (len > p->iov.size) { + len = p->iov.size; + } +@@ -244,7 +252,15 @@ static void do_token_out(USBDevice *s, USBPacket *p) + + case SETUP_STATE_DATA: + if (!(s->setup_buf[0] & USB_DIR_IN)) { +- int len = s->setup_len - s->setup_index; ++ int len; ++ if (s->setup_len > sizeof(s->data_buf)) { ++ fprintf(stderr, ++ "usb_generic_handle_packet: ctrl buffer too small do_token_out(%d > %zu)\n", ++ s->setup_len, sizeof(s->data_buf)); ++ p->status = USB_RET_STALL; ++ return; ++ } ++ len = s->setup_len - s->setup_index; + if (len > p->iov.size) { + len = p->iov.size; + } +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 6caa7ac6c2..1415107315 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -612,6 +612,8 @@ static void ehci_free_queue(EHCIQueue *q, const char *warn) + ehci_trace_guest_bug(q->ehci, warn); + } + QTAILQ_REMOVE(head, q, next); ++ memset(q, 0, sizeof(*q)); ++ *(volatile char *)q = *(volatile char *)q; + g_free(q); + } + +-- +2.27.0 + diff --git a/bugfix-fix-possible-memory-leak.patch b/bugfix-fix-possible-memory-leak.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e6a611ed470f6d0acdbbaa2889bcbd90c089353 --- /dev/null +++ b/bugfix-fix-possible-memory-leak.patch @@ -0,0 +1,97 @@ +From 03e7e232a323c45205d3c6ecb7d8e52e7209d9eb Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 22:12:50 +0800 +Subject: [PATCH] bugfix: fix possible memory leak + +Signed-off-by: caojinhua +Signed-off-by: jiangdongxu +--- + migration/savevm.c | 2 ++ + qga/main.c | 18 +++++++++++++----- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/migration/savevm.c b/migration/savevm.c +index d59e976d50..803cd9004d 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1427,6 +1427,7 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, + ret = vmstate_save(f, se, vmdesc); + if (ret) { + qemu_file_set_error(f, ret); ++ json_writer_free(vmdesc); + return ret; + } + trace_savevm_section_end(se->idstr, se->section_id, 0); +@@ -1443,6 +1444,7 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, + error_report("%s: bdrv_inactivate_all() failed (%d)", + __func__, ret); + qemu_file_set_error(f, ret); ++ json_writer_free(vmdesc); + return ret; + } + } +diff --git a/qga/main.c b/qga/main.c +index 15fd3a4149..6f09a689ac 100644 +--- a/qga/main.c ++++ b/qga/main.c +@@ -1283,7 +1283,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) + if (g_mkdir_with_parents(config->state_dir, S_IRWXU) == -1) { + g_critical("unable to create (an ancestor of) the state directory" + " '%s': %s", config->state_dir, strerror(errno)); +- return NULL; ++ goto failed; + } + #endif + +@@ -1308,7 +1308,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) + if (!log_file) { + g_critical("unable to open specified log file: %s", + strerror(errno)); +- return NULL; ++ goto failed; + } + s->log_file = log_file; + } +@@ -1319,7 +1319,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) + s->pstate_filepath, + ga_is_frozen(s))) { + g_critical("failed to load persistent state"); +- return NULL; ++ goto failed; + } + + config->blacklist = ga_command_blacklist_init(config->blacklist); +@@ -1340,7 +1340,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) + #ifndef _WIN32 + if (!register_signal_handlers()) { + g_critical("failed to register signal handlers"); +- return NULL; ++ goto failed; + } + #endif + +@@ -1353,12 +1353,20 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) + s->wakeup_event = CreateEvent(NULL, TRUE, FALSE, TEXT("WakeUp")); + if (s->wakeup_event == NULL) { + g_critical("CreateEvent failed"); +- return NULL; ++ goto failed; + } + #endif + + ga_state = s; + return s; ++failed: ++ g_free(s->pstate_filepath); ++ g_free(s->state_filepath_isfrozen); ++ if (s->log_file) { ++ fclose(s->log_file); ++ } ++ g_free(s); ++ return NULL; + } + + static void cleanup_agent(GAState *s) +-- +2.27.0 + diff --git a/bugfix-fix-some-illegal-memory-access-and-memory-lea.patch b/bugfix-fix-some-illegal-memory-access-and-memory-lea.patch new file mode 100644 index 0000000000000000000000000000000000000000..48c7970efa46bf78c772159cae0c501ff997ae1a --- /dev/null +++ b/bugfix-fix-some-illegal-memory-access-and-memory-lea.patch @@ -0,0 +1,53 @@ +From 0a0a490c805fadc7191489277e77fbf9688b39ab Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 21:32:37 +0800 +Subject: [PATCH] bugfix: fix some illegal memory access and memory leak + +Signed-off-by: yuxiating +Signed-off-by: jiangdongxu +--- + contrib/elf2dmp/main.c | 1 + + hw/display/cirrus_vga.c | 2 +- + util/range.c | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c +index 20b477d582..3f0d1eb709 100644 +--- a/contrib/elf2dmp/main.c ++++ b/contrib/elf2dmp/main.c +@@ -125,6 +125,7 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb, + + if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) { + eprintf("Failed to extract entire KDBG\n"); ++ free(kdbg); + return NULL; + } + +diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c +index fdca6ca659..c66ed801ef 100644 +--- a/hw/display/cirrus_vga.c ++++ b/hw/display/cirrus_vga.c +@@ -834,7 +834,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) + word alignment, so we keep them for the next line */ + /* XXX: keep alignment to speed up transfer */ + end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; +- copy_count = s->cirrus_srcptr_end - end_ptr; ++ copy_count = MIN(s->cirrus_srcptr_end - end_ptr, CIRRUS_BLTBUFSIZE); + memmove(s->cirrus_bltbuf, end_ptr, copy_count); + s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; + s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; +diff --git a/util/range.c b/util/range.c +index 098d9d2dc0..83d1a6c302 100644 +--- a/util/range.c ++++ b/util/range.c +@@ -65,6 +65,7 @@ GList *range_list_insert(GList *list, Range *data) + range_extend(l->data, l->next->data); + g_free(l->next->data); + new_l = g_list_delete_link(list, l->next); ++ l->next = NULL; + assert(new_l == list); + } + +-- +2.27.0 + diff --git a/bugfix-irq-Avoid-covering-object-refcount-of-qemu_ir.patch b/bugfix-irq-Avoid-covering-object-refcount-of-qemu_ir.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a329c7f1d4ed1472e22909b75bcd56cd92b32a0 --- /dev/null +++ b/bugfix-irq-Avoid-covering-object-refcount-of-qemu_ir.patch @@ -0,0 +1,32 @@ +From 32353a7838f9ff38c5bd768252a79bd8e485658b Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 27 Jul 2020 20:39:07 +0800 +Subject: [PATCH] bugfix: irq: Avoid covering object refcount of qemu_irq + +Avoid covering object refcount of qemu_irq, otherwise it may causes +memory leak. + +Signed-off-by: Keqian Zhu +--- + hw/core/irq.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/core/irq.c b/hw/core/irq.c +index 8a9cbdd556..700a6373d8 100644 +--- a/hw/core/irq.c ++++ b/hw/core/irq.c +@@ -126,7 +126,10 @@ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n) + int i; + qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n); + for (i = 0; i < n; i++) { +- *old_irqs[i] = *gpio_in[i]; ++ old_irqs[i]->handler = gpio_in[i]->handler; ++ old_irqs[i]->opaque = gpio_in[i]->opaque; ++ old_irqs[i]->n = gpio_in[i]->n; ++ + gpio_in[i]->handler = handler; + gpio_in[i]->opaque = &old_irqs[i]; + } +-- +2.27.0 + diff --git a/bugfix-pointer-double-free-in-func-qemu_savevm_state.patch b/bugfix-pointer-double-free-in-func-qemu_savevm_state.patch new file mode 100644 index 0000000000000000000000000000000000000000..e6e0c2d8d212c18d4120c3c17f135cf00ad6f934 --- /dev/null +++ b/bugfix-pointer-double-free-in-func-qemu_savevm_state.patch @@ -0,0 +1,38 @@ +From 48ff0d29c594ccfa80a3d58c97bdb7e656c8f541 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Mon, 20 Jun 2022 17:19:44 +0800 +Subject: [PATCH 9/9] bugfix: pointer double free in func + qemu_savevm_state_complete_precopy_non_iterable + +vmdesc defined in qemu_savevm_state_complete_precopy_non_iterable is a g_autoptr, +it will be auto freed when function return. thus when we call json_writer_free +before function return to free vmdesc, it will be double freed. fix it. + +Signed-off-by: jiangdongxu +--- + migration/savevm.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/migration/savevm.c b/migration/savevm.c +index 803cd9004d..d59e976d50 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1427,7 +1427,6 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, + ret = vmstate_save(f, se, vmdesc); + if (ret) { + qemu_file_set_error(f, ret); +- json_writer_free(vmdesc); + return ret; + } + trace_savevm_section_end(se->idstr, se->section_id, 0); +@@ -1444,7 +1443,6 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, + error_report("%s: bdrv_inactivate_all() failed (%d)", + __func__, ret); + qemu_file_set_error(f, ret); +- json_writer_free(vmdesc); + return ret; + } + } +-- +2.27.0 + diff --git a/build-smt-processor-structure-to-support-smt-topolog.patch b/build-smt-processor-structure-to-support-smt-topolog.patch deleted file mode 100644 index ed01d38bb17dd4931a1f23b5a21127a2c5dd0425..0000000000000000000000000000000000000000 --- a/build-smt-processor-structure-to-support-smt-topolog.patch +++ /dev/null @@ -1,104 +0,0 @@ -From af8740502815be450709e88df44ad322da2b071f Mon Sep 17 00:00:00 2001 -From: Henglong Fan -Date: Tue, 18 Aug 2020 21:42:33 +0800 -Subject: [PATCH] build smt processor structure to support smt topology - -if vcpu support smt, create new smt hierarchy according to -Processor Properties Topology Table(PPTT) in acpi spec 6.3. -Threads sharing a core must be grouped under a unique Processor -hierarchy node structure for each group of threads - -Signed-off-by: Henglong Fan ---- - hw/acpi/aml-build.c | 40 ++++++++++++++++++++++++++++++++-------- - 1 file changed, 32 insertions(+), 8 deletions(-) - -diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 74e95005..8a3b51c8 100644 ---- a/hw/acpi/aml-build.c -+++ b/hw/acpi/aml-build.c -@@ -53,7 +53,7 @@ static void build_append_array(GArray *array, GArray *val) - } - - /* -- * ACPI 6.2 Processor Properties Topology Table (PPTT) -+ * ACPI 6.3 Processor Properties Topology Table (PPTT) - */ - #ifdef __aarch64__ - static void build_cache_head(GArray *tbl, uint32_t next_level) -@@ -126,7 +126,7 @@ static void build_arm_socket_hierarchy(GArray *tbl, - build_append_int_noprefix(tbl, offset, 4); - } - --static void build_arm_cpu_hierarchy(GArray *tbl, -+static void build_arm_core_hierarchy(GArray *tbl, - struct offset_status *offset, uint32_t id) - { - if (!offset) { -@@ -144,18 +144,35 @@ static void build_arm_cpu_hierarchy(GArray *tbl, - build_append_int_noprefix(tbl, offset->l2_offset, 4); - } - -+static void build_arm_smt_hierarchy(GArray *tbl, -+ uint32_t offset, uint32_t id) -+{ -+ if (!offset) { -+ return; -+ } -+ build_append_byte(tbl, 0); /* Type 0 - processor */ -+ build_append_byte(tbl, 20); /* Length, add private resources */ -+ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ -+ build_append_int_noprefix(tbl, 14, 4); /* Valid id*/ -+ build_append_int_noprefix(tbl, offset, 4); -+ build_append_int_noprefix(tbl, id, 4); -+ build_append_int_noprefix(tbl, 0, 4); /* Num private resources */ -+} -+ - void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) - { - int pptt_start = table_data->len; -- int uid = 0, cpus = 0, socket; -+ int uid = 0, socket; -+ uint32_t core_offset; - struct offset_status offset; - const MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cores = ms->smp.cores; -+ unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads); - - acpi_data_push(table_data, sizeof(AcpiTableHeader)); - -- for (socket = 0; cpus < possible_cpus; socket++) { -- int core; -+ for (socket = 0; socket < smp_sockets; socket++) { -+ int core,thread; - uint32_t l3_offset = table_data->len - pptt_start; - build_cache_hierarchy(table_data, 0, ARM_L3_CACHE); - -@@ -169,14 +186,21 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) - build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE); - offset.l1i_offset = table_data->len - pptt_start; - build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE); -- build_arm_cpu_hierarchy(table_data, &offset, uid++); -- cpus++; -+ core_offset = table_data->len - pptt_start; -+ if (ms->smp.threads <= 1) { -+ build_arm_core_hierarchy(table_data, &offset, uid++); -+ } else { -+ build_arm_core_hierarchy(table_data, &offset, core); -+ for (thread = 0; thread < ms->smp.threads; thread++) { -+ build_arm_smt_hierarchy(table_data, core_offset, uid++); -+ } -+ } - } - } - - build_header(linker, table_data, - (void *)(table_data->data + pptt_start), "PPTT", -- table_data->len - pptt_start, 1, NULL, NULL); -+ table_data->len - pptt_start, 2, NULL, NULL); - } - - #else --- -2.23.0 - diff --git a/char-fix-use-after-free-with-dup-chardev-reconnect.patch b/char-fix-use-after-free-with-dup-chardev-reconnect.patch deleted file mode 100644 index fd81015a18beced443caef903d0ec1f2a1fd8850..0000000000000000000000000000000000000000 --- a/char-fix-use-after-free-with-dup-chardev-reconnect.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 902a8192600ff81681a162509e23bf95619d1f04 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 20 Apr 2020 13:20:12 +0200 -Subject: [PATCH] char: fix use-after-free with dup chardev & reconnect -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -With a reconnect socket, qemu_char_open() will start a background -thread. It should keep a reference on the chardev. - -Fixes invalid read: -READ of size 8 at 0x6040000ac858 thread T7 - #0 0x5555598d37b8 in unix_connect_saddr /home/elmarco/src/qq/util/qemu-sockets.c:954 - #1 0x5555598d4751 in socket_connect /home/elmarco/src/qq/util/qemu-sockets.c:1109 - #2 0x555559707c34 in qio_channel_socket_connect_sync /home/elmarco/src/qq/io/channel-socket.c:145 - #3 0x5555596adebb in tcp_chr_connect_client_task /home/elmarco/src/qq/chardev/char-socket.c:1104 - #4 0x555559723d55 in qio_task_thread_worker /home/elmarco/src/qq/io/task.c:123 - #5 0x5555598a6731 in qemu_thread_start /home/elmarco/src/qq/util/qemu-thread-posix.c:519 - #6 0x7ffff40d4431 in start_thread (/lib64/libpthread.so.0+0x9431) - #7 0x7ffff40029d2 in __clone (/lib64/libc.so.6+0x1019d2) - -Signed-off-by: Marc-André Lureau -Reviewed-by: Daniel P. Berrangé -Message-Id: <20200420112012.567284-1-marcandre.lureau@redhat.com> -Signed-off-by: Zhenyu Ye ---- - chardev/char-socket.c | 3 ++- - tests/test-char.c | 53 ++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 54 insertions(+), 2 deletions(-) - -diff --git a/chardev/char-socket.c b/chardev/char-socket.c -index 7ca5d97a..701b62f9 100644 ---- a/chardev/char-socket.c -+++ b/chardev/char-socket.c -@@ -1118,7 +1118,8 @@ static void tcp_chr_connect_client_async(Chardev *chr) - */ - s->connect_task = qio_task_new(OBJECT(sioc), - qemu_chr_socket_connected, -- chr, NULL); -+ object_ref(OBJECT(chr)), -+ (GDestroyNotify)object_unref); - qio_task_run_in_thread(s->connect_task, - tcp_chr_connect_client_task, - s->addr, -diff --git a/tests/test-char.c b/tests/test-char.c -index f9440cdc..0e4069fb 100644 ---- a/tests/test-char.c -+++ b/tests/test-char.c -@@ -871,6 +871,53 @@ typedef struct { - } CharSocketClientTestConfig; - - -+static void char_socket_client_dupid_test(gconstpointer opaque) -+{ -+ const CharSocketClientTestConfig *config = opaque; -+ QIOChannelSocket *ioc; -+ char *optstr; -+ Chardev *chr1, *chr2; -+ SocketAddress *addr; -+ QemuOpts *opts; -+ Error *local_err = NULL; -+ -+ /* -+ * Setup a listener socket and determine get its address -+ * so we know the TCP port for the client later -+ */ -+ ioc = qio_channel_socket_new(); -+ g_assert_nonnull(ioc); -+ qio_channel_socket_listen_sync(ioc, config->addr, &error_abort); -+ addr = qio_channel_socket_get_local_address(ioc, &error_abort); -+ g_assert_nonnull(addr); -+ -+ /* -+ * Populate the chardev address based on what the server -+ * is actually listening on -+ */ -+ optstr = char_socket_addr_to_opt_str(addr, -+ config->fd_pass, -+ config->reconnect, -+ false); -+ -+ opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), -+ optstr, true); -+ g_assert_nonnull(opts); -+ chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); -+ g_assert_nonnull(chr1); -+ -+ chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); -+ g_assert_null(chr2); -+ error_free_or_abort(&local_err); -+ -+ object_unref(OBJECT(ioc)); -+ qemu_opts_del(opts); -+ object_unparent(OBJECT(chr1)); -+ qapi_free_SocketAddress(addr); -+ g_free(optstr); -+} -+ -+ - static void char_socket_client_test(gconstpointer opaque) - { - const CharSocketClientTestConfig *config = opaque; -@@ -1425,6 +1472,8 @@ int main(int argc, char **argv) - { addr, NULL, false, true }; \ - CharSocketClientTestConfig client6 ## name = \ - { addr, NULL, true, true }; \ -+ CharSocketClientTestConfig client7 ## name = \ -+ { addr, ",reconnect=1", false, false }; \ - g_test_add_data_func("/char/socket/client/mainloop/" # name, \ - &client1 ##name, char_socket_client_test); \ - g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ -@@ -1436,7 +1485,9 @@ int main(int argc, char **argv) - g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ - &client5 ##name, char_socket_client_test); \ - g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ -- &client6 ##name, char_socket_client_test) -+ &client6 ##name, char_socket_client_test); \ -+ g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ -+ &client7 ##name, char_socket_client_dupid_test) - - SOCKET_SERVER_TEST(tcp, &tcpaddr); - SOCKET_CLIENT_TEST(tcp, &tcpaddr); --- -2.22.0.windows.1 - diff --git a/chardev-char-socket-set-s-listener-NULL-in-char_sock.patch b/chardev-char-socket-set-s-listener-NULL-in-char_sock.patch new file mode 100644 index 0000000000000000000000000000000000000000..5567ce3f0d27e38af08c7970e87f78a6d25ffe0e --- /dev/null +++ b/chardev-char-socket-set-s-listener-NULL-in-char_sock.patch @@ -0,0 +1,75 @@ +From 936bf87a5acca3414625768c351fcc4e378fa30d Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Mon, 8 May 2023 00:24:18 -0700 +Subject: [PATCH] chardev/char-socket: set s->listener = NULL in + char_socket_finalize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit b8a7f51f59e28d5a8e0c07ed3919cc9695560ed2 + +After live migration with virtio block device, qemu crash at: + + #0 0x000055914f46f795 in object_dynamic_cast_assert (obj=0x559151b7b090, typename=0x55914f80fbc4 "qio-channel", file=0x55914f80fb90 "/images/testvfe/sw/qemu.gerrit/include/io/channel.h", line=30, func=0x55914f80fcb8 <__func__.17257> "QIO_CHANNEL") at ../qom/object.c:872 + #1 0x000055914f480d68 in QIO_CHANNEL (obj=0x559151b7b090) at /images/testvfe/sw/qemu.gerrit/include/io/channel.h:29 + #2 0x000055914f4812f8 in qio_net_listener_set_client_func_full (listener=0x559151b7a720, func=0x55914f580b97 , data=0x5591519f4ea0, notify=0x0, context=0x0) at ../io/net-listener.c:166 + #3 0x000055914f580059 in tcp_chr_update_read_handler (chr=0x5591519f4ea0) at ../chardev/char-socket.c:637 + #4 0x000055914f583dca in qemu_chr_be_update_read_handlers (s=0x5591519f4ea0, context=0x0) at ../chardev/char.c:226 + #5 0x000055914f57b7c9 in qemu_chr_fe_set_handlers_full (b=0x559152bf23a0, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=false, sync_state=true) at ../chardev/char-fe.c:279 + #6 0x000055914f57b86d in qemu_chr_fe_set_handlers (b=0x559152bf23a0, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=false) at ../chardev/char-fe.c:304 + #7 0x000055914f378caf in vhost_user_async_close (d=0x559152bf21a0, chardev=0x559152bf23a0, vhost=0x559152bf2420, cb=0x55914f2fb8c1 ) at ../hw/virtio/vhost-user.c:2725 + #8 0x000055914f2fba40 in vhost_user_blk_event (opaque=0x559152bf21a0, event=CHR_EVENT_CLOSED) at ../hw/block/vhost-user-blk.c:395 + #9 0x000055914f58388c in chr_be_event (s=0x5591519f4ea0, event=CHR_EVENT_CLOSED) at ../chardev/char.c:61 + #10 0x000055914f583905 in qemu_chr_be_event (s=0x5591519f4ea0, event=CHR_EVENT_CLOSED) at ../chardev/char.c:81 + #11 0x000055914f581275 in char_socket_finalize (obj=0x5591519f4ea0) at ../chardev/char-socket.c:1083 + #12 0x000055914f46f073 in object_deinit (obj=0x5591519f4ea0, type=0x5591519055c0) at ../qom/object.c:680 + #13 0x000055914f46f0e5 in object_finalize (data=0x5591519f4ea0) at ../qom/object.c:694 + #14 0x000055914f46ff06 in object_unref (objptr=0x5591519f4ea0) at ../qom/object.c:1202 + #15 0x000055914f4715a4 in object_finalize_child_property (obj=0x559151b76c50, name=0x559151b7b250 "char3", opaque=0x5591519f4ea0) at ../qom/object.c:1747 + #16 0x000055914f46ee86 in object_property_del_all (obj=0x559151b76c50) at ../qom/object.c:632 + #17 0x000055914f46f0d2 in object_finalize (data=0x559151b76c50) at ../qom/object.c:693 + #18 0x000055914f46ff06 in object_unref (objptr=0x559151b76c50) at ../qom/object.c:1202 + #19 0x000055914f4715a4 in object_finalize_child_property (obj=0x559151b6b560, name=0x559151b76630 "chardevs", opaque=0x559151b76c50) at ../qom/object.c:1747 + #20 0x000055914f46ef67 in object_property_del_child (obj=0x559151b6b560, child=0x559151b76c50) at ../qom/object.c:654 + #21 0x000055914f46f042 in object_unparent (obj=0x559151b76c50) at ../qom/object.c:673 + #22 0x000055914f58632a in qemu_chr_cleanup () at ../chardev/char.c:1189 + #23 0x000055914f16c66c in qemu_cleanup () at ../softmmu/runstate.c:830 + #24 0x000055914eee7b9e in qemu_default_main () at ../softmmu/main.c:38 + #25 0x000055914eee7bcc in main (argc=86, argv=0x7ffc97cb8d88) at ../softmmu/main.c:48 + +In char_socket_finalize after s->listener freed, event callback function +vhost_user_blk_event will be called to handle CHR_EVENT_CLOSED. +vhost_user_blk_event is calling qio_net_listener_set_client_func_full which +is still using s->listener. + +Setting s->listener = NULL after object_unref(OBJECT(s->listener)) can +solve this issue. + +Signed-off-by: Yajun Wu +Acked-by: Jiri Pirko +Message-Id: <20230214021430.3638579-1-yajunw@nvidia.com> +Reviewed-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: Wanghe Xiao +--- + chardev/char-socket.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 57ae53304a..459b9b72bd 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -1142,6 +1142,7 @@ static void char_socket_finalize(Object *obj) + qio_net_listener_set_client_func_full(s->listener, NULL, NULL, + NULL, chr->gcontext); + object_unref(OBJECT(s->listener)); ++ s->listener = NULL; + } + if (s->tls_creds) { + object_unref(OBJECT(s->tls_creds)); +-- +2.41.0.windows.1 + diff --git a/chardev-fix-segfault-in-finalize.patch b/chardev-fix-segfault-in-finalize.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a1813bbd46875cbfcd36e8a13827d363ecec271 --- /dev/null +++ b/chardev-fix-segfault-in-finalize.patch @@ -0,0 +1,66 @@ +From 670866f0349229045c5cddaeb08f07347bb7583b Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Tue, 29 Nov 2022 02:12:06 +0000 +Subject: [PATCH 01/17] chardev: fix segfault in finalize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +from mainline-v7.2.0-rc2 +commit fc0c128531ed55f058bfbad4f1348ebd9a0187f2 +category: bugfix + +----------------------- + +If finalize chardev-msmouse or chardev-wctable is called immediately after +init it cases QEMU to crash with segfault. This happens because of +QTAILQ_REMOVE in qemu_input_handler_unregister tries to dereference +NULL pointer. +For instance, this error can be reproduced via qom-list-properties +command. + +Signed-off-by: Maksim Davydov davydov-max@yandex-team.ru +Reviewed-by: Marc-André Lureau marcandre.lureau@redhat.com +Reviewed-by: Vladimir Sementsov-Ogievskiy vsementsov@yandex-team.ru +Message-Id: 20220825165247.33704-1-davydov-max@yandex-team.ru + +Signed-off-by: cmss_dx +--- + chardev/msmouse.c | 4 +++- + chardev/wctablet.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/chardev/msmouse.c b/chardev/msmouse.c +index eb9231dcdb..2cc1b16561 100644 +--- a/chardev/msmouse.c ++++ b/chardev/msmouse.c +@@ -146,7 +146,9 @@ static void char_msmouse_finalize(Object *obj) + { + MouseChardev *mouse = MOUSE_CHARDEV(obj); + +- qemu_input_handler_unregister(mouse->hs); ++ if (mouse->hs) { ++ qemu_input_handler_unregister(mouse->hs); ++ } + } + + static QemuInputHandler msmouse_handler = { +diff --git a/chardev/wctablet.c b/chardev/wctablet.c +index e8b292c43c..43bdf6b608 100644 +--- a/chardev/wctablet.c ++++ b/chardev/wctablet.c +@@ -319,7 +319,9 @@ static void wctablet_chr_finalize(Object *obj) + { + TabletChardev *tablet = WCTABLET_CHARDEV(obj); + +- qemu_input_handler_unregister(tablet->hs); ++ if (tablet->hs) { ++ qemu_input_handler_unregister(tablet->hs); ++ } + } + + static void wctablet_chr_open(Chardev *chr, +-- +2.27.0 + diff --git a/chardev-report-the-handshake-error.patch b/chardev-report-the-handshake-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..57066235dd00df0568fb28b2c08b65da47df38b9 --- /dev/null +++ b/chardev-report-the-handshake-error.patch @@ -0,0 +1,58 @@ +From 30f9cc7263e44faf2b43c4fdf3d7c64ffb409502 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 14 Aug 2023 14:37:36 +0800 +Subject: [PATCH] chardev: report the handshake error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 81cd34a359a36656d2f6542226235bd318ff8873 + +This can help to debug connection issues. + +Related to: +https://bugzilla.redhat.com/show_bug.cgi?id=2196182 + +Signed-off-by: Marc-André Lureau +Reviewed-by: Daniel P. Berrangé +Message-Id: <20230510072531.3937189-1-marcandre.lureau@redhat.com> +Signed-off-by: qihao_yewu +--- + chardev/char-socket.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 459b9b72bd..ef5d3053f3 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -819,8 +819,12 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data) + { + Chardev *chr = user_data; + SocketChardev *s = user_data; ++ Error *err = NULL; + +- if (qio_task_propagate_error(task, NULL)) { ++ if (qio_task_propagate_error(task, &err)) { ++ error_reportf_err(err, ++ "websock handshake of character device %s failed: ", ++ chr->label); + tcp_chr_disconnect(chr); + } else { + if (s->do_telnetopt) { +@@ -855,8 +859,12 @@ static void tcp_chr_tls_handshake(QIOTask *task, + { + Chardev *chr = user_data; + SocketChardev *s = user_data; ++ Error *err = NULL; + +- if (qio_task_propagate_error(task, NULL)) { ++ if (qio_task_propagate_error(task, &err)) { ++ error_reportf_err(err, ++ "TLS handshake of character device %s failed: ", ++ chr->label); + tcp_chr_disconnect(chr); + } else { + if (s->is_websock) { +-- +2.41.0.windows.1 + diff --git a/chardev-tcp-Fix-error-message-double-free-error.patch b/chardev-tcp-Fix-error-message-double-free-error.patch deleted file mode 100644 index 175ddfe2dea85111016d162aa0cd95d79a49a492..0000000000000000000000000000000000000000 --- a/chardev-tcp-Fix-error-message-double-free-error.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 4488ab4700d344b049ddef808a64eda4b5867902 Mon Sep 17 00:00:00 2001 -From: lichun -Date: Mon, 22 Jun 2020 05:30:17 +0800 -Subject: [PATCH 06/11] chardev/tcp: Fix error message double free error - -Errors are already freed by error_report_err, so we only need to call -error_free when that function is not called. - -Cc: qemu-stable@nongnu.org -Signed-off-by: lichun -Message-Id: <20200621213017.17978-1-lichun@ruijie.com.cn> -Reviewed-by: Markus Armbruster -[Commit message improved, cc: qemu-stable] -Signed-off-by: Markus Armbruster -Signed-off-by: BiaoXiang Ye ---- - chardev/char-socket.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/chardev/char-socket.c b/chardev/char-socket.c -index 701b62f9..9b06c8aa 100644 ---- a/chardev/char-socket.c -+++ b/chardev/char-socket.c -@@ -141,6 +141,8 @@ static void check_report_connect_error(Chardev *chr, - error_report("Unable to connect character device %s: %s", - chr->label, error_get_pretty(err)); - s->connect_err_reported = true; -+ } else { -+ error_free(err); - } - qemu_chr_socket_restart_timer(chr); - } -@@ -1074,7 +1076,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) - if (qio_task_propagate_error(task, &err)) { - tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); - check_report_connect_error(chr, err); -- error_free(err); - goto cleanup; - } - --- -2.27.0.dirty - diff --git a/colo-compare-Fix-memory-leak-in-packet_enqueue.patch b/colo-compare-Fix-memory-leak-in-packet_enqueue.patch deleted file mode 100644 index ca5e43c49a6ad18fa7c6d204c1eabfac7ed6ddd5..0000000000000000000000000000000000000000 --- a/colo-compare-Fix-memory-leak-in-packet_enqueue.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 19afb1431bd730a1e4e09e3c0835c35572517268 Mon Sep 17 00:00:00 2001 -From: Derek Su -Date: Fri, 22 May 2020 15:53:57 +0800 -Subject: [PATCH 07/11] colo-compare: Fix memory leak in packet_enqueue() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The patch is to fix the "pkt" memory leak in packet_enqueue(). -The allocated "pkt" needs to be freed if the colo compare -primary or secondary queue is too big. - -Replace the error_report of full queue with a trace event. - -Signed-off-by: Derek Su -Reviewed-by: Zhang Chen -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Zhang Chen -Signed-off-by: Jason Wang -Signed-off-by: BiaoXiang Ye ---- - net/colo-compare.c | 23 +++++++++++++++-------- - net/trace-events | 1 + - 2 files changed, 16 insertions(+), 8 deletions(-) - -diff --git a/net/colo-compare.c b/net/colo-compare.c -index 7ee17f2c..3168407e 100644 ---- a/net/colo-compare.c -+++ b/net/colo-compare.c -@@ -120,6 +120,10 @@ enum { - SECONDARY_IN, - }; - -+static const char *colo_mode[] = { -+ [PRIMARY_IN] = "primary", -+ [SECONDARY_IN] = "secondary", -+}; - - static int compare_chr_send(CompareState *s, - const uint8_t *buf, -@@ -215,6 +219,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) - ConnectionKey key; - Packet *pkt = NULL; - Connection *conn; -+ int ret; - - if (mode == PRIMARY_IN) { - pkt = packet_new(s->pri_rs.buf, -@@ -243,16 +248,18 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) - } - - if (mode == PRIMARY_IN) { -- if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) { -- error_report("colo compare primary queue size too big," -- "drop packet"); -- } -+ ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack); - } else { -- if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) { -- error_report("colo compare secondary queue size too big," -- "drop packet"); -- } -+ ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack); - } -+ -+ if (!ret) { -+ trace_colo_compare_drop_packet(colo_mode[mode], -+ "queue size too big, drop packet"); -+ packet_destroy(pkt, NULL); -+ pkt = NULL; -+ } -+ - *con = conn; - - return 0; -diff --git a/net/trace-events b/net/trace-events -index ac570564..a9995387 100644 ---- a/net/trace-events -+++ b/net/trace-events -@@ -12,6 +12,7 @@ colo_proxy_main(const char *chr) ": %s" - - # colo-compare.c - colo_compare_main(const char *chr) ": %s" -+colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s" - colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" - colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" - colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" --- -2.27.0.dirty - diff --git a/configure-Add-.-on-front-of-glob-of-config-devices.m.patch b/configure-Add-.-on-front-of-glob-of-config-devices.m.patch new file mode 100644 index 0000000000000000000000000000000000000000..1da3c3931a8b8cf68e19b630a685334f1d66a260 --- /dev/null +++ b/configure-Add-.-on-front-of-glob-of-config-devices.m.patch @@ -0,0 +1,40 @@ +From 05facfc2f1442dc96b862fff97dde7f600a41491 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Thu, 24 Nov 2022 19:33:04 +0800 +Subject: [PATCH 26/29] configure: Add './' on front of glob of + */config-devices.mak.d +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Shellcheck warns that in + rm -f */config-devices.mak.d +the glob might expand to something with a '-' in it, which would +then be misinterpreted as an option to rm. Fix this by adding './'. + +Signed-off-by: Peter Maydell +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220825150703.4074125-5-peter.maydell@linaro.org + +Signed-off-by: wangjinlei +--- + configure | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure b/configure +index 8cbf186296..7e81444ade 100755 +--- a/configure ++++ b/configure +@@ -1479,7 +1479,7 @@ exit 0 + fi + + # Remove old dependency files to make sure that they get properly regenerated +-rm -f */config-devices.mak.d ++rm -f ./*/config-devices.mak.d + + if test -z "$python" + then +-- +2.27.0 + diff --git a/configure-Add-missing-quoting-for-some-easy-cases.patch b/configure-Add-missing-quoting-for-some-easy-cases.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6eb4a31eb938d7f1b499fc786e2c1a829cadf7d --- /dev/null +++ b/configure-Add-missing-quoting-for-some-easy-cases.patch @@ -0,0 +1,90 @@ +From 6f1b97c06f116945553846cb0c5c3d949c953890 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Thu, 24 Nov 2022 19:29:07 +0800 +Subject: [PATCH 19/29] configure: Add missing quoting for some easy cases +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds quotes in some places which: + * are spotted by shellcheck + * are obviously incorrect + * are easy to fix just by adding the quotes + +It doesn't attempt fix all of the places shellcheck finds errors, +or even all the ones which are easy to fix. It's just a random +sampling which is hopefully easy to review and which cuts +down the size of the problem for next time somebody wants to +try to look at shellcheck errors. + +Signed-off-by: Peter Maydell +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220825150703.4074125-4-peter.maydell@linaro.org + +Signed-off-by: wangjinlei +--- + configure | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/configure b/configure +index 8cbf186296..737572c8e6 100755 +--- a/configure ++++ b/configure +@@ -57,7 +57,7 @@ GNUmakefile: ; + + EOF + cd build +- exec $source_path/configure "$@" ++ exec "$source_path/configure" "$@" + fi + + # Temporary directory used for files created while +@@ -728,7 +728,7 @@ fi + + werror="" + +-. $source_path/scripts/meson-buildoptions.sh ++. "$source_path/scripts/meson-buildoptions.sh" + + meson_options= + meson_option_parse() { +@@ -745,7 +745,7 @@ for opt do + case "$opt" in + --help|-h) show_help=yes + ;; +- --version|-V) exec cat $source_path/VERSION ++ --version|-V) exec cat "$source_path/VERSION" + ;; + --prefix=*) prefix="$optarg" + ;; +@@ -1503,7 +1503,7 @@ python="$python -B" + if test -z "$meson"; then + if test "$explicit_python" = no && has meson && version_ge "$(meson --version)" 0.59.3; then + meson=meson +- elif test $git_submodules_action != 'ignore' ; then ++ elif test "$git_submodules_action" != 'ignore' ; then + meson=git + elif test -e "${source_path}/meson/meson.py" ; then + meson=internal +@@ -3352,7 +3352,7 @@ if test "$QEMU_GA_DISTRO" = ""; then + QEMU_GA_DISTRO=Linux + fi + if test "$QEMU_GA_VERSION" = ""; then +- QEMU_GA_VERSION=$(cat $source_path/VERSION) ++ QEMU_GA_VERSION=$(cat "$source_path"/VERSION) + fi + + QEMU_GA_MSI_MINGW_DLL_PATH="$($pkg_config --variable=prefix glib-2.0)/bin" +@@ -3790,7 +3790,7 @@ fi + for target in $target_list; do + target_dir="$target" + target_name=$(echo $target | cut -d '-' -f 1) +- mkdir -p $target_dir ++ mkdir -p "$target_dir" + case $target in + *-user) symlink "../qemu-$target_name" "$target_dir/qemu-$target_name" ;; + *) symlink "../qemu-system-$target_name" "$target_dir/qemu-system-$target_name" ;; +-- +2.27.0 + diff --git a/configure-Check-mkdir-result-directly-not-via.patch b/configure-Check-mkdir-result-directly-not-via.patch new file mode 100644 index 0000000000000000000000000000000000000000..c8bc9fb2ed237e70f4d682d98456b7bce71b78f8 --- /dev/null +++ b/configure-Check-mkdir-result-directly-not-via.patch @@ -0,0 +1,39 @@ +From d5ad002a22aade5086722fd9aa2addf2f95e52c3 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Thu, 24 Nov 2022 19:39:33 +0800 +Subject: [PATCH 27/29] configure: Check mkdir result directly, not via $? +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Shellcheck warns that we have one place where we run a command and +then check if it failed using $?; this is better written to simply +check the command in the 'if' statement directly. + +Signed-off-by: Peter Maydell +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220825150703.4074125-7-peter.maydell@linaro.org + +Signed-off-by: wangjinlei +--- + configure | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/configure b/configure +index 8cbf186296..561c86c913 100755 +--- a/configure ++++ b/configure +@@ -67,8 +67,7 @@ fi + # it when configure exits.) + TMPDIR1="config-temp" + rm -rf "${TMPDIR1}" +-mkdir -p "${TMPDIR1}" +-if [ $? -ne 0 ]; then ++if ! mkdir -p "${TMPDIR1}"; then + echo "ERROR: failed to create temporary directory" + exit 1 + fi +-- +2.27.0 + diff --git a/configure-Enable-test-and-libs-for-zstd.patch b/configure-Enable-test-and-libs-for-zstd.patch deleted file mode 100644 index bf900cf343d4d77c997d203ffcd12a8dc6c434fb..0000000000000000000000000000000000000000 --- a/configure-Enable-test-and-libs-for-zstd.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 5a79ccd388ee09dc1db93d26791d1e4a6b2ced47 Mon Sep 17 00:00:00 2001 -From: Juan Quintela -Date: Wed, 3 Feb 2021 17:33:44 +0800 -Subject: [PATCH] configure: Enable test and libs for zstd - -configure: Enable test and libs for zstd -Add it to several build systems to make testing good. - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert - -Signed-off-by: Jiajie Li ---- - .gitlab-ci.yml | 1 + - .travis.yml | 1 + - configure | 30 ++++++++++++++++++++++++++++++ - 3 files changed, 32 insertions(+) - -diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml -index c63bf2f822..3d9b7f9262 100644 ---- a/.gitlab-ci.yml -+++ b/.gitlab-ci.yml -@@ -16,6 +16,7 @@ build-system2: - script: - - apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev - libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev -+ libzstd-dev - - ./configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu - microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu - sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu" -diff --git a/.travis.yml b/.travis.yml -index caf0a1f8fa..f3fe04fba9 100644 ---- a/.travis.yml -+++ b/.travis.yml -@@ -35,6 +35,7 @@ addons: - - liburcu-dev - - libusb-1.0-0-dev - - libvte-2.91-dev -+ - libzstd-dev - - sparse - - uuid-dev - - gcovr -diff --git a/configure b/configure -index 714e7fb6a1..577533e9ed 100755 ---- a/configure -+++ b/configure -@@ -446,6 +446,7 @@ lzo="" - snappy="" - bzip2="" - lzfse="" -+zstd="" - guest_agent="" - guest_agent_with_vss="no" - guest_agent_ntddscsi="no" -@@ -1358,6 +1359,10 @@ for opt do - ;; - --disable-lzfse) lzfse="no" - ;; -+ --disable-zstd) zstd="no" -+ ;; -+ --enable-zstd) zstd="yes" -+ ;; - --enable-guest-agent) guest_agent="yes" - ;; - --disable-guest-agent) guest_agent="no" -@@ -1812,6 +1817,8 @@ disabled with --disable-FEATURE, default is enabled if available: - (for reading bzip2-compressed dmg images) - lzfse support of lzfse compression library - (for reading lzfse-compressed dmg images) -+ zstd support for zstd compression library -+ (for migration compression) - seccomp seccomp support - coroutine-pool coroutine freelist (better performance) - glusterfs GlusterFS backend -@@ -2407,6 +2414,24 @@ EOF - fi - fi - -+########################################## -+# zstd check -+ -+if test "$zstd" != "no" ; then -+ if $pkg_config --exist libzstd ; then -+ zstd_cflags="$($pkg_config --cflags libzstd)" -+ zstd_libs="$($pkg_config --libs libzstd)" -+ LIBS="$zstd_libs $LIBS" -+ QEMU_CFLAGS="$QEMU_CFLAGS $zstd_cflags" -+ zstd="yes" -+ else -+ if test "$zstd" = "yes" ; then -+ feature_not_found "libzstd" "Install libzstd devel" -+ fi -+ zstd="no" -+ fi -+fi -+ - ########################################## - # libseccomp check - -@@ -6460,6 +6485,7 @@ echo "lzo support $lzo" - echo "snappy support $snappy" - echo "bzip2 support $bzip2" - echo "lzfse support $lzfse" -+echo "zstd support $zstd" - echo "NUMA host support $numa" - echo "libxml2 $libxml2" - echo "tcmalloc support $tcmalloc" -@@ -7024,6 +7050,10 @@ if test "$lzfse" = "yes" ; then - echo "LZFSE_LIBS=-llzfse" >> $config_host_mak - fi - -+if test "$zstd" = "yes" ; then -+ echo "CONFIG_ZSTD=y" >> $config_host_mak -+fi -+ - if test "$libiscsi" = "yes" ; then - echo "CONFIG_LIBISCSI=m" >> $config_host_mak - echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak --- -2.27.0 - diff --git a/configure-Remove-unused-meson_args-variable.patch b/configure-Remove-unused-meson_args-variable.patch new file mode 100644 index 0000000000000000000000000000000000000000..559d60988b7674650b160028d6565a7b6538a71d --- /dev/null +++ b/configure-Remove-unused-meson_args-variable.patch @@ -0,0 +1,37 @@ +From 280fca570579e659aa38def7f55151eea4f42712 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Thu, 24 Nov 2022 15:38:49 +0800 +Subject: [PATCH 17/29] configure: Remove unused meson_args variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The meson_args variable was added in commit 3b4da13293482134b, but +was not used in that commit and isn't used today. Delete the +unnecessary assignment. + +Signed-off-by: Peter Maydell +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220825150703.4074125-3-peter.maydell@linaro.org + +Signed-off-by: wangjinlei +--- + configure | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/configure b/configure +index e12ef3d842..8cbf186296 100755 +--- a/configure ++++ b/configure +@@ -361,7 +361,6 @@ plugins="$default_feature" + rng_none="no" + secret_keyring="$default_feature" + meson="" +-meson_args="" + ninja="" + gio="$default_feature" + skip_meson=no +-- +2.27.0 + diff --git a/configure-Remove-unused-python_version-variable.patch b/configure-Remove-unused-python_version-variable.patch new file mode 100644 index 0000000000000000000000000000000000000000..a18f502cf772e5a0754f9ea507e3864a28738231 --- /dev/null +++ b/configure-Remove-unused-python_version-variable.patch @@ -0,0 +1,42 @@ +From 6933c65bc3835f69f2c774c7d27c8ebcd05d55d6 Mon Sep 17 00:00:00 2001 +From: wangjinlei +Date: Thu, 24 Nov 2022 14:54:20 +0800 +Subject: [PATCH 16/29] configure: Remove unused python_version variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Shellcheck correctly reports that we set python_version and never use +it. This is a leftover from commit f9332757898a7: we used to use +python_version purely to as part of the summary information printed +at the end of a configure run, and that commit changed to printing +the information from meson (which looks up the python version +itself). Remove the unused variable. + +Signed-off-by: Peter Maydell +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220825150703.4074125-2-peter.maydell@linaro.org + +Signed-off-by: wangjinlei +--- + configure | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/configure b/configure +index 0ae7bcf065..e12ef3d842 100755 +--- a/configure ++++ b/configure +@@ -1498,9 +1498,6 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (3,6))'; then + "Use --python=/path/to/python to specify a supported Python." + fi + +-# Preserve python version since some functionality is dependent on it +-python_version=$($python -c 'import sys; print("%d.%d.%d" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null) +- + # Suppress writing compiled files + python="$python -B" + +-- +2.27.0 + diff --git a/configure-meson-move-AVX-tests-to-meson.patch b/configure-meson-move-AVX-tests-to-meson.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a11ed781621fef6cf0de748a20a6f56a5e725cd --- /dev/null +++ b/configure-meson-move-AVX-tests-to-meson.patch @@ -0,0 +1,290 @@ +From 54625fb7d039ef746f88ad0bf78515e96af7305d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 8 Nov 2021 13:38:58 +0100 +Subject: [PATCH] configure, meson: move AVX tests to meson + +mainline inclusion +from mainline-v7.0.0-rc0 +commit 622753d2fb501509ab03c241d476815f378d4ba5 +category: feature +feature: AVX512 support for xbzrle_encode_buffer +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Z50P + +Intel-SIG: commit 622753d2fb50 ("configure, meson: move AVX tests to meson") + +------------------------------------- + +configure, meson: move AVX tests to meson + +For consistency with other tests, --enable-avx2 and --enable-avx512f +fail to compile on x86 systems if cpuid.h is not available. + +Reviewed-by: Richard Henderson +Signed-off-by: Paolo Bonzini +Signed-off-by: Aichun Shi +--- + configure | 103 ---------------------------------- + meson.build | 50 ++++++++++++++++- + meson_options.txt | 4 ++ + scripts/meson-buildoptions.sh | 6 ++ + 4 files changed, 58 insertions(+), 105 deletions(-) + +diff --git a/configure b/configure +index a84dc891cc..d7a4502a8b 100755 +--- a/configure ++++ b/configure +@@ -329,8 +329,6 @@ qom_cast_debug="yes" + trace_backends="log" + trace_file="trace" + opengl="$default_feature" +-cpuid_h="no" +-avx2_opt="$default_feature" + guest_agent="$default_feature" + guest_agent_with_vss="no" + guest_agent_ntddscsi="no" +@@ -1053,14 +1051,6 @@ for opt do + ;; + --disable-tools) want_tools="no" + ;; +- --disable-avx2) avx2_opt="no" +- ;; +- --enable-avx2) avx2_opt="yes" +- ;; +- --disable-avx512f) avx512f_opt="no" +- ;; +- --enable-avx512f) avx512f_opt="yes" +- ;; + --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) + echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2 + ;; +@@ -1456,8 +1446,6 @@ cat << EOF + tpm TPM support + libssh ssh block device support + numa libnuma support +- avx2 AVX2 optimization support +- avx512f AVX512F optimization support + replication replication support + opengl opengl support + xfsctl xfsctl support +@@ -2893,85 +2881,6 @@ else # "$safe_stack" = "" + fi + fi + +-######################################## +-# check if cpuid.h is usable. +- +-cat > $TMPC << EOF +-#include +-int main(void) { +- unsigned a, b, c, d; +- int max = __get_cpuid_max(0, 0); +- +- if (max >= 1) { +- __cpuid(1, a, b, c, d); +- } +- +- if (max >= 7) { +- __cpuid_count(7, 0, a, b, c, d); +- } +- +- return 0; +-} +-EOF +-if compile_prog "" "" ; then +- cpuid_h=yes +-fi +- +-########################################## +-# avx2 optimization requirement check +-# +-# There is no point enabling this if cpuid.h is not usable, +-# since we won't be able to select the new routines. +- +-if test "$cpuid_h" = "yes" && test "$avx2_opt" != "no"; then +- cat > $TMPC << EOF +-#pragma GCC push_options +-#pragma GCC target("avx2") +-#include +-#include +-static int bar(void *a) { +- __m256i x = *(__m256i *)a; +- return _mm256_testz_si256(x, x); +-} +-int main(int argc, char *argv[]) { return bar(argv[0]); } +-EOF +- if compile_object "-Werror" ; then +- avx2_opt="yes" +- else +- avx2_opt="no" +- fi +-fi +- +-########################################## +-# avx512f optimization requirement check +-# +-# There is no point enabling this if cpuid.h is not usable, +-# since we won't be able to select the new routines. +-# by default, it is turned off. +-# if user explicitly want to enable it, check environment +- +-if test "$cpuid_h" = "yes" && test "$avx512f_opt" = "yes"; then +- cat > $TMPC << EOF +-#pragma GCC push_options +-#pragma GCC target("avx512f") +-#include +-#include +-static int bar(void *a) { +- __m512i x = *(__m512i *)a; +- return _mm512_test_epi64_mask(x, x); +-} +-int main(int argc, char *argv[]) +-{ +- return bar(argv[0]); +-} +-EOF +- if ! compile_object "-Werror" ; then +- avx512f_opt="no" +- fi +-else +- avx512f_opt="no" +-fi +- + ######################################## + # check if __[u]int128_t is usable. + +@@ -3587,14 +3496,6 @@ if test "$opengl" = "yes" ; then + echo "OPENGL_LIBS=$opengl_libs" >> $config_host_mak + fi + +-if test "$avx2_opt" = "yes" ; then +- echo "CONFIG_AVX2_OPT=y" >> $config_host_mak +-fi +- +-if test "$avx512f_opt" = "yes" ; then +- echo "CONFIG_AVX512F_OPT=y" >> $config_host_mak +-fi +- + # XXX: suppress that + if [ "$bsd" = "yes" ] ; then + echo "CONFIG_BSD=y" >> $config_host_mak +@@ -3627,10 +3528,6 @@ if test "$have_tsan" = "yes" && test "$have_tsan_iface_fiber" = "yes" ; then + echo "CONFIG_TSAN=y" >> $config_host_mak + fi + +-if test "$cpuid_h" = "yes" ; then +- echo "CONFIG_CPUID_H=y" >> $config_host_mak +-fi +- + if test "$int128" = "yes" ; then + echo "CONFIG_INT128=y" >> $config_host_mak + fi +diff --git a/meson.build b/meson.build +index d80426b3e8..9f77254861 100644 +--- a/meson.build ++++ b/meson.build +@@ -1750,6 +1750,52 @@ config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + ''' + return getauxval(AT_HWCAP) == 0; + }''')) + ++have_cpuid_h = cc.links(''' ++ #include ++ int main(void) { ++ unsigned a, b, c, d; ++ unsigned max = __get_cpuid_max(0, 0); ++ ++ if (max >= 1) { ++ __cpuid(1, a, b, c, d); ++ } ++ ++ if (max >= 7) { ++ __cpuid_count(7, 0, a, b, c, d); ++ } ++ ++ return 0; ++ }''') ++config_host_data.set('CONFIG_CPUID_H', have_cpuid_h) ++ ++config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ ++ .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX2') \ ++ .require(cc.links(''' ++ #pragma GCC push_options ++ #pragma GCC target("avx2") ++ #include ++ #include ++ static int bar(void *a) { ++ __m256i x = *(__m256i *)a; ++ return _mm256_testz_si256(x, x); ++ } ++ int main(int argc, char *argv[]) { return bar(argv[0]); } ++ '''), error_message: 'AVX2 not available').allowed()) ++ ++config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ ++ .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512F') \ ++ .require(cc.links(''' ++ #pragma GCC push_options ++ #pragma GCC target("avx512f") ++ #include ++ #include ++ static int bar(void *a) { ++ __m512i x = *(__m512i *)a; ++ return _mm512_test_epi64_mask(x, x); ++ } ++ int main(int argc, char *argv[]) { return bar(argv[0]); } ++ '''), error_message: 'AVX512F not available').allowed()) ++ + config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' + #include + #include +@@ -3271,8 +3317,8 @@ summary_info += {'membarrier': config_host.has_key('CONFIG_MEMBARRIER')} + summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')} + summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')} + summary_info += {'memory allocator': get_option('malloc')} +-summary_info += {'avx2 optimization': config_host.has_key('CONFIG_AVX2_OPT')} +-summary_info += {'avx512f optimization': config_host.has_key('CONFIG_AVX512F_OPT')} ++summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} ++summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} + summary_info += {'gprof enabled': config_host.has_key('CONFIG_GPROF')} + summary_info += {'gcov': get_option('b_coverage')} + summary_info += {'thread sanitizer': config_host.has_key('CONFIG_TSAN')} +diff --git a/meson_options.txt b/meson_options.txt +index e392323732..e9cbe48cb9 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -66,6 +66,10 @@ option('cfi_debug', type: 'boolean', value: 'false', + description: 'Verbose errors in case of CFI violation') + option('multiprocess', type: 'feature', value: 'auto', + description: 'Out of process device emulation support') ++option('avx2', type: 'feature', value: 'auto', ++ description: 'AVX2 optimizations') ++option('avx512f', type: 'feature', value: 'disabled', ++ description: 'AVX512F optimizations') + + option('attr', type : 'feature', value : 'auto', + description: 'attr/xattr support') +diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh +index 7a17ff4218..b994bf16f0 100644 +--- a/scripts/meson-buildoptions.sh ++++ b/scripts/meson-buildoptions.sh +@@ -25,6 +25,8 @@ meson_options_help() { + printf "%s\n" ' alsa ALSA sound support' + printf "%s\n" ' attr attr/xattr support' + printf "%s\n" ' auth-pam PAM access control' ++ printf "%s\n" ' avx2 AVX2 optimizations' ++ printf "%s\n" ' avx512f AVX512F optimizations' + printf "%s\n" ' bpf eBPF support' + printf "%s\n" ' brlapi brlapi character device driver' + printf "%s\n" ' bzip2 bzip2 support for DMG images' +@@ -107,6 +109,10 @@ _meson_option_parse() { + --disable-attr) printf "%s" -Dattr=disabled ;; + --enable-auth-pam) printf "%s" -Dauth_pam=enabled ;; + --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; ++ --enable-avx2) printf "%s" -Davx2=enabled ;; ++ --disable-avx2) printf "%s" -Davx2=disabled ;; ++ --enable-avx512f) printf "%s" -Davx512f=enabled ;; ++ --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-bpf) printf "%s" -Dbpf=enabled ;; + --disable-bpf) printf "%s" -Dbpf=disabled ;; + --enable-brlapi) printf "%s" -Dbrlapi=enabled ;; +-- +2.27.0 + diff --git a/contrib-libvhost-user-Protect-slave-fd-with-mutex.patch b/contrib-libvhost-user-Protect-slave-fd-with-mutex.patch deleted file mode 100644 index 44fc4283ca652bb9743c186b2127f073e32b5043..0000000000000000000000000000000000000000 --- a/contrib-libvhost-user-Protect-slave-fd-with-mutex.patch +++ /dev/null @@ -1,121 +0,0 @@ -From f076af734a5964c3e48b2d223130f855b86f40e5 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Fri, 1 Mar 2019 11:18:30 +0000 -Subject: [PATCH] contrib/libvhost-user: Protect slave fd with mutex -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In future patches we'll be performing commands on the slave-fd driven -by commands on queues, since those queues will be driven by individual -threads we need to make sure they don't attempt to use the slave-fd -for multiple commands in parallel. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Dr. David Alan Gilbert ---- - contrib/libvhost-user/libvhost-user.c | 24 ++++++++++++++++++++---- - contrib/libvhost-user/libvhost-user.h | 3 +++ - 2 files changed, 23 insertions(+), 4 deletions(-) - -diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c -index cb5f5770e4..fb75837032 100644 ---- a/contrib/libvhost-user/libvhost-user.c -+++ b/contrib/libvhost-user/libvhost-user.c -@@ -387,26 +387,37 @@ vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) - return vu_message_write(dev, conn_fd, vmsg); - } - -+/* -+ * Processes a reply on the slave channel. -+ * Entered with slave_mutex held and releases it before exit. -+ * Returns true on success. -+ */ - static bool - vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg) - { - VhostUserMsg msg_reply; -+ bool result = false; - - if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) { -- return true; -+ result = true; -+ goto out; - } - - if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) { -- return false; -+ goto out; - } - - if (msg_reply.request != vmsg->request) { - DPRINT("Received unexpected msg type. Expected %d received %d", - vmsg->request, msg_reply.request); -- return false; -+ goto out; - } - -- return msg_reply.payload.u64 == 0; -+ result = msg_reply.payload.u64 == 0; -+ -+out: -+ pthread_mutex_unlock(&dev->slave_mutex); -+ return result; - } - - /* Kick the log_call_fd if required. */ -@@ -1102,10 +1113,13 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, - return false; - } - -+ pthread_mutex_lock(&dev->slave_mutex); - if (!vu_message_write(dev, dev->slave_fd, &vmsg)) { -+ pthread_mutex_unlock(&dev->slave_mutex); - return false; - } - -+ /* Also unlocks the slave_mutex */ - return vu_process_message_reply(dev, &vmsg); - } - -@@ -1625,6 +1639,7 @@ vu_deinit(VuDev *dev) - close(dev->slave_fd); - dev->slave_fd = -1; - } -+ pthread_mutex_destroy(&dev->slave_mutex); - - if (dev->sock != -1) { - close(dev->sock); -@@ -1660,6 +1675,7 @@ vu_init(VuDev *dev, - dev->remove_watch = remove_watch; - dev->iface = iface; - dev->log_call_fd = -1; -+ pthread_mutex_init(&dev->slave_mutex, NULL); - dev->slave_fd = -1; - dev->max_queues = max_queues; - -diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h -index 46b600799b..1844b6f8d4 100644 ---- a/contrib/libvhost-user/libvhost-user.h -+++ b/contrib/libvhost-user/libvhost-user.h -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include "standard-headers/linux/virtio_ring.h" - - /* Based on qemu/hw/virtio/vhost-user.c */ -@@ -355,6 +356,8 @@ struct VuDev { - VuVirtq *vq; - VuDevInflightInfo inflight_info; - int log_call_fd; -+ /* Must be held while using slave_fd */ -+ pthread_mutex_t slave_mutex; - int slave_fd; - uint64_t log_size; - uint8_t *log_table; --- -2.27.0 - diff --git a/core-cpu-common-Fix-the-wrong-ifdef-__aarch64__.patch b/core-cpu-common-Fix-the-wrong-ifdef-__aarch64__.patch new file mode 100644 index 0000000000000000000000000000000000000000..79a70ec61e2c13e21eeffa39769f3dc5a7c67f91 --- /dev/null +++ b/core-cpu-common-Fix-the-wrong-ifdef-__aarch64__.patch @@ -0,0 +1,32 @@ +From a6f84e8f2c1fef8ca8f48f81e2e6a1b823d9a90e Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Fri, 21 Apr 2023 14:53:46 +0800 +Subject: [PATCH] core/cpu-common: Fix the wrong '#ifdef __aarch64__' + +commit c3f86c199885 ("arm/virt: Correct timing of executing +cpu_synchronize_post_init for hot-plugged cpus") used the +wrong '#ifdef __aarch64__'. It should be '#ifndef __aarch64__'. + +Fixes: c3f86c199885 ("arm/virt: Correct timing of executing +cpu_synchronize_post_init for hot-plugged cpus") +Signed-off-by: Kunkun Jiang +--- + hw/core/cpu-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index 2213840260..92d15f2f49 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -206,7 +206,7 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) + } + } + +-#ifdef __aarch64__ ++#ifndef __aarch64__ + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); + cpu_resume(cpu); +-- +2.27.0 + diff --git a/coro-support-live-patch-for-libcare.patch b/coro-support-live-patch-for-libcare.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e287eb8965a7dceae982963097dc196874f3347 --- /dev/null +++ b/coro-support-live-patch-for-libcare.patch @@ -0,0 +1,120 @@ +From 2135fe8e9c4d459d3f06babf3bfd71b5387b0214 Mon Sep 17 00:00:00 2001 +From: jiang-dawei15 +Date: Tue, 15 Mar 2022 10:28:34 +0800 +Subject: [PATCH] coro: support live patch for libcare + +Description: +For coroutine live patch, we need find all coroutines stack and check them +before patching. There is no structure to manage all coroutines in qemu. So we +add a list which contain all running coroutines to accelerate libcare live +patch. +--- + include/qemu/coroutine_int.h | 3 ++- + util/coroutine-ucontext.c | 52 ++++++++++++++++++++++++++++++++++++ + util/qemu-coroutine.c | 4 +++ + 3 files changed, 58 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h +index 1da148552f..11b550a0fc 100644 +--- a/include/qemu/coroutine_int.h ++++ b/include/qemu/coroutine_int.h +@@ -73,5 +73,6 @@ Coroutine *qemu_coroutine_new(void); + void qemu_coroutine_delete(Coroutine *co); + CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to, + CoroutineAction action); +- ++void qemu_coroutine_info_add(const Coroutine *co_); ++void qemu_coroutine_info_delete(const Coroutine *co_); + #endif +diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c +index 904b375192..23ab7cdf74 100644 +--- a/util/coroutine-ucontext.c ++++ b/util/coroutine-ucontext.c +@@ -79,6 +79,19 @@ union cc_arg { + int i[2]; + }; + ++/** ++ * coroutines list for libcare ++ */ ++struct CoroutineInformation { ++ sigjmp_buf *env; ++ QLIST_ENTRY(CoroutineInformation) next; ++}; ++ ++static QemuMutex coro_mtx; ++QLIST_HEAD(, CoroutineInformation) coro_info_list = QLIST_HEAD_INITIALIZER(pool); ++int coro_env_offset = offsetof(struct CoroutineInformation, env); ++int coro_next_offset = offsetof(struct CoroutineInformation, next); ++ + /* + * QEMU_ALWAYS_INLINE only does so if __OPTIMIZE__, so we cannot use it. + * always_inline is required to avoid TSan runtime fatal errors. +@@ -330,3 +343,42 @@ bool qemu_in_coroutine(void) + { + return current && current->caller; + } ++ ++static void __attribute__((constructor)) coro_mutex_init(void) ++{ ++ qemu_mutex_init(&coro_mtx); ++} ++ ++void qemu_coroutine_info_add(const Coroutine *co_) ++{ ++ CoroutineUContext *co; ++ struct CoroutineInformation *coro_info; ++ ++ /* save coroutine env to coro_info_list */ ++ co = DO_UPCAST(CoroutineUContext, base, co_); ++ coro_info = g_malloc0(sizeof(struct CoroutineInformation)); ++ coro_info->env = &co->env; ++ ++ qemu_mutex_lock(&coro_mtx); ++ QLIST_INSERT_HEAD(&coro_info_list, coro_info, next); ++ qemu_mutex_unlock(&coro_mtx); ++} ++ ++void qemu_coroutine_info_delete(const Coroutine *co_) ++{ ++ CoroutineUContext *co; ++ struct CoroutineInformation *coro_info; ++ ++ /* Remove relative coroutine env info from coro_info_list */ ++ co = DO_UPCAST(CoroutineUContext, base, co_); ++ ++ qemu_mutex_lock(&coro_mtx); ++ QLIST_FOREACH(coro_info, &coro_info_list, next) { ++ if (coro_info->env == &co->env) { ++ QLIST_REMOVE(coro_info, next); ++ g_free(coro_info); ++ break; ++ } ++ } ++ qemu_mutex_unlock(&coro_mtx); ++} +diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c +index b9586d6929..9c81336d8e 100644 +--- a/util/qemu-coroutine.c ++++ b/util/qemu-coroutine.c +@@ -75,6 +75,8 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) + co = qemu_coroutine_new(); + } + ++ qemu_coroutine_info_add(co); ++ + co->entry = entry; + co->entry_arg = opaque; + QSIMPLEQ_INIT(&co->co_queue_wakeup); +@@ -85,6 +87,8 @@ static void coroutine_delete(Coroutine *co) + { + co->caller = NULL; + ++ qemu_coroutine_info_delete(co); ++ + if (CONFIG_COROUTINE_POOL) { + if (release_pool_size < POOL_BATCH_SIZE * 2) { + QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); +-- +2.27.0 + diff --git a/coroutine-Add-qemu_co_mutex_assert_locked.patch b/coroutine-Add-qemu_co_mutex_assert_locked.patch deleted file mode 100644 index fb1f2589f3edd987f0311288d049951c726ddeb8..0000000000000000000000000000000000000000 --- a/coroutine-Add-qemu_co_mutex_assert_locked.patch +++ /dev/null @@ -1,50 +0,0 @@ -From e9bb3d942e268a19e03fc5d404586d2ed1564282 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Thu, 24 Oct 2019 16:26:57 +0200 -Subject: [PATCH] coroutine: Add qemu_co_mutex_assert_locked() - -Some functions require that the caller holds a certain CoMutex for them -to operate correctly. Add a function so that they can assert the lock is -really held. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Kevin Wolf -Tested-by: Michael Weiser -Reviewed-by: Michael Weiser -Reviewed-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Denis V. Lunev -Reviewed-by: Max Reitz -(cherry picked from commit 944f3d5dd216fcd8cb007eddd4f82dced0a15b3d) -Signed-off-by: Michael Roth ---- - include/qemu/coroutine.h | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h -index 9801e7f5a4..f4843b5f59 100644 ---- a/include/qemu/coroutine.h -+++ b/include/qemu/coroutine.h -@@ -167,6 +167,21 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); - */ - void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); - -+/** -+ * Assert that the current coroutine holds @mutex. -+ */ -+static inline coroutine_fn void qemu_co_mutex_assert_locked(CoMutex *mutex) -+{ -+ /* -+ * mutex->holder doesn't need any synchronisation if the assertion holds -+ * true because the mutex protects it. If it doesn't hold true, we still -+ * don't mind if another thread takes or releases mutex behind our back, -+ * because the condition will be false no matter whether we read NULL or -+ * the pointer for any other coroutine. -+ */ -+ assert(atomic_read(&mutex->locked) && -+ mutex->holder == qemu_coroutine_self()); -+} - - /** - * CoQueues are a mechanism to queue coroutines in order to continue executing --- -2.23.0 diff --git a/cpu-add-Cortex-A72-processor-kvm-target-support-v2.patch b/cpu-add-Cortex-A72-processor-kvm-target-support-v2.patch new file mode 100644 index 0000000000000000000000000000000000000000..a98198975b194350bdfc574a426704f213f5cbba --- /dev/null +++ b/cpu-add-Cortex-A72-processor-kvm-target-support-v2.patch @@ -0,0 +1,59 @@ +From 8ddc2bcb196a34cc641d50b057550e4b11dc8700 Mon Sep 17 00:00:00 2001 +From: Xu Yandong +Date: Wed, 9 Feb 2022 17:39:34 +0800 +Subject: [PATCH 3/3] cpu: add Cortex-A72 processor kvm target support + +The ARM Cortex-A72 is ARMv8-A micro-architecture, +add kvm target to ARM Cortex-A72 processor definition. + +Signed-off-by: Xu Yandong +Signed-off-by: Mingwang Li +--- + target/arm/cpu64.c | 2 +- + target/arm/kvm-consts.h | 3 +++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 26419fe994..1b56261964 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -202,6 +202,7 @@ static void aarch64_a72_initfn(Object *obj) + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a72"; ++ cpu->kvm_target = QEMU_KVM_ARM_TARGET_GENERIC_V8; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); +@@ -265,7 +266,6 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x110305408; + cpu->isar.id_aa64isar0 = 0x10211120; + cpu->isar.id_aa64mmfr0 = 0x101125; +- cpu->kvm_target = KVM_ARM_TARGET_GENERIC_V8; + } + + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) +diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h +index 580f1c1fee..5f1311ade7 100644 +--- a/target/arm/kvm-consts.h ++++ b/target/arm/kvm-consts.h +@@ -130,6 +130,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED); + #define QEMU_KVM_ARM_TARGET_CORTEX_A57 2 + #define QEMU_KVM_ARM_TARGET_XGENE_POTENZA 3 + #define QEMU_KVM_ARM_TARGET_CORTEX_A53 4 ++/* Generic ARM v8 target */ ++#define QEMU_KVM_ARM_TARGET_GENERIC_V8 5 + + /* There's no kernel define for this: sentinel value which + * matches no KVM target value for either 64 or 32 bit +@@ -141,6 +143,7 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA); + MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53); ++MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_GENERIC_V8, KVM_ARM_TARGET_GENERIC_V8); + + #define CP_REG_ARM64 0x6000000000000000ULL + #define CP_REG_ARM_COPROC_MASK 0x000000000FFF0000 +-- +2.27.0 + diff --git a/cpu-add-Cortex-A72-processor-kvm-target-support.patch b/cpu-add-Cortex-A72-processor-kvm-target-support.patch index a310c37de95cb5fac446418afcd1efe3650180af..9a83a8d560cde00b49675184bb86c780c0a33691 100644 --- a/cpu-add-Cortex-A72-processor-kvm-target-support.patch +++ b/cpu-add-Cortex-A72-processor-kvm-target-support.patch @@ -1,39 +1,32 @@ -From 4304d1de2c790ac75ed2f5984c4a3a2760c08fff Mon Sep 17 00:00:00 2001 +From f0da7fa5230b5f771570b2c12288e4a56a20dd97 Mon Sep 17 00:00:00 2001 From: Xu Yandong -Date: Mon, 23 Sep 2019 14:35:25 +0800 +Date: Tue, 8 Feb 2022 22:18:55 +0800 Subject: [PATCH] cpu: add Cortex-A72 processor kvm target support The ARM Cortex-A72 is ARMv8-A micro-architecture, add kvm target to ARM Cortex-A72 processor definition. Signed-off-by: Xu Yandong +Signed-off-by: Mingwang Li --- - target/arm/cpu64.c | 2 +- + target/arm/cpu64.c | 1 + target/arm/kvm-consts.h | 3 +++ - 2 files changed, 4 insertions(+), 1 deletion(-) + 2 files changed, 4 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index e408f50d..afbfd1ec 100644 +index aaca79f7c3..556b6f3691 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -212,6 +212,7 @@ static void aarch64_a72_initfn(Object *obj) +@@ -202,6 +202,7 @@ static void aarch64_a72_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); cpu->dtb_compatible = "arm,cortex-a72"; + cpu->kvm_target = QEMU_KVM_ARM_TARGET_GENERIC_V8; set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); -@@ -276,7 +277,6 @@ static void aarch64_kunpeng_t82_initfn(Object *obj) - cpu->id_aa64dfr0 = 0x110305408; - cpu->isar.id_aa64isar0 = 0x10211120; - cpu->isar.id_aa64mmfr0 = 0x101125; -- cpu->kvm_target = KVM_ARM_TARGET_GENERIC_V8; - } - - static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h -index aad28258..b7dac596 100644 +index 580f1c1fee..5f1311ade7 100644 --- a/target/arm/kvm-consts.h +++ b/target/arm/kvm-consts.h @@ -130,6 +130,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED); @@ -45,14 +38,14 @@ index aad28258..b7dac596 100644 /* There's no kernel define for this: sentinel value which * matches no KVM target value for either 64 or 32 bit -@@ -142,6 +144,7 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8); +@@ -141,6 +143,7 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8); MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57); MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA); MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53); +MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_GENERIC_V8, KVM_ARM_TARGET_GENERIC_V8); - #else - MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15); - MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7); + + #define CP_REG_ARM64 0x6000000000000000ULL + #define CP_REG_ARM_COPROC_MASK 0x000000000FFF0000 -- -2.23.0 +2.27.0 diff --git a/cpu-add-Kunpeng-920-cpu-support.patch b/cpu-add-Kunpeng-920-cpu-support.patch index 74e27645ac18a07c00a04283f428bec515cf259e..5e24be91c6cf13417cb239f561c60bd4704c0711 100644 --- a/cpu-add-Kunpeng-920-cpu-support.patch +++ b/cpu-add-Kunpeng-920-cpu-support.patch @@ -1,66 +1,68 @@ -From 70063948181062161a341a8738a53708d8ed0a0b Mon Sep 17 00:00:00 2001 +From 8ebab06c4824626ab4d7204133cd1e7b9c67f468 Mon Sep 17 00:00:00 2001 From: Xu Yandong -Date: Wed, 28 Aug 2019 01:36:21 -0400 +Date: Tue, 8 Feb 2022 21:36:22 +0800 Subject: [PATCH] cpu: add Kunpeng-920 cpu support -Add the Kunpeng-920 CPU model. +Add the Kunpeng-920 CPU model Signed-off-by: Xu Yandong +Signed-off-by: Mingwang Li --- hw/arm/virt.c | 1 + target/arm/cpu64.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index f89757df..11468b72 100644 +index 30da05dfe0..a4a35584e9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -179,6 +179,7 @@ static const char *valid_cpus[] = { +@@ -201,6 +201,7 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("Kunpeng-920"), + ARM_CPU_TYPE_NAME("a64fx"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), - }; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 228906f2..5581d5e1 100644 +index 019edc66c9..aaca79f7c3 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -258,6 +258,26 @@ static void aarch64_a72_initfn(Object *obj) +@@ -248,6 +248,26 @@ static void aarch64_a72_initfn(Object *obj) define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); } - + +static void aarch64_kunpeng_920_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + /* + * Hisilicon Kunpeng-920 CPU is similar to cortex-a72, -+ * so first initialize cpu data as cortex-a72 CPU, -+ * and then update the special registers. ++ * so first initialize cpu data as cortex-a72, ++ * and then update the special register. + */ + aarch64_a72_initfn(obj); + + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; + cpu->isar.id_aa64pfr0 = 0x11001111; -+ cpu->id_aa64dfr0 = 0x110305408; ++ cpu->isar.id_aa64dfr0 = 0x110305408; + cpu->isar.id_aa64isar0 = 0x10211120; + cpu->isar.id_aa64mmfr0 = 0x101125; + cpu->kvm_target = KVM_ARM_TARGET_GENERIC_V8; +} + - static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { -@@ -388,6 +408,7 @@ static const ARMCPUInfo aarch64_cpus[] = { + /* +@@ -892,6 +912,7 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, -+ { .name = "Kunpeng-920", .initfn = aarch64_kunpeng_920_initfn }, ++ { .name = "Kunpeng-920", .initfn = aarch64_kunpeng_920_initfn}, + { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, - { .name = NULL } }; --- -2.19.1 +-- +2.27.0 + diff --git a/cpu-features-fix-bug-for-memory-leakage.patch b/cpu-features-fix-bug-for-memory-leakage.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb7010440d9d395acd9bb0bc9792de279a4d4088 --- /dev/null +++ b/cpu-features-fix-bug-for-memory-leakage.patch @@ -0,0 +1,25 @@ +From 12706113392018fd7aa6471a3cbada62f0180539 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 12:51:19 +0800 +Subject: [PATCH 13/15] cpu/features: fix bug for memory leakage + +strList hash not free after used, Fix it. +--- + target/i386/cpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index aa9e636800..b9690e3250 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4752,6 +4752,7 @@ static void x86_cpu_get_unavailable_features(Object *obj, Visitor *v, + + x86_cpu_list_feature_names(xc->filtered_features, &result); + visit_type_strList(v, "unavailable-features", &result, errp); ++ qapi_free_strList(result); + } + + /* Check for missing features that may prevent the CPU class from +-- +2.27.0 + diff --git a/cpu-parse-feature-to-avoid-failure.patch b/cpu-parse-feature-to-avoid-failure.patch index 78178bfa3dd2a9dd1413dd3c12bbc8e6ed6d2869..4ae42d904b815b115399e9560f3e456de96c712f 100644 --- a/cpu-parse-feature-to-avoid-failure.patch +++ b/cpu-parse-feature-to-avoid-failure.patch @@ -1,35 +1,28 @@ -From ba1ca232cfa2ca273c610beda40bee2143f11964 Mon Sep 17 00:00:00 2001 +From ef83cde8dd2c9b404527354489b14d2bd238733d Mon Sep 17 00:00:00 2001 From: Xu Yandong -Date: Tue, 3 Sep 2019 16:27:39 +0800 +Date: Tue, 8 Feb 2022 20:48:17 +0800 Subject: [PATCH] cpu: parse +/- feature to avoid failure -To avoid cpu feature parse failuer, +/- feature is added. +To avoid cpu feature parse failure, +/- feature is added. Signed-off-by: Xu Yandong +Signed-off-by: Mingwang Li --- - target/arm/cpu64.c | 38 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 38 insertions(+) + target/arm/cpu64.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 0d492877..6ce87ce0 100644 +index 15245a60a8..019edc66c9 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -30,6 +30,7 @@ - #include "sysemu/kvm.h" - #include "kvm_arm.h" - #include "qapi/visitor.h" -+#include "hw/qdev-properties.h" - - static inline void set_feature(CPUARMState *env, int feature) - { -@@ -455,10 +456,47 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) +@@ -933,10 +933,47 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) return g_strdup("aarch64"); } +/* Parse "+feature,-feature,feature=foo" CPU feature string + */ +static void arm_cpu_parse_featurestr(const char *typename, char *features, -+ Error **errp) ++ Error **errp ) +{ + char *featurestr; + char *val; @@ -67,9 +60,9 @@ index 0d492877..6ce87ce0 100644 CPUClass *cc = CPU_CLASS(oc); + cc->parse_features = arm_cpu_parse_featurestr; - cc->cpu_exec_interrupt = arm_cpu_exec_interrupt; cc->gdb_read_register = aarch64_cpu_gdb_read_register; cc->gdb_write_register = aarch64_cpu_gdb_write_register; + cc->gdb_num_core_regs = 34; -- -2.19.1 +2.27.0 diff --git a/cpus-Introduce-cpu_list_generation_id.patch b/cpus-Introduce-cpu_list_generation_id.patch new file mode 100644 index 0000000000000000000000000000000000000000..23cc872659803aa33121a55578f37ef9f294faef --- /dev/null +++ b/cpus-Introduce-cpu_list_generation_id.patch @@ -0,0 +1,73 @@ +From 6e057dd5df580f0e525d808f5476ee973280371d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:31 +0800 +Subject: [PATCH 2/3] cpus: Introduce cpu_list_generation_id +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce cpu_list_generation_id to track cpu list generation so +that cpu hotplug/unplug can be detected during measurement of +dirty page rate. + +cpu_list_generation_id could be used to detect changes of cpu +list, which is prepared for dirty page rate measurement. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Peter Xu +Message-Id: <06e1f1362b2501a471dce796abb065b04f320fa5.1656177590.git.huangy81@chinatelecom.cn> +Signed-off-by: Dr. David Alan Gilbert +--- + cpus-common.c | 8 ++++++++ + include/exec/cpu-common.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/cpus-common.c b/cpus-common.c +index 6e73d3e58d..31c6415f37 100644 +--- a/cpus-common.c ++++ b/cpus-common.c +@@ -73,6 +73,12 @@ static int cpu_get_free_index(void) + } + + CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); ++static unsigned int cpu_list_generation_id; ++ ++unsigned int cpu_list_generation_id_get(void) ++{ ++ return cpu_list_generation_id; ++} + + void cpu_list_add(CPUState *cpu) + { +@@ -84,6 +90,7 @@ void cpu_list_add(CPUState *cpu) + assert(!cpu_index_auto_assigned); + } + QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); ++ cpu_list_generation_id++; + } + + void cpu_list_remove(CPUState *cpu) +@@ -96,6 +103,7 @@ void cpu_list_remove(CPUState *cpu) + + QTAILQ_REMOVE_RCU(&cpus, cpu, node); + cpu->cpu_index = UNASSIGNED_CPU_INDEX; ++ cpu_list_generation_id++; + } + + CPUState *qemu_get_cpu(int index) +diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h +index 039d422bf4..cdee668f20 100644 +--- a/include/exec/cpu-common.h ++++ b/include/exec/cpu-common.h +@@ -11,6 +11,7 @@ + void qemu_init_cpu_list(void); + void cpu_list_lock(void); + void cpu_list_unlock(void); ++unsigned int cpu_list_generation_id_get(void); + + void tcg_flush_softmmu_tlb(CPUState *cs); + +-- +2.27.0 + diff --git a/cris-do-not-leak-struct-cris_disasm_data.patch b/cris-do-not-leak-struct-cris_disasm_data.patch deleted file mode 100644 index fa7623fe1878eca815805e853d64ff9b2d8a88a3..0000000000000000000000000000000000000000 --- a/cris-do-not-leak-struct-cris_disasm_data.patch +++ /dev/null @@ -1,139 +0,0 @@ -From d0586065e67b5df2611f4cf61eb791d48b78ff77 Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 14:42:59 +0800 -Subject: [PATCH] cris: do not leak struct cris_disasm_data - -Use a stack-allocated struct to avoid a memory leak. - -Signed-off-by: Paolo Bonzini ---- - disas/cris.c | 65 ++++++++++++++++++++++++++++------------------------ - 1 file changed, 35 insertions(+), 30 deletions(-) - -diff --git a/disas/cris.c b/disas/cris.c -index 2f43c9b2..f3ff44ba 100644 ---- a/disas/cris.c -+++ b/disas/cris.c -@@ -1294,24 +1294,17 @@ static int cris_constraint - /* Parse disassembler options and store state in info. FIXME: For the - time being, we abuse static variables. */ - --static bfd_boolean --cris_parse_disassembler_options (disassemble_info *info, -+static void -+cris_parse_disassembler_options (struct cris_disasm_data *disdata, -+ char *disassembler_options, - enum cris_disass_family distype) - { -- struct cris_disasm_data *disdata; -- -- info->private_data = calloc (1, sizeof (struct cris_disasm_data)); -- disdata = (struct cris_disasm_data *) info->private_data; -- if (disdata == NULL) -- return false; -- - /* Default true. */ - disdata->trace_case -- = (info->disassembler_options == NULL -- || (strcmp (info->disassembler_options, "nocase") != 0)); -+ = (disassembler_options == NULL -+ || (strcmp (disassembler_options, "nocase") != 0)); - - disdata->distype = distype; -- return true; - } - - static const struct cris_spec_reg * -@@ -2736,9 +2729,11 @@ static int - print_insn_cris_with_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_v0_v10); -+ - return print_insn_cris_generic (vma, info, true); - } - /* Disassemble, prefixing register names with `$'. CRIS v32. */ -@@ -2747,9 +2742,11 @@ static int - print_insn_crisv32_with_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_v32)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_v32); -+ - return print_insn_cris_generic (vma, info, true); - } - -@@ -2761,9 +2758,11 @@ static int - print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_common_v10_v32); -+ - return print_insn_cris_generic (vma, info, true); - } - -@@ -2773,9 +2772,11 @@ static int - print_insn_cris_without_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_v0_v10); -+ - return print_insn_cris_generic (vma, info, false); - } - -@@ -2785,9 +2786,11 @@ static int - print_insn_crisv32_without_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_v32)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_v32); -+ - return print_insn_cris_generic (vma, info, false); - } - -@@ -2798,9 +2801,11 @@ static int - print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, - disassemble_info *info) - { -- if (info->private_data == NULL -- && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) -- return -1; -+ struct cris_disasm_data disdata; -+ info->private_data = &disdata; -+ cris_parse_disassembler_options (&disdata, info->disassembler_options, -+ cris_dis_common_v10_v32); -+ - return print_insn_cris_generic (vma, info, false); - } - #endif --- -2.19.1 - diff --git a/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch b/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch deleted file mode 100644 index d204f017b830d15bb9609570e39fb11e34676203..0000000000000000000000000000000000000000 --- a/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch +++ /dev/null @@ -1,346 +0,0 @@ -From 84352558eec97cfb0e4517fbb53d75d9f15cbcf9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= -Date: Mon, 14 Oct 2019 17:28:27 +0100 -Subject: [PATCH] crypto: add support for gcrypt's native XTS impl -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Libgcrypt 1.8.0 added support for the XTS mode. Use this because long -term we wish to delete QEMU's XTS impl to avoid carrying private crypto -algorithm impls. - -As an added benefit, using this improves performance from 531 MB/sec to -670 MB/sec, since we are avoiding several layers of function call -indirection. - -This is even more noticable with the gcrypt builds in Fedora or RHEL-8 -which have a non-upstream patch for FIPS mode which does mutex locking. -This is catastrophic for encryption performance with small block sizes, -meaning this patch improves encryption from 240 MB/sec to 670 MB/sec. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefano Garzarella -Signed-off-by: Daniel P. Berrangé ---- - configure | 22 ++++++++++ - crypto/Makefile.objs | 2 +- - crypto/cipher-gcrypt.c | 97 ++++++++++++++++++++++++++++-------------- - tests/Makefile.include | 2 +- - 4 files changed, 88 insertions(+), 35 deletions(-) - -diff --git a/configure b/configure -index 5dcaac3b95..a88cdd5109 100755 ---- a/configure -+++ b/configure -@@ -476,6 +476,8 @@ nettle="" - nettle_xts="no" - gcrypt="" - gcrypt_hmac="no" -+gcrypt_xts="no" -+qemu_private_xts="yes" - auth_pam="" - vte="" - virglrenderer="" -@@ -2974,6 +2976,18 @@ EOF - if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then - gcrypt_hmac=yes - fi -+ cat > $TMPC << EOF -+#include -+int main(void) { -+ gcry_cipher_hd_t handle; -+ gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_XTS, 0); -+ return 0; -+} -+EOF -+ if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then -+ gcrypt_xts=yes -+ qemu_private_xts=no -+ fi - elif test "$gcrypt" = "yes"; then - feature_not_found "gcrypt" "Install gcrypt devel >= 1.5.0" - else -@@ -6404,6 +6418,11 @@ echo "VTE support $vte $(echo_version $vte $vteversion)" - echo "TLS priority $tls_priority" - echo "GNUTLS support $gnutls" - echo "libgcrypt $gcrypt" -+if test "$gcrypt" = "yes" -+then -+ echo " hmac $gcrypt_hmac" -+ echo " XTS $gcrypt_xts" -+fi - echo "nettle $nettle $(echo_version $nettle $nettle_version)" - if test "$nettle" = "yes" - then -@@ -6889,6 +6908,9 @@ if test "$nettle" = "yes" ; then - echo "CONFIG_NETTLE=y" >> $config_host_mak - echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak - fi -+if test "$qemu_private_xts" = "yes" ; then -+ echo "CONFIG_QEMU_PRIVATE_XTS=y" >> $config_host_mak -+fi - if test "$tasn1" = "yes" ; then - echo "CONFIG_TASN1=y" >> $config_host_mak - fi -diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs -index 7fe2fa9da2..cdb01f9de9 100644 ---- a/crypto/Makefile.objs -+++ b/crypto/Makefile.objs -@@ -31,7 +31,7 @@ crypto-obj-y += ivgen-essiv.o - crypto-obj-y += ivgen-plain.o - crypto-obj-y += ivgen-plain64.o - crypto-obj-y += afsplit.o --crypto-obj-y += xts.o -+crypto-obj-$(CONFIG_QEMU_PRIVATE_XTS) += xts.o - crypto-obj-y += block.o - crypto-obj-y += block-qcow.o - crypto-obj-y += block-luks.o -diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c -index 5cece9b244..2864099527 100644 ---- a/crypto/cipher-gcrypt.c -+++ b/crypto/cipher-gcrypt.c -@@ -19,7 +19,9 @@ - */ - - #include "qemu/osdep.h" -+#ifdef CONFIG_QEMU_PRIVATE_XTS - #include "crypto/xts.h" -+#endif - #include "cipherpriv.h" - - #include -@@ -59,10 +61,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, - typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; - struct QCryptoCipherGcrypt { - gcry_cipher_hd_t handle; -- gcry_cipher_hd_t tweakhandle; - size_t blocksize; -+#ifdef CONFIG_QEMU_PRIVATE_XTS -+ gcry_cipher_hd_t tweakhandle; - /* Initialization vector or Counter */ - uint8_t *iv; -+#endif - }; - - static void -@@ -74,10 +78,12 @@ qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, - } - - gcry_cipher_close(ctx->handle); -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - gcry_cipher_close(ctx->tweakhandle); - } - g_free(ctx->iv); -+#endif - g_free(ctx); - } - -@@ -94,8 +100,14 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: -+ gcrymode = GCRY_CIPHER_MODE_ECB; -+ break; - case QCRYPTO_CIPHER_MODE_XTS: -+#ifdef CONFIG_QEMU_PRIVATE_XTS - gcrymode = GCRY_CIPHER_MODE_ECB; -+#else -+ gcrymode = GCRY_CIPHER_MODE_XTS; -+#endif - break; - case QCRYPTO_CIPHER_MODE_CBC: - gcrymode = GCRY_CIPHER_MODE_CBC; -@@ -172,6 +184,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - gcry_strerror(err)); - goto error; - } -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); - if (err != 0) { -@@ -180,6 +193,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - goto error; - } - } -+#endif - - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { - /* We're using standard DES cipher from gcrypt, so we need -@@ -191,6 +205,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - g_free(rfbkey); - ctx->blocksize = 8; - } else { -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - nkey /= 2; - err = gcry_cipher_setkey(ctx->handle, key, nkey); -@@ -201,8 +216,11 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - } - err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); - } else { -+#endif - err = gcry_cipher_setkey(ctx->handle, key, nkey); -+#ifdef CONFIG_QEMU_PRIVATE_XTS - } -+#endif - if (err != 0) { - error_setg(errp, "Cannot set key: %s", - gcry_strerror(err)); -@@ -228,6 +246,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - } - } - -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (ctx->blocksize != XTS_BLOCK_SIZE) { - error_setg(errp, -@@ -237,6 +256,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - } - ctx->iv = g_new0(uint8_t, ctx->blocksize); - } -+#endif - - return ctx; - -@@ -253,6 +273,7 @@ qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) - } - - -+#ifdef CONFIG_QEMU_PRIVATE_XTS - static void qcrypto_gcrypt_xts_encrypt(const void *ctx, - size_t length, - uint8_t *dst, -@@ -272,6 +293,7 @@ static void qcrypto_gcrypt_xts_decrypt(const void *ctx, - err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); - g_assert(err == 0); - } -+#endif - - static int - qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, -@@ -289,20 +311,23 @@ qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, - return -1; - } - -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { - xts_encrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_encrypt, - qcrypto_gcrypt_xts_decrypt, - ctx->iv, len, out, in); -- } else { -- err = gcry_cipher_encrypt(ctx->handle, -- out, len, -- in, len); -- if (err != 0) { -- error_setg(errp, "Cannot encrypt data: %s", -- gcry_strerror(err)); -- return -1; -- } -+ return 0; -+ } -+#endif -+ -+ err = gcry_cipher_encrypt(ctx->handle, -+ out, len, -+ in, len); -+ if (err != 0) { -+ error_setg(errp, "Cannot encrypt data: %s", -+ gcry_strerror(err)); -+ return -1; - } - - return 0; -@@ -325,20 +350,23 @@ qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, - return -1; - } - -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { - xts_decrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_encrypt, - qcrypto_gcrypt_xts_decrypt, - ctx->iv, len, out, in); -- } else { -- err = gcry_cipher_decrypt(ctx->handle, -- out, len, -- in, len); -- if (err != 0) { -- error_setg(errp, "Cannot decrypt data: %s", -- gcry_strerror(err)); -- return -1; -- } -+ return 0; -+ } -+#endif -+ -+ err = gcry_cipher_decrypt(ctx->handle, -+ out, len, -+ in, len); -+ if (err != 0) { -+ error_setg(errp, "Cannot decrypt data: %s", -+ gcry_strerror(err)); -+ return -1; - } - - return 0; -@@ -358,24 +386,27 @@ qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, - return -1; - } - -+#ifdef CONFIG_QEMU_PRIVATE_XTS - if (ctx->iv) { - memcpy(ctx->iv, iv, niv); -- } else { -- if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { -- err = gcry_cipher_setctr(ctx->handle, iv, niv); -- if (err != 0) { -- error_setg(errp, "Cannot set Counter: %s", -+ return 0; -+ } -+#endif -+ -+ if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { -+ err = gcry_cipher_setctr(ctx->handle, iv, niv); -+ if (err != 0) { -+ error_setg(errp, "Cannot set Counter: %s", - gcry_strerror(err)); -- return -1; -- } -- } else { -- gcry_cipher_reset(ctx->handle); -- err = gcry_cipher_setiv(ctx->handle, iv, niv); -- if (err != 0) { -- error_setg(errp, "Cannot set IV: %s", -+ return -1; -+ } -+ } else { -+ gcry_cipher_reset(ctx->handle); -+ err = gcry_cipher_setiv(ctx->handle, iv, niv); -+ if (err != 0) { -+ error_setg(errp, "Cannot set IV: %s", - gcry_strerror(err)); -- return -1; -- } -+ return -1; - } - } - -diff --git a/tests/Makefile.include b/tests/Makefile.include -index d6de4e1042..3be60ab999 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -132,7 +132,7 @@ check-unit-y += tests/test-base64$(EXESUF) - check-unit-$(call land,$(CONFIG_BLOCK),$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT))) += tests/test-crypto-pbkdf$(EXESUF) - check-unit-$(CONFIG_BLOCK) += tests/test-crypto-ivgen$(EXESUF) - check-unit-$(CONFIG_BLOCK) += tests/test-crypto-afsplit$(EXESUF) --check-unit-$(CONFIG_BLOCK) += tests/test-crypto-xts$(EXESUF) -+check-unit-$(if $(CONFIG_BLOCK),$(CONFIG_QEMU_PRIVATE_XTS)) += tests/test-crypto-xts$(EXESUF) - check-unit-$(CONFIG_BLOCK) += tests/test-crypto-block$(EXESUF) - check-unit-y += tests/test-logging$(EXESUF) - check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF) --- -2.27.0 - diff --git a/crypto-add-support-for-nettle-s-native-XTS-impl.patch b/crypto-add-support-for-nettle-s-native-XTS-impl.patch deleted file mode 100644 index 5aed7d626edf019c94c64939f35357274e39136a..0000000000000000000000000000000000000000 --- a/crypto-add-support-for-nettle-s-native-XTS-impl.patch +++ /dev/null @@ -1,126 +0,0 @@ -From c4db6fcb2c45b800cd46e088f8265ccc0631b6fc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= -Date: Mon, 14 Oct 2019 17:28:27 +0100 -Subject: [PATCH] crypto: add support for nettle's native XTS impl -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Nettle 3.5.0 will add support for the XTS mode. Use this because long -term we wish to delete QEMU's XTS impl to avoid carrying private crypto -algorithm impls. - -Unfortunately this degrades nettle performance from 612 MB/s to 568 MB/s -as nettle's XTS impl isn't so well optimized yet. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefano Garzarella -Signed-off-by: Daniel P. Berrangé ---- - configure | 18 ++++++++++++++++++ - crypto/cipher-nettle.c | 18 ++++++++++++++++++ - 2 files changed, 36 insertions(+) - -diff --git a/configure b/configure -index 577533e9ed..5dcaac3b95 100755 ---- a/configure -+++ b/configure -@@ -473,6 +473,7 @@ gtk_gl="no" - tls_priority="NORMAL" - gnutls="" - nettle="" -+nettle_xts="no" - gcrypt="" - gcrypt_hmac="no" - auth_pam="" -@@ -2918,6 +2919,19 @@ if test "$nettle" != "no"; then - pass="yes" - fi - fi -+ if test "$pass" = "yes" -+ then -+ cat > $TMPC << EOF -+#include -+int main(void) { -+ return 0; -+} -+EOF -+ if compile_prog "$nettle_cflags" "$nettle_libs" ; then -+ nettle_xts=yes -+ qemu_private_xts=no -+ fi -+ fi - if test "$pass" = "no" && test "$nettle" = "yes"; then - feature_not_found "nettle" "Install nettle devel >= 2.7.1" - else -@@ -6391,6 +6405,10 @@ echo "TLS priority $tls_priority" - echo "GNUTLS support $gnutls" - echo "libgcrypt $gcrypt" - echo "nettle $nettle $(echo_version $nettle $nettle_version)" -+if test "$nettle" = "yes" -+then -+ echo " XTS $nettle_xts" -+fi - echo "libtasn1 $tasn1" - echo "PAM $auth_pam" - echo "iconv support $iconv" -diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c -index d7411bb8ff..7e9a4cc199 100644 ---- a/crypto/cipher-nettle.c -+++ b/crypto/cipher-nettle.c -@@ -19,7 +19,9 @@ - */ - - #include "qemu/osdep.h" -+#ifdef CONFIG_QEMU_PRIVATE_XTS - #include "crypto/xts.h" -+#endif - #include "cipherpriv.h" - - #include -@@ -30,6 +32,9 @@ - #include - #include - #include -+#ifndef CONFIG_QEMU_PRIVATE_XTS -+#include -+#endif - - typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx, - size_t length, -@@ -626,9 +631,15 @@ qcrypto_nettle_cipher_encrypt(QCryptoCipher *cipher, - break; - - case QCRYPTO_CIPHER_MODE_XTS: -+#ifdef CONFIG_QEMU_PRIVATE_XTS - xts_encrypt(ctx->ctx, ctx->ctx_tweak, - ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper, - ctx->iv, len, out, in); -+#else -+ xts_encrypt_message(ctx->ctx, ctx->ctx_tweak, -+ ctx->alg_encrypt_native, -+ ctx->iv, len, out, in); -+#endif - break; - - case QCRYPTO_CIPHER_MODE_CTR: -@@ -673,9 +684,16 @@ qcrypto_nettle_cipher_decrypt(QCryptoCipher *cipher, - break; - - case QCRYPTO_CIPHER_MODE_XTS: -+#ifdef CONFIG_QEMU_PRIVATE_XTS - xts_decrypt(ctx->ctx, ctx->ctx_tweak, - ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper, - ctx->iv, len, out, in); -+#else -+ xts_decrypt_message(ctx->ctx, ctx->ctx_tweak, -+ ctx->alg_decrypt_native, -+ ctx->alg_encrypt_native, -+ ctx->iv, len, out, in); -+#endif - break; - case QCRYPTO_CIPHER_MODE_CTR: - ctr_crypt(ctx->ctx, ctx->alg_encrypt_native, --- -2.27.0 - diff --git a/crypto-remove-shadowed-ret-variable.patch b/crypto-remove-shadowed-ret-variable.patch new file mode 100644 index 0000000000000000000000000000000000000000..ee0bf6ddcf428c7788233bb564fea4ae9123240d --- /dev/null +++ b/crypto-remove-shadowed-ret-variable.patch @@ -0,0 +1,36 @@ +From b055bedb3fba592ab7e73615faf29854a18b0abc Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 10 Oct 2023 15:24:35 +0800 +Subject: [PATCH] crypto: remove shadowed 'ret' variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 3cc9fe177f412494f084923149338c51dd232b9b + +Both instances of 'ret' are used to store a gnutls API return code. + +Signed-off-by: Daniel P. Berrangé +Message-ID: <20230922160644.438631-2-berrange@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Signed-off-by: qihao_yewu +--- + crypto/tls-cipher-suites.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c +index 5e4f597464..d0df4badc0 100644 +--- a/crypto/tls-cipher-suites.c ++++ b/crypto/tls-cipher-suites.c +@@ -52,7 +52,6 @@ GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, + byte_array = g_byte_array_new(); + + for (i = 0;; i++) { +- int ret; + unsigned idx; + const char *name; + IANA_TLS_CIPHER cipher; +-- +2.41.0.windows.1 + diff --git a/curl-Fix-error-path-in-curl_open.patch b/curl-Fix-error-path-in-curl_open.patch new file mode 100644 index 0000000000000000000000000000000000000000..215bd7ac46b77b42a1b8531447702af8268edc66 --- /dev/null +++ b/curl-Fix-error-path-in-curl_open.patch @@ -0,0 +1,48 @@ +From 745dd52e9a737f2d1e16fdc79b0f701d63df3606 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 16 Mar 2023 16:20:44 +0800 +Subject: [PATCH] curl: Fix error path in curl_open() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +g_hash_table_destroy() and g_hash_table_foreach_remove() (called by +curl_drop_all_sockets()) both require the table to be non-NULL, or will +print assertion failures (just print, no abort). +There are several paths in curl_open() that can lead to the out_noclean +label without s->sockets being allocated, so clean it only if it has +been allocated. +Example reproducer: +$ qemu-img info -f http '' +qemu-img: GLib: g_hash_table_foreach_remove: assertion 'hash_table != NULL' failed +qemu-img: GLib: g_hash_table_destroy: assertion 'hash_table != NULL' failed +qemu-img: Could not open '': http curl driver cannot handle the URL '' (does not start with 'http://') + +Closes: https://gitlab.com/qemu-project/qemu/-/issues/1475 +Suggested-by: Daniel P. Berrangé +Signed-off-by: Hanna Czenczek +Signed-off-by: jianchunfu +--- + block/curl.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/curl.c b/block/curl.c +index 4a8ae2b269..5aebb08002 100644 +--- a/block/curl.c ++++ b/block/curl.c +@@ -821,8 +821,10 @@ out_noclean: + g_free(s->username); + g_free(s->proxyusername); + g_free(s->proxypassword); +- curl_drop_all_sockets(s->sockets); +- g_hash_table_destroy(s->sockets); ++ if (s->sockets) { ++ curl_drop_all_sockets(s->sockets); ++ g_hash_table_destroy(s->sockets); ++ } + qemu_opts_del(opts); + return -EINVAL; + } +-- +2.27.0 + diff --git a/delete-the-in-tpm.txt.patch b/delete-the-in-tpm.txt.patch deleted file mode 100644 index 01ce3ace541aca115bccd47100f5dbd954643764..0000000000000000000000000000000000000000 --- a/delete-the-in-tpm.txt.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 3020ae141ef40f06b17eb0f16d2a3c6d5872ff89 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Wed, 29 Jul 2020 08:45:50 +0000 -Subject: [PATCH 05/19] delete the in tpm.txt - -Signed-off-by: jiangfangjie ---- - docs/specs/tpm.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt -index 5d8c26b1..9c8cca04 100644 ---- a/docs/specs/tpm.txt -+++ b/docs/specs/tpm.txt -@@ -89,7 +89,7 @@ TPM upon reboot. The PPI specification defines the operation requests and the - actions the firmware has to take. The system administrator passes the operation - request number to the firmware through an ACPI interface which writes this - number to a memory location that the firmware knows. Upon reboot, the firmware --finds the number and sends commands to the the TPM. The firmware writes the TPM -+finds the number and sends commands to the TPM. The firmware writes the TPM - result code and the operation request number to a memory location that ACPI can - read from and pass the result on to the administrator. - --- -2.23.0 - diff --git a/disas-hppa-Show-hexcode-of-instruction-along-with-di.patch b/disas-hppa-Show-hexcode-of-instruction-along-with-di.patch new file mode 100644 index 0000000000000000000000000000000000000000..16cd69a7ef3a4994c3604bc2dcbb551860b0190f --- /dev/null +++ b/disas-hppa-Show-hexcode-of-instruction-along-with-di.patch @@ -0,0 +1,48 @@ +From 7949977cef7b7b4170dad873f9b5788f0c4e40ee Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 10:54:54 +0800 +Subject: [PATCH] disas/hppa: Show hexcode of instruction along with + disassembly + +cherry picked from 2f926bfd5b79e6219ae65a1e530b38f37d62b384 + +On hppa many instructions can be expressed by different bytecodes. +To be able to debug qemu translation bugs it's therefore necessary to see the +currently executed byte codes without the need to lookup the sequence without +the full executable. +With this patch the instruction byte code is shown beside the disassembly. + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson + +Signed-off-by: boringandboring +--- + disas/hppa.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/disas/hppa.c b/disas/hppa.c +index dcf9a47f34..cce4f4aa37 100644 +--- a/disas/hppa.c ++++ b/disas/hppa.c +@@ -1968,6 +1968,10 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info) + + insn = bfd_getb32 (buffer); + ++ info->fprintf_func(info->stream, " %02x %02x %02x %02x ", ++ (insn >> 24) & 0xff, (insn >> 16) & 0xff, ++ (insn >> 8) & 0xff, insn & 0xff); ++ + for (i = 0; i < NUMOPCODES; ++i) + { + const struct pa_opcode *opcode = &pa_opcodes[i]; +@@ -2826,6 +2830,6 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info) + return sizeof (insn); + } + } +- (*info->fprintf_func) (info->stream, "#%8x", insn); ++ info->fprintf_func(info->stream, ""); + return sizeof (insn); + } +-- +2.27.0 + diff --git a/disas-riscv-Fix-ctzw-disassemble.patch b/disas-riscv-Fix-ctzw-disassemble.patch new file mode 100644 index 0000000000000000000000000000000000000000..8157ce2bd2df8728cbd395ffdbce43b19cc6ce16 --- /dev/null +++ b/disas-riscv-Fix-ctzw-disassemble.patch @@ -0,0 +1,37 @@ +From 6872e7bf919dd5f2852c07850899cdb510eccfdf Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Tue, 1 Aug 2023 23:46:43 -0700 +Subject: [PATCH] disas/riscv Fix ctzw disassemble + +cherry picked from commit 270629024df1f9f4e704ce8325f958858c5cbff7 + +Due to typo in opcode list, ctzw is disassembled as clzw instruction. + +Signed-off-by: Ivan Klokov +Fixes: 02c1b569a15b ("disas/riscv: Add Zb[abcs] instructions") +Reviewed-by: Weiwei Li +Reviewed-by: Daniel Henrique Barboza +Message-ID: <20230217151459.54649-1-ivan.klokov@syntacore.com> +Signed-off-by: Palmer Dabbelt + +Signed-off-by: Wanghe Xiao +--- + disas/riscv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/disas/riscv.c b/disas/riscv.c +index 793ad14c27..6768ec8188 100644 +--- a/disas/riscv.c ++++ b/disas/riscv.c +@@ -1189,7 +1189,7 @@ const rv_opcode_data opcode_data[] = { + { "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, +- { "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, ++ { "ctzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "slli.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, +-- +2.41.0.windows.1 + diff --git a/disas-riscv-Fix-the-typo-of-inverted-order-of-pmpadd.patch b/disas-riscv-Fix-the-typo-of-inverted-order-of-pmpadd.patch new file mode 100644 index 0000000000000000000000000000000000000000..3185723a95d72a6d00a33aeebacd62eb74ca3c90 --- /dev/null +++ b/disas-riscv-Fix-the-typo-of-inverted-order-of-pmpadd.patch @@ -0,0 +1,37 @@ +From 80fd3d8f92b8a2c3b640d1dfa436da8331b37b01 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 16 Oct 2023 09:47:25 +0800 +Subject: [PATCH] disas/riscv: Fix the typo of inverted order of pmpaddr13 and + pmpaddr14 + +cheery-pick from cffa9954908830276c93b430681f66cc0e599aef + +Fix the inverted order of pmpaddr13 and pmpaddr14 in csr_name(). + +Signed-off-by: Alvin Chang +Reviewed-by: Alistair Francis +Message-ID: <20230907084500.328-1-alvinga@andestech.com> +Signed-off-by: Alistair Francis +Signed-off-by: qihao_yewu +--- + disas/riscv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/disas/riscv.c b/disas/riscv.c +index 6768ec8188..ad7b978815 100644 +--- a/disas/riscv.c ++++ b/disas/riscv.c +@@ -1307,8 +1307,8 @@ static const char *csr_name(int csrno) + case 0x03ba: return "pmpaddr10"; + case 0x03bb: return "pmpaddr11"; + case 0x03bc: return "pmpaddr12"; +- case 0x03bd: return "pmpaddr14"; +- case 0x03be: return "pmpaddr13"; ++ case 0x03bd: return "pmpaddr13"; ++ case 0x03be: return "pmpaddr14"; + case 0x03bf: return "pmpaddr15"; + case 0x0780: return "mtohost"; + case 0x0781: return "mfromhost"; +-- +2.41.0.windows.1 + diff --git a/display-bochs-display-fix-memory-leak.patch b/display-bochs-display-fix-memory-leak.patch deleted file mode 100644 index 4dd3aa61c2b2b1026e0065c708ead4aeb79b3c21..0000000000000000000000000000000000000000 --- a/display-bochs-display-fix-memory-leak.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 7edca67dc630e31043644e87ede2e05e504f845b Mon Sep 17 00:00:00 2001 -From: Cameron Esfahani -Date: Tue, 10 Dec 2019 13:27:54 -0800 -Subject: [PATCH 1/8] display/bochs-display: fix memory leak -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix memory leak in bochs_display_update(). Leaks 304 bytes per frame. - -Fixes: 33ebad54056 -Signed-off-by: Cameron Esfahani -Message-Id: -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Gerd Hoffmann ---- - hw/display/bochs-display.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c -index 8e83b51..b601b2f 100644 ---- a/hw/display/bochs-display.c -+++ b/hw/display/bochs-display.c -@@ -251,6 +251,8 @@ static void bochs_display_update(void *opaque) - dpy_gfx_update(s->con, 0, ys, - mode.width, y - ys); - } -+ -+ g_free(snap); - } - } - --- -1.8.3.1 - diff --git a/display-qxl-render-fix-race-condition-in-qxl_cursor-.patch b/display-qxl-render-fix-race-condition-in-qxl_cursor-.patch new file mode 100644 index 0000000000000000000000000000000000000000..4470b651d1ef340493dabceb063e80370d3ee830 --- /dev/null +++ b/display-qxl-render-fix-race-condition-in-qxl_cursor-.patch @@ -0,0 +1,38 @@ +From 98c106af8a2f761f615690494b425aed57b308db Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Thu, 7 Apr 2022 10:11:06 +0200 +Subject: [PATCH 1/2] display/qxl-render: fix race condition in qxl_cursor + (CVE-2021-4207) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid fetching 'width' and 'height' a second time to prevent possible +race condition. Refer to security advisory +https://starlabs.sg/advisories/22-4207/ for more information. + +Fixes: CVE-2021-4207 +Signed-off-by: Mauro Matteo Cascella +Reviewed-by: Marc-André Lureau +Message-Id: <20220407081106.343235-1-mcascell@redhat.com> +Signed-off-by: Gerd Hoffmann +--- + hw/display/qxl-render.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index d28849b121..237ed293ba 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -266,7 +266,7 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor, + } + break; + case SPICE_CURSOR_TYPE_ALPHA: +- size = sizeof(uint32_t) * cursor->header.width * cursor->header.height; ++ size = sizeof(uint32_t) * c->width * c->height; + qxl_unpack_chunks(c->data, size, qxl, &cursor->chunk, group_id); + if (qxl->debug > 2) { + cursor_print_ascii_art(c, "qxl/alpha"); +-- +2.27.0 + diff --git a/dma-Have-dma_buf_read-dma_buf_write-take-a-void-poin.patch b/dma-Have-dma_buf_read-dma_buf_write-take-a-void-poin.patch new file mode 100644 index 0000000000000000000000000000000000000000..c62656c98b34fa3df2cdd3da4c35847f9282ddc7 --- /dev/null +++ b/dma-Have-dma_buf_read-dma_buf_write-take-a-void-poin.patch @@ -0,0 +1,164 @@ +From 0f43c97e5a88131fc5d30dc2150d3265c99725d7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 16 Dec 2021 11:27:23 +0100 +Subject: [PATCH 09/25] dma: Have dma_buf_read() / dma_buf_write() take a void + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DMA operations are run on any kind of buffer, not arrays of +uint8_t. Convert dma_buf_read/dma_buf_write functions to take +a void pointer argument and save us pointless casts to uint8_t *. + +Remove this pointless casts in the megasas device model. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-9-philmd@redhat.com> +--- + hw/scsi/megasas.c | 22 +++++++++++----------- + include/sysemu/dma.h | 4 ++-- + softmmu/dma-helpers.c | 4 ++-- + 3 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 6d21bf9fdd..fac46c54ab 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -847,7 +847,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) + MFI_INFO_PDMIX_SATA | + MFI_INFO_PDMIX_LD); + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -877,7 +877,7 @@ static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd) + info.disable_preboot_cli = 1; + info.cluster_disable = 1; + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -898,7 +898,7 @@ static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd) + info.expose_all_drives = 1; + } + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -909,7 +909,7 @@ static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd) + + fw_time = cpu_to_le64(megasas_fw_time()); + +- cmd->iov_size -= dma_buf_read((uint8_t *)&fw_time, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&fw_time, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -936,7 +936,7 @@ static int megasas_event_info(MegasasState *s, MegasasCmd *cmd) + info.shutdown_seq_num = cpu_to_le32(s->shutdown_event); + info.boot_seq_num = cpu_to_le32(s->boot_event); + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -1005,7 +1005,7 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd) + info.size = cpu_to_le32(offset); + info.count = cpu_to_le32(num_pd_disks); + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, offset, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, offset, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -1171,7 +1171,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) + info.ld_count = cpu_to_le32(num_ld_disks); + trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); + +- resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(&info, dcmd_size, &cmd->qsg); + cmd->iov_size = dcmd_size - resid; + return MFI_STAT_OK; + } +@@ -1220,7 +1220,7 @@ static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) + info.size = dcmd_size; + trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); + +- resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(&info, dcmd_size, &cmd->qsg); + cmd->iov_size = dcmd_size - resid; + return MFI_STAT_OK; + } +@@ -1389,7 +1389,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) + ld_offset += sizeof(struct mfi_ld_config); + } + +- cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(data, info->size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -1419,7 +1419,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd) + info.ecc_bucket_leak_rate = cpu_to_le16(1440); + info.expose_encl_devices = 1; + +- cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); + return MFI_STAT_OK; + } + +@@ -1464,7 +1464,7 @@ static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) + dcmd_size); + return MFI_STAT_INVALID_PARAMETER; + } +- dma_buf_write((uint8_t *)&info, dcmd_size, &cmd->qsg); ++ dma_buf_write(&info, dcmd_size, &cmd->qsg); + trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); + return MFI_STAT_OK; + } +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 97ff6f29f8..0d5b836013 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -302,8 +302,8 @@ BlockAIOCB *dma_blk_read(BlockBackend *blk, + BlockAIOCB *dma_blk_write(BlockBackend *blk, + QEMUSGList *sg, uint64_t offset, uint32_t align, + BlockCompletionFunc *cb, void *opaque); +-uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg); +-uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg); ++uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg); ++uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg); + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, + QEMUSGList *sg, enum BlockAcctType type); +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 09e29997ee..7f37548394 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -317,12 +317,12 @@ static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + return resid; + } + +-uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg) ++uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg) + { + return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE); + } + +-uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg) ++uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg) + { + return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE); + } +-- +2.27.0 + diff --git a/dma-Have-dma_buf_rw-take-a-void-pointer.patch b/dma-Have-dma_buf_rw-take-a-void-pointer.patch new file mode 100644 index 0000000000000000000000000000000000000000..7dd112de0ae73d05813a71a9e3c45176d0b9290e --- /dev/null +++ b/dma-Have-dma_buf_rw-take-a-void-pointer.patch @@ -0,0 +1,38 @@ +From cb11b87fe29fa0f4ee664bacff242ed34bf3f33e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 16 Dec 2021 11:24:56 +0100 +Subject: [PATCH 08/25] dma: Have dma_buf_rw() take a void pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DMA operations are run on any kind of buffer, not arrays of +uint8_t. Convert dma_buf_rw() to take a void pointer argument +to save us pointless casts to uint8_t *. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-8-philmd@redhat.com> +--- + softmmu/dma-helpers.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 3c06a2fedd..09e29997ee 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -294,9 +294,10 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, + } + + +-static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, ++static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + DMADirection dir) + { ++ uint8_t *ptr = buf; + uint64_t resid; + int sg_cur_index; + +-- +2.27.0 + diff --git a/dma-Let-dma_buf_read-take-MemTxAttrs-argument.patch b/dma-Let-dma_buf_read-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fd0aba5720b2375070fe8f4acc24e14dbc33d31 --- /dev/null +++ b/dma-Let-dma_buf_read-take-MemTxAttrs-argument.patch @@ -0,0 +1,218 @@ +From ccdbeeb4171a532acc75ee2b78253aa24b3faa73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 23:29:52 +0100 +Subject: [PATCH 13/25] dma: Let dma_buf_read() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_buf_read(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-13-philmd@redhat.com> +--- + hw/ide/ahci.c | 4 ++-- + hw/nvme/ctrl.c | 2 +- + hw/scsi/megasas.c | 24 ++++++++++++------------ + hw/scsi/scsi-bus.c | 2 +- + include/sysemu/dma.h | 2 +- + softmmu/dma-helpers.c | 5 ++--- + 6 files changed, 19 insertions(+), 20 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 8e27fb8b35..1e482738de 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -1386,7 +1386,7 @@ static void ahci_pio_transfer(const IDEDMA *dma) + if (is_write) { + dma_buf_write(s->data_ptr, size, &s->sg, attrs); + } else { +- dma_buf_read(s->data_ptr, size, &s->sg); ++ dma_buf_read(s->data_ptr, size, &s->sg, attrs); + } + } + +@@ -1481,7 +1481,7 @@ static int ahci_dma_rw_buf(const IDEDMA *dma, bool is_write) + } + + if (is_write) { +- dma_buf_read(p, l, &s->sg); ++ dma_buf_read(p, l, &s->sg, MEMTXATTRS_UNSPECIFIED); + } else { + dma_buf_write(p, l, &s->sg, MEMTXATTRS_UNSPECIFIED); + } +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index e1a531d5d6..462f79a1f6 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -1152,7 +1152,7 @@ static uint16_t nvme_tx(NvmeCtrl *n, NvmeSg *sg, uint8_t *ptr, uint32_t len, + if (dir == NVME_TX_DIRECTION_TO_DEVICE) { + residual = dma_buf_write(ptr, len, &sg->qsg, attrs); + } else { +- residual = dma_buf_read(ptr, len, &sg->qsg); ++ residual = dma_buf_read(ptr, len, &sg->qsg, attrs); + } + + if (unlikely(residual)) { +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 72376d92f6..f1c4d5782b 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -847,7 +847,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) + MFI_INFO_PDMIX_SATA | + MFI_INFO_PDMIX_LD); + +- cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -877,7 +877,7 @@ static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd) + info.disable_preboot_cli = 1; + info.cluster_disable = 1; + +- cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -898,7 +898,7 @@ static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd) + info.expose_all_drives = 1; + } + +- cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -909,7 +909,7 @@ static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd) + + fw_time = cpu_to_le64(megasas_fw_time()); + +- cmd->iov_size -= dma_buf_read(&fw_time, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&fw_time, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -936,7 +936,7 @@ static int megasas_event_info(MegasasState *s, MegasasCmd *cmd) + info.shutdown_seq_num = cpu_to_le32(s->shutdown_event); + info.boot_seq_num = cpu_to_le32(s->boot_event); + +- cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -1005,7 +1005,7 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd) + info.size = cpu_to_le32(offset); + info.count = cpu_to_le32(num_pd_disks); + +- cmd->iov_size -= dma_buf_read(&info, offset, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, offset, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -1099,7 +1099,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, + info->connected_port_bitmap = 0x1; + info->device_speed = 1; + info->link_speed = 1; +- resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + g_free(cmd->iov_buf); + cmd->iov_size = dcmd_size - resid; + cmd->iov_buf = NULL; +@@ -1171,7 +1171,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) + info.ld_count = cpu_to_le32(num_ld_disks); + trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); + +- resid = dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + cmd->iov_size = dcmd_size - resid; + return MFI_STAT_OK; + } +@@ -1220,7 +1220,7 @@ static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) + info.size = dcmd_size; + trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); + +- resid = dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + cmd->iov_size = dcmd_size - resid; + return MFI_STAT_OK; + } +@@ -1270,7 +1270,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, + info->ld_config.span[0].num_blocks = info->size; + info->ld_config.span[0].array_ref = cpu_to_le16(sdev_id); + +- resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg); ++ resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + g_free(cmd->iov_buf); + cmd->iov_size = dcmd_size - resid; + cmd->iov_buf = NULL; +@@ -1389,7 +1389,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) + ld_offset += sizeof(struct mfi_ld_config); + } + +- cmd->iov_size -= dma_buf_read(data, info->size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(data, info->size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +@@ -1419,7 +1419,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd) + info.ecc_bucket_leak_rate = cpu_to_le16(1440); + info.expose_encl_devices = 1; + +- cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg); ++ cmd->iov_size -= dma_buf_read(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + return MFI_STAT_OK; + } + +diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c +index 6fe30327b1..2b613ad2b3 100644 +--- a/hw/scsi/scsi-bus.c ++++ b/hw/scsi/scsi-bus.c +@@ -1428,7 +1428,7 @@ void scsi_req_data(SCSIRequest *req, int len) + + buf = scsi_req_get_buf(req); + if (req->cmd.mode == SCSI_XFER_FROM_DEV) { +- req->resid = dma_buf_read(buf, len, req->sg); ++ req->resid = dma_buf_read(buf, len, req->sg, MEMTXATTRS_UNSPECIFIED); + } else { + req->resid = dma_buf_write(buf, len, req->sg, MEMTXATTRS_UNSPECIFIED); + } +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index e3dd74a9c4..fd8f16003d 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -302,7 +302,7 @@ BlockAIOCB *dma_blk_read(BlockBackend *blk, + BlockAIOCB *dma_blk_write(BlockBackend *blk, + QEMUSGList *sg, uint64_t offset, uint32_t align, + BlockCompletionFunc *cb, void *opaque); +-uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg); ++uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs); + uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs); + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 2f1a241b81..a391773c29 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -316,10 +316,9 @@ static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + return resid; + } + +-uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg) ++uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE, +- MEMTXATTRS_UNSPECIFIED); ++ return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE, attrs); + } + + uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs) +-- +2.27.0 + diff --git a/dma-Let-dma_buf_rw-propagate-MemTxResult.patch b/dma-Let-dma_buf_rw-propagate-MemTxResult.patch new file mode 100644 index 0000000000000000000000000000000000000000..c35f6df059af7a67195e1222000377578bb664d3 --- /dev/null +++ b/dma-Let-dma_buf_rw-propagate-MemTxResult.patch @@ -0,0 +1,87 @@ +From 829b5bede922364061540abc51e80bb2e8b39085 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 23:38:52 +0100 +Subject: [PATCH 14/25] dma: Let dma_buf_rw() propagate MemTxResult +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dma_memory_rw() returns a MemTxResult type. Do not discard +it, return it to the caller. + +Since dma_buf_rw() was previously returning the QEMUSGList +size not consumed, add an extra argument where this size +can be stored. + +Update the 2 callers. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-14-philmd@redhat.com> +--- + softmmu/dma-helpers.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index a391773c29..b0be156479 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -294,12 +294,14 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, + } + + +-static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, +- DMADirection dir, MemTxAttrs attrs) ++static MemTxResult dma_buf_rw(void *buf, int32_t len, uint64_t *residp, ++ QEMUSGList *sg, DMADirection dir, ++ MemTxAttrs attrs) + { + uint8_t *ptr = buf; + uint64_t resid; + int sg_cur_index; ++ MemTxResult res = MEMTX_OK; + + resid = sg->size; + sg_cur_index = 0; +@@ -307,23 +309,34 @@ static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + while (len > 0) { + ScatterGatherEntry entry = sg->sg[sg_cur_index++]; + int32_t xfer = MIN(len, entry.len); +- dma_memory_rw(sg->as, entry.base, ptr, xfer, dir, attrs); ++ res |= dma_memory_rw(sg->as, entry.base, ptr, xfer, dir, attrs); + ptr += xfer; + len -= xfer; + resid -= xfer; + } + +- return resid; ++ if (residp) { ++ *residp = resid; ++ } ++ return res; + } + + uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE, attrs); ++ uint64_t resid; ++ ++ dma_buf_rw(ptr, len, &resid, sg, DMA_DIRECTION_FROM_DEVICE, attrs); ++ ++ return resid; + } + + uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE, attrs); ++ uint64_t resid; ++ ++ dma_buf_rw(ptr, len, &resid, sg, DMA_DIRECTION_TO_DEVICE, attrs); ++ ++ return resid; + } + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, +-- +2.27.0 + diff --git a/dma-Let-dma_buf_rw-take-MemTxAttrs-argument.patch b/dma-Let-dma_buf_rw-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef234b49e16a48a5c9b4a73a2b30c41cd1f2a660 --- /dev/null +++ b/dma-Let-dma_buf_rw-take-MemTxAttrs-argument.patch @@ -0,0 +1,62 @@ +From 1afc40c527dd25dd02d4b4d78530542d25d2d739 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 22:59:46 +0100 +Subject: [PATCH 11/25] dma: Let dma_buf_rw() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling dma_buf_rw(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the 2 callers. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-11-philmd@redhat.com> +--- + softmmu/dma-helpers.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 7f37548394..fa81d2b386 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -295,7 +295,7 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, + + + static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, +- DMADirection dir) ++ DMADirection dir, MemTxAttrs attrs) + { + uint8_t *ptr = buf; + uint64_t resid; +@@ -307,8 +307,7 @@ static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + while (len > 0) { + ScatterGatherEntry entry = sg->sg[sg_cur_index++]; + int32_t xfer = MIN(len, entry.len); +- dma_memory_rw(sg->as, entry.base, ptr, xfer, dir, +- MEMTXATTRS_UNSPECIFIED); ++ dma_memory_rw(sg->as, entry.base, ptr, xfer, dir, attrs); + ptr += xfer; + len -= xfer; + resid -= xfer; +@@ -319,12 +318,14 @@ static uint64_t dma_buf_rw(void *buf, int32_t len, QEMUSGList *sg, + + uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE); ++ return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_FROM_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + } + + uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE); ++ return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + } + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, +-- +2.27.0 + diff --git a/dma-Let-dma_buf_write-take-MemTxAttrs-argument.patch b/dma-Let-dma_buf_write-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..85f8f92a444a2d8d683e52f6a62a9bed607a7e38 --- /dev/null +++ b/dma-Let-dma_buf_write-take-MemTxAttrs-argument.patch @@ -0,0 +1,126 @@ +From f08ff9489ec9d42246b038d90df11457928d6886 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 23:02:21 +0100 +Subject: [PATCH 12/25] dma: Let dma_buf_write() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_buf_write(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-12-philmd@redhat.com> +--- + hw/ide/ahci.c | 6 ++++-- + hw/nvme/ctrl.c | 3 ++- + hw/scsi/megasas.c | 2 +- + hw/scsi/scsi-bus.c | 2 +- + include/sysemu/dma.h | 2 +- + softmmu/dma-helpers.c | 5 ++--- + 6 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 7580bd2a96..8e27fb8b35 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -1381,8 +1381,10 @@ static void ahci_pio_transfer(const IDEDMA *dma) + has_sglist ? "" : "o"); + + if (has_sglist && size) { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ + if (is_write) { +- dma_buf_write(s->data_ptr, size, &s->sg); ++ dma_buf_write(s->data_ptr, size, &s->sg, attrs); + } else { + dma_buf_read(s->data_ptr, size, &s->sg); + } +@@ -1481,7 +1483,7 @@ static int ahci_dma_rw_buf(const IDEDMA *dma, bool is_write) + if (is_write) { + dma_buf_read(p, l, &s->sg); + } else { +- dma_buf_write(p, l, &s->sg); ++ dma_buf_write(p, l, &s->sg, MEMTXATTRS_UNSPECIFIED); + } + + /* free sglist, update byte count */ +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 5f573c417b..e1a531d5d6 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -1146,10 +1146,11 @@ static uint16_t nvme_tx(NvmeCtrl *n, NvmeSg *sg, uint8_t *ptr, uint32_t len, + assert(sg->flags & NVME_SG_ALLOC); + + if (sg->flags & NVME_SG_DMA) { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + uint64_t residual; + + if (dir == NVME_TX_DIRECTION_TO_DEVICE) { +- residual = dma_buf_write(ptr, len, &sg->qsg); ++ residual = dma_buf_write(ptr, len, &sg->qsg, attrs); + } else { + residual = dma_buf_read(ptr, len, &sg->qsg); + } +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index fac46c54ab..72376d92f6 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -1464,7 +1464,7 @@ static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) + dcmd_size); + return MFI_STAT_INVALID_PARAMETER; + } +- dma_buf_write(&info, dcmd_size, &cmd->qsg); ++ dma_buf_write(&info, dcmd_size, &cmd->qsg, MEMTXATTRS_UNSPECIFIED); + trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); + return MFI_STAT_OK; + } +diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c +index 9d37f490ce..6fe30327b1 100644 +--- a/hw/scsi/scsi-bus.c ++++ b/hw/scsi/scsi-bus.c +@@ -1430,7 +1430,7 @@ void scsi_req_data(SCSIRequest *req, int len) + if (req->cmd.mode == SCSI_XFER_FROM_DEV) { + req->resid = dma_buf_read(buf, len, req->sg); + } else { +- req->resid = dma_buf_write(buf, len, req->sg); ++ req->resid = dma_buf_write(buf, len, req->sg, MEMTXATTRS_UNSPECIFIED); + } + scsi_req_continue(req); + } +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 0d5b836013..e3dd74a9c4 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -303,7 +303,7 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, + QEMUSGList *sg, uint64_t offset, uint32_t align, + BlockCompletionFunc *cb, void *opaque); + uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg); +-uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg); ++uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs); + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, + QEMUSGList *sg, enum BlockAcctType type); +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index fa81d2b386..2f1a241b81 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -322,10 +322,9 @@ uint64_t dma_buf_read(void *ptr, int32_t len, QEMUSGList *sg) + MEMTXATTRS_UNSPECIFIED); + } + +-uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg) ++uint64_t dma_buf_write(void *ptr, int32_t len, QEMUSGList *sg, MemTxAttrs attrs) + { +- return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE, +- MEMTXATTRS_UNSPECIFIED); ++ return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE, attrs); + } + + void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, +-- +2.27.0 + diff --git a/dma-Let-dma_memory_map-take-MemTxAttrs-argument.patch b/dma-Let-dma_memory_map-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..08dac5d1cbebc8d1040b7f65990ab133d1d6195b --- /dev/null +++ b/dma-Let-dma_memory_map-take-MemTxAttrs-argument.patch @@ -0,0 +1,223 @@ +From 61b0b2e243c382da97cc97c6a96ee8e14197fd33 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 11:00:47 +0200 +Subject: [PATCH 07/25] dma: Let dma_memory_map() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_memory_map(). + +Patch created mechanically using spatch with this script: + + @@ + expression E1, E2, E3, E4; + @@ + - dma_memory_map(E1, E2, E3, E4) + + dma_memory_map(E1, E2, E3, E4, MEMTXATTRS_UNSPECIFIED) + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-7-philmd@redhat.com> +--- + hw/display/virtio-gpu.c | 10 ++++++---- + hw/hyperv/vmbus.c | 8 +++++--- + hw/ide/ahci.c | 8 +++++--- + hw/usb/libhw.c | 3 ++- + hw/virtio/virtio.c | 6 ++++-- + include/hw/pci/pci.h | 3 ++- + include/sysemu/dma.h | 5 +++-- + softmmu/dma-helpers.c | 3 ++- + 8 files changed, 29 insertions(+), 17 deletions(-) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index d78b9700c7..c6dc818988 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -814,8 +814,9 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, + + do { + len = l; +- map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, +- a, &len, DMA_DIRECTION_TO_DEVICE); ++ map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, a, &len, ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + if (!map) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" + " element %d\n", __func__, e); +@@ -1252,8 +1253,9 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, + for (i = 0; i < res->iov_cnt; i++) { + hwaddr len = res->iov[i].iov_len; + res->iov[i].iov_base = +- dma_memory_map(VIRTIO_DEVICE(g)->dma_as, +- res->addrs[i], &len, DMA_DIRECTION_TO_DEVICE); ++ dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len, ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + + if (!res->iov[i].iov_base || len != res->iov[i].iov_len) { + /* Clean up the half-a-mapping we just created... */ +diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c +index dbce3b35fb..8aad29f1bb 100644 +--- a/hw/hyperv/vmbus.c ++++ b/hw/hyperv/vmbus.c +@@ -373,7 +373,8 @@ static ssize_t gpadl_iter_io(GpadlIter *iter, void *buf, uint32_t len) + + maddr = (iter->gpadl->gfns[idx] << TARGET_PAGE_BITS) | off_in_page; + +- iter->map = dma_memory_map(iter->as, maddr, &mlen, iter->dir); ++ iter->map = dma_memory_map(iter->as, maddr, &mlen, iter->dir, ++ MEMTXATTRS_UNSPECIFIED); + if (mlen != pgleft) { + dma_memory_unmap(iter->as, iter->map, mlen, iter->dir, 0); + iter->map = NULL; +@@ -490,7 +491,8 @@ int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, + goto err; + } + +- iov[ret_cnt].iov_base = dma_memory_map(sgl->as, a, &l, dir); ++ iov[ret_cnt].iov_base = dma_memory_map(sgl->as, a, &l, dir, ++ MEMTXATTRS_UNSPECIFIED); + if (!l) { + ret = -EFAULT; + goto err; +@@ -566,7 +568,7 @@ static vmbus_ring_buffer *ringbuf_map_hdr(VMBusRingBufCommon *ringbuf) + dma_addr_t mlen = sizeof(*rb); + + rb = dma_memory_map(ringbuf->as, ringbuf->rb_addr, &mlen, +- DMA_DIRECTION_FROM_DEVICE); ++ DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); + if (mlen != sizeof(*rb)) { + dma_memory_unmap(ringbuf->as, rb, mlen, + DMA_DIRECTION_FROM_DEVICE, 0); +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 256b58026a..7580bd2a96 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -249,7 +249,8 @@ static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr, + dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len); + } + +- *ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE); ++ *ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + if (len < wanted && *ptr) { + dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len); + *ptr = NULL; +@@ -939,7 +940,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, + + /* map PRDT */ + if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len, +- DMA_DIRECTION_TO_DEVICE))){ ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED))){ + trace_ahci_populate_sglist_no_map(ad->hba, ad->port_no); + return -1; + } +@@ -1301,7 +1303,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) + tbl_addr = le64_to_cpu(cmd->tbl_addr); + cmd_len = 0x80; + cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len, +- DMA_DIRECTION_TO_DEVICE); ++ DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); + if (!cmd_fis) { + trace_handle_cmd_badfis(s, port); + return -1; +diff --git a/hw/usb/libhw.c b/hw/usb/libhw.c +index 9c33a1640f..f350eae443 100644 +--- a/hw/usb/libhw.c ++++ b/hw/usb/libhw.c +@@ -36,7 +36,8 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl) + + while (len) { + dma_addr_t xlen = len; +- mem = dma_memory_map(sgl->as, base, &xlen, dir); ++ mem = dma_memory_map(sgl->as, base, &xlen, dir, ++ MEMTXATTRS_UNSPECIFIED); + if (!mem) { + goto err; + } +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 120672672e..f8ab48e6bd 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -1306,7 +1306,8 @@ static bool virtqueue_map_desc(VirtIODevice *vdev, unsigned int *p_num_sg, + iov[num_sg].iov_base = dma_memory_map(vdev->dma_as, pa, &len, + is_write ? + DMA_DIRECTION_FROM_DEVICE : +- DMA_DIRECTION_TO_DEVICE); ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + if (!iov[num_sg].iov_base) { + virtio_error(vdev, "virtio: bogus descriptor or out of resources"); + goto out; +@@ -1355,7 +1356,8 @@ static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg, + sg[i].iov_base = dma_memory_map(vdev->dma_as, + addr[i], &len, is_write ? + DMA_DIRECTION_FROM_DEVICE : +- DMA_DIRECTION_TO_DEVICE); ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + if (!sg[i].iov_base) { + error_report("virtio: error trying to map MMIO memory"); + exit(1); +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index c72d61bfd8..c3d5e06364 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -890,7 +890,8 @@ static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, + { + void *buf; + +- buf = dma_memory_map(pci_get_address_space(dev), addr, plen, dir); ++ buf = dma_memory_map(pci_get_address_space(dev), addr, plen, dir, ++ MEMTXATTRS_UNSPECIFIED); + return buf; + } + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 522682bf38..97ff6f29f8 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -202,16 +202,17 @@ MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr, + * @addr: address within that address space + * @len: pointer to length of buffer; updated on return + * @dir: indicates the transfer direction ++ * @attrs: memory attributes + */ + static inline void *dma_memory_map(AddressSpace *as, + dma_addr_t addr, dma_addr_t *len, +- DMADirection dir) ++ DMADirection dir, MemTxAttrs attrs) + { + hwaddr xlen = *len; + void *p; + + p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE, +- MEMTXATTRS_UNSPECIFIED); ++ attrs); + *len = xlen; + return p; + } +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 5bf76fff6b..3c06a2fedd 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -143,7 +143,8 @@ static void dma_blk_cb(void *opaque, int ret) + while (dbs->sg_cur_index < dbs->sg->nsg) { + cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte; + cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte; +- mem = dma_memory_map(dbs->sg->as, cur_addr, &cur_len, dbs->dir); ++ mem = dma_memory_map(dbs->sg->as, cur_addr, &cur_len, dbs->dir, ++ MEMTXATTRS_UNSPECIFIED); + /* + * Make reads deterministic in icount mode. Windows sometimes issues + * disk read requests with overlapping SGs. It leads +-- +2.27.0 + diff --git a/dma-Let-dma_memory_read-write-take-MemTxAttrs-argume.patch b/dma-Let-dma_memory_read-write-take-MemTxAttrs-argume.patch new file mode 100644 index 0000000000000000000000000000000000000000..c96bd6ca8fba12fadf5f8c56582204fb3aeaf836 --- /dev/null +++ b/dma-Let-dma_memory_read-write-take-MemTxAttrs-argume.patch @@ -0,0 +1,1450 @@ +From cb3acb1c694d7a6ce4424789f5e5a1b6becc551a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 10:08:29 +0200 +Subject: [PATCH 06/25] dma: Let dma_memory_read/write() take MemTxAttrs + argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_memory_read() or dma_memory_write(). + +Patch created mechanically using spatch with this script: + + @@ + expression E1, E2, E3, E4; + @@ + ( + - dma_memory_read(E1, E2, E3, E4) + + dma_memory_read(E1, E2, E3, E4, MEMTXATTRS_UNSPECIFIED) + | + - dma_memory_write(E1, E2, E3, E4) + + dma_memory_write(E1, E2, E3, E4, MEMTXATTRS_UNSPECIFIED) + ) + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-6-philmd@redhat.com> +--- + hw/arm/musicpal.c | 13 +++++++------ + hw/arm/smmu-common.c | 3 ++- + hw/arm/smmuv3.c | 14 +++++++++----- + hw/core/generic-loader.c | 3 ++- + hw/dma/pl330.c | 12 ++++++++---- + hw/dma/sparc32_dma.c | 16 ++++++++++------ + hw/dma/xlnx-zynq-devcfg.c | 6 ++++-- + hw/dma/xlnx_dpdma.c | 10 ++++++---- + hw/i386/amd_iommu.c | 16 +++++++++------- + hw/i386/intel_iommu.c | 28 +++++++++++++++++----------- + hw/ide/macio.c | 2 +- + hw/intc/xive.c | 7 ++++--- + hw/misc/bcm2835_property.c | 3 ++- + hw/misc/macio/mac_dbdma.c | 10 ++++++---- + hw/net/allwinner-sun8i-emac.c | 18 ++++++++++++------ + hw/net/ftgmac100.c | 25 ++++++++++++++++--------- + hw/net/imx_fec.c | 32 ++++++++++++++++++++------------ + hw/net/npcm7xx_emc.c | 20 ++++++++++++-------- + hw/nvram/fw_cfg.c | 9 ++++++--- + hw/pci-host/pnv_phb3.c | 5 +++-- + hw/pci-host/pnv_phb3_msi.c | 9 ++++++--- + hw/pci-host/pnv_phb4.c | 5 +++-- + hw/sd/allwinner-sdhost.c | 14 ++++++++------ + hw/sd/sdhci.c | 35 ++++++++++++++++++++++------------- + hw/usb/hcd-dwc2.c | 8 ++++---- + hw/usb/hcd-ehci.c | 6 ++++-- + hw/usb/hcd-ohci.c | 18 +++++++++++------- + hw/usb/hcd-xhci.c | 18 +++++++++++------- + include/hw/ppc/spapr_vio.h | 6 ++++-- + include/sysemu/dma.h | 20 ++++++++++++-------- + 30 files changed, 241 insertions(+), 150 deletions(-) + +diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c +index 2d612cc0c9..2680ec55b5 100644 +--- a/hw/arm/musicpal.c ++++ b/hw/arm/musicpal.c +@@ -185,13 +185,13 @@ static void eth_rx_desc_put(AddressSpace *dma_as, uint32_t addr, + cpu_to_le16s(&desc->buffer_size); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); +- dma_memory_write(dma_as, addr, desc, sizeof(*desc)); ++ dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); + } + + static void eth_rx_desc_get(AddressSpace *dma_as, uint32_t addr, + mv88w8618_rx_desc *desc) + { +- dma_memory_read(dma_as, addr, desc, sizeof(*desc)); ++ dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->bytes); + le16_to_cpus(&desc->buffer_size); +@@ -215,7 +215,7 @@ static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) + eth_rx_desc_get(&s->dma_as, desc_addr, &desc); + if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { + dma_memory_write(&s->dma_as, desc.buffer + s->vlan_header, +- buf, size); ++ buf, size, MEMTXATTRS_UNSPECIFIED); + desc.bytes = size + s->vlan_header; + desc.cmdstat &= ~MP_ETH_RX_OWN; + s->cur_rx[i] = desc.next; +@@ -241,13 +241,13 @@ static void eth_tx_desc_put(AddressSpace *dma_as, uint32_t addr, + cpu_to_le16s(&desc->bytes); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); +- dma_memory_write(dma_as, addr, desc, sizeof(*desc)); ++ dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); + } + + static void eth_tx_desc_get(AddressSpace *dma_as, uint32_t addr, + mv88w8618_tx_desc *desc) + { +- dma_memory_read(dma_as, addr, desc, sizeof(*desc)); ++ dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->res); + le16_to_cpus(&desc->bytes); +@@ -269,7 +269,8 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) + if (desc.cmdstat & MP_ETH_TX_OWN) { + len = desc.bytes; + if (len < 2048) { +- dma_memory_read(&s->dma_as, desc.buffer, buf, len); ++ dma_memory_read(&s->dma_as, desc.buffer, buf, len, ++ MEMTXATTRS_UNSPECIFIED); + qemu_send_packet(qemu_get_queue(s->nic), buf, len); + } + desc.cmdstat &= ~MP_ETH_TX_OWN; +diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c +index 2ec4222c93..f253a27e1a 100644 +--- a/hw/arm/smmu-common.c ++++ b/hw/arm/smmu-common.c +@@ -193,7 +193,8 @@ static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte, + dma_addr_t addr = baseaddr + index * sizeof(*pte); + + /* TODO: guarantee 64-bit single-copy atomicity */ +- ret = dma_memory_read(&address_space_memory, addr, pte, sizeof(*pte)); ++ ret = dma_memory_read(&address_space_memory, addr, pte, sizeof(*pte), ++ MEMTXATTRS_UNSPECIFIED); + + if (ret != MEMTX_OK) { + info->type = SMMU_PTW_ERR_WALK_EABT; +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 291e3a12e8..2bd9f22055 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -106,7 +106,8 @@ static inline MemTxResult queue_read(SMMUQueue *q, void *data) + { + dma_addr_t addr = Q_CONS_ENTRY(q); + +- return dma_memory_read(&address_space_memory, addr, data, q->entry_size); ++ return dma_memory_read(&address_space_memory, addr, data, q->entry_size, ++ MEMTXATTRS_UNSPECIFIED); + } + + static MemTxResult queue_write(SMMUQueue *q, void *data) +@@ -114,7 +115,8 @@ static MemTxResult queue_write(SMMUQueue *q, void *data) + dma_addr_t addr = Q_PROD_ENTRY(q); + MemTxResult ret; + +- ret = dma_memory_write(&address_space_memory, addr, data, q->entry_size); ++ ret = dma_memory_write(&address_space_memory, addr, data, q->entry_size, ++ MEMTXATTRS_UNSPECIFIED); + if (ret != MEMTX_OK) { + return ret; + } +@@ -289,7 +291,8 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf, + + trace_smmuv3_get_ste(addr); + /* TODO: guarantee 64-bit single-copy atomicity */ +- ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf)); ++ ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf), ++ MEMTXATTRS_UNSPECIFIED); + if (ret != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot fetch pte at address=0x%"PRIx64"\n", addr); +@@ -310,7 +313,8 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid, + + trace_smmuv3_get_cd(addr); + /* TODO: guarantee 64-bit single-copy atomicity */ +- ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf)); ++ ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf), ++ MEMTXATTRS_UNSPECIFIED); + if (ret != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot fetch pte at address=0x%"PRIx64"\n", addr); +@@ -416,7 +420,7 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, + l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std)); + /* TODO: guarantee 64-bit single-copy atomicity */ + ret = dma_memory_read(&address_space_memory, l1ptr, &l1std, +- sizeof(l1std)); ++ sizeof(l1std), MEMTXATTRS_UNSPECIFIED); + if (ret != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Could not read L1PTR at 0X%"PRIx64"\n", l1ptr); +diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c +index d14f932eea..9a24ffb880 100644 +--- a/hw/core/generic-loader.c ++++ b/hw/core/generic-loader.c +@@ -57,7 +57,8 @@ static void generic_loader_reset(void *opaque) + + if (s->data_len) { + assert(s->data_len < sizeof(s->data)); +- dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len); ++ dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len, ++ MEMTXATTRS_UNSPECIFIED); + } + } + +diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c +index 0cb46191c1..31ce01b7c5 100644 +--- a/hw/dma/pl330.c ++++ b/hw/dma/pl330.c +@@ -1111,7 +1111,8 @@ static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch) + uint8_t opcode; + int i; + +- dma_memory_read(ch->parent->mem_as, ch->pc, &opcode, 1); ++ dma_memory_read(ch->parent->mem_as, ch->pc, &opcode, 1, ++ MEMTXATTRS_UNSPECIFIED); + for (i = 0; insn_desc[i].size; i++) { + if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) { + return &insn_desc[i]; +@@ -1125,7 +1126,8 @@ static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn) + uint8_t buf[PL330_INSN_MAXSIZE]; + + assert(insn->size <= PL330_INSN_MAXSIZE); +- dma_memory_read(ch->parent->mem_as, ch->pc, buf, insn->size); ++ dma_memory_read(ch->parent->mem_as, ch->pc, buf, insn->size, ++ MEMTXATTRS_UNSPECIFIED); + insn->exec(ch, buf[0], &buf[1], insn->size - 1); + } + +@@ -1189,7 +1191,8 @@ static int pl330_exec_cycle(PL330Chan *channel) + if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) { + int len = q->len - (q->addr & (q->len - 1)); + +- dma_memory_read(s->mem_as, q->addr, buf, len); ++ dma_memory_read(s->mem_as, q->addr, buf, len, ++ MEMTXATTRS_UNSPECIFIED); + trace_pl330_exec_cycle(q->addr, len); + if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) { + pl330_hexdump(buf, len); +@@ -1220,7 +1223,8 @@ static int pl330_exec_cycle(PL330Chan *channel) + fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag); + } + if (fifo_res == PL330_FIFO_OK || q->z) { +- dma_memory_write(s->mem_as, q->addr, buf, len); ++ dma_memory_write(s->mem_as, q->addr, buf, len, ++ MEMTXATTRS_UNSPECIFIED); + trace_pl330_exec_cycle(q->addr, len); + if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) { + pl330_hexdump(buf, len); +diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c +index 03bc500878..0ef13c5e9a 100644 +--- a/hw/dma/sparc32_dma.c ++++ b/hw/dma/sparc32_dma.c +@@ -81,11 +81,11 @@ void ledma_memory_read(void *opaque, hwaddr addr, + addr |= s->dmaregs[3]; + trace_ledma_memory_read(addr, len); + if (do_bswap) { +- dma_memory_read(&is->iommu_as, addr, buf, len); ++ dma_memory_read(&is->iommu_as, addr, buf, len, MEMTXATTRS_UNSPECIFIED); + } else { + addr &= ~1; + len &= ~1; +- dma_memory_read(&is->iommu_as, addr, buf, len); ++ dma_memory_read(&is->iommu_as, addr, buf, len, MEMTXATTRS_UNSPECIFIED); + for(i = 0; i < len; i += 2) { + bswap16s((uint16_t *)(buf + i)); + } +@@ -103,7 +103,8 @@ void ledma_memory_write(void *opaque, hwaddr addr, + addr |= s->dmaregs[3]; + trace_ledma_memory_write(addr, len); + if (do_bswap) { +- dma_memory_write(&is->iommu_as, addr, buf, len); ++ dma_memory_write(&is->iommu_as, addr, buf, len, ++ MEMTXATTRS_UNSPECIFIED); + } else { + addr &= ~1; + len &= ~1; +@@ -114,7 +115,8 @@ void ledma_memory_write(void *opaque, hwaddr addr, + for(i = 0; i < l; i += 2) { + tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i)); + } +- dma_memory_write(&is->iommu_as, addr, tmp_buf, l); ++ dma_memory_write(&is->iommu_as, addr, tmp_buf, l, ++ MEMTXATTRS_UNSPECIFIED); + len -= l; + buf += l; + addr += l; +@@ -148,7 +150,8 @@ void espdma_memory_read(void *opaque, uint8_t *buf, int len) + IOMMUState *is = (IOMMUState *)s->iommu; + + trace_espdma_memory_read(s->dmaregs[1], len); +- dma_memory_read(&is->iommu_as, s->dmaregs[1], buf, len); ++ dma_memory_read(&is->iommu_as, s->dmaregs[1], buf, len, ++ MEMTXATTRS_UNSPECIFIED); + s->dmaregs[1] += len; + } + +@@ -158,7 +161,8 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len) + IOMMUState *is = (IOMMUState *)s->iommu; + + trace_espdma_memory_write(s->dmaregs[1], len); +- dma_memory_write(&is->iommu_as, s->dmaregs[1], buf, len); ++ dma_memory_write(&is->iommu_as, s->dmaregs[1], buf, len, ++ MEMTXATTRS_UNSPECIFIED); + s->dmaregs[1] += len; + } + +diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c +index e33112b6f0..f5ad1a0d22 100644 +--- a/hw/dma/xlnx-zynq-devcfg.c ++++ b/hw/dma/xlnx-zynq-devcfg.c +@@ -161,12 +161,14 @@ static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s) + btt = MIN(btt, dmah->dest_len); + } + DB_PRINT("reading %x bytes from %x\n", btt, dmah->src_addr); +- dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt); ++ dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt, ++ MEMTXATTRS_UNSPECIFIED); + dmah->src_len -= btt; + dmah->src_addr += btt; + if (loopback && (dmah->src_len || dmah->dest_len)) { + DB_PRINT("writing %x bytes from %x\n", btt, dmah->dest_addr); +- dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt); ++ dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt, ++ MEMTXATTRS_UNSPECIFIED); + dmah->dest_len -= btt; + dmah->dest_addr += btt; + } +diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c +index 967548abd3..2d7eae72cd 100644 +--- a/hw/dma/xlnx_dpdma.c ++++ b/hw/dma/xlnx_dpdma.c +@@ -652,7 +652,7 @@ size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel, + } + + if (dma_memory_read(&address_space_memory, desc_addr, &desc, +- sizeof(DPDMADescriptor))) { ++ sizeof(DPDMADescriptor), MEMTXATTRS_UNSPECIFIED)) { + s->registers[DPDMA_EISR] |= ((1 << 1) << channel); + xlnx_dpdma_update_irq(s); + s->operation_finished[channel] = true; +@@ -708,7 +708,8 @@ size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel, + if (dma_memory_read(&address_space_memory, + source_addr[0], + &s->data[channel][ptr], +- line_size)) { ++ line_size, ++ MEMTXATTRS_UNSPECIFIED)) { + s->registers[DPDMA_ISR] |= ((1 << 12) << channel); + xlnx_dpdma_update_irq(s); + DPRINTF("Can't get data.\n"); +@@ -736,7 +737,8 @@ size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel, + if (dma_memory_read(&address_space_memory, + source_addr[frag], + &(s->data[channel][ptr]), +- fragment_len)) { ++ fragment_len, ++ MEMTXATTRS_UNSPECIFIED)) { + s->registers[DPDMA_ISR] |= ((1 << 12) << channel); + xlnx_dpdma_update_irq(s); + DPRINTF("Can't get data.\n"); +@@ -754,7 +756,7 @@ size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel, + DPRINTF("update the descriptor with the done flag set.\n"); + xlnx_dpdma_desc_set_done(&desc); + dma_memory_write(&address_space_memory, desc_addr, &desc, +- sizeof(DPDMADescriptor)); ++ sizeof(DPDMADescriptor), MEMTXATTRS_UNSPECIFIED); + } + + if (xlnx_dpdma_desc_completion_interrupt(&desc)) { +diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c +index 91fe34ae58..4d13d8e697 100644 +--- a/hw/i386/amd_iommu.c ++++ b/hw/i386/amd_iommu.c +@@ -181,7 +181,7 @@ static void amdvi_log_event(AMDVIState *s, uint64_t *evt) + } + + if (dma_memory_write(&address_space_memory, s->evtlog + s->evtlog_tail, +- evt, AMDVI_EVENT_LEN)) { ++ evt, AMDVI_EVENT_LEN, MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_evntlog_fail(s->evtlog, s->evtlog_tail); + } + +@@ -376,7 +376,8 @@ static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd) + } + if (extract64(cmd[0], 0, 1)) { + if (dma_memory_write(&address_space_memory, addr, &data, +- AMDVI_COMPLETION_DATA_SIZE)) { ++ AMDVI_COMPLETION_DATA_SIZE, ++ MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_completion_wait_fail(addr); + } + } +@@ -502,7 +503,7 @@ static void amdvi_cmdbuf_exec(AMDVIState *s) + uint64_t cmd[2]; + + if (dma_memory_read(&address_space_memory, s->cmdbuf + s->cmdbuf_head, +- cmd, AMDVI_COMMAND_SIZE)) { ++ cmd, AMDVI_COMMAND_SIZE, MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_command_read_fail(s->cmdbuf, s->cmdbuf_head); + amdvi_log_command_error(s, s->cmdbuf + s->cmdbuf_head); + return; +@@ -836,7 +837,7 @@ static bool amdvi_get_dte(AMDVIState *s, int devid, uint64_t *entry) + uint32_t offset = devid * AMDVI_DEVTAB_ENTRY_SIZE; + + if (dma_memory_read(&address_space_memory, s->devtab + offset, entry, +- AMDVI_DEVTAB_ENTRY_SIZE)) { ++ AMDVI_DEVTAB_ENTRY_SIZE, MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_dte_get_fail(s->devtab, offset); + /* log error accessing dte */ + amdvi_log_devtab_error(s, devid, s->devtab + offset, 0); +@@ -881,7 +882,8 @@ static inline uint64_t amdvi_get_pte_entry(AMDVIState *s, uint64_t pte_addr, + { + uint64_t pte; + +- if (dma_memory_read(&address_space_memory, pte_addr, &pte, sizeof(pte))) { ++ if (dma_memory_read(&address_space_memory, pte_addr, ++ &pte, sizeof(pte), MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_get_pte_hwerror(pte_addr); + amdvi_log_pagetab_error(s, devid, pte_addr, 0); + pte = 0; +@@ -1048,7 +1050,7 @@ static int amdvi_get_irte(AMDVIState *s, MSIMessage *origin, uint64_t *dte, + trace_amdvi_ir_irte(irte_root, offset); + + if (dma_memory_read(&address_space_memory, irte_root + offset, +- irte, sizeof(*irte))) { ++ irte, sizeof(*irte), MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_ir_err("failed to get irte"); + return -AMDVI_IR_GET_IRTE; + } +@@ -1108,7 +1110,7 @@ static int amdvi_get_irte_ga(AMDVIState *s, MSIMessage *origin, uint64_t *dte, + trace_amdvi_ir_irte(irte_root, offset); + + if (dma_memory_read(&address_space_memory, irte_root + offset, +- irte, sizeof(*irte))) { ++ irte, sizeof(*irte), MEMTXATTRS_UNSPECIFIED)) { + trace_amdvi_ir_err("failed to get irte_ga"); + return -AMDVI_IR_GET_IRTE; + } +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index fae282ef5e..6501d93f7e 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -569,7 +569,8 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index, + dma_addr_t addr; + + addr = s->root + index * sizeof(*re); +- if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) { ++ if (dma_memory_read(&address_space_memory, addr, ++ re, sizeof(*re), MEMTXATTRS_UNSPECIFIED)) { + re->lo = 0; + return -VTD_FR_ROOT_TABLE_INV; + } +@@ -602,7 +603,8 @@ static int vtd_get_context_entry_from_root(IntelIOMMUState *s, + } + + addr = addr + index * ce_size; +- if (dma_memory_read(&address_space_memory, addr, ce, ce_size)) { ++ if (dma_memory_read(&address_space_memory, addr, ++ ce, ce_size, MEMTXATTRS_UNSPECIFIED)) { + return -VTD_FR_CONTEXT_TABLE_INV; + } + +@@ -639,8 +641,8 @@ static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index) + assert(index < VTD_SL_PT_ENTRY_NR); + + if (dma_memory_read(&address_space_memory, +- base_addr + index * sizeof(slpte), &slpte, +- sizeof(slpte))) { ++ base_addr + index * sizeof(slpte), ++ &slpte, sizeof(slpte), MEMTXATTRS_UNSPECIFIED)) { + slpte = (uint64_t)-1; + return slpte; + } +@@ -704,7 +706,8 @@ static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base, + index = VTD_PASID_DIR_INDEX(pasid); + entry_size = VTD_PASID_DIR_ENTRY_SIZE; + addr = pasid_dir_base + index * entry_size; +- if (dma_memory_read(&address_space_memory, addr, pdire, entry_size)) { ++ if (dma_memory_read(&address_space_memory, addr, ++ pdire, entry_size, MEMTXATTRS_UNSPECIFIED)) { + return -VTD_FR_PASID_TABLE_INV; + } + +@@ -728,7 +731,8 @@ static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s, + index = VTD_PASID_TABLE_INDEX(pasid); + entry_size = VTD_PASID_ENTRY_SIZE; + addr = addr + index * entry_size; +- if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) { ++ if (dma_memory_read(&address_space_memory, addr, ++ pe, entry_size, MEMTXATTRS_UNSPECIFIED)) { + return -VTD_FR_PASID_TABLE_INV; + } + +@@ -2275,7 +2279,8 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s, + uint32_t dw = s->iq_dw ? 32 : 16; + dma_addr_t addr = base_addr + offset * dw; + +- if (dma_memory_read(&address_space_memory, addr, inv_desc, dw)) { ++ if (dma_memory_read(&address_space_memory, addr, ++ inv_desc, dw, MEMTXATTRS_UNSPECIFIED)) { + error_report_once("Read INV DESC failed."); + return false; + } +@@ -2308,8 +2313,9 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) + dma_addr_t status_addr = inv_desc->hi; + trace_vtd_inv_desc_wait_sw(status_addr, status_data); + status_data = cpu_to_le32(status_data); +- if (dma_memory_write(&address_space_memory, status_addr, &status_data, +- sizeof(status_data))) { ++ if (dma_memory_write(&address_space_memory, status_addr, ++ &status_data, sizeof(status_data), ++ MEMTXATTRS_UNSPECIFIED)) { + trace_vtd_inv_desc_wait_write_fail(inv_desc->hi, inv_desc->lo); + return false; + } +@@ -3120,8 +3126,8 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + } + + addr = iommu->intr_root + index * sizeof(*entry); +- if (dma_memory_read(&address_space_memory, addr, entry, +- sizeof(*entry))) { ++ if (dma_memory_read(&address_space_memory, addr, ++ entry, sizeof(*entry), MEMTXATTRS_UNSPECIFIED)) { + error_report_once("%s: read failed: ind=0x%x addr=0x%" PRIx64, + __func__, index, addr); + return -VTD_FR_IR_ROOT_INVAL; +diff --git a/hw/ide/macio.c b/hw/ide/macio.c +index b03d401ceb..f08318cf97 100644 +--- a/hw/ide/macio.c ++++ b/hw/ide/macio.c +@@ -97,7 +97,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) + /* Non-block ATAPI transfer - just copy to RAM */ + s->io_buffer_size = MIN(s->io_buffer_size, io->len); + dma_memory_write(&address_space_memory, io->addr, s->io_buffer, +- s->io_buffer_size); ++ s->io_buffer_size, MEMTXATTRS_UNSPECIFIED); + io->len = 0; + ide_atapi_cmd_ok(s); + m->dma_active = false; +diff --git a/hw/intc/xive.c b/hw/intc/xive.c +index 190194d27f..f15f98588a 100644 +--- a/hw/intc/xive.c ++++ b/hw/intc/xive.c +@@ -1246,8 +1246,8 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon) + uint64_t qaddr = qaddr_base + (qindex << 2); + uint32_t qdata = -1; + +- if (dma_memory_read(&address_space_memory, qaddr, &qdata, +- sizeof(qdata))) { ++ if (dma_memory_read(&address_space_memory, qaddr, ++ &qdata, sizeof(qdata), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to read EQ @0x%" + HWADDR_PRIx "\n", qaddr); + return; +@@ -1311,7 +1311,8 @@ static void xive_end_enqueue(XiveEND *end, uint32_t data) + uint32_t qdata = cpu_to_be32((qgen << 31) | (data & 0x7fffffff)); + uint32_t qentries = 1 << (qsize + 10); + +- if (dma_memory_write(&address_space_memory, qaddr, &qdata, sizeof(qdata))) { ++ if (dma_memory_write(&address_space_memory, qaddr, ++ &qdata, sizeof(qdata), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to write END data @0x%" + HWADDR_PRIx "\n", qaddr); + return; +diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c +index 73941bdae9..76ea511d53 100644 +--- a/hw/misc/bcm2835_property.c ++++ b/hw/misc/bcm2835_property.c +@@ -69,7 +69,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) + break; + case 0x00010003: /* Get board MAC address */ + resplen = sizeof(s->macaddr.a); +- dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen); ++ dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen, ++ MEMTXATTRS_UNSPECIFIED); + break; + case 0x00010004: /* Get board serial */ + qemu_log_mask(LOG_UNIMP, +diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c +index e220f1a927..efcc02609f 100644 +--- a/hw/misc/macio/mac_dbdma.c ++++ b/hw/misc/macio/mac_dbdma.c +@@ -94,7 +94,7 @@ static void dbdma_cmdptr_load(DBDMA_channel *ch) + DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n", + ch->regs[DBDMA_CMDPTR_LO]); + dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], +- &ch->current, sizeof(dbdma_cmd)); ++ &ch->current, sizeof(dbdma_cmd), MEMTXATTRS_UNSPECIFIED); + } + + static void dbdma_cmdptr_save(DBDMA_channel *ch) +@@ -104,7 +104,7 @@ static void dbdma_cmdptr_save(DBDMA_channel *ch) + le16_to_cpu(ch->current.xfer_status), + le16_to_cpu(ch->current.res_count)); + dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], +- &ch->current, sizeof(dbdma_cmd)); ++ &ch->current, sizeof(dbdma_cmd), MEMTXATTRS_UNSPECIFIED); + } + + static void kill_channel(DBDMA_channel *ch) +@@ -371,7 +371,8 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr, + return; + } + +- dma_memory_read(&address_space_memory, addr, ¤t->cmd_dep, len); ++ dma_memory_read(&address_space_memory, addr, ¤t->cmd_dep, len, ++ MEMTXATTRS_UNSPECIFIED); + + if (conditional_wait(ch)) + goto wait; +@@ -403,7 +404,8 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr, + return; + } + +- dma_memory_write(&address_space_memory, addr, ¤t->cmd_dep, len); ++ dma_memory_write(&address_space_memory, addr, ¤t->cmd_dep, len, ++ MEMTXATTRS_UNSPECIFIED); + + if (conditional_wait(ch)) + goto wait; +diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c +index ff611f18fb..ecc0245fe8 100644 +--- a/hw/net/allwinner-sun8i-emac.c ++++ b/hw/net/allwinner-sun8i-emac.c +@@ -350,7 +350,8 @@ static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s, + FrameDescriptor *desc, + uint32_t phys_addr) + { +- dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc)); ++ dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc), ++ MEMTXATTRS_UNSPECIFIED); + } + + static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s, +@@ -402,7 +403,8 @@ static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s, + FrameDescriptor *desc, + uint32_t phys_addr) + { +- dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc)); ++ dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc), ++ MEMTXATTRS_UNSPECIFIED); + } + + static bool allwinner_sun8i_emac_can_receive(NetClientState *nc) +@@ -460,7 +462,8 @@ static ssize_t allwinner_sun8i_emac_receive(NetClientState *nc, + << RX_DESC_STATUS_FRM_LEN_SHIFT; + } + +- dma_memory_write(&s->dma_as, desc.addr, buf, desc_bytes); ++ dma_memory_write(&s->dma_as, desc.addr, buf, desc_bytes, ++ MEMTXATTRS_UNSPECIFIED); + allwinner_sun8i_emac_flush_desc(s, &desc, s->rx_desc_curr); + trace_allwinner_sun8i_emac_receive(s->rx_desc_curr, desc.addr, + desc_bytes); +@@ -512,7 +515,8 @@ static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s) + desc.status |= TX_DESC_STATUS_LENGTH_ERR; + break; + } +- dma_memory_read(&s->dma_as, desc.addr, packet_buf + packet_bytes, bytes); ++ dma_memory_read(&s->dma_as, desc.addr, packet_buf + packet_bytes, ++ bytes, MEMTXATTRS_UNSPECIFIED); + packet_bytes += bytes; + desc.status &= ~DESC_STATUS_CTL; + allwinner_sun8i_emac_flush_desc(s, &desc, s->tx_desc_curr); +@@ -634,7 +638,8 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, + break; + case REG_TX_CUR_BUF: /* Transmit Current Buffer */ + if (s->tx_desc_curr != 0) { +- dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc)); ++ dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc), ++ MEMTXATTRS_UNSPECIFIED); + value = desc.addr; + } else { + value = 0; +@@ -647,7 +652,8 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, + break; + case REG_RX_CUR_BUF: /* Receive Current Buffer */ + if (s->rx_desc_curr != 0) { +- dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc)); ++ dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc), ++ MEMTXATTRS_UNSPECIFIED); + value = desc.addr; + } else { + value = 0; +diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c +index 25685ba3a9..83ef0a783e 100644 +--- a/hw/net/ftgmac100.c ++++ b/hw/net/ftgmac100.c +@@ -453,7 +453,8 @@ static void do_phy_ctl(FTGMAC100State *s) + + static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr) + { +- if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) { ++ if (dma_memory_read(&address_space_memory, addr, ++ bd, sizeof(*bd), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -473,7 +474,8 @@ static int ftgmac100_write_bd(FTGMAC100Desc *bd, dma_addr_t addr) + lebd.des1 = cpu_to_le32(bd->des1); + lebd.des2 = cpu_to_le32(bd->des2); + lebd.des3 = cpu_to_le32(bd->des3); +- if (dma_memory_write(&address_space_memory, addr, &lebd, sizeof(lebd))) { ++ if (dma_memory_write(&address_space_memory, addr, ++ &lebd, sizeof(lebd), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to write descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -554,7 +556,8 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, + len = sizeof(s->frame) - frame_size; + } + +- if (dma_memory_read(&address_space_memory, bd.des3, ptr, len)) { ++ if (dma_memory_read(&address_space_memory, bd.des3, ++ ptr, len, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read packet @ 0x%x\n", + __func__, bd.des3); + s->isr |= FTGMAC100_INT_AHB_ERR; +@@ -1030,20 +1033,24 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, + bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL; + + if (s->maccr & FTGMAC100_MACCR_RM_VLAN) { +- dma_memory_write(&address_space_memory, buf_addr, buf, 12); +- dma_memory_write(&address_space_memory, buf_addr + 12, buf + 16, +- buf_len - 16); ++ dma_memory_write(&address_space_memory, buf_addr, buf, 12, ++ MEMTXATTRS_UNSPECIFIED); ++ dma_memory_write(&address_space_memory, buf_addr + 12, ++ buf + 16, buf_len - 16, ++ MEMTXATTRS_UNSPECIFIED); + } else { +- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); ++ dma_memory_write(&address_space_memory, buf_addr, buf, ++ buf_len, MEMTXATTRS_UNSPECIFIED); + } + } else { + bd.des1 = 0; +- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); ++ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len, ++ MEMTXATTRS_UNSPECIFIED); + } + buf += buf_len; + if (size < 4) { + dma_memory_write(&address_space_memory, buf_addr + buf_len, +- crc_ptr, 4 - size); ++ crc_ptr, 4 - size, MEMTXATTRS_UNSPECIFIED); + crc_ptr += 4 - size; + } + +diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c +index 9c7035bc94..0db9aaf76a 100644 +--- a/hw/net/imx_fec.c ++++ b/hw/net/imx_fec.c +@@ -387,19 +387,22 @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) + + static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) + { +- dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); ++ dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd), ++ MEMTXATTRS_UNSPECIFIED); + + trace_imx_fec_read_bd(addr, bd->flags, bd->length, bd->data); + } + + static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) + { +- dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); ++ dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd), ++ MEMTXATTRS_UNSPECIFIED); + } + + static void imx_enet_read_bd(IMXENETBufDesc *bd, dma_addr_t addr) + { +- dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); ++ dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd), ++ MEMTXATTRS_UNSPECIFIED); + + trace_imx_enet_read_bd(addr, bd->flags, bd->length, bd->data, + bd->option, bd->status); +@@ -407,7 +410,8 @@ static void imx_enet_read_bd(IMXENETBufDesc *bd, dma_addr_t addr) + + static void imx_enet_write_bd(IMXENETBufDesc *bd, dma_addr_t addr) + { +- dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); ++ dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd), ++ MEMTXATTRS_UNSPECIFIED); + } + + static void imx_eth_update(IMXFECState *s) +@@ -474,7 +478,8 @@ static void imx_fec_do_tx(IMXFECState *s) + len = ENET_MAX_FRAME_SIZE - frame_size; + s->regs[ENET_EIR] |= ENET_INT_BABT; + } +- dma_memory_read(&address_space_memory, bd.data, ptr, len); ++ dma_memory_read(&address_space_memory, bd.data, ptr, len, ++ MEMTXATTRS_UNSPECIFIED); + ptr += len; + frame_size += len; + if (bd.flags & ENET_BD_L) { +@@ -555,7 +560,8 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) + len = ENET_MAX_FRAME_SIZE - frame_size; + s->regs[ENET_EIR] |= ENET_INT_BABT; + } +- dma_memory_read(&address_space_memory, bd.data, ptr, len); ++ dma_memory_read(&address_space_memory, bd.data, ptr, len, ++ MEMTXATTRS_UNSPECIFIED); + ptr += len; + frame_size += len; + if (bd.flags & ENET_BD_L) { +@@ -1103,11 +1109,12 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, + buf_len += size - 4; + } + buf_addr = bd.data; +- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); ++ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len, ++ MEMTXATTRS_UNSPECIFIED); + buf += buf_len; + if (size < 4) { + dma_memory_write(&address_space_memory, buf_addr + buf_len, +- crc_ptr, 4 - size); ++ crc_ptr, 4 - size, MEMTXATTRS_UNSPECIFIED); + crc_ptr += 4 - size; + } + bd.flags &= ~ENET_BD_E; +@@ -1210,8 +1217,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, + */ + const uint8_t zeros[2] = { 0 }; + +- dma_memory_write(&address_space_memory, buf_addr, +- zeros, sizeof(zeros)); ++ dma_memory_write(&address_space_memory, buf_addr, zeros, ++ sizeof(zeros), MEMTXATTRS_UNSPECIFIED); + + buf_addr += sizeof(zeros); + buf_len -= sizeof(zeros); +@@ -1220,11 +1227,12 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, + shift16 = false; + } + +- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); ++ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len, ++ MEMTXATTRS_UNSPECIFIED); + buf += buf_len; + if (size < 4) { + dma_memory_write(&address_space_memory, buf_addr + buf_len, +- crc_ptr, 4 - size); ++ crc_ptr, 4 - size, MEMTXATTRS_UNSPECIFIED); + crc_ptr += 4 - size; + } + bd.flags &= ~ENET_BD_E; +diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c +index 7c892f820f..df2efe1bf8 100644 +--- a/hw/net/npcm7xx_emc.c ++++ b/hw/net/npcm7xx_emc.c +@@ -200,7 +200,8 @@ static void emc_update_irq_from_reg_change(NPCM7xxEMCState *emc) + + static int emc_read_tx_desc(dma_addr_t addr, NPCM7xxEMCTxDesc *desc) + { +- if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) { ++ if (dma_memory_read(&address_space_memory, addr, desc, ++ sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -221,7 +222,7 @@ static int emc_write_tx_desc(const NPCM7xxEMCTxDesc *desc, dma_addr_t addr) + le_desc.status_and_length = cpu_to_le32(desc->status_and_length); + le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa); + if (dma_memory_write(&address_space_memory, addr, &le_desc, +- sizeof(le_desc))) { ++ sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -231,7 +232,8 @@ static int emc_write_tx_desc(const NPCM7xxEMCTxDesc *desc, dma_addr_t addr) + + static int emc_read_rx_desc(dma_addr_t addr, NPCM7xxEMCRxDesc *desc) + { +- if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) { ++ if (dma_memory_read(&address_space_memory, addr, desc, ++ sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -252,7 +254,7 @@ static int emc_write_rx_desc(const NPCM7xxEMCRxDesc *desc, dma_addr_t addr) + le_desc.reserved = cpu_to_le32(desc->reserved); + le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa); + if (dma_memory_write(&address_space_memory, addr, &le_desc, +- sizeof(le_desc))) { ++ sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; +@@ -360,7 +362,8 @@ static void emc_try_send_next_packet(NPCM7xxEMCState *emc) + buf = malloced_buf; + } + +- if (dma_memory_read(&address_space_memory, next_buf_addr, buf, length)) { ++ if (dma_memory_read(&address_space_memory, next_buf_addr, buf, ++ length, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n", + __func__, next_buf_addr); + emc_set_mista(emc, REG_MISTA_TXBERR); +@@ -545,10 +548,11 @@ static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1) + + buf_addr = rx_desc.rxbsa; + emc->regs[REG_CRXBSA] = buf_addr; +- if (dma_memory_write(&address_space_memory, buf_addr, buf, len) || ++ if (dma_memory_write(&address_space_memory, buf_addr, buf, ++ len, MEMTXATTRS_UNSPECIFIED) || + (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC) && +- dma_memory_write(&address_space_memory, buf_addr + len, crc_ptr, +- 4))) { ++ dma_memory_write(&address_space_memory, buf_addr + len, ++ crc_ptr, 4, MEMTXATTRS_UNSPECIFIED))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bus error writing packet\n", + __func__); + emc_set_mista(emc, REG_MISTA_RXBERR); +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index f7803fe3c3..9b91b15cb0 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -357,7 +357,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + dma_addr = s->dma_addr; + s->dma_addr = 0; + +- if (dma_memory_read(s->dma_as, dma_addr, &dma, sizeof(dma))) { ++ if (dma_memory_read(s->dma_as, dma_addr, ++ &dma, sizeof(dma), MEMTXATTRS_UNSPECIFIED)) { + stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control), + FW_CFG_DMA_CTL_ERROR); + return; +@@ -419,7 +420,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + */ + if (read) { + if (dma_memory_write(s->dma_as, dma.address, +- &e->data[s->cur_offset], len)) { ++ &e->data[s->cur_offset], len, ++ MEMTXATTRS_UNSPECIFIED)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; + } + } +@@ -427,7 +429,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + if (!e->allow_write || + len != dma.length || + dma_memory_read(s->dma_as, dma.address, +- &e->data[s->cur_offset], len)) { ++ &e->data[s->cur_offset], len, ++ MEMTXATTRS_UNSPECIFIED)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; + } else if (e->write_cb) { + e->write_cb(e->callback_opaque, s->cur_offset, len); +diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c +index a7f9685005..947efa77dc 100644 +--- a/hw/pci-host/pnv_phb3.c ++++ b/hw/pci-host/pnv_phb3.c +@@ -715,7 +715,8 @@ static bool pnv_phb3_resolve_pe(PnvPhb3DMASpace *ds) + bus_num = pci_bus_num(ds->bus); + addr = rtt & PHB_RTT_BASE_ADDRESS_MASK; + addr += 2 * ((bus_num << 8) | ds->devfn); +- if (dma_memory_read(&address_space_memory, addr, &rte, sizeof(rte))) { ++ if (dma_memory_read(&address_space_memory, addr, &rte, ++ sizeof(rte), MEMTXATTRS_UNSPECIFIED)) { + phb3_error(ds->phb, "Failed to read RTT entry at 0x%"PRIx64, addr); + /* Set error bits ? fence ? ... */ + return false; +@@ -794,7 +795,7 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr, + /* Grab the TCE address */ + taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3); + if (dma_memory_read(&address_space_memory, taddr, &tce, +- sizeof(tce))) { ++ sizeof(tce), MEMTXATTRS_UNSPECIFIED)) { + phb3_error(phb, "Failed to read TCE at 0x%"PRIx64, taddr); + return; + } +diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c +index 099d2092a2..8bcbc2cc4f 100644 +--- a/hw/pci-host/pnv_phb3_msi.c ++++ b/hw/pci-host/pnv_phb3_msi.c +@@ -53,7 +53,8 @@ static bool phb3_msi_read_ive(PnvPHB3 *phb, int srcno, uint64_t *out_ive) + return false; + } + +- if (dma_memory_read(&address_space_memory, ive_addr, &ive, sizeof(ive))) { ++ if (dma_memory_read(&address_space_memory, ive_addr, ++ &ive, sizeof(ive), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "Failed to read IVE at 0x%" PRIx64, + ive_addr); + return false; +@@ -73,7 +74,8 @@ static void phb3_msi_set_p(Phb3MsiState *msi, int srcno, uint8_t gen) + return; + } + +- if (dma_memory_write(&address_space_memory, ive_addr + 4, &p, 1)) { ++ if (dma_memory_write(&address_space_memory, ive_addr + 4, ++ &p, 1, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Failed to write IVE (set P) at 0x%" PRIx64, ive_addr); + } +@@ -89,7 +91,8 @@ static void phb3_msi_set_q(Phb3MsiState *msi, int srcno) + return; + } + +- if (dma_memory_write(&address_space_memory, ive_addr + 5, &q, 1)) { ++ if (dma_memory_write(&address_space_memory, ive_addr + 5, ++ &q, 1, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Failed to write IVE (set Q) at 0x%" PRIx64, ive_addr); + } +diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c +index 5c375a9f28..4e17a48d35 100644 +--- a/hw/pci-host/pnv_phb4.c ++++ b/hw/pci-host/pnv_phb4.c +@@ -891,7 +891,8 @@ static bool pnv_phb4_resolve_pe(PnvPhb4DMASpace *ds) + bus_num = pci_bus_num(ds->bus); + addr = rtt & PHB_RTT_BASE_ADDRESS_MASK; + addr += 2 * PCI_BUILD_BDF(bus_num, ds->devfn); +- if (dma_memory_read(&address_space_memory, addr, &rte, sizeof(rte))) { ++ if (dma_memory_read(&address_space_memory, addr, &rte, ++ sizeof(rte), MEMTXATTRS_UNSPECIFIED)) { + phb_error(ds->phb, "Failed to read RTT entry at 0x%"PRIx64, addr); + /* Set error bits ? fence ? ... */ + return false; +@@ -961,7 +962,7 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr, + /* Grab the TCE address */ + taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3); + if (dma_memory_read(&address_space_memory, taddr, &tce, +- sizeof(tce))) { ++ sizeof(tce), MEMTXATTRS_UNSPECIFIED)) { + phb_error(ds->phb, "Failed to read TCE at 0x%"PRIx64, taddr); + return; + } +diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c +index 9166d6638d..de5bc49e68 100644 +--- a/hw/sd/allwinner-sdhost.c ++++ b/hw/sd/allwinner-sdhost.c +@@ -311,7 +311,8 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, + uint8_t buf[1024]; + + /* Read descriptor */ +- dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc)); ++ dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc), ++ MEMTXATTRS_UNSPECIFIED); + if (desc->size == 0) { + desc->size = klass->max_desc_size; + } else if (desc->size > klass->max_desc_size) { +@@ -337,23 +338,24 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, + /* Write to SD bus */ + if (is_write) { + dma_memory_read(&s->dma_as, +- (desc->addr & DESC_SIZE_MASK) + num_done, +- buf, buf_bytes); ++ (desc->addr & DESC_SIZE_MASK) + num_done, buf, ++ buf_bytes, MEMTXATTRS_UNSPECIFIED); + sdbus_write_data(&s->sdbus, buf, buf_bytes); + + /* Read from SD bus */ + } else { + sdbus_read_data(&s->sdbus, buf, buf_bytes); + dma_memory_write(&s->dma_as, +- (desc->addr & DESC_SIZE_MASK) + num_done, +- buf, buf_bytes); ++ (desc->addr & DESC_SIZE_MASK) + num_done, buf, ++ buf_bytes, MEMTXATTRS_UNSPECIFIED); + } + num_done += buf_bytes; + } + + /* Clear hold flag and flush descriptor */ + desc->status &= ~DESC_STATUS_HOLD; +- dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc)); ++ dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc), ++ MEMTXATTRS_UNSPECIFIED); + + return num_done; + } +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index c9dc065cc5..e0bbc90344 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -616,8 +616,8 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) + s->blkcnt--; + } + } +- dma_memory_write(s->dma_as, s->sdmasysad, +- &s->fifo_buffer[begin], s->data_count - begin); ++ dma_memory_write(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], ++ s->data_count - begin, MEMTXATTRS_UNSPECIFIED); + s->sdmasysad += s->data_count - begin; + if (s->data_count == block_size) { + s->data_count = 0; +@@ -637,8 +637,8 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) + s->data_count = block_size; + boundary_count -= block_size - begin; + } +- dma_memory_read(s->dma_as, s->sdmasysad, +- &s->fifo_buffer[begin], s->data_count - begin); ++ dma_memory_read(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], ++ s->data_count - begin, MEMTXATTRS_UNSPECIFIED); + s->sdmasysad += s->data_count - begin; + if (s->data_count == block_size) { + sdbus_write_data(&s->sdbus, s->fifo_buffer, block_size); +@@ -670,9 +670,11 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s) + + if (s->trnmod & SDHC_TRNS_READ) { + sdbus_read_data(&s->sdbus, s->fifo_buffer, datacnt); +- dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); ++ dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt, ++ MEMTXATTRS_UNSPECIFIED); + } else { +- dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); ++ dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt, ++ MEMTXATTRS_UNSPECIFIED); + sdbus_write_data(&s->sdbus, s->fifo_buffer, datacnt); + } + s->blkcnt--; +@@ -694,7 +696,8 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) + hwaddr entry_addr = (hwaddr)s->admasysaddr; + switch (SDHC_DMA_TYPE(s->hostctl1)) { + case SDHC_CTRL_ADMA2_32: +- dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2)); ++ dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2), ++ MEMTXATTRS_UNSPECIFIED); + adma2 = le64_to_cpu(adma2); + /* The spec does not specify endianness of descriptor table. + * We currently assume that it is LE. +@@ -705,7 +708,8 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) + dscr->incr = 8; + break; + case SDHC_CTRL_ADMA1_32: +- dma_memory_read(s->dma_as, entry_addr, &adma1, sizeof(adma1)); ++ dma_memory_read(s->dma_as, entry_addr, &adma1, sizeof(adma1), ++ MEMTXATTRS_UNSPECIFIED); + adma1 = le32_to_cpu(adma1); + dscr->addr = (hwaddr)(adma1 & 0xFFFFF000); + dscr->attr = (uint8_t)extract32(adma1, 0, 7); +@@ -717,10 +721,13 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) + } + break; + case SDHC_CTRL_ADMA2_64: +- dma_memory_read(s->dma_as, entry_addr, &dscr->attr, 1); +- dma_memory_read(s->dma_as, entry_addr + 2, &dscr->length, 2); ++ dma_memory_read(s->dma_as, entry_addr, &dscr->attr, 1, ++ MEMTXATTRS_UNSPECIFIED); ++ dma_memory_read(s->dma_as, entry_addr + 2, &dscr->length, 2, ++ MEMTXATTRS_UNSPECIFIED); + dscr->length = le16_to_cpu(dscr->length); +- dma_memory_read(s->dma_as, entry_addr + 4, &dscr->addr, 8); ++ dma_memory_read(s->dma_as, entry_addr + 4, &dscr->addr, 8, ++ MEMTXATTRS_UNSPECIFIED); + dscr->addr = le64_to_cpu(dscr->addr); + dscr->attr &= (uint8_t) ~0xC0; + dscr->incr = 12; +@@ -785,7 +792,8 @@ static void sdhci_do_adma(SDHCIState *s) + } + dma_memory_write(s->dma_as, dscr.addr, + &s->fifo_buffer[begin], +- s->data_count - begin); ++ s->data_count - begin, ++ MEMTXATTRS_UNSPECIFIED); + dscr.addr += s->data_count - begin; + if (s->data_count == block_size) { + s->data_count = 0; +@@ -810,7 +818,8 @@ static void sdhci_do_adma(SDHCIState *s) + } + dma_memory_read(s->dma_as, dscr.addr, + &s->fifo_buffer[begin], +- s->data_count - begin); ++ s->data_count - begin, ++ MEMTXATTRS_UNSPECIFIED); + dscr.addr += s->data_count - begin; + if (s->data_count == block_size) { + sdbus_write_data(&s->sdbus, s->fifo_buffer, block_size); +diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c +index e1d96acf7e..8755e9cbb0 100644 +--- a/hw/usb/hcd-dwc2.c ++++ b/hw/usb/hcd-dwc2.c +@@ -272,8 +272,8 @@ static void dwc2_handle_packet(DWC2State *s, uint32_t devadr, USBDevice *dev, + + if (pid != USB_TOKEN_IN) { + trace_usb_dwc2_memory_read(hcdma, tlen); +- if (dma_memory_read(&s->dma_as, hcdma, +- s->usb_buf[chan], tlen) != MEMTX_OK) { ++ if (dma_memory_read(&s->dma_as, hcdma, s->usb_buf[chan], tlen, ++ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n", + __func__); + } +@@ -328,8 +328,8 @@ babble: + + if (pid == USB_TOKEN_IN) { + trace_usb_dwc2_memory_write(hcdma, actual); +- if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan], +- actual) != MEMTX_OK) { ++ if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan], actual, ++ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n", + __func__); + } +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 1415107315..0289b3696d 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -383,7 +383,8 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr, + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { +- dma_memory_read(ehci->as, addr, buf, sizeof(*buf)); ++ dma_memory_read(ehci->as, addr, buf, sizeof(*buf), ++ MEMTXATTRS_UNSPECIFIED); + *buf = le32_to_cpu(*buf); + } + +@@ -405,7 +406,8 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); +- dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp)); ++ dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp), ++ MEMTXATTRS_UNSPECIFIED); + } + + return num; +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index 56e2315c73..a93d6b2e98 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -452,7 +452,8 @@ static inline int get_dwords(OHCIState *ohci, + addr += ohci->localmem_base; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { +- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { ++ if (dma_memory_read(ohci->as, addr, ++ buf, sizeof(*buf), MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + *buf = le32_to_cpu(*buf); +@@ -471,7 +472,8 @@ static inline int put_dwords(OHCIState *ohci, + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); +- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { ++ if (dma_memory_write(ohci->as, addr, ++ &tmp, sizeof(tmp), MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + } +@@ -488,7 +490,8 @@ static inline int get_words(OHCIState *ohci, + addr += ohci->localmem_base; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { +- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { ++ if (dma_memory_read(ohci->as, addr, ++ buf, sizeof(*buf), MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + *buf = le16_to_cpu(*buf); +@@ -507,7 +510,8 @@ static inline int put_words(OHCIState *ohci, + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint16_t tmp = cpu_to_le16(*buf); +- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { ++ if (dma_memory_write(ohci->as, addr, ++ &tmp, sizeof(tmp), MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + } +@@ -537,8 +541,8 @@ static inline int ohci_read_iso_td(OHCIState *ohci, + static inline int ohci_read_hcca(OHCIState *ohci, + dma_addr_t addr, struct ohci_hcca *hcca) + { +- return dma_memory_read(ohci->as, addr + ohci->localmem_base, +- hcca, sizeof(*hcca)); ++ return dma_memory_read(ohci->as, addr + ohci->localmem_base, hcca, ++ sizeof(*hcca), MEMTXATTRS_UNSPECIFIED); + } + + static inline int ohci_put_ed(OHCIState *ohci, +@@ -572,7 +576,7 @@ static inline int ohci_put_hcca(OHCIState *ohci, + return dma_memory_write(ohci->as, + addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, + (char *)hcca + HCCA_WRITEBACK_OFFSET, +- HCCA_WRITEBACK_SIZE); ++ HCCA_WRITEBACK_SIZE, MEMTXATTRS_UNSPECIFIED); + } + + /* Read/Write the contents of a TD from/to main memory. */ +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 08cd63e159..c76091c657 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -488,7 +488,7 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, + + assert((len % sizeof(uint32_t)) == 0); + +- dma_memory_read(xhci->as, addr, buf, len); ++ dma_memory_read(xhci->as, addr, buf, len, MEMTXATTRS_UNSPECIFIED); + + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + buf[i] = le32_to_cpu(buf[i]); +@@ -508,7 +508,7 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, + for (i = 0; i < n; i++) { + tmp[i] = cpu_to_le32(buf[i]); + } +- dma_memory_write(xhci->as, addr, tmp, len); ++ dma_memory_write(xhci->as, addr, tmp, len, MEMTXATTRS_UNSPECIFIED); + } + + static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) +@@ -619,7 +619,7 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) + ev_trb.status, ev_trb.control); + + addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; +- dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE); ++ dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE, MEMTXATTRS_UNSPECIFIED); + + intr->er_ep_idx++; + if (intr->er_ep_idx >= intr->er_size) { +@@ -680,7 +680,8 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, + + while (1) { + TRBType type; +- dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE); ++ dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE, ++ MEMTXATTRS_UNSPECIFIED); + trb->addr = ring->dequeue; + trb->ccs = ring->ccs; + le64_to_cpus(&trb->parameter); +@@ -727,7 +728,8 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) + + while (1) { + TRBType type; +- dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE); ++ dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE, ++ MEMTXATTRS_UNSPECIFIED); + le64_to_cpus(&trb.parameter); + le32_to_cpus(&trb.status); + le32_to_cpus(&trb.control); +@@ -782,7 +784,8 @@ static void xhci_er_reset(XHCIState *xhci, int v) + xhci_die(xhci); + return; + } +- dma_memory_read(xhci->as, erstba, &seg, sizeof(seg)); ++ dma_memory_read(xhci->as, erstba, &seg, sizeof(seg), ++ MEMTXATTRS_UNSPECIFIED); + le32_to_cpus(&seg.addr_low); + le32_to_cpus(&seg.addr_high); + le32_to_cpus(&seg.size); +@@ -2398,7 +2401,8 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) + /* TODO: actually implement real values here */ + bw_ctx[0] = 0; + memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ +- dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx)); ++ dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx), ++ MEMTXATTRS_UNSPECIFIED); + + return CC_SUCCESS; + } +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index c90e74a67d..5d2ea8e665 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -97,14 +97,16 @@ static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr, + static inline int spapr_vio_dma_read(SpaprVioDevice *dev, uint64_t taddr, + void *buf, uint32_t size) + { +- return (dma_memory_read(&dev->as, taddr, buf, size) != 0) ? ++ return (dma_memory_read(&dev->as, taddr, ++ buf, size, MEMTXATTRS_UNSPECIFIED) != 0) ? + H_DEST_PARM : H_SUCCESS; + } + + static inline int spapr_vio_dma_write(SpaprVioDevice *dev, uint64_t taddr, + const void *buf, uint32_t size) + { +- return (dma_memory_write(&dev->as, taddr, buf, size) != 0) ? ++ return (dma_memory_write(&dev->as, taddr, ++ buf, size, MEMTXATTRS_UNSPECIFIED) != 0) ? + H_DEST_PARM : H_SUCCESS; + } + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index e8ad42226f..522682bf38 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -143,12 +143,14 @@ static inline MemTxResult dma_memory_rw(AddressSpace *as, dma_addr_t addr, + * @addr: address within that address space + * @buf: buffer with the data transferred + * @len: length of the data transferred ++ * @attrs: memory transaction attributes + */ + static inline MemTxResult dma_memory_read(AddressSpace *as, dma_addr_t addr, +- void *buf, dma_addr_t len) ++ void *buf, dma_addr_t len, ++ MemTxAttrs attrs) + { + return dma_memory_rw(as, addr, buf, len, +- DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); ++ DMA_DIRECTION_TO_DEVICE, attrs); + } + + /** +@@ -162,12 +164,14 @@ static inline MemTxResult dma_memory_read(AddressSpace *as, dma_addr_t addr, + * @addr: address within that address space + * @buf: buffer with the data transferred + * @len: the number of bytes to write ++ * @attrs: memory transaction attributes + */ + static inline MemTxResult dma_memory_write(AddressSpace *as, dma_addr_t addr, +- const void *buf, dma_addr_t len) ++ const void *buf, dma_addr_t len, ++ MemTxAttrs attrs) + { + return dma_memory_rw(as, addr, (void *)buf, len, +- DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); ++ DMA_DIRECTION_FROM_DEVICE, attrs); + } + + /** +@@ -239,7 +243,7 @@ static inline void dma_memory_unmap(AddressSpace *as, + dma_addr_t addr) \ + { \ + uint##_bits##_t val; \ +- dma_memory_read(as, addr, &val, (_bits) / 8); \ ++ dma_memory_read(as, addr, &val, (_bits) / 8, MEMTXATTRS_UNSPECIFIED); \ + return _end##_bits##_to_cpu(val); \ + } \ + static inline void st##_sname##_##_end##_dma(AddressSpace *as, \ +@@ -247,20 +251,20 @@ static inline void dma_memory_unmap(AddressSpace *as, + uint##_bits##_t val) \ + { \ + val = cpu_to_##_end##_bits(val); \ +- dma_memory_write(as, addr, &val, (_bits) / 8); \ ++ dma_memory_write(as, addr, &val, (_bits) / 8, MEMTXATTRS_UNSPECIFIED); \ + } + + static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr) + { + uint8_t val; + +- dma_memory_read(as, addr, &val, 1); ++ dma_memory_read(as, addr, &val, 1, MEMTXATTRS_UNSPECIFIED); + return val; + } + + static inline void stb_dma(AddressSpace *as, dma_addr_t addr, uint8_t val) + { +- dma_memory_write(as, addr, &val, 1); ++ dma_memory_write(as, addr, &val, 1, MEMTXATTRS_UNSPECIFIED); + } + + DEFINE_LDST_DMA(uw, w, 16, le); +-- +2.27.0 + diff --git a/dma-Let-dma_memory_rw-take-MemTxAttrs-argument.patch b/dma-Let-dma_memory_rw-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..10952641b716a148d50b8dbc4a3d207d0426214f --- /dev/null +++ b/dma-Let-dma_memory_rw-take-MemTxAttrs-argument.patch @@ -0,0 +1,154 @@ +From a3bdca7d4684ecb0b785f14020e68b4ba80831b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 09:37:43 +0200 +Subject: [PATCH 05/25] dma: Let dma_memory_rw() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_memory_rw(). + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-5-philmd@redhat.com> +--- + hw/intc/spapr_xive.c | 3 ++- + hw/usb/hcd-ohci.c | 10 ++++++---- + include/hw/pci/pci.h | 3 ++- + include/sysemu/dma.h | 11 ++++++----- + softmmu/dma-helpers.c | 3 ++- + 5 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c +index 4ec659b93e..eae95c716f 100644 +--- a/hw/intc/spapr_xive.c ++++ b/hw/intc/spapr_xive.c +@@ -1684,7 +1684,8 @@ static target_ulong h_int_esb(PowerPCCPU *cpu, + mmio_addr = xive->vc_base + xive_source_esb_mgmt(xsrc, lisn) + offset; + + if (dma_memory_rw(&address_space_memory, mmio_addr, &data, 8, +- (flags & SPAPR_XIVE_ESB_STORE))) { ++ (flags & SPAPR_XIVE_ESB_STORE), ++ MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to access ESB @0x%" + HWADDR_PRIx "\n", mmio_addr); + return H_HARDWARE; +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index 1cf2816772..56e2315c73 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -586,7 +586,8 @@ static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, + if (n > len) + n = len; + +- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { ++ if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, ++ n, dir, MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + if (n == len) { +@@ -595,7 +596,7 @@ static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, + ptr = td->be & ~0xfffu; + buf += n; + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, +- len - n, dir)) { ++ len - n, dir, MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + return 0; +@@ -613,7 +614,8 @@ static int ohci_copy_iso_td(OHCIState *ohci, + if (n > len) + n = len; + +- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { ++ if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, ++ n, dir, MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + if (n == len) { +@@ -622,7 +624,7 @@ static int ohci_copy_iso_td(OHCIState *ohci, + ptr = end_addr & ~0xfffu; + buf += n; + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, +- len - n, dir)) { ++ len - n, dir, MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + return 0; +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index 809eb32f4a..c72d61bfd8 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -823,7 +823,8 @@ static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len, + DMADirection dir) + { +- return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, dir); ++ return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, ++ dir, MEMTXATTRS_UNSPECIFIED); + } + + /** +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 3be803cf3f..e8ad42226f 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -121,15 +121,15 @@ static inline MemTxResult dma_memory_write_relaxed(AddressSpace *as, + * @buf: buffer with the data transferred + * @len: the number of bytes to read or write + * @dir: indicates the transfer direction ++ * @attrs: memory transaction attributes + */ + static inline MemTxResult dma_memory_rw(AddressSpace *as, dma_addr_t addr, + void *buf, dma_addr_t len, +- DMADirection dir) ++ DMADirection dir, MemTxAttrs attrs) + { + dma_barrier(as, dir); + +- return dma_memory_rw_relaxed(as, addr, buf, len, dir, +- MEMTXATTRS_UNSPECIFIED); ++ return dma_memory_rw_relaxed(as, addr, buf, len, dir, attrs); + } + + /** +@@ -147,7 +147,8 @@ static inline MemTxResult dma_memory_rw(AddressSpace *as, dma_addr_t addr, + static inline MemTxResult dma_memory_read(AddressSpace *as, dma_addr_t addr, + void *buf, dma_addr_t len) + { +- return dma_memory_rw(as, addr, buf, len, DMA_DIRECTION_TO_DEVICE); ++ return dma_memory_rw(as, addr, buf, len, ++ DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); + } + + /** +@@ -166,7 +167,7 @@ static inline MemTxResult dma_memory_write(AddressSpace *as, dma_addr_t addr, + const void *buf, dma_addr_t len) + { + return dma_memory_rw(as, addr, (void *)buf, len, +- DMA_DIRECTION_FROM_DEVICE); ++ DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); + } + + /** +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 1f07217ad4..5bf76fff6b 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -305,7 +305,8 @@ static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, + while (len > 0) { + ScatterGatherEntry entry = sg->sg[sg_cur_index++]; + int32_t xfer = MIN(len, entry.len); +- dma_memory_rw(sg->as, entry.base, ptr, xfer, dir); ++ dma_memory_rw(sg->as, entry.base, ptr, xfer, dir, ++ MEMTXATTRS_UNSPECIFIED); + ptr += xfer; + len -= xfer; + resid -= xfer; +-- +2.27.0 + diff --git a/dma-Let-dma_memory_rw_relaxed-take-MemTxAttrs-argume.patch b/dma-Let-dma_memory_rw_relaxed-take-MemTxAttrs-argume.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ad294345116f6589e243939706d48bca32430c3 --- /dev/null +++ b/dma-Let-dma_memory_rw_relaxed-take-MemTxAttrs-argume.patch @@ -0,0 +1,75 @@ +From 167e155f710ec769a1db9df92ad6a077bf6225a0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 09:30:10 +0200 +Subject: [PATCH 04/25] dma: Let dma_memory_rw_relaxed() take MemTxAttrs + argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We will add the MemTxAttrs argument to dma_memory_rw() in +the next commit. Since dma_memory_rw_relaxed() is only used +by dma_memory_rw(), modify it first in a separate commit to +keep the next commit easier to review. + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-4-philmd@redhat.com> +--- + include/sysemu/dma.h | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index d23516f020..3be803cf3f 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -83,9 +83,10 @@ static inline bool dma_memory_valid(AddressSpace *as, + static inline MemTxResult dma_memory_rw_relaxed(AddressSpace *as, + dma_addr_t addr, + void *buf, dma_addr_t len, +- DMADirection dir) ++ DMADirection dir, ++ MemTxAttrs attrs) + { +- return address_space_rw(as, addr, MEMTXATTRS_UNSPECIFIED, ++ return address_space_rw(as, addr, attrs, + buf, len, dir == DMA_DIRECTION_FROM_DEVICE); + } + +@@ -93,7 +94,9 @@ static inline MemTxResult dma_memory_read_relaxed(AddressSpace *as, + dma_addr_t addr, + void *buf, dma_addr_t len) + { +- return dma_memory_rw_relaxed(as, addr, buf, len, DMA_DIRECTION_TO_DEVICE); ++ return dma_memory_rw_relaxed(as, addr, buf, len, ++ DMA_DIRECTION_TO_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + } + + static inline MemTxResult dma_memory_write_relaxed(AddressSpace *as, +@@ -102,7 +105,8 @@ static inline MemTxResult dma_memory_write_relaxed(AddressSpace *as, + dma_addr_t len) + { + return dma_memory_rw_relaxed(as, addr, (void *)buf, len, +- DMA_DIRECTION_FROM_DEVICE); ++ DMA_DIRECTION_FROM_DEVICE, ++ MEMTXATTRS_UNSPECIFIED); + } + + /** +@@ -124,7 +128,8 @@ static inline MemTxResult dma_memory_rw(AddressSpace *as, dma_addr_t addr, + { + dma_barrier(as, dir); + +- return dma_memory_rw_relaxed(as, addr, buf, len, dir); ++ return dma_memory_rw_relaxed(as, addr, buf, len, dir, ++ MEMTXATTRS_UNSPECIFIED); + } + + /** +-- +2.27.0 + diff --git a/dma-Let-dma_memory_set-take-MemTxAttrs-argument.patch b/dma-Let-dma_memory_set-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d7cc93535b828c8f9dcd66c6a931b58af4688fc --- /dev/null +++ b/dma-Let-dma_memory_set-take-MemTxAttrs-argument.patch @@ -0,0 +1,94 @@ +From ba242eb5be5fdfdccf22d2d818880ed9c89ababd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 10:28:32 +0200 +Subject: [PATCH 03/25] dma: Let dma_memory_set() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_memory_set(). + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-3-philmd@redhat.com> +--- + hw/nvram/fw_cfg.c | 3 ++- + include/hw/ppc/spapr_vio.h | 3 ++- + include/sysemu/dma.h | 3 ++- + softmmu/dma-helpers.c | 5 ++--- + 4 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index c06b30de11..f7803fe3c3 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -399,7 +399,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + * tested before. + */ + if (read) { +- if (dma_memory_set(s->dma_as, dma.address, 0, len)) { ++ if (dma_memory_set(s->dma_as, dma.address, 0, len, ++ MEMTXATTRS_UNSPECIFIED)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; + } + } +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index 4c45f1579f..c90e74a67d 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -111,7 +111,8 @@ static inline int spapr_vio_dma_write(SpaprVioDevice *dev, uint64_t taddr, + static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr, + uint8_t c, uint32_t size) + { +- return (dma_memory_set(&dev->as, taddr, c, size) != 0) ? ++ return (dma_memory_set(&dev->as, taddr, ++ c, size, MEMTXATTRS_UNSPECIFIED) != 0) ? + H_DEST_PARM : H_SUCCESS; + } + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 296f3b57c9..d23516f020 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -175,9 +175,10 @@ static inline MemTxResult dma_memory_write(AddressSpace *as, dma_addr_t addr, + * @addr: address within that address space + * @c: constant byte to fill the memory + * @len: the number of bytes to fill with the constant byte ++ * @attrs: memory transaction attributes + */ + MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr, +- uint8_t c, dma_addr_t len); ++ uint8_t c, dma_addr_t len, MemTxAttrs attrs); + + /** + * address_space_map: Map a physical memory region into a host virtual address. +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index 7d766a5e89..1f07217ad4 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -19,7 +19,7 @@ + /* #define DEBUG_IOMMU */ + + MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr, +- uint8_t c, dma_addr_t len) ++ uint8_t c, dma_addr_t len, MemTxAttrs attrs) + { + dma_barrier(as, DMA_DIRECTION_FROM_DEVICE); + +@@ -31,8 +31,7 @@ MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr, + memset(fillbuf, c, FILLBUF_SIZE); + while (len > 0) { + l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; +- error |= address_space_write(as, addr, MEMTXATTRS_UNSPECIFIED, +- fillbuf, l); ++ error |= address_space_write(as, addr, attrs, fillbuf, l); + len -= l; + addr += l; + } +-- +2.27.0 + diff --git a/dma-Let-dma_memory_valid-take-MemTxAttrs-argument.patch b/dma-Let-dma_memory_valid-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b466b7048e4e56e01c68e63060816ca6d6a4c40 --- /dev/null +++ b/dma-Let-dma_memory_valid-take-MemTxAttrs-argument.patch @@ -0,0 +1,56 @@ +From 46e7b55f326a115f42019add488a1ca1887aa89c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 3 Sep 2020 09:28:49 +0200 +Subject: [PATCH 02/25] dma: Let dma_memory_valid() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling +dma_memory_valid(). + +Reviewed-by: Richard Henderson +Reviewed-by: Li Qiang +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Stefan Hajnoczi +Message-Id: <20211223115554.3155328-2-philmd@redhat.com> +--- + include/hw/ppc/spapr_vio.h | 2 +- + include/sysemu/dma.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index 4bea87f39c..4c45f1579f 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -91,7 +91,7 @@ static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev) + static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr, + uint32_t size, DMADirection dir) + { +- return dma_memory_valid(&dev->as, taddr, size, dir); ++ return dma_memory_valid(&dev->as, taddr, size, dir, MEMTXATTRS_UNSPECIFIED); + } + + static inline int spapr_vio_dma_read(SpaprVioDevice *dev, uint64_t taddr, +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 3201e7901d..296f3b57c9 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -73,11 +73,11 @@ static inline void dma_barrier(AddressSpace *as, DMADirection dir) + * dma_memory_{read,write}() and check for errors */ + static inline bool dma_memory_valid(AddressSpace *as, + dma_addr_t addr, dma_addr_t len, +- DMADirection dir) ++ DMADirection dir, MemTxAttrs attrs) + { + return address_space_access_valid(as, addr, len, + dir == DMA_DIRECTION_FROM_DEVICE, +- MEMTXATTRS_UNSPECIFIED); ++ attrs); + } + + static inline MemTxResult dma_memory_rw_relaxed(AddressSpace *as, +-- +2.27.0 + diff --git a/dma-Let-ld-_dma-propagate-MemTxResult.patch b/dma-Let-ld-_dma-propagate-MemTxResult.patch new file mode 100644 index 0000000000000000000000000000000000000000..baee5efe1157c72ae4bef43ff999613f3fd22d2a --- /dev/null +++ b/dma-Let-ld-_dma-propagate-MemTxResult.patch @@ -0,0 +1,171 @@ +From e52e5e44ca9afd06639cc166b60cc8fbdb081593 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 22:31:11 +0100 +Subject: [PATCH 18/25] dma: Let ld*_dma() propagate MemTxResult +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dma_memory_read() returns a MemTxResult type. Do not discard +it, return it to the caller. + +Update the few callers. + +Reviewed-by: Richard Henderson +Reviewed-by: Cédric Le Goater +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-19-philmd@redhat.com> +--- + hw/intc/pnv_xive.c | 8 ++++---- + hw/usb/hcd-xhci.c | 7 ++++--- + include/hw/pci/pci.h | 6 ++++-- + include/hw/ppc/spapr_vio.h | 6 +++++- + include/sysemu/dma.h | 25 ++++++++++++------------- + 5 files changed, 29 insertions(+), 23 deletions(-) + +diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c +index d9249bbc0c..bb207514f2 100644 +--- a/hw/intc/pnv_xive.c ++++ b/hw/intc/pnv_xive.c +@@ -172,7 +172,7 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type, + + /* Get the page size of the indirect table. */ + vsd_addr = vsd & VSD_ADDRESS_MASK; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr, MEMTXATTRS_UNSPECIFIED); ++ ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +@@ -195,8 +195,8 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type, + /* Load the VSD we are looking for, if not already done */ + if (vsd_idx) { + vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr, +- MEMTXATTRS_UNSPECIFIED); ++ ldq_be_dma(&address_space_memory, vsd_addr, &vsd, ++ MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +@@ -543,7 +543,7 @@ static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type) + + /* Get the page size of the indirect table. */ + vsd_addr = vsd & VSD_ADDRESS_MASK; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr, MEMTXATTRS_UNSPECIFIED); ++ ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 1f7b796ce3..30c477f36e 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -2063,7 +2063,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, + assert(slotid >= 1 && slotid <= xhci->numslots); + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); +- poctx = ldq_le_dma(xhci->as, dcbaap + 8 * slotid, MEMTXATTRS_UNSPECIFIED); ++ ldq_le_dma(xhci->as, dcbaap + 8 * slotid, &poctx, MEMTXATTRS_UNSPECIFIED); + ictx = xhci_mask64(pictx); + octx = xhci_mask64(poctx); + +@@ -3433,6 +3433,7 @@ static int usb_xhci_post_load(void *opaque, int version_id) + uint32_t slot_ctx[4]; + uint32_t ep_ctx[5]; + int slotid, epid, state; ++ uint64_t addr; + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); + +@@ -3441,8 +3442,8 @@ static int usb_xhci_post_load(void *opaque, int version_id) + if (!slot->addressed) { + continue; + } +- slot->ctx = xhci_mask64(ldq_le_dma(xhci->as, dcbaap + 8 * slotid, +- MEMTXATTRS_UNSPECIFIED)); ++ ldq_le_dma(xhci->as, dcbaap + 8 * slotid, &addr, MEMTXATTRS_UNSPECIFIED); ++ slot->ctx = xhci_mask64(addr); + xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx)); + slot->uport = xhci_lookup_uport(xhci, slot_ctx); + if (!slot->uport) { +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index b287b3a19f..71c6513641 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -869,8 +869,10 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr) \ + { \ +- return ld##_l##_dma(pci_get_address_space(dev), addr, \ +- MEMTXATTRS_UNSPECIFIED); \ ++ uint##_bits##_t val; \ ++ ld##_l##_dma(pci_get_address_space(dev), addr, &val, \ ++ MEMTXATTRS_UNSPECIFIED); \ ++ return val; \ + } \ + static inline void st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, uint##_bits##_t val) \ +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index d2ec9b0637..7eae1a4847 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -127,7 +127,11 @@ static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr, + #define vio_stq(_dev, _addr, _val) \ + (stq_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) + #define vio_ldq(_dev, _addr) \ +- (ldq_be_dma(&(_dev)->as, (_addr), MEMTXATTRS_UNSPECIFIED)) ++ ({ \ ++ uint64_t _val; \ ++ ldq_be_dma(&(_dev)->as, (_addr), &_val, MEMTXATTRS_UNSPECIFIED); \ ++ _val; \ ++ }) + + int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq); + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 895044d747..b3faef41b2 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -240,14 +240,15 @@ static inline void dma_memory_unmap(AddressSpace *as, + } + + #define DEFINE_LDST_DMA(_lname, _sname, _bits, _end) \ +- static inline uint##_bits##_t ld##_lname##_##_end##_dma(AddressSpace *as, \ +- dma_addr_t addr, \ +- MemTxAttrs attrs) \ +- { \ +- uint##_bits##_t val; \ +- dma_memory_read(as, addr, &val, (_bits) / 8, attrs); \ +- return _end##_bits##_to_cpu(val); \ +- } \ ++ static inline MemTxResult ld##_lname##_##_end##_dma(AddressSpace *as, \ ++ dma_addr_t addr, \ ++ uint##_bits##_t *pval, \ ++ MemTxAttrs attrs) \ ++ { \ ++ MemTxResult res = dma_memory_read(as, addr, pval, (_bits) / 8, attrs); \ ++ _end##_bits##_to_cpus(pval); \ ++ return res; \ ++ } \ + static inline MemTxResult st##_sname##_##_end##_dma(AddressSpace *as, \ + dma_addr_t addr, \ + uint##_bits##_t val, \ +@@ -257,12 +258,10 @@ static inline void dma_memory_unmap(AddressSpace *as, + return dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ + } + +-static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr, MemTxAttrs attrs) ++static inline MemTxResult ldub_dma(AddressSpace *as, dma_addr_t addr, ++ uint8_t *val, MemTxAttrs attrs) + { +- uint8_t val; +- +- dma_memory_read(as, addr, &val, 1, attrs); +- return val; ++ return dma_memory_read(as, addr, val, 1, attrs); + } + + static inline MemTxResult stb_dma(AddressSpace *as, dma_addr_t addr, +-- +2.27.0 + diff --git a/dma-Let-ld-_dma-take-MemTxAttrs-argument.patch b/dma-Let-ld-_dma-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..749564c738a44fb8ac43551855b0ae15a52a56f2 --- /dev/null +++ b/dma-Let-ld-_dma-take-MemTxAttrs-argument.patch @@ -0,0 +1,147 @@ +From 52cca6d99c5c59d6550d3729f84ffcba50ff4ed3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 22:18:07 +0100 +Subject: [PATCH 16/25] dma: Let ld*_dma() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling ld*_dma(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Richard Henderson +Reviewed-by: Cédric Le Goater +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-17-philmd@redhat.com> +--- + hw/intc/pnv_xive.c | 7 ++++--- + hw/usb/hcd-xhci.c | 6 +++--- + include/hw/pci/pci.h | 3 ++- + include/hw/ppc/spapr_vio.h | 3 ++- + include/sysemu/dma.h | 11 ++++++----- + 5 files changed, 17 insertions(+), 13 deletions(-) + +diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c +index ad43483612..d9249bbc0c 100644 +--- a/hw/intc/pnv_xive.c ++++ b/hw/intc/pnv_xive.c +@@ -172,7 +172,7 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type, + + /* Get the page size of the indirect table. */ + vsd_addr = vsd & VSD_ADDRESS_MASK; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr); ++ vsd = ldq_be_dma(&address_space_memory, vsd_addr, MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +@@ -195,7 +195,8 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type, + /* Load the VSD we are looking for, if not already done */ + if (vsd_idx) { + vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr); ++ vsd = ldq_be_dma(&address_space_memory, vsd_addr, ++ MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +@@ -542,7 +543,7 @@ static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type) + + /* Get the page size of the indirect table. */ + vsd_addr = vsd & VSD_ADDRESS_MASK; +- vsd = ldq_be_dma(&address_space_memory, vsd_addr); ++ vsd = ldq_be_dma(&address_space_memory, vsd_addr, MEMTXATTRS_UNSPECIFIED); + + if (!(vsd & VSD_ADDRESS_MASK)) { + #ifdef XIVE_DEBUG +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index c76091c657..1f7b796ce3 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -2063,7 +2063,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, + assert(slotid >= 1 && slotid <= xhci->numslots); + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); +- poctx = ldq_le_dma(xhci->as, dcbaap + 8 * slotid); ++ poctx = ldq_le_dma(xhci->as, dcbaap + 8 * slotid, MEMTXATTRS_UNSPECIFIED); + ictx = xhci_mask64(pictx); + octx = xhci_mask64(poctx); + +@@ -3441,8 +3441,8 @@ static int usb_xhci_post_load(void *opaque, int version_id) + if (!slot->addressed) { + continue; + } +- slot->ctx = +- xhci_mask64(ldq_le_dma(xhci->as, dcbaap + 8 * slotid)); ++ slot->ctx = xhci_mask64(ldq_le_dma(xhci->as, dcbaap + 8 * slotid, ++ MEMTXATTRS_UNSPECIFIED)); + xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx)); + slot->uport = xhci_lookup_uport(xhci, slot_ctx); + if (!slot->uport) { +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index 52e2ca2f2e..b287b3a19f 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -869,7 +869,8 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr) \ + { \ +- return ld##_l##_dma(pci_get_address_space(dev), addr); \ ++ return ld##_l##_dma(pci_get_address_space(dev), addr, \ ++ MEMTXATTRS_UNSPECIFIED); \ + } \ + static inline void st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, uint##_bits##_t val) \ +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index e87f8e6f59..d2ec9b0637 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -126,7 +126,8 @@ static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr, + (stl_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) + #define vio_stq(_dev, _addr, _val) \ + (stq_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) +-#define vio_ldq(_dev, _addr) (ldq_be_dma(&(_dev)->as, (_addr))) ++#define vio_ldq(_dev, _addr) \ ++ (ldq_be_dma(&(_dev)->as, (_addr), MEMTXATTRS_UNSPECIFIED)) + + int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq); + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index 009dd3ca96..d1635f5587 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -241,10 +241,11 @@ static inline void dma_memory_unmap(AddressSpace *as, + + #define DEFINE_LDST_DMA(_lname, _sname, _bits, _end) \ + static inline uint##_bits##_t ld##_lname##_##_end##_dma(AddressSpace *as, \ +- dma_addr_t addr) \ ++ dma_addr_t addr, \ ++ MemTxAttrs attrs) \ + { \ + uint##_bits##_t val; \ +- dma_memory_read(as, addr, &val, (_bits) / 8, MEMTXATTRS_UNSPECIFIED); \ ++ dma_memory_read(as, addr, &val, (_bits) / 8, attrs); \ + return _end##_bits##_to_cpu(val); \ + } \ + static inline void st##_sname##_##_end##_dma(AddressSpace *as, \ +@@ -253,14 +254,14 @@ static inline void dma_memory_unmap(AddressSpace *as, + MemTxAttrs attrs) \ + { \ + val = cpu_to_##_end##_bits(val); \ +- dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ ++ dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ + } + +-static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr) ++static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr, MemTxAttrs attrs) + { + uint8_t val; + +- dma_memory_read(as, addr, &val, 1, MEMTXATTRS_UNSPECIFIED); ++ dma_memory_read(as, addr, &val, 1, attrs); + return val; + } + +-- +2.27.0 + diff --git a/dma-Let-st-_dma-propagate-MemTxResult.patch b/dma-Let-st-_dma-propagate-MemTxResult.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff45a0a90f8fdbb8cf0f6d56bba8bed5ff4c14a9 --- /dev/null +++ b/dma-Let-st-_dma-propagate-MemTxResult.patch @@ -0,0 +1,61 @@ +From 323fc6abd2b727d888acaec1788bb7b7aefa295b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 23:56:14 +0100 +Subject: [PATCH 17/25] dma: Let st*_dma() propagate MemTxResult +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dma_memory_write() returns a MemTxResult type. Do not discard +it, return it to the caller. + +Reviewed-by: Richard Henderson +Reviewed-by: Cédric Le Goater +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-18-philmd@redhat.com> +--- + include/sysemu/dma.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index d1635f5587..895044d747 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -248,13 +248,13 @@ static inline void dma_memory_unmap(AddressSpace *as, + dma_memory_read(as, addr, &val, (_bits) / 8, attrs); \ + return _end##_bits##_to_cpu(val); \ + } \ +- static inline void st##_sname##_##_end##_dma(AddressSpace *as, \ +- dma_addr_t addr, \ +- uint##_bits##_t val, \ +- MemTxAttrs attrs) \ +- { \ +- val = cpu_to_##_end##_bits(val); \ +- dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ ++ static inline MemTxResult st##_sname##_##_end##_dma(AddressSpace *as, \ ++ dma_addr_t addr, \ ++ uint##_bits##_t val, \ ++ MemTxAttrs attrs) \ ++ { \ ++ val = cpu_to_##_end##_bits(val); \ ++ return dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ + } + + static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr, MemTxAttrs attrs) +@@ -265,10 +265,10 @@ static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr, MemTxAttrs att + return val; + } + +-static inline void stb_dma(AddressSpace *as, dma_addr_t addr, +- uint8_t val, MemTxAttrs attrs) ++static inline MemTxResult stb_dma(AddressSpace *as, dma_addr_t addr, ++ uint8_t val, MemTxAttrs attrs) + { +- dma_memory_write(as, addr, &val, 1, attrs); ++ return dma_memory_write(as, addr, &val, 1, attrs); + } + + DEFINE_LDST_DMA(uw, w, 16, le); +-- +2.27.0 + diff --git a/dma-Let-st-_dma-take-MemTxAttrs-argument.patch b/dma-Let-st-_dma-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..c4e021d06ab1b01ca065762322568fcb6ba0a7e2 --- /dev/null +++ b/dma-Let-st-_dma-take-MemTxAttrs-argument.patch @@ -0,0 +1,116 @@ +From c9fb8525402c4a3d3e3f5c104a289fbf080fcda3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 23:53:34 +0100 +Subject: [PATCH 15/25] dma: Let st*_dma() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling st*_dma(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Richard Henderson +Reviewed-by: Cédric Le Goater +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-16-philmd@redhat.com> +--- + hw/nvram/fw_cfg.c | 4 ++-- + include/hw/pci/pci.h | 3 ++- + include/hw/ppc/spapr_vio.h | 12 ++++++++---- + include/sysemu/dma.h | 10 ++++++---- + 4 files changed, 18 insertions(+), 11 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 9b91b15cb0..e5f3c98184 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -360,7 +360,7 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + if (dma_memory_read(s->dma_as, dma_addr, + &dma, sizeof(dma), MEMTXATTRS_UNSPECIFIED)) { + stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control), +- FW_CFG_DMA_CTL_ERROR); ++ FW_CFG_DMA_CTL_ERROR, MEMTXATTRS_UNSPECIFIED); + return; + } + +@@ -446,7 +446,7 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + } + + stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control), +- dma.control); ++ dma.control, MEMTXATTRS_UNSPECIFIED); + + trace_fw_cfg_read(s, 0); + } +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index c7177646a4..52e2ca2f2e 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -874,7 +874,8 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + static inline void st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, uint##_bits##_t val) \ + { \ +- st##_s##_dma(pci_get_address_space(dev), addr, val); \ ++ st##_s##_dma(pci_get_address_space(dev), addr, val, \ ++ MEMTXATTRS_UNSPECIFIED); \ + } + + PCI_DMA_DEFINE_LDST(ub, b, 8); +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index 5d2ea8e665..e87f8e6f59 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -118,10 +118,14 @@ static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr, + H_DEST_PARM : H_SUCCESS; + } + +-#define vio_stb(_dev, _addr, _val) (stb_dma(&(_dev)->as, (_addr), (_val))) +-#define vio_sth(_dev, _addr, _val) (stw_be_dma(&(_dev)->as, (_addr), (_val))) +-#define vio_stl(_dev, _addr, _val) (stl_be_dma(&(_dev)->as, (_addr), (_val))) +-#define vio_stq(_dev, _addr, _val) (stq_be_dma(&(_dev)->as, (_addr), (_val))) ++#define vio_stb(_dev, _addr, _val) \ ++ (stb_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) ++#define vio_sth(_dev, _addr, _val) \ ++ (stw_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) ++#define vio_stl(_dev, _addr, _val) \ ++ (stl_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) ++#define vio_stq(_dev, _addr, _val) \ ++ (stq_be_dma(&(_dev)->as, (_addr), (_val), MEMTXATTRS_UNSPECIFIED)) + #define vio_ldq(_dev, _addr) (ldq_be_dma(&(_dev)->as, (_addr))) + + int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq); +diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h +index fd8f16003d..009dd3ca96 100644 +--- a/include/sysemu/dma.h ++++ b/include/sysemu/dma.h +@@ -249,10 +249,11 @@ static inline void dma_memory_unmap(AddressSpace *as, + } \ + static inline void st##_sname##_##_end##_dma(AddressSpace *as, \ + dma_addr_t addr, \ +- uint##_bits##_t val) \ ++ uint##_bits##_t val, \ ++ MemTxAttrs attrs) \ + { \ + val = cpu_to_##_end##_bits(val); \ +- dma_memory_write(as, addr, &val, (_bits) / 8, MEMTXATTRS_UNSPECIFIED); \ ++ dma_memory_write(as, addr, &val, (_bits) / 8, attrs); \ + } + + static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr) +@@ -263,9 +264,10 @@ static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr) + return val; + } + +-static inline void stb_dma(AddressSpace *as, dma_addr_t addr, uint8_t val) ++static inline void stb_dma(AddressSpace *as, dma_addr_t addr, ++ uint8_t val, MemTxAttrs attrs) + { +- dma_memory_write(as, addr, &val, 1, MEMTXATTRS_UNSPECIFIED); ++ dma_memory_write(as, addr, &val, 1, attrs); + } + + DEFINE_LDST_DMA(uw, w, 16, le); +-- +2.27.0 + diff --git a/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch b/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch deleted file mode 100644 index c61c9fd848c4e1d68baa778388c8440a8d28ec32..0000000000000000000000000000000000000000 --- a/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch +++ /dev/null @@ -1,79 +0,0 @@ -From fbde196c30e4797a51bda046ba514b187963d4ba Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 29 Jul 2019 23:34:16 +0200 -Subject: [PATCH] dma-helpers: ensure AIO callback is invoked after - cancellation - -dma_aio_cancel unschedules the BH if there is one, which corresponds -to the reschedule_dma case of dma_blk_cb. This can stall the DMA -permanently, because dma_complete will never get invoked and therefore -nobody will ever invoke the original AIO callback in dbs->common.cb. - -Fix this by invoking the callback (which is ensured to happen after -a bdrv_aio_cancel_async, or done manually in the dbs->bh case), and -add assertions to check that the DMA state machine is indeed waiting -for dma_complete or reschedule_dma, but never both. - -Reported-by: John Snow -Signed-off-by: Paolo Bonzini -Message-id: 20190729213416.1972-1-pbonzini@redhat.com -Signed-off-by: John Snow -(cherry picked from commit 539343c0a47e19d5dd64d846d64d084d9793681f) -Signed-off-by: Michael Roth ---- - dma-helpers.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -diff --git a/dma-helpers.c b/dma-helpers.c -index 2d7e02d35e..d3871dc61e 100644 ---- a/dma-helpers.c -+++ b/dma-helpers.c -@@ -90,6 +90,7 @@ static void reschedule_dma(void *opaque) - { - DMAAIOCB *dbs = (DMAAIOCB *)opaque; - -+ assert(!dbs->acb && dbs->bh); - qemu_bh_delete(dbs->bh); - dbs->bh = NULL; - dma_blk_cb(dbs, 0); -@@ -111,15 +112,12 @@ static void dma_complete(DMAAIOCB *dbs, int ret) - { - trace_dma_complete(dbs, ret, dbs->common.cb); - -+ assert(!dbs->acb && !dbs->bh); - dma_blk_unmap(dbs); - if (dbs->common.cb) { - dbs->common.cb(dbs->common.opaque, ret); - } - qemu_iovec_destroy(&dbs->iov); -- if (dbs->bh) { -- qemu_bh_delete(dbs->bh); -- dbs->bh = NULL; -- } - qemu_aio_unref(dbs); - } - -@@ -179,14 +177,21 @@ static void dma_aio_cancel(BlockAIOCB *acb) - - trace_dma_aio_cancel(dbs); - -+ assert(!(dbs->acb && dbs->bh)); - if (dbs->acb) { -+ /* This will invoke dma_blk_cb. */ - blk_aio_cancel_async(dbs->acb); -+ return; - } -+ - if (dbs->bh) { - cpu_unregister_map_client(dbs->bh); - qemu_bh_delete(dbs->bh); - dbs->bh = NULL; - } -+ if (dbs->common.cb) { -+ dbs->common.cb(dbs->common.opaque, -ECANCELED); -+ } - } - - static AioContext *dma_get_aio_context(BlockAIOCB *acb) --- -2.23.0 diff --git a/doc-Add-the-SGX-numa-description.patch b/doc-Add-the-SGX-numa-description.patch new file mode 100644 index 0000000000000000000000000000000000000000..92889422e538fc278e887567332d62914df8f3ed --- /dev/null +++ b/doc-Add-the-SGX-numa-description.patch @@ -0,0 +1,81 @@ +From adba5254ecbd9eace360d8eb3d5c635d3acd8d71 Mon Sep 17 00:00:00 2001 +From: Yang Zhong +Date: Mon, 1 Nov 2021 12:20:08 -0400 +Subject: [PATCH 3/9] doc: Add the SGX numa description + +mainline inclusion +from mainline-v7.0.0-rc0 +commit d1889b36098c79e2e6ac90faf3d0dc5ec0057677 +category: feature +feature: NUMA support for SGX EPC sections +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5K27A + +Intel-SIG: commit d1889b36098c ("doc: Add the SGX numa description") + +------------------------------------- + +doc: Add the SGX numa description + +Add the SGX numa reference command and how to check if +SGX numa is support or not with multiple EPC sections. + +Signed-off-by: Yang Zhong +Message-Id: <20211101162009.62161-5-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + docs/system/i386/sgx.rst | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/docs/system/i386/sgx.rst b/docs/system/i386/sgx.rst +index f8fade5ac2..0f0a73f758 100644 +--- a/docs/system/i386/sgx.rst ++++ b/docs/system/i386/sgx.rst +@@ -141,8 +141,7 @@ To launch a SGX guest: + |qemu_system_x86| \\ + -cpu host,+sgx-provisionkey \\ + -object memory-backend-epc,id=mem1,size=64M,prealloc=on \\ +- -object memory-backend-epc,id=mem2,size=28M \\ +- -M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2 ++ -M sgx-epc.0.memdev=mem1,sgx-epc.0.node=0 + + Utilizing SGX in the guest requires a kernel/OS with SGX support. + The support can be determined in guest by:: +@@ -152,8 +151,32 @@ The support can be determined in guest by:: + and SGX epc info by:: + + $ dmesg | grep sgx +- [ 1.242142] sgx: EPC section 0x180000000-0x181bfffff +- [ 1.242319] sgx: EPC section 0x181c00000-0x1837fffff ++ [ 0.182807] sgx: EPC section 0x140000000-0x143ffffff ++ [ 0.183695] sgx: [Firmware Bug]: Unable to map EPC section to online node. Fallback to the NUMA node 0. ++ ++To launch a SGX numa guest: ++ ++.. parsed-literal:: ++ ++ |qemu_system_x86| \\ ++ -cpu host,+sgx-provisionkey \\ ++ -object memory-backend-ram,size=2G,host-nodes=0,policy=bind,id=node0 \\ ++ -object memory-backend-epc,id=mem0,size=64M,prealloc=on,host-nodes=0,policy=bind \\ ++ -numa node,nodeid=0,cpus=0-1,memdev=node0 \\ ++ -object memory-backend-ram,size=2G,host-nodes=1,policy=bind,id=node1 \\ ++ -object memory-backend-epc,id=mem1,size=28M,prealloc=on,host-nodes=1,policy=bind \\ ++ -numa node,nodeid=1,cpus=2-3,memdev=node1 \\ ++ -M sgx-epc.0.memdev=mem0,sgx-epc.0.node=0,sgx-epc.1.memdev=mem1,sgx-epc.1.node=1 ++ ++and SGX epc numa info by:: ++ ++ $ dmesg | grep sgx ++ [ 0.369937] sgx: EPC section 0x180000000-0x183ffffff ++ [ 0.370259] sgx: EPC section 0x184000000-0x185bfffff ++ ++ $ dmesg | grep SRAT ++ [ 0.009981] ACPI: SRAT: Node 0 PXM 0 [mem 0x180000000-0x183ffffff] ++ [ 0.009982] ACPI: SRAT: Node 1 PXM 1 [mem 0x184000000-0x185bfffff] + + References + ---------- +-- +2.27.0 + diff --git a/doc-Update-multi-thread-compression-doc.patch b/doc-Update-multi-thread-compression-doc.patch index 33ef835acaf040ed3a404b6f0314a9e5c4af0673..d020d23bb07bd6ec16f5e6470b760c72b33f6275 100644 --- a/doc-Update-multi-thread-compression-doc.patch +++ b/doc-Update-multi-thread-compression-doc.patch @@ -1,10 +1,11 @@ -From 642df85795097017e9370a9721f702cbec50c173 Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From 213bd45d2c5337f10216c69c13f0438dd40c58d8 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 16:36:47 +0800 -Subject: [PATCH] doc: Update multi-thread compression doc +Subject: [PATCH 14/14] doc: Update multi-thread compression doc Modify the doc to fit the previous changes. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- diff --git a/docs-Add-generic-vhost-vdpa-device-documentation.patch b/docs-Add-generic-vhost-vdpa-device-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..19572c705f06992a0c111a3c252ea9b7434dd782 --- /dev/null +++ b/docs-Add-generic-vhost-vdpa-device-documentation.patch @@ -0,0 +1,76 @@ +From 8e62b2af62ea165f6bb7dbd1128ed1542a63eb6b Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 12 Nov 2022 22:40:13 +0800 +Subject: [PATCH 6/7] docs: Add generic vhost-vdpa device documentation + +Signed-off-by: Longpeng +--- + docs/system/device-emulation.rst | 1 + + .../devices/vhost-vdpa-generic-device.rst | 46 +++++++++++++++++++ + 2 files changed, 47 insertions(+) + create mode 100644 docs/system/devices/vhost-vdpa-generic-device.rst + +diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst +index 19944f526c..ef299a2fcd 100644 +--- a/docs/system/device-emulation.rst ++++ b/docs/system/device-emulation.rst +@@ -89,3 +89,4 @@ Emulated Devices + devices/vhost-user.rst + devices/virtio-pmem.rst + devices/vhost-user-rng.rst ++ devices/vhost-vdpa-generic-device.rst +diff --git a/docs/system/devices/vhost-vdpa-generic-device.rst b/docs/system/devices/vhost-vdpa-generic-device.rst +new file mode 100644 +index 0000000000..25fbcac60e +--- /dev/null ++++ b/docs/system/devices/vhost-vdpa-generic-device.rst +@@ -0,0 +1,46 @@ ++ ++========================= ++vhost-vDPA generic device ++========================= ++ ++This document explains the usage of the vhost-vDPA generic device. ++ ++Description ++----------- ++ ++vDPA(virtio data path acceleration) device is a device that uses a datapath ++which complies with the virtio specifications with vendor specific control ++path. ++ ++QEMU provides two types of vhost-vDPA devices to enable the vDPA device, one ++is type sensitive which means QEMU needs to know the actual device type ++(e.g. net, blk, scsi) and another is called "vhost-vDPA generic device" which ++is type insensitive ++ ++The vhost-vDPA generic device builds on the vhost-vdpa subsystem and virtio ++subsystem. It is quite small, but it can support any type of virtio device. ++ ++Examples ++-------- ++ ++Prepare the vhost-vDPA backends first: ++ ++:: ++ host# ls -l /dev/vhost-vdpa-* ++ crw------- 1 root root 236, 0 Nov 2 00:49 /dev/vhost-vdpa-0 ++ ++Start QEMU with virtio-mmio bus: ++ ++:: ++ host# qemu-system \ ++ -M microvm -m 512 -smp 2 -kernel ... -initrd ... \ ++ -device vhost-vdpa-device,vhostdev=/dev/vhost-vdpa-0 \ ++ ... ++ ++Start QEMU with virtio-pci bus: ++ ++:: ++ host# qemu-system \ ++ -M pc -m 512 -smp 2 \ ++ -device vhost-vdpa-device-pci,vhostdev=/dev/vhost-vdpa-0 \ ++ ...\ +-- +2.27.0 + diff --git a/docs-about-build-platforms-Refine-the-distro-support.patch b/docs-about-build-platforms-Refine-the-distro-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..f775939d8a7669f61a887e112eeb2ec33af3bc47 --- /dev/null +++ b/docs-about-build-platforms-Refine-the-distro-support.patch @@ -0,0 +1,40 @@ +From 97db7448bb28e42fae5acb3eb556cfa03a11e0a8 Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Wed, 2 Aug 2023 00:02:08 -0700 +Subject: [PATCH] docs/about/build-platforms: Refine the distro support policy + +cherry picked from commit 270629024df1f9f4e704ce8325f958858c5cbff7 + +For long-term distributions that release a new version only very +seldom, we limit the support to five years after the initial release. +Otherwise, we might need to support distros like openSUSE 15 for +up to 7 or even more years in total due to our "two more years +after the next major release" rule, which is just way too much to +handle in a project like QEMU that only has limited human resources. + +Message-Id: <20230223193257.1068205-1-thuth@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Thomas Huth + +Signed-off-by: Wanghe Xiao +--- + docs/about/build-platforms.rst | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst +index c29a4b8fe6..d893a2be1c 100644 +--- a/docs/about/build-platforms.rst ++++ b/docs/about/build-platforms.rst +@@ -67,7 +67,8 @@ Non-supported architectures may be removed in the future following the + Linux OS, macOS, FreeBSD, NetBSD, OpenBSD + ----------------------------------------- + +-The project aims to support the most recent major version at all times. Support ++The project aims to support the most recent major version at all times for ++up to five years after its initial release. Support + for the previous major version will be dropped 2 years after the new major + version is released or when the vendor itself drops support, whichever comes + first. In this context, third-party efforts to extend the lifetime of a distro +-- +2.41.0.windows.1 + diff --git a/docs-specs-Add-ACPI-GED-documentation.patch b/docs-specs-Add-ACPI-GED-documentation.patch deleted file mode 100644 index 46e8c17483ba33af2b75e954233c3cbdc5c7cddc..0000000000000000000000000000000000000000 --- a/docs-specs-Add-ACPI-GED-documentation.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 9c1752703fb8a5b70985cf4c9caabc3388c5953b Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:31 +0100 -Subject: [PATCH] docs/specs: Add ACPI GED documentation - -Documents basic concepts of ACPI Generic Event device(GED) -and interface between QEMU and the ACPI BIOS. - -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Message-Id: <20190918130633.4872-10-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - docs/specs/acpi_hw_reduced_hotplug.rst | 70 ++++++++++++++++++++++++++ - docs/specs/index.rst | 1 + - 2 files changed, 71 insertions(+) - create mode 100644 docs/specs/acpi_hw_reduced_hotplug.rst - -diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst -new file mode 100644 -index 0000000000..911a98255b ---- /dev/null -+++ b/docs/specs/acpi_hw_reduced_hotplug.rst -@@ -0,0 +1,70 @@ -+================================================== -+QEMU and ACPI BIOS Generic Event Device interface -+================================================== -+ -+The ACPI *Generic Event Device* (GED) is a HW reduced platform -+specific device introduced in ACPI v6.1 that handles all platform -+events, including the hotplug ones. GED is modelled as a device -+in the namespace with a _HID defined to be ACPI0013. This document -+describes the interface between QEMU and the ACPI BIOS. -+ -+GED allows HW reduced platforms to handle interrupts in ACPI ASL -+statements. It follows a very similar approach to the _EVT method -+from GPIO events. All interrupts are listed in _CRS and the handler -+is written in _EVT method. However, the QEMU implementation uses a -+single interrupt for the GED device, relying on an IO memory region -+to communicate the type of device affected by the interrupt. This way, -+we can support up to 32 events with a unique interrupt. -+ -+**Here is an example,** -+ -+:: -+ -+ Device (\_SB.GED) -+ { -+ Name (_HID, "ACPI0013") -+ Name (_UID, Zero) -+ Name (_CRS, ResourceTemplate () -+ { -+ Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) -+ { -+ 0x00000029, -+ } -+ }) -+ OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) -+ Field (EREG, DWordAcc, NoLock, WriteAsZeros) -+ { -+ ESEL, 32 -+ } -+ Method (_EVT, 1, Serialized) -+ { -+ Local0 = ESEL // ESEL = IO memory region which specifies the -+ // device type. -+ If (((Local0 & One) == One)) -+ { -+ MethodEvent1() -+ } -+ If ((Local0 & 0x2) == 0x2) -+ { -+ MethodEvent2() -+ } -+ ... -+ } -+ } -+ -+GED IO interface (4 byte access) -+-------------------------------- -+**read access:** -+ -+:: -+ -+ [0x0-0x3] Event selector bit field (32 bit) set by QEMU. -+ -+ bits: -+ 0: Memory hotplug event -+ 1: System power down event -+ 2-31: Reserved -+ -+**write_access:** -+ -+Nothing is expected to be written into GED IO memory -diff --git a/docs/specs/index.rst b/docs/specs/index.rst -index 40adb97c5e..984ba44029 100644 ---- a/docs/specs/index.rst -+++ b/docs/specs/index.rst -@@ -12,3 +12,4 @@ Contents: - - ppc-xive - ppc-spapr-xive -+ acpi_hw_reduced_hotplug --- -2.19.1 diff --git a/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch b/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch deleted file mode 100644 index f0be64a937fd5b1f78c54f5f74854f388c023786..0000000000000000000000000000000000000000 --- a/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch +++ /dev/null @@ -1,66 +0,0 @@ -From dd7f6cc3bcd71681920e3530f2c53041c812c5d3 Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Thu, 5 Mar 2020 17:51:46 +0100 -Subject: [PATCH 16/19] docs/specs/tpm: Document TPM_TIS sysbus device for ARM - -Update the documentation with recent changes related to the -sysbus TPM_TIS device addition and add the command line -to be used with arm VIRT. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Message-id: 20200305165149.618-8-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - docs/specs/tpm.rst | 25 ++++++++++++++++++++++++- - 1 file changed, 24 insertions(+), 1 deletion(-) - -diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst -index 2bdf637f..da9eb39c 100644 ---- a/docs/specs/tpm.rst -+++ b/docs/specs/tpm.rst -@@ -18,9 +18,15 @@ The TIS interface makes a memory mapped IO region in the area - 0xfed40000-0xfed44fff available to the guest operating system. - - QEMU files related to TPM TIS interface: -- - ``hw/tpm/tpm_tis.c`` -+ - ``hw/tpm/tpm_tis_common.c`` -+ - ``hw/tpm/tpm_tis_isa.c`` -+ - ``hw/tpm/tpm_tis_sysbus.c`` - - ``hw/tpm/tpm_tis.h`` - -+Both an ISA device and a sysbus device are available. The former is -+used with pc/q35 machine while the latter can be instantiated in the -+ARM virt machine. -+ - CRB interface - ------------- - -@@ -325,6 +331,23 @@ In case a pSeries machine is emulated, use the following command line: - -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ - -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 - -+In case an ARM virt machine is emulated, use the following command line: -+ -+.. code-block:: console -+ -+ qemu-system-aarch64 -machine virt,gic-version=3,accel=kvm \ -+ -cpu host -m 4G \ -+ -nographic -no-acpi \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-tis-device,tpmdev=tpm0 \ -+ -device virtio-blk-pci,drive=drv0 \ -+ -drive format=qcow2,file=hda.qcow2,if=none,id=drv0 \ -+ -drive if=pflash,format=raw,file=flash0.img,readonly \ -+ -drive if=pflash,format=raw,file=flash1.img -+ -+ On ARM, ACPI boot with TPM is not yet supported. -+ - In case SeaBIOS is used as firmware, it should show the TPM menu item - after entering the menu with 'ESC'. - --- -2.23.0 - diff --git a/docs-specs-tpm-reST-ify-TPM-documentation.patch b/docs-specs-tpm-reST-ify-TPM-documentation.patch deleted file mode 100644 index d4648994bde2fc4b68ce49f28f4a612f53e65551..0000000000000000000000000000000000000000 --- a/docs-specs-tpm-reST-ify-TPM-documentation.patch +++ /dev/null @@ -1,993 +0,0 @@ -From 5d1865496ca39f08142a0c1eb2c9b14ec1ec9140 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 21 Jan 2020 10:29:35 -0500 -Subject: [PATCH 09/19] docs/specs/tpm: reST-ify TPM documentation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Marc-André Lureau -Reviewed-by: Stefan Berger -Message-Id: <20200121152935.649898-7-stefanb@linux.ibm.com> -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - docs/specs/index.rst | 1 + - docs/specs/tpm.rst | 503 +++++++++++++++++++++++++++++++++++++++++++ - docs/specs/tpm.txt | 445 -------------------------------------- - 3 files changed, 504 insertions(+), 445 deletions(-) - create mode 100644 docs/specs/tpm.rst - delete mode 100644 docs/specs/tpm.txt - -diff --git a/docs/specs/index.rst b/docs/specs/index.rst -index 984ba440..de46a8b5 100644 ---- a/docs/specs/index.rst -+++ b/docs/specs/index.rst -@@ -13,3 +13,4 @@ Contents: - ppc-xive - ppc-spapr-xive - acpi_hw_reduced_hotplug -+ tpm -diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst -new file mode 100644 -index 00000000..2bdf637f ---- /dev/null -+++ b/docs/specs/tpm.rst -@@ -0,0 +1,503 @@ -+=============== -+QEMU TPM Device -+=============== -+ -+Guest-side hardware interface -+============================= -+ -+TIS interface -+------------- -+ -+The QEMU TPM emulation implements a TPM TIS hardware interface -+following the Trusted Computing Group's specification "TCG PC Client -+Specific TPM Interface Specification (TIS)", Specification Version -+1.3, 21 March 2013. (see the `TIS specification`_, or a later version -+of it). -+ -+The TIS interface makes a memory mapped IO region in the area -+0xfed40000-0xfed44fff available to the guest operating system. -+ -+QEMU files related to TPM TIS interface: -+ - ``hw/tpm/tpm_tis.c`` -+ - ``hw/tpm/tpm_tis.h`` -+ -+CRB interface -+------------- -+ -+QEMU also implements a TPM CRB interface following the Trusted -+Computing Group's specification "TCG PC Client Platform TPM Profile -+(PTP) Specification", Family "2.0", Level 00 Revision 01.03 v22, May -+22, 2017. (see the `CRB specification`_, or a later version of it) -+ -+The CRB interface makes a memory mapped IO region in the area -+0xfed40000-0xfed40fff (1 locality) available to the guest -+operating system. -+ -+QEMU files related to TPM CRB interface: -+ - ``hw/tpm/tpm_crb.c`` -+ -+SPAPR interface -+--------------- -+ -+pSeries (ppc64) machines offer a tpm-spapr device model. -+ -+QEMU files related to the SPAPR interface: -+ - ``hw/tpm/tpm_spapr.c`` -+ -+fw_cfg interface -+================ -+ -+The bios/firmware may read the ``"etc/tpm/config"`` fw_cfg entry for -+configuring the guest appropriately. -+ -+The entry of 6 bytes has the following content, in little-endian: -+ -+.. code-block:: c -+ -+ #define TPM_VERSION_UNSPEC 0 -+ #define TPM_VERSION_1_2 1 -+ #define TPM_VERSION_2_0 2 -+ -+ #define TPM_PPI_VERSION_NONE 0 -+ #define TPM_PPI_VERSION_1_30 1 -+ -+ struct FwCfgTPMConfig { -+ uint32_t tpmppi_address; /* PPI memory location */ -+ uint8_t tpm_version; /* TPM version */ -+ uint8_t tpmppi_version; /* PPI version */ -+ }; -+ -+ACPI interface -+============== -+ -+The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT -+and passes it into the guest through the fw_cfg device. The device -+description contains the base address of the TIS interface 0xfed40000 -+and the size of the MMIO area (0x5000). In case a TPM2 is used by -+QEMU, a TPM2 ACPI table is also provided. The device is described to -+be used in polling mode rather than interrupt mode primarily because -+no unused IRQ could be found. -+ -+To support measurement logs to be written by the firmware, -+e.g. SeaBIOS, a TCPA table is implemented. This table provides a 64kb -+buffer where the firmware can write its log into. For TPM 2 only a -+more recent version of the TPM2 table provides support for -+measurements logs and a TCPA table does not need to be created. -+ -+The TCPA and TPM2 ACPI tables follow the Trusted Computing Group -+specification "TCG ACPI Specification" Family "1.2" and "2.0", Level -+00 Revision 00.37. (see the `ACPI specification`_, or a later version -+of it) -+ -+ACPI PPI Interface -+------------------ -+ -+QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and -+TPM 2. This interface requires ACPI and firmware support. (see the -+`PPI specification`_) -+ -+PPI enables a system administrator (root) to request a modification to -+the TPM upon reboot. The PPI specification defines the operation -+requests and the actions the firmware has to take. The system -+administrator passes the operation request number to the firmware -+through an ACPI interface which writes this number to a memory -+location that the firmware knows. Upon reboot, the firmware finds the -+number and sends commands to the TPM. The firmware writes the TPM -+result code and the operation request number to a memory location that -+ACPI can read from and pass the result on to the administrator. -+ -+The PPI specification defines a set of mandatory and optional -+operations for the firmware to implement. The ACPI interface also -+allows an administrator to list the supported operations. In QEMU the -+ACPI code is generated by QEMU, yet the firmware needs to implement -+support on a per-operations basis, and different firmwares may support -+a different subset. Therefore, QEMU introduces the virtual memory -+device for PPI where the firmware can indicate which operations it -+supports and ACPI can enable the ones that are supported and disable -+all others. This interface lies in main memory and has the following -+layout: -+ -+ +-------------+--------+--------+-------------------------------------------+ -+ | Field | Length | Offset | Description | -+ +=============+========+========+===========================================+ -+ | ``func`` | 0x100 | 0x000 | Firmware sets values for each supported | -+ | | | | operation. See defined values below. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``ppin`` | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | -+ | | | | Not supported. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``ppip`` | 0x4 | 0x101 | ACPI function index to pass to SMM code. | -+ | | | | Set by ACPI. Not supported. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``pprp`` | 0x4 | 0x105 | Result of last executed operation. Set by | -+ | | | | firmware. See function index 5 for values.| -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``pprq`` | 0x4 | 0x109 | Operation request number to execute. See | -+ | | | | 'Physical Presence Interface Operation | -+ | | | | Summary' tables in specs. Set by ACPI. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``pprm`` | 0x4 | 0x10d | Operation request optional parameter. | -+ | | | | Values depend on operation. Set by ACPI. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``lppr`` | 0x4 | 0x111 | Last executed operation request number. | -+ | | | | Copied from pprq field by firmware. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``fret`` | 0x4 | 0x115 | Result code from SMM function. | -+ | | | | Not supported. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``res1`` | 0x40 | 0x119 | Reserved for future use | -+ +-------------+--------+--------+-------------------------------------------+ -+ |``next_step``| 0x1 | 0x159 | Operation to execute after reboot by | -+ | | | | firmware. Used by firmware. | -+ +-------------+--------+--------+-------------------------------------------+ -+ | ``movv`` | 0x1 | 0x15a | Memory overwrite variable | -+ +-------------+--------+--------+-------------------------------------------+ -+ -+The following values are supported for the ``func`` field. They -+correspond to the values used by ACPI function index 8. -+ -+ +----------+-------------------------------------------------------------+ -+ | Value | Description | -+ +==========+=============================================================+ -+ | 0 | Operation is not implemented. | -+ +----------+-------------------------------------------------------------+ -+ | 1 | Operation is only accessible through firmware. | -+ +----------+-------------------------------------------------------------+ -+ | 2 | Operation is blocked for OS by firmware configuration. | -+ +----------+-------------------------------------------------------------+ -+ | 3 | Operation is allowed and physically present user required. | -+ +----------+-------------------------------------------------------------+ -+ | 4 | Operation is allowed and physically present user is not | -+ | | required. | -+ +----------+-------------------------------------------------------------+ -+ -+The location of the table is given by the fw_cfg ``tpmppi_address`` -+field. The PPI memory region size is 0x400 (``TPM_PPI_ADDR_SIZE``) to -+leave enough room for future updates. -+ -+QEMU files related to TPM ACPI tables: -+ - ``hw/i386/acpi-build.c`` -+ - ``include/hw/acpi/tpm.h`` -+ -+TPM backend devices -+=================== -+ -+The TPM implementation is split into two parts, frontend and -+backend. The frontend part is the hardware interface, such as the TPM -+TIS interface described earlier, and the other part is the TPM backend -+interface. The backend interfaces implement the interaction with a TPM -+device, which may be a physical or an emulated device. The split -+between the front- and backend devices allows a frontend to be -+connected with any available backend. This enables the TIS interface -+to be used with the passthrough backend or the swtpm backend. -+ -+QEMU files related to TPM backends: -+ - ``backends/tpm.c`` -+ - ``include/sysemu/tpm_backend.h`` -+ - ``include/sysemu/tpm_backend_int.h`` -+ -+The QEMU TPM passthrough device -+------------------------------- -+ -+In case QEMU is run on Linux as the host operating system it is -+possible to make the hardware TPM device available to a single QEMU -+guest. In this case the user must make sure that no other program is -+using the device, e.g., /dev/tpm0, before trying to start QEMU with -+it. -+ -+The passthrough driver uses the host's TPM device for sending TPM -+commands and receiving responses from. Besides that it accesses the -+TPM device's sysfs entry for support of command cancellation. Since -+none of the state of a hardware TPM can be migrated between hosts, -+virtual machine migration is disabled when the TPM passthrough driver -+is used. -+ -+Since the host's TPM device will already be initialized by the host's -+firmware, certain commands, e.g. ``TPM_Startup()``, sent by the -+virtual firmware for device initialization, will fail. In this case -+the firmware should not use the TPM. -+ -+Sharing the device with the host is generally not a recommended usage -+scenario for a TPM device. The primary reason for this is that two -+operating systems can then access the device's single set of -+resources, such as platform configuration registers -+(PCRs). Applications or kernel security subsystems, such as the Linux -+Integrity Measurement Architecture (IMA), are not expecting to share -+PCRs. -+ -+QEMU files related to the TPM passthrough device: -+ - ``hw/tpm/tpm_passthrough.c`` -+ - ``hw/tpm/tpm_util.c`` -+ - ``hw/tpm/tpm_util.h`` -+ -+ -+Command line to start QEMU with the TPM passthrough device using the host's -+hardware TPM ``/dev/tpm0``: -+ -+.. code-block:: console -+ -+ qemu-system-x86_64 -display sdl -accel kvm \ -+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -+ -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ -+ -device tpm-tis,tpmdev=tpm0 test.img -+ -+ -+The following commands should result in similar output inside the VM -+with a Linux kernel that either has the TPM TIS driver built-in or -+available as a module: -+ -+.. code-block:: console -+ -+ # dmesg | grep -i tpm -+ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) -+ -+ # dmesg | grep TCPA -+ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ -+ BXPCTCPA 0000001 BXPC 00000001) -+ -+ # ls -l /dev/tpm* -+ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 -+ -+ # find /sys/devices/ | grep pcrs$ | xargs cat -+ PCR-00: 35 4E 3B CE 23 9F 38 59 ... -+ ... -+ PCR-23: 00 00 00 00 00 00 00 00 ... -+ -+The QEMU TPM emulator device -+---------------------------- -+ -+The TPM emulator device uses an external TPM emulator called 'swtpm' -+for sending TPM commands to and receiving responses from. The swtpm -+program must have been started before trying to access it through the -+TPM emulator with QEMU. -+ -+The TPM emulator implements a command channel for transferring TPM -+commands and responses as well as a control channel over which control -+commands can be sent. (see the `SWTPM protocol`_ specification) -+ -+The control channel serves the purpose of resetting, initializing, and -+migrating the TPM state, among other things. -+ -+The swtpm program behaves like a hardware TPM and therefore needs to -+be initialized by the firmware running inside the QEMU virtual -+machine. One necessary step for initializing the device is to send -+the TPM_Startup command to it. SeaBIOS, for example, has been -+instrumented to initialize a TPM 1.2 or TPM 2 device using this -+command. -+ -+QEMU files related to the TPM emulator device: -+ - ``hw/tpm/tpm_emulator.c`` -+ - ``hw/tpm/tpm_util.c`` -+ - ``hw/tpm/tpm_util.h`` -+ -+The following commands start the swtpm with a UnixIO control channel over -+a socket interface. They do not need to be run as root. -+ -+.. code-block:: console -+ -+ mkdir /tmp/mytpm1 -+ swtpm socket --tpmstate dir=/tmp/mytpm1 \ -+ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -+ --log level=20 -+ -+Command line to start QEMU with the TPM emulator device communicating -+with the swtpm (x86): -+ -+.. code-block:: console -+ -+ qemu-system-x86_64 -display sdl -accel kvm \ -+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-tis,tpmdev=tpm0 test.img -+ -+In case a pSeries machine is emulated, use the following command line: -+ -+.. code-block:: console -+ -+ qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ -+ -m 1024 -bios slof.bin -boot menu=on \ -+ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-spapr,tpmdev=tpm0 \ -+ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ -+ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ -+ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 -+ -+In case SeaBIOS is used as firmware, it should show the TPM menu item -+after entering the menu with 'ESC'. -+ -+.. code-block:: console -+ -+ Select boot device: -+ 1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] -+ [...] -+ 5. Legacy option rom -+ -+ t. TPM Configuration -+ -+The following commands should result in similar output inside the VM -+with a Linux kernel that either has the TPM TIS driver built-in or -+available as a module: -+ -+.. code-block:: console -+ -+ # dmesg | grep -i tpm -+ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) -+ -+ # dmesg | grep TCPA -+ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ -+ BXPCTCPA 0000001 BXPC 00000001) -+ -+ # ls -l /dev/tpm* -+ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 -+ -+ # find /sys/devices/ | grep pcrs$ | xargs cat -+ PCR-00: 35 4E 3B CE 23 9F 38 59 ... -+ ... -+ PCR-23: 00 00 00 00 00 00 00 00 ... -+ -+Migration with the TPM emulator -+=============================== -+ -+The TPM emulator supports the following types of virtual machine -+migration: -+ -+- VM save / restore (migration into a file) -+- Network migration -+- Snapshotting (migration into storage like QoW2 or QED) -+ -+The following command sequences can be used to test VM save / restore. -+ -+In a 1st terminal start an instance of a swtpm using the following command: -+ -+.. code-block:: console -+ -+ mkdir /tmp/mytpm1 -+ swtpm socket --tpmstate dir=/tmp/mytpm1 \ -+ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -+ --log level=20 --tpm2 -+ -+In a 2nd terminal start the VM: -+ -+.. code-block:: console -+ -+ qemu-system-x86_64 -display sdl -accel kvm \ -+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-tis,tpmdev=tpm0 \ -+ -monitor stdio \ -+ test.img -+ -+Verify that the attached TPM is working as expected using applications -+inside the VM. -+ -+To store the state of the VM use the following command in the QEMU -+monitor in the 2nd terminal: -+ -+.. code-block:: console -+ -+ (qemu) migrate "exec:cat > testvm.bin" -+ (qemu) quit -+ -+At this point a file called ``testvm.bin`` should exists and the swtpm -+and QEMU processes should have ended. -+ -+To test 'VM restore' you have to start the swtpm with the same -+parameters as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 -+must now be passed again on the command line. -+ -+In the 1st terminal restart the swtpm with the same command line as -+before: -+ -+.. code-block:: console -+ -+ swtpm socket --tpmstate dir=/tmp/mytpm1 \ -+ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -+ --log level=20 --tpm2 -+ -+In the 2nd terminal restore the state of the VM using the additional -+'-incoming' option. -+ -+.. code-block:: console -+ -+ qemu-system-x86_64 -display sdl -accel kvm \ -+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-tis,tpmdev=tpm0 \ -+ -incoming "exec:cat < testvm.bin" \ -+ test.img -+ -+Troubleshooting migration -+------------------------- -+ -+There are several reasons why migration may fail. In case of problems, -+please ensure that the command lines adhere to the following rules -+and, if possible, that identical versions of QEMU and swtpm are used -+at all times. -+ -+VM save and restore: -+ -+ - QEMU command line parameters should be identical apart from the -+ '-incoming' option on VM restore -+ -+ - swtpm command line parameters should be identical -+ -+VM migration to 'localhost': -+ -+ - QEMU command line parameters should be identical apart from the -+ '-incoming' option on the destination side -+ -+ - swtpm command line parameters should point to two different -+ directories on the source and destination swtpm (--tpmstate dir=...) -+ (especially if different versions of libtpms were to be used on the -+ same machine). -+ -+VM migration across the network: -+ -+ - QEMU command line parameters should be identical apart from the -+ '-incoming' option on the destination side -+ -+ - swtpm command line parameters should be identical -+ -+VM Snapshotting: -+ - QEMU command line parameters should be identical -+ -+ - swtpm command line parameters should be identical -+ -+ -+Besides that, migration failure reasons on the swtpm level may include -+the following: -+ -+ - the versions of the swtpm on the source and destination sides are -+ incompatible -+ -+ - downgrading of TPM state may not be supported -+ -+ - the source and destination libtpms were compiled with different -+ compile-time options and the destination side refuses to accept the -+ state -+ -+ - different migration keys are used on the source and destination side -+ and the destination side cannot decrypt the migrated state -+ (swtpm ... --migration-key ... ) -+ -+ -+.. _TIS specification: -+ https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ -+ -+.. _CRB specification: -+ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ -+ -+ -+.. _ACPI specification: -+ https://trustedcomputinggroup.org/tcg-acpi-specification/ -+ -+.. _PPI specification: -+ https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ -+ -+.. _SWTPM protocol: -+ https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod -diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt -deleted file mode 100644 -index 9c3e67d8..00000000 ---- a/docs/specs/tpm.txt -+++ /dev/null -@@ -1,445 +0,0 @@ --QEMU TPM Device --=============== -- --= Guest-side Hardware Interface = -- --The QEMU TPM emulation implements a TPM TIS hardware interface following the --Trusted Computing Group's specification "TCG PC Client Specific TPM Interface --Specification (TIS)", Specification Version 1.3, 21 March 2013. This --specification, or a later version of it, can be accessed from the following --URL: -- --https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ -- --The TIS interface makes a memory mapped IO region in the area 0xfed40000 - --0xfed44fff available to the guest operating system. -- -- --QEMU files related to TPM TIS interface: -- - hw/tpm/tpm_tis.c -- - hw/tpm/tpm_tis.h -- -- --QEMU also implements a TPM CRB interface following the Trusted Computing --Group's specification "TCG PC Client Platform TPM Profile (PTP) --Specification", Family "2.0", Level 00 Revision 01.03 v22, May 22, 2017. --This specification, or a later version of it, can be accessed from the --following URL: -- --https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ -- --The CRB interface makes a memory mapped IO region in the area 0xfed40000 - --0xfed40fff (1 locality) available to the guest operating system. -- --QEMU files related to TPM CRB interface: -- - hw/tpm/tpm_crb.c -- -- --pSeries (ppc64) machines offer a tpm-spapr device model. -- --QEMU files related to the SPAPR interface: -- - hw/tpm/tpm_spapr.c -- --= fw_cfg interface = -- --The bios/firmware may read the "etc/tpm/config" fw_cfg entry for --configuring the guest appropriately. -- --The entry of 6 bytes has the following content, in little-endian: -- -- #define TPM_VERSION_UNSPEC 0 -- #define TPM_VERSION_1_2 1 -- #define TPM_VERSION_2_0 2 -- -- #define TPM_PPI_VERSION_NONE 0 -- #define TPM_PPI_VERSION_1_30 1 -- -- struct FwCfgTPMConfig { -- uint32_t tpmppi_address; /* PPI memory location */ -- uint8_t tpm_version; /* TPM version */ -- uint8_t tpmppi_version; /* PPI version */ -- }; -- --= ACPI Interface = -- --The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes --it into the guest through the fw_cfg device. The device description contains --the base address of the TIS interface 0xfed40000 and the size of the MMIO area --(0x5000). In case a TPM2 is used by QEMU, a TPM2 ACPI table is also provided. --The device is described to be used in polling mode rather than interrupt mode --primarily because no unused IRQ could be found. -- --To support measurement logs to be written by the firmware, e.g. SeaBIOS, a TCPA --table is implemented. This table provides a 64kb buffer where the firmware can --write its log into. For TPM 2 only a more recent version of the TPM2 table --provides support for measurements logs and a TCPA table does not need to be --created. -- --The TCPA and TPM2 ACPI tables follow the Trusted Computing Group specification --"TCG ACPI Specification" Family "1.2" and "2.0", Level 00 Revision 00.37. This --specification, or a later version of it, can be accessed from the following --URL: -- --https://trustedcomputinggroup.org/tcg-acpi-specification/ -- --== ACPI PPI Interface == -- --QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This --interface requires ACPI and firmware support. The specification can be found at --the following URL: -- --https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ -- --PPI enables a system administrator (root) to request a modification to the --TPM upon reboot. The PPI specification defines the operation requests and the --actions the firmware has to take. The system administrator passes the operation --request number to the firmware through an ACPI interface which writes this --number to a memory location that the firmware knows. Upon reboot, the firmware --finds the number and sends commands to the TPM. The firmware writes the TPM --result code and the operation request number to a memory location that ACPI can --read from and pass the result on to the administrator. -- --The PPI specification defines a set of mandatory and optional operations for --the firmware to implement. The ACPI interface also allows an administrator to --list the supported operations. In QEMU the ACPI code is generated by QEMU, yet --the firmware needs to implement support on a per-operations basis, and --different firmwares may support a different subset. Therefore, QEMU introduces --the virtual memory device for PPI where the firmware can indicate which --operations it supports and ACPI can enable the ones that are supported and --disable all others. This interface lies in main memory and has the following --layout: -- -- +----------+--------+--------+-------------------------------------------+ -- | Field | Length | Offset | Description | -- +----------+--------+--------+-------------------------------------------+ -- | func | 0x100 | 0x000 | Firmware sets values for each supported | -- | | | | operation. See defined values below. | -- +----------+--------+--------+-------------------------------------------+ -- | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | -- | | | | Not supported. | -- +----------+--------+--------+-------------------------------------------+ -- | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. | -- | | | | Set by ACPI. Not supported. | -- +----------+--------+--------+-------------------------------------------+ -- | pprp | 0x4 | 0x105 | Result of last executed operation. Set by | -- | | | | firmware. See function index 5 for values.| -- +----------+--------+--------+-------------------------------------------+ -- | pprq | 0x4 | 0x109 | Operation request number to execute. See | -- | | | | 'Physical Presence Interface Operation | -- | | | | Summary' tables in specs. Set by ACPI. | -- +----------+--------+--------+-------------------------------------------+ -- | pprm | 0x4 | 0x10d | Operation request optional parameter. | -- | | | | Values depend on operation. Set by ACPI. | -- +----------+--------+--------+-------------------------------------------+ -- | lppr | 0x4 | 0x111 | Last executed operation request number. | -- | | | | Copied from pprq field by firmware. | -- +----------+--------+--------+-------------------------------------------+ -- | fret | 0x4 | 0x115 | Result code from SMM function. | -- | | | | Not supported. | -- +----------+--------+--------+-------------------------------------------+ -- | res1 | 0x40 | 0x119 | Reserved for future use | -- +----------+--------+--------+-------------------------------------------+ -- | next_step| 0x1 | 0x159 | Operation to execute after reboot by | -- | | | | firmware. Used by firmware. | -- +----------+--------+--------+-------------------------------------------+ -- | movv | 0x1 | 0x15a | Memory overwrite variable | -- +----------+--------+--------+-------------------------------------------+ -- -- The following values are supported for the 'func' field. They correspond -- to the values used by ACPI function index 8. -- -- +----------+-------------------------------------------------------------+ -- | value | Description | -- +----------+-------------------------------------------------------------+ -- | 0 | Operation is not implemented. | -- +----------+-------------------------------------------------------------+ -- | 1 | Operation is only accessible through firmware. | -- +----------+-------------------------------------------------------------+ -- | 2 | Operation is blocked for OS by firmware configuration. | -- +----------+-------------------------------------------------------------+ -- | 3 | Operation is allowed and physically present user required. | -- +----------+-------------------------------------------------------------+ -- | 4 | Operation is allowed and physically present user is not | -- | | required. | -- +----------+-------------------------------------------------------------+ -- --The location of the table is given by the fw_cfg tpmppi_address field. --The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave --enough room for future updates. -- -- --QEMU files related to TPM ACPI tables: -- - hw/i386/acpi-build.c -- - include/hw/acpi/tpm.h -- -- --= TPM backend devices = -- --The TPM implementation is split into two parts, frontend and backend. The --frontend part is the hardware interface, such as the TPM TIS interface --described earlier, and the other part is the TPM backend interface. The backend --interfaces implement the interaction with a TPM device, which may be a physical --or an emulated device. The split between the front- and backend devices allows --a frontend to be connected with any available backend. This enables the TIS --interface to be used with the passthrough backend or the (future) swtpm backend. -- -- --QEMU files related to TPM backends: -- - backends/tpm.c -- - include/sysemu/tpm_backend.h -- - include/sysemu/tpm_backend_int.h -- -- --== The QEMU TPM passthrough device == -- --In case QEMU is run on Linux as the host operating system it is possible to --make the hardware TPM device available to a single QEMU guest. In this case the --user must make sure that no other program is using the device, e.g., /dev/tpm0, --before trying to start QEMU with it. -- --The passthrough driver uses the host's TPM device for sending TPM commands --and receiving responses from. Besides that it accesses the TPM device's sysfs --entry for support of command cancellation. Since none of the state of a --hardware TPM can be migrated between hosts, virtual machine migration is --disabled when the TPM passthrough driver is used. -- --Since the host's TPM device will already be initialized by the host's firmware, --certain commands, e.g. TPM_Startup(), sent by the virtual firmware for device --initialization, will fail. In this case the firmware should not use the TPM. -- --Sharing the device with the host is generally not a recommended usage scenario --for a TPM device. The primary reason for this is that two operating systems can --then access the device's single set of resources, such as platform configuration --registers (PCRs). Applications or kernel security subsystems, such as the --Linux Integrity Measurement Architecture (IMA), are not expecting to share PCRs. -- -- --QEMU files related to the TPM passthrough device: -- - hw/tpm/tpm_passthrough.c -- - hw/tpm/tpm_util.c -- - hw/tpm/tpm_util.h -- -- --Command line to start QEMU with the TPM passthrough device using the host's --hardware TPM /dev/tpm0: -- --qemu-system-x86_64 -display sdl -accel kvm \ -- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -- -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ -- -device tpm-tis,tpmdev=tpm0 test.img -- --The following commands should result in similar output inside the VM with a --Linux kernel that either has the TPM TIS driver built-in or available as a --module: -- --#> dmesg | grep -i tpm --[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) -- --#> dmesg | grep TCPA --[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ -- BXPCTCPA 0000001 BXPC 00000001) -- --#> ls -l /dev/tpm* --crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 -- --#> find /sys/devices/ | grep pcrs$ | xargs cat --PCR-00: 35 4E 3B CE 23 9F 38 59 ... --... --PCR-23: 00 00 00 00 00 00 00 00 ... -- -- --== The QEMU TPM emulator device == -- --The TPM emulator device uses an external TPM emulator called 'swtpm' for --sending TPM commands to and receiving responses from. The swtpm program --must have been started before trying to access it through the TPM emulator --with QEMU. -- --The TPM emulator implements a command channel for transferring TPM commands --and responses as well as a control channel over which control commands can --be sent. The specification for the control channel can be found here: -- --https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod -- -- --The control channel serves the purpose of resetting, initializing, and --migrating the TPM state, among other things. -- --The swtpm program behaves like a hardware TPM and therefore needs to be --initialized by the firmware running inside the QEMU virtual machine. --One necessary step for initializing the device is to send the TPM_Startup --command to it. SeaBIOS, for example, has been instrumented to initialize --a TPM 1.2 or TPM 2 device using this command. -- -- --QEMU files related to the TPM emulator device: -- - hw/tpm/tpm_emulator.c -- - hw/tpm/tpm_util.c -- - hw/tpm/tpm_util.h -- -- --The following commands start the swtpm with a UnixIO control channel over --a socket interface. They do not need to be run as root. -- --mkdir /tmp/mytpm1 --swtpm socket --tpmstate dir=/tmp/mytpm1 \ -- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -- --log level=20 -- --Command line to start QEMU with the TPM emulator device communicating with --the swtpm (x86): -- --qemu-system-x86_64 -display sdl -accel kvm \ -- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -- -tpmdev emulator,id=tpm0,chardev=chrtpm \ -- -device tpm-tis,tpmdev=tpm0 test.img -- --In case a pSeries machine is emulated, use the following command line: -- --qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ -- -m 1024 -bios slof.bin -boot menu=on \ -- -nodefaults -device VGA -device pci-ohci -device usb-kbd \ -- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -- -tpmdev emulator,id=tpm0,chardev=chrtpm \ -- -device tpm-spapr,tpmdev=tpm0 \ -- -device spapr-vscsi,id=scsi0,reg=0x00002000 \ -- -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ -- -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 -- -- --In case SeaBIOS is used as firmware, it should show the TPM menu item --after entering the menu with 'ESC'. -- --Select boot device: --1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] --[...] --5. Legacy option rom -- --t. TPM Configuration -- -- --The following commands should result in similar output inside the VM with a --Linux kernel that either has the TPM TIS driver built-in or available as a --module: -- --#> dmesg | grep -i tpm --[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) -- --#> dmesg | grep TCPA --[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ -- BXPCTCPA 0000001 BXPC 00000001) -- --#> ls -l /dev/tpm* --crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 -- --#> find /sys/devices/ | grep pcrs$ | xargs cat --PCR-00: 35 4E 3B CE 23 9F 38 59 ... --... --PCR-23: 00 00 00 00 00 00 00 00 ... -- -- --=== Migration with the TPM emulator === -- --The TPM emulator supports the following types of virtual machine migration: -- --- VM save / restore (migration into a file) --- Network migration --- Snapshotting (migration into storage like QoW2 or QED) -- --The following command sequences can be used to test VM save / restore. -- -- --In a 1st terminal start an instance of a swtpm using the following command: -- --mkdir /tmp/mytpm1 --swtpm socket --tpmstate dir=/tmp/mytpm1 \ -- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -- --log level=20 --tpm2 -- --In a 2nd terminal start the VM: -- --qemu-system-x86_64 -display sdl -accel kvm \ -- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -- -tpmdev emulator,id=tpm0,chardev=chrtpm \ -- -device tpm-tis,tpmdev=tpm0 \ -- -monitor stdio \ -- test.img -- --Verify that the attached TPM is working as expected using applications inside --the VM. -- --To store the state of the VM use the following command in the QEMU monitor in --the 2nd terminal: -- --(qemu) migrate "exec:cat > testvm.bin" --(qemu) quit -- --At this point a file called 'testvm.bin' should exists and the swtpm and QEMU --processes should have ended. -- --To test 'VM restore' you have to start the swtpm with the same parameters --as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be --passed again on the command line. -- --In the 1st terminal restart the swtpm with the same command line as before: -- --swtpm socket --tpmstate dir=/tmp/mytpm1 \ -- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ -- --log level=20 --tpm2 -- --In the 2nd terminal restore the state of the VM using the additional --'-incoming' option. -- --qemu-system-x86_64 -display sdl -accel kvm \ -- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -- -tpmdev emulator,id=tpm0,chardev=chrtpm \ -- -device tpm-tis,tpmdev=tpm0 \ -- -incoming "exec:cat < testvm.bin" \ -- test.img -- -- --Troubleshooting migration: -- --There are several reasons why migration may fail. In case of problems, --please ensure that the command lines adhere to the following rules and, --if possible, that identical versions of QEMU and swtpm are used at all --times. -- --VM save and restore: -- - QEMU command line parameters should be identical apart from the -- '-incoming' option on VM restore -- - swtpm command line parameters should be identical -- --VM migration to 'localhost': -- - QEMU command line parameters should be identical apart from the -- '-incoming' option on the destination side -- - swtpm command line parameters should point to two different -- directories on the source and destination swtpm (--tpmstate dir=...) -- (especially if different versions of libtpms were to be used on the -- same machine). -- --VM migration across the network: -- - QEMU command line parameters should be identical apart from the -- '-incoming' option on the destination side -- - swtpm command line parameters should be identical -- --VM Snapshotting: -- - QEMU command line parameters should be identical -- - swtpm command line parameters should be identical -- -- --Besides that, migration failure reasons on the swtpm level may include --the following: -- -- - the versions of the swtpm on the source and destination sides are -- incompatible -- - downgrading of TPM state may not be supported -- - the source and destination libtpms were compiled with different -- compile-time options and the destination side refuses to accept the -- state -- - different migration keys are used on the source and destination side -- and the destination side cannot decrypt the migrated state -- (swtpm ... --migration-key ... ) --- -2.23.0 - diff --git a/drive-backup-create-do_backup_common.patch b/drive-backup-create-do_backup_common.patch deleted file mode 100644 index cccbc2e967c1529f5072ac64cbad1f6de3c3aee1..0000000000000000000000000000000000000000 --- a/drive-backup-create-do_backup_common.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 98dcfbd5ee53f3be705df7acf37e8706533f494f Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:52 -0400 -Subject: [PATCH] drive-backup: create do_backup_common - -Create a common core that comprises the actual meat of what the backup API -boundary needs to do, and then switch drive-backup to use it. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20190709232550.10724-3-jsnow@redhat.com -Signed-off-by: John Snow ---- - blockdev.c | 102 ++++++++++++++++++++++++++++++----------------------- - 1 file changed, 57 insertions(+), 45 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 99c92b96d2..a29838a1c8 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3469,20 +3469,16 @@ out: - aio_context_release(aio_context); - } - --static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, -- Error **errp) -+/* Common QMP interface for drive-backup and blockdev-backup */ -+static BlockJob *do_backup_common(BackupCommon *backup, -+ BlockDriverState *bs, -+ BlockDriverState *target_bs, -+ AioContext *aio_context, -+ JobTxn *txn, Error **errp) - { -- BlockDriverState *bs; -- BlockDriverState *target_bs; -- BlockDriverState *source = NULL; - BlockJob *job = NULL; - BdrvDirtyBitmap *bmap = NULL; -- AioContext *aio_context; -- QDict *options = NULL; -- Error *local_err = NULL; -- int flags, job_flags = JOB_DEFAULT; -- int64_t size; -- bool set_backing_hd = false; -+ int job_flags = JOB_DEFAULT; - int ret; - - if (!backup->has_speed) { -@@ -3494,9 +3490,6 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - if (!backup->has_on_target_error) { - backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT; - } -- if (!backup->has_mode) { -- backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; -- } - if (!backup->has_job_id) { - backup->job_id = NULL; - } -@@ -3510,6 +3503,54 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - backup->compress = false; - } - -+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -+ if (ret < 0) { -+ return NULL; -+ } -+ -+ if (backup->has_bitmap) { -+ bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); -+ if (!bmap) { -+ error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); -+ return NULL; -+ } -+ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { -+ return NULL; -+ } -+ } -+ -+ if (!backup->auto_finalize) { -+ job_flags |= JOB_MANUAL_FINALIZE; -+ } -+ if (!backup->auto_dismiss) { -+ job_flags |= JOB_MANUAL_DISMISS; -+ } -+ -+ job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, -+ backup->sync, bmap, backup->compress, -+ backup->on_source_error, backup->on_target_error, -+ job_flags, NULL, NULL, txn, errp); -+ return job; -+} -+ -+static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, -+ Error **errp) -+{ -+ BlockDriverState *bs; -+ BlockDriverState *target_bs; -+ BlockDriverState *source = NULL; -+ BlockJob *job = NULL; -+ AioContext *aio_context; -+ QDict *options = NULL; -+ Error *local_err = NULL; -+ int flags; -+ int64_t size; -+ bool set_backing_hd = false; -+ -+ if (!backup->has_mode) { -+ backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; -+ } -+ - bs = bdrv_lookup_bs(backup->device, backup->device, errp); - if (!bs) { - return NULL; -@@ -3585,12 +3626,6 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - goto out; - } - -- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); -- if (ret < 0) { -- bdrv_unref(target_bs); -- goto out; -- } -- - if (set_backing_hd) { - bdrv_set_backing_hd(target_bs, source, &local_err); - if (local_err) { -@@ -3598,31 +3633,8 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, - } - } - -- if (backup->has_bitmap) { -- bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); -- if (!bmap) { -- error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); -- goto unref; -- } -- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { -- goto unref; -- } -- } -- if (!backup->auto_finalize) { -- job_flags |= JOB_MANUAL_FINALIZE; -- } -- if (!backup->auto_dismiss) { -- job_flags |= JOB_MANUAL_DISMISS; -- } -- -- job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, -- backup->sync, bmap, backup->compress, -- backup->on_source_error, backup->on_target_error, -- job_flags, NULL, NULL, txn, &local_err); -- if (local_err != NULL) { -- error_propagate(errp, local_err); -- goto unref; -- } -+ job = do_backup_common(qapi_DriveBackup_base(backup), -+ bs, target_bs, aio_context, txn, errp); - - unref: - bdrv_unref(target_bs); --- -2.27.0 - diff --git a/dsoundaudio-fix-crackling-audio-recordings.patch b/dsoundaudio-fix-crackling-audio-recordings.patch new file mode 100644 index 0000000000000000000000000000000000000000..a697ca842861bd82642cbb6b058528f124b47ea8 --- /dev/null +++ b/dsoundaudio-fix-crackling-audio-recordings.patch @@ -0,0 +1,62 @@ +From b1985a8f51ce0496aa4e8802c42a64b90f1f891d Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Mar 2023 02:50:07 +0000 +Subject: [PATCH] dsoundaudio: fix crackling audio recordings mainline + inclusion commit 9d90ceb27461d7d0d172fd941b812d511794a6c6 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +Audio recordings with the DirectSound backend don't sound right. +A look a the Microsoft online documentation tells us why. + +From the DirectSound Programming Guide, Capture Buffer Information: +'You can safely copy data from the buffer only up to the read +cursor.' + +Change the code to read up to the read cursor instead of the +capture cursor. + +Signed-off-by: Volker Rümelin +Message-Id: <20211226154017.6067-2-vr_qemu@t-online.de> +Signed-off-by: Gerd Hoffmann + +Signed-off-by: tangbinzy +--- + audio/dsoundaudio.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c +index cfc79c129e..3dd2c4d4a6 100644 +--- a/audio/dsoundaudio.c ++++ b/audio/dsoundaudio.c +@@ -536,13 +536,12 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size) + DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; + LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; + HRESULT hr; +- DWORD cpos, rpos, act_size; ++ DWORD rpos, act_size; + size_t req_size; + int err; + void *ret; + +- hr = IDirectSoundCaptureBuffer_GetCurrentPosition( +- dscb, &cpos, ds->first_time ? &rpos : NULL); ++ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, NULL, &rpos); + if (FAILED(hr)) { + dsound_logerr(hr, "Could not get capture buffer position\n"); + *size = 0; +@@ -554,7 +553,7 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size) + ds->first_time = false; + } + +- req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul); ++ req_size = audio_ring_dist(rpos, hw->pos_emul, hw->size_emul); + req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul)); + + if (req_size == 0) { +-- +2.27.0 + diff --git a/e1000-set-RX-descriptor-status-in-a-separate-operati.patch b/e1000-set-RX-descriptor-status-in-a-separate-operati.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffa0f9654e24dbee18add738aead20bf835d4adc --- /dev/null +++ b/e1000-set-RX-descriptor-status-in-a-separate-operati.patch @@ -0,0 +1,89 @@ +From dcebeb0f7acf549620faff1badf73baba04b2068 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 10:15:09 +0000 +Subject: [PATCH] e1000: set RX descriptor status in a separate operation + mainline inclusion commit 034d00d4858161e1d4cff82d8d230bce874a04d3 category: + bugfix + +--------------------------------------------------------------- + +The code of setting RX descriptor status field maybe work fine in +previously, however with the update of glibc version, it shows two +issues when guest using dpdk receive packets: + + 1. The dpdk has a certain probability getting wrong buffer_addr + + this impact may be not obvious, such as lost a packet once in + a while + + 2. The dpdk may consume a packet twice when scan the RX desc queue + over again + + this impact will lead a infinite wait in Qemu, since the RDT + (tail pointer) be inscreased to equal to RDH by unexpected, + which regard as the RX desc queue is full + +Write a whole of RX desc with DD flag on is not quite correct, because +when the underlying implementation of memcpy using XMM registers to +copy e1000_rx_desc (when AVX or something else CPU feature is usable), +the bytes order of desc writing to memory is indeterminacy + +We can use full-scale test case to reproduce the issue-2 by +https://github.com/BASM/qemu_dpdk_e1000_test (thanks to Leonid Myravjev) + +I also write a POC test case at https://github.com/cdkey/e1000_poc +which can reproduce both of them, and easy to verify the patch effect. + +The hw watchpoint also shows that, when Qemu using XMM related instructions +writing 16 bytes e1000_rx_desc, concurrent with DPDK using movb +writing 1 byte status, the final result of writing to memory will be one +of them, if it made by Qemu which DD flag is on, DPDK will consume it +again. + +Setting DD status in a separate operation, can prevent the impact of +disorder memory writing by memcpy, also avoid unexpected data when +concurrent writing status by qemu and guest dpdk. + +Links: https://lore.kernel.org/qemu-devel/20200102110504.GG121208@stefanha-x1.localdomain/T/ + +Reported-by: Leonid Myravjev +Cc: Stefan Hajnoczi +Cc: Paolo Bonzini +Cc: Michael S. Tsirkin +Cc: qemu-stable@nongnu.org +Tested-by: Jing Zhang +Reviewed-by: Frank Lee +Signed-off-by: Ding Hui +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + hw/net/e1000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index f5bc81296d..e26e0a64c1 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -979,7 +979,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) + base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; + pci_dma_read(d, base, &desc, sizeof(desc)); + desc.special = vlan_special; +- desc.status |= (vlan_status | E1000_RXD_STAT_DD); ++ desc.status &= ~E1000_RXD_STAT_DD; + if (desc.buffer_addr) { + if (desc_offset < size) { + size_t iov_copy; +@@ -1013,6 +1013,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) + DBGOUT(RX, "Null RX descriptor!!\n"); + } + pci_dma_write(d, base, &desc, sizeof(desc)); ++ desc.status |= (vlan_status | E1000_RXD_STAT_DD); ++ pci_dma_write(d, base + offsetof(struct e1000_rx_desc, status), ++ &desc.status, sizeof(desc.status)); + + if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) + s->mac_reg[RDH] = 0; +-- +2.27.0 + diff --git a/ehci-fix-queue-dev-null-ptr-dereference.patch b/ehci-fix-queue-dev-null-ptr-dereference.patch deleted file mode 100644 index 18114e984199f44d7689e939152ed160d6dc0292..0000000000000000000000000000000000000000 --- a/ehci-fix-queue-dev-null-ptr-dereference.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 901ac0dee4b17890db815d143a8efeeac5d105f7 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 21 Aug 2019 10:53:19 +0200 -Subject: [PATCH 1/5] ehci: fix queue->dev null ptr dereference - -In case we don't have a device for an active queue, just skip -processing the queue (same we do for inactive queues) and log -a guest bug. - -Reported-by: Guenter Roeck -Signed-off-by: Gerd Hoffmann -Tested-by: Guenter Roeck -Message-id: 20190821085319.13711-1-kraxel@redhat.com -(cherry-picked from commit 1be344b7ad25d572dadeee46d80f0103354352b2) ---- - hw/usb/hcd-ehci.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 62dab05..5f089f3 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -1834,6 +1834,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q) - ehci_set_state(q->ehci, q->async, EST_EXECUTING); - break; - } -+ } else if (q->dev == NULL) { -+ ehci_trace_guest_bug(q->ehci, "no device attached to queue"); -+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - } else { - p = ehci_alloc_packet(q); - p->qtdaddr = q->qtdaddr; --- -1.8.3.1 - diff --git a/elf2dmp-Fix-memory-leak-on-main-error-paths.patch b/elf2dmp-Fix-memory-leak-on-main-error-paths.patch deleted file mode 100644 index 219cec31e799c1f32912a717982740f08c70a3c0..0000000000000000000000000000000000000000 --- a/elf2dmp-Fix-memory-leak-on-main-error-paths.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 1f63f8c20a4cb7b752981ef07b2614bbea828b30 Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Wed, 26 Aug 2020 18:15:53 +0800 -Subject: [PATCH] elf2dmp: Fix memory leak on main() error paths - -The 'kdgb' is allocating memory in get_kdbg(), but it is not freed -in both fill_header() and fill_context() failed branches, fix it. - -Signed-off-by: AlexChen -Reviewed-by: Li Qiang -Reviewed-by: Viktor Prutyanov -Reviewed-by: Thomas Huth -Message-Id: <5F463659.8080101@huawei.com> -Signed-off-by: Laurent Vivier -(cherry-picked from commit 885538fdc9) ---- - contrib/elf2dmp/main.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c -index 9a2dbc2902..ac746e49e0 100644 ---- a/contrib/elf2dmp/main.c -+++ b/contrib/elf2dmp/main.c -@@ -568,12 +568,12 @@ int main(int argc, char *argv[]) - if (fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg, - KdVersionBlock, qemu_elf.state_nr)) { - err = 1; -- goto out_pdb; -+ goto out_kdbg; - } - - if (fill_context(kdbg, &vs, &qemu_elf)) { - err = 1; -- goto out_pdb; -+ goto out_kdbg; - } - - if (write_dump(&ps, &header, argv[2])) { --- -2.27.0 - diff --git a/es1370-check-total-frame-count-against-current-frame.patch b/es1370-check-total-frame-count-against-current-frame.patch deleted file mode 100644 index fb1e7a7cdfa6f8046b6aa2ebb270b557dcae14a5..0000000000000000000000000000000000000000 --- a/es1370-check-total-frame-count-against-current-frame.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 22bbf1a90ac11fe30e1665c09f9ad904683b6ddc Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 15 May 2020 01:36:08 +0530 -Subject: [PATCH 1/9] es1370: check total frame count against current frame - -A guest user may set channel frame count via es1370_write() -such that, in es1370_transfer_audio(), total frame count -'size' is lesser than the number of frames that are processed -'cnt'. - - int cnt = d->frame_cnt >> 16; - int size = d->frame_cnt & 0xffff; - -if (size < cnt), it results in incorrect calculations leading -to OOB access issue(s). Add check to avoid it. - -Reported-by: Ren Ding -Reported-by: Hanqing Zhao -Signed-off-by: Prasad J Pandit -Message-id: 20200514200608.1744203-1-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann ---- - hw/audio/es1370.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c -index 260c142b70..eff7d03ae1 100644 ---- a/hw/audio/es1370.c -+++ b/hw/audio/es1370.c -@@ -643,6 +643,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - int csc_bytes = (csc + 1) << d->shift; - int cnt = d->frame_cnt >> 16; - int size = d->frame_cnt & 0xffff; -+ if (size < cnt) { -+ return; -+ } - int left = ((size - cnt + 1) << 2) + d->leftover; - int transferred = 0; - int temp = audio_MIN (max, audio_MIN (left, csc_bytes)); -@@ -651,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - addr += (cnt << 2) + d->leftover; - - if (index == ADC_CHANNEL) { -- while (temp) { -+ while (temp > 0) { - int acquired, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); -@@ -669,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - else { - SWVoiceOut *voice = s->dac_voice[index]; - -- while (temp) { -+ while (temp > 0) { - int copied, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); --- -2.25.1 - diff --git a/esp-restrict-non-DMA-transfer-length-to-that-of-avai.patch b/esp-restrict-non-DMA-transfer-length-to-that-of-avai.patch new file mode 100644 index 0000000000000000000000000000000000000000..830404665fb97e44665f5a185ebb2c2650085eac --- /dev/null +++ b/esp-restrict-non-DMA-transfer-length-to-that-of-avai.patch @@ -0,0 +1,43 @@ +From 67f1bc4fc4d1864a55f6c626967defe5467f5134 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Wed, 13 Sep 2023 21:44:09 +0100 +Subject: [PATCH] esp: restrict non-DMA transfer length to that of available + data (CVE-2024-24474) + +In the case where a SCSI layer transfer is incorrectly terminated, it is +possible for a TI command to cause a SCSI buffer overflow due to the +expected transfer data length being less than the available data in the +FIFO. When this occurs the unsigned async_len variable underflows and +becomes a large offset which writes past the end of the allocated SCSI +buffer. + +Restrict the non-DMA transfer length to be the smallest of the expected +transfer length and the available FIFO data to ensure that it is no longer +possible for the SCSI buffer overflow to occur. + +Signed-off-by: Mark Cave-Ayland +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1810 +Reviewed-by: Thomas Huth +Message-ID: <20230913204410.65650-3-mark.cave-ayland@ilande.co.uk> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/esp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index f38231f8cd..435a81bbfd 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -754,7 +754,8 @@ static void esp_do_nodma(ESPState *s) + } + + if (to_device) { +- len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ); ++ len = MIN(s->async_len, ESP_FIFO_SZ); ++ len = MIN(len, fifo8_num_used(&s->fifo)); + esp_fifo_pop_buf(&s->fifo, s->async_buf, len); + s->async_buf += len; + s->async_len -= len; +-- +2.27.0 + diff --git a/exec-memory-Extract-address_space_set-from-dma_memor.patch b/exec-memory-Extract-address_space_set-from-dma_memor.patch new file mode 100644 index 0000000000000000000000000000000000000000..e42d70b2c6bf139a5e200a1e6dee186672691e12 --- /dev/null +++ b/exec-memory-Extract-address_space_set-from-dma_memor.patch @@ -0,0 +1,116 @@ +From d9a1de34f34c853dc8596ba64b5d9c5d33c2f0cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Sat, 15 Jan 2022 21:37:23 +0100 +Subject: [PATCH 1/5] exec/memory: Extract address_space_set() from + dma_memory_set() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dma_memory_set() does a DMA barrier, set the address space with +a constant value. The constant value filling code is not specific +to DMA and can be used for AddressSpace. Extract it as a new +helper: address_space_set(). + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laurent Vivier +Reviewed-by: Stefano Garzarella +Reviewed-by: Richard Henderson +[lv: rebase] +Signed-off-by: Laurent Vivier +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Xu +Message-Id: <20220115203725.3834712-2-laurent@vivier.eu> +Signed-off-by: zhangxinhao +--- + include/exec/memory.h | 16 ++++++++++++++++ + softmmu/dma-helpers.c | 15 +-------------- + softmmu/physmem.c | 19 +++++++++++++++++++ + 3 files changed, 36 insertions(+), 14 deletions(-) + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 3e84d62e40..afa6039a9f 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -2966,6 +2966,22 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, + } + } + ++/** ++ * address_space_set: Fill address space with a constant byte. ++ * ++ * Return a MemTxResult indicating whether the operation succeeded ++ * or failed (eg unassigned memory, device rejected the transaction, ++ * IOMMU fault). ++ * ++ * @as: #AddressSpace to be accessed ++ * @addr: address within that address space ++ * @c: constant byte to fill the memory ++ * @len: the number of bytes to fill with the constant byte ++ * @attrs: memory transaction attributes ++ */ ++MemTxResult address_space_set(AddressSpace *as, hwaddr addr, ++ uint8_t c, hwaddr len, MemTxAttrs attrs); ++ + #ifdef NEED_CPU_H + /* enum device_endian to MemOp. */ + static inline MemOp devend_memop(enum device_endian end) +diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c +index b0be156479..c2028b6585 100644 +--- a/softmmu/dma-helpers.c ++++ b/softmmu/dma-helpers.c +@@ -23,20 +23,7 @@ MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr, + { + dma_barrier(as, DMA_DIRECTION_FROM_DEVICE); + +-#define FILLBUF_SIZE 512 +- uint8_t fillbuf[FILLBUF_SIZE]; +- int l; +- MemTxResult error = MEMTX_OK; +- +- memset(fillbuf, c, FILLBUF_SIZE); +- while (len > 0) { +- l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; +- error |= address_space_write(as, addr, attrs, fillbuf, l); +- len -= l; +- addr += l; +- } +- +- return error; ++ return address_space_set(as, addr, c, len, attrs); + } + + void qemu_sglist_init(QEMUSGList *qsg, DeviceState *dev, int alloc_hint, +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index be39a49ceb..0e709ae384 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -2983,6 +2983,25 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, + } + } + ++MemTxResult address_space_set(AddressSpace *as, hwaddr addr, ++ uint8_t c, hwaddr len, MemTxAttrs attrs) ++{ ++#define FILLBUF_SIZE 512 ++ uint8_t fillbuf[FILLBUF_SIZE]; ++ int l; ++ MemTxResult error = MEMTX_OK; ++ ++ memset(fillbuf, c, FILLBUF_SIZE); ++ while (len > 0) { ++ l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; ++ error |= address_space_write(as, addr, attrs, fillbuf, l); ++ len -= l; ++ addr += l; ++ } ++ ++ return error; ++} ++ + void cpu_physical_memory_rw(hwaddr addr, void *buf, + hwaddr len, bool is_write) + { +-- +2.27.0 + diff --git a/exec-set-map-length-to-zero-when-returning-NULL.patch b/exec-set-map-length-to-zero-when-returning-NULL.patch deleted file mode 100644 index 64c918e8d9de6eb3dd357c955d75488ff5f11c48..0000000000000000000000000000000000000000 --- a/exec-set-map-length-to-zero-when-returning-NULL.patch +++ /dev/null @@ -1,54 +0,0 @@ -From a1a9d6f908b21878daa7868313243c30b7a90fcf Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 26 May 2020 16:47:43 +0530 -Subject: [PATCH 2/9] exec: set map length to zero when returning NULL -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When mapping physical memory into host's virtual address space, -'address_space_map' may return NULL if BounceBuffer is in_use. -Set and return '*plen = 0' to avoid later NULL pointer dereference. - -Reported-by: Alexander Bulekov -Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 -Suggested-by: Paolo Bonzini -Suggested-by: Peter Maydell -Signed-off-by: Prasad J Pandit -Message-Id: <20200526111743.428367-1-ppandit@redhat.com> -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Paolo Bonzini ---- - exec.c | 1 + - include/exec/memory.h | 3 ++- - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/exec.c b/exec.c -index 3e78de3b8f..85c6d80353 100644 ---- a/exec.c -+++ b/exec.c -@@ -3739,6 +3739,7 @@ void *address_space_map(AddressSpace *as, - if (!memory_access_is_direct(mr, is_write)) { - if (atomic_xchg(&bounce.in_use, true)) { - rcu_read_unlock(); -+ *plen = 0; - return NULL; - } - /* Avoid unbounded allocations */ -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 611a89122d..dca8184277 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -2064,7 +2064,8 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, hwaddr len, - /* address_space_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 if resources needed to perform the mapping are exhausted. -+ * May return %NULL and set *@plen to zero(0), if resources needed to perform -+ * the mapping are exhausted. - * Use only for reads OR writes - not for read-modify-write operations. - * Use cpu_register_map_client() to know when retrying the map operation is - * likely to succeed. --- -2.25.1 - diff --git a/feature-Add-log-for-each-modules.patch b/feature-Add-log-for-each-modules.patch new file mode 100644 index 0000000000000000000000000000000000000000..62d2f1ad4960d4eca4d464d88a7d5c3b894a59e6 --- /dev/null +++ b/feature-Add-log-for-each-modules.patch @@ -0,0 +1,262 @@ +From 1a0b974a0aaff667a76972403c28c66416c2947b Mon Sep 17 00:00:00 2001 +From: "wangxinxin.wang@huawei.com" +Date: Tue, 27 Jun 2017 17:42:23 +0800 +Subject: [PATCH 2/3] feature: Add log for each modules + +add log for each modules. + +Signed-off-by: miaoyubo +Signed-off-by: Jingyi Wang +--- + accel/kvm/kvm-all.c | 5 ++++- + hw/char/virtio-serial-bus.c | 5 +++++ + hw/pci/pci.c | 1 + + hw/usb/bus.c | 6 ++++++ + hw/usb/host-libusb.c | 5 +++++ + hw/virtio/virtio-scsi-pci.c | 3 +++ + monitor/monitor.c | 1 + + monitor/qmp-cmds.c | 3 +++ + os-posix.c | 1 + + qapi/qmp-dispatch.c | 15 +++++++++++++++ + softmmu/qdev-monitor.c | 5 +++++ + 11 files changed, 49 insertions(+), 1 deletion(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index b128d311c2..8a98446b7c 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -1751,7 +1751,10 @@ void kvm_irqchip_commit_routes(KVMState *s) + s->irq_routes->flags = 0; + trace_kvm_irqchip_commit_routes(); + ret = kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes); +- assert(ret == 0); ++ if (ret < 0) { ++ error_report("Set GSI routing failed: %m"); ++ abort(); ++ } + } + + static void kvm_add_routing_entry(KVMState *s, +diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c +index f01ec2137c..edb7a44ee9 100644 +--- a/hw/char/virtio-serial-bus.c ++++ b/hw/char/virtio-serial-bus.c +@@ -257,6 +257,8 @@ static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id, + virtio_stw_p(vdev, &cpkt.value, value); + + trace_virtio_serial_send_control_event(port_id, event, value); ++ qemu_log("virtio serial port %d send control message" ++ " event = %d, value = %d\n", port_id, event, value); + return send_control_msg(vser, &cpkt, sizeof(cpkt)); + } + +@@ -364,6 +366,9 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) + cpkt.value = virtio_lduw_p(vdev, &gcpkt->value); + + trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value); ++ qemu_log("virtio serial port '%u' handle control message" ++ " event = %d, value = %d\n", ++ virtio_ldl_p(vdev, &gcpkt->id), cpkt.event, cpkt.value); + + if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) { + if (!cpkt.value) { +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 850735fc46..0743dc7c42 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -2411,6 +2411,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, + } else { + snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); + } ++ qemu_log("add rom file: %s\n", name); + pdev->has_rom = true; + memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, pdev->romsize, &error_fatal); + ptr = memory_region_get_ram_ptr(&pdev->rom); +diff --git a/hw/usb/bus.c b/hw/usb/bus.c +index 92d6ed5626..20cd9b6e6f 100644 +--- a/hw/usb/bus.c ++++ b/hw/usb/bus.c +@@ -536,6 +536,10 @@ void usb_check_attach(USBDevice *dev, Error **errp) + bus->qbus.name, port->path, portspeed); + return; + } ++ ++ qemu_log("attach usb device \"%s\" (%s speed) to VM bus \"%s\", " ++ "port \"%s\" (%s speed)\n", dev->product_desc, devspeed, ++ bus->qbus.name, port->path, portspeed); + } + + void usb_device_attach(USBDevice *dev, Error **errp) +@@ -564,6 +568,8 @@ int usb_device_detach(USBDevice *dev) + + usb_detach(port); + dev->attached = false; ++ qemu_log("detach usb device \"%s\" from VM bus \"%s\", port \"%s\"\n", ++ dev->product_desc, bus->qbus.name, port->path); + return 0; + } + +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index 8f521ad586..3394b04f50 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -992,6 +992,8 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) + + rc = libusb_open(dev, &s->dh); + if (rc != 0) { ++ qemu_log("libusb open usb device bus %d, device %d failed\n", ++ bus_num, addr); + goto fail; + } + } else { +@@ -1019,6 +1021,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) + + libusb_get_device_descriptor(dev, &s->ddesc); + usb_host_get_port(s->dev, s->port, sizeof(s->port)); ++ qemu_log("open a host usb device on bus %d, device %d\n", bus_num, addr); + + usb_ep_init(udev); + usb_host_ep_update(s); +@@ -1146,6 +1149,8 @@ static int usb_host_close(USBHostDevice *s) + usb_device_detach(udev); + } + ++ qemu_log("begin to reset the usb device, bus : %d, device : %d\n", ++ s->bus_num, s->addr); + usb_host_release_interfaces(s); + libusb_reset_device(s->dh); + usb_host_attach_kernel(s); +diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c +index 97fab74236..498f9e2c98 100644 +--- a/hw/virtio/virtio-scsi-pci.c ++++ b/hw/virtio/virtio-scsi-pci.c +@@ -18,6 +18,7 @@ + #include "hw/qdev-properties.h" + #include "hw/virtio/virtio-scsi.h" + #include "qemu/module.h" ++#include "qemu/log.h" + #include "virtio-pci.h" + #include "qom/object.h" + +@@ -51,6 +52,8 @@ static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + VirtIOSCSIConf *conf = &dev->vdev.parent_obj.conf; + char *bus_name; + ++ qemu_log("virtio scsi HBA %s begin to initialize.\n", ++ !proxy->id ? "NULL" : proxy->id); + if (conf->num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) { + conf->num_queues = + virtio_pci_optimal_num_queues(VIRTIO_SCSI_VQ_NUM_FIXED); +diff --git a/monitor/monitor.c b/monitor/monitor.c +index 621e79eb66..28206bedc4 100644 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -23,6 +23,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/log.h" + #include "monitor-internal.h" + #include "qapi/error.h" + #include "qapi/opts-visitor.h" +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index 98868cee03..d71beace6a 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -21,6 +21,7 @@ + #include "sysemu/sysemu.h" + #include "qemu/config-file.h" + #include "qemu/uuid.h" ++#include "qemu/log.h" + #include "chardev/char.h" + #include "ui/qemu-spice.h" + #include "ui/console.h" +@@ -150,8 +151,10 @@ void qmp_cont(Error **errp) + } + + if (runstate_check(RUN_STATE_INMIGRATE)) { ++ qemu_log("qmp cont is received in migration\n"); + autostart = 1; + } else { ++ qemu_log("qmp cont is received and vm is started\n"); + vm_start(); + } + } +diff --git a/os-posix.c b/os-posix.c +index ae6c9f2a5e..306c442bc8 100644 +--- a/os-posix.c ++++ b/os-posix.c +@@ -322,6 +322,7 @@ int os_mlock(void) + #ifdef HAVE_MLOCKALL + int ret = 0; + ++ qemu_log("do mlockall\n"); + ret = mlockall(MCL_CURRENT | MCL_FUTURE); + if (ret < 0) { + error_report("mlockall: %s", strerror(errno)); +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index bb005594d3..392ddb097c 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -26,6 +26,7 @@ + #include "qemu/coroutine.h" + #include "qemu/main-loop.h" + #include "qemu/log.h" ++#include "qapi/qmp/qstring.h" + + Visitor *qobject_input_visitor_new_qmp(QObject *obj) + { +@@ -221,6 +222,20 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, + + assert(!(oob && qemu_in_coroutine())); + assert(monitor_cur() == NULL); ++ ++ json = qobject_to_json(QOBJECT(args)); ++ if (json) { ++ if ((strcmp(command, "query-block-jobs") != 0) ++ && (strcmp(command, "query-migrate") != 0) ++ && (strcmp(command, "query-blockstats") != 0) ++ && (strcmp(command, "query-balloon") != 0) ++ && (strcmp(command, "set_password") != 0)) { ++ qemu_log("qmp_cmd_name: %s, arguments: %s\n", ++ command, json->str); ++ } ++ g_string_free(json, true); ++ } ++ + if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) { + monitor_set_cur(qemu_coroutine_self(), cur_mon); + cmd->fn(args, &ret, &err); +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 4a20f5dbd7..05e1d88d99 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -636,6 +636,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, + if (path != NULL) { + bus = qbus_find(path, errp); + if (!bus) { ++ qemu_log("can not find bus for %s\n", driver); + return NULL; + } + if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) { +@@ -706,6 +707,8 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, + object_set_properties_from_keyval(&dev->parent_obj, dev->opts, from_json, + errp); + if (*errp) { ++ qemu_log("the bus %s -driver %s set property failed\n", ++ bus ? bus->name : "None", driver); + goto err_del_dev; + } + qemu_log("add qdev %s:%s success\n", driver, dev->id ? dev->id : "none"); +@@ -730,6 +733,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + + ret = qdev_device_add_from_qdict(qdict, false, errp); + if (ret) { ++ qemu_log("add qdev %s:%s success\n", qemu_opt_get(opts, "driver"), ++ qemu_opts_id(opts) ? qemu_opts_id(opts) : "none"); + qemu_opts_del(opts); + } + qobject_unref(qdict); +-- +2.30.0 + diff --git a/feature-Add-logs-for-vm-start-and-destroy.patch b/feature-Add-logs-for-vm-start-and-destroy.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b6484d4c3f8186eb1f3863ffc34f3a46f3858bc --- /dev/null +++ b/feature-Add-logs-for-vm-start-and-destroy.patch @@ -0,0 +1,157 @@ +From afbf800fa1f5e104a5edf116db4956289990ebe1 Mon Sep 17 00:00:00 2001 +From: "wangxinxin.wang@huawei.com" +Date: Thu, 22 Jun 2017 08:30:04 +0800 +Subject: [PATCH 3/3] feature: Add logs for vm start and destroy + +Add QEMU_LOG for vm start and destroy + +Signed-off-by: miaoyubo +Signed-off-by: Jingyi Wang +--- + hw/acpi/core.c | 4 ++++ + hw/core/reset.c | 2 ++ + softmmu/main.c | 2 ++ + softmmu/runstate.c | 2 ++ + softmmu/vl.c | 6 ++++++ + 5 files changed, 16 insertions(+) + +diff --git a/hw/acpi/core.c b/hw/acpi/core.c +index 1e004d0078..eb631caa91 100644 +--- a/hw/acpi/core.c ++++ b/hw/acpi/core.c +@@ -24,6 +24,7 @@ + #include "hw/acpi/acpi.h" + #include "hw/nvram/fw_cfg.h" + #include "qemu/config-file.h" ++#include "qemu/log.h" + #include "qapi/error.h" + #include "qapi/opts-visitor.h" + #include "qapi/qapi-events-run-state.h" +@@ -560,13 +561,16 @@ static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) + uint16_t sus_typ = (val >> 10) & 7; + switch (sus_typ) { + case 0: /* soft power off */ ++ qemu_log("VM will be soft power off\n"); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + break; + case 1: ++ qemu_log("VM will be suspend state\n"); + qemu_system_suspend_request(); + break; + default: + if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ ++ qemu_log("VM will be S4 state\n"); + qapi_event_send_suspend_disk(); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } +diff --git a/hw/core/reset.c b/hw/core/reset.c +index 9c477f2bf5..e923723d38 100644 +--- a/hw/core/reset.c ++++ b/hw/core/reset.c +@@ -25,6 +25,7 @@ + + #include "qemu/osdep.h" + #include "qemu/queue.h" ++#include "qemu/log.h" + #include "sysemu/reset.h" + + /* reset/shutdown handler */ +@@ -64,6 +65,7 @@ void qemu_devices_reset(void) + { + QEMUResetEntry *re, *nre; + ++ qemu_log("reset all devices\n"); + /* reset all devices */ + QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) { + re->func(re->opaque); +diff --git a/softmmu/main.c b/softmmu/main.c +index 639c67ff48..0acb41bd30 100644 +--- a/softmmu/main.c ++++ b/softmmu/main.c +@@ -23,6 +23,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/log.h" + #include "qemu-common.h" + #include "sysemu/sysemu.h" + +@@ -47,6 +48,7 @@ int main(int argc, char **argv) + int main(int argc, char **argv, char **envp) + { + qemu_init(argc, argv, envp); ++ qemu_log("qemu enter main_loop\n"); + qemu_main_loop(); + qemu_cleanup(); + +diff --git a/softmmu/runstate.c b/softmmu/runstate.c +index 5736d908db..52fc3b7d6f 100644 +--- a/softmmu/runstate.c ++++ b/softmmu/runstate.c +@@ -708,9 +708,11 @@ static bool main_loop_should_exit(void) + } + if (qemu_powerdown_requested()) { + qemu_system_powerdown(); ++ qemu_log("domain is power down by outside operation\n"); + } + if (qemu_vmstop_requested(&r)) { + vm_stop(r); ++ qemu_log("domain is stopped by outside operation\n"); + } + return false; + } +diff --git a/softmmu/vl.c b/softmmu/vl.c +index d9e4c619d3..d8996f3d6e 100644 +--- a/softmmu/vl.c ++++ b/softmmu/vl.c +@@ -26,6 +26,7 @@ + #include "qemu-common.h" + #include "qemu/datadir.h" + #include "qemu/units.h" ++#include "qemu/log.h" + #include "exec/cpu-common.h" + #include "hw/qdev-properties.h" + #include "qapi/compat-policy.h" +@@ -2680,6 +2681,7 @@ static void qemu_create_cli_devices(void) + } + + /* init generic devices */ ++ qemu_log("device init start\n"); + rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE); + qemu_opts_foreach(qemu_find_opts("device"), + device_init_func, NULL, &error_fatal); +@@ -2819,6 +2821,7 @@ void qemu_init(int argc, char **argv, char **envp) + + qemu_init_subsystems(); + ++ qemu_log("qemu pid is %d, options parsing start\n", getpid()); + /* first pass of option parsing */ + optind = 1; + while (optind < argc) { +@@ -3027,6 +3030,7 @@ void qemu_init(int argc, char **argv, char **envp) + exit(0); + break; + case QEMU_OPTION_m: ++ qemu_log("memory options parse start\n"); + opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), + optarg, true); + if (!opts) { +@@ -3744,6 +3748,7 @@ void qemu_init(int argc, char **argv, char **envp) + */ + + machine_class = MACHINE_GET_CLASS(current_machine); ++ qemu_log("configure accelerator %s start\n", machine_class->name); + if (!qtest_enabled() && machine_class->deprecation_reason) { + error_report("Machine type '%s' is deprecated: %s", + machine_class->name, machine_class->deprecation_reason); +@@ -3757,6 +3762,7 @@ void qemu_init(int argc, char **argv, char **envp) + + qemu_create_late_backends(); + ++ qemu_log("machine init start\n"); + /* parse features once if machine provides default cpu_type */ + current_machine->cpu_type = machine_class->default_cpu_type; + if (cpu_option) { +-- +2.30.0 + diff --git a/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch b/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch deleted file mode 100644 index 28c1e3bc6837063888bb8c862fb1e629f70de8be..0000000000000000000000000000000000000000 --- a/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 94be73a20d42482cdf30115e672c36af2fe9068d Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Fri, 17 Jul 2020 12:54:26 +0200 -Subject: [PATCH 5/5] file-posix: Fix leaked fd in raw_open_common() error path - -Signed-off-by: Kevin Wolf -Message-Id: <20200717105426.51134-4-kwolf@redhat.com> -Reviewed-by: Max Reitz -Signed-off-by: Kevin Wolf -Signed-off-by: Zhenyu Ye ---- - block/file-posix.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/block/file-posix.c b/block/file-posix.c -index 2184aa98..1259bf58 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -671,6 +671,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, - bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; - ret = 0; - fail: -+ if (ret < 0 && s->fd != -1) { -+ qemu_close(s->fd); -+ } - if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { - unlink(filename); - } --- -2.22.0.windows.1 - diff --git a/file-posix-Handle-undetectable-alignment.patch b/file-posix-Handle-undetectable-alignment.patch deleted file mode 100644 index 87a97dc4fdd67b160b89726f2ec9425d868df325..0000000000000000000000000000000000000000 --- a/file-posix-Handle-undetectable-alignment.patch +++ /dev/null @@ -1,158 +0,0 @@ -From b4bbef6714a45ffd7b4a57e5a0522c7006f504a6 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Tue, 13 Aug 2019 21:21:03 +0300 -Subject: [PATCH] file-posix: Handle undetectable alignment - -In some cases buf_align or request_alignment cannot be detected: - -1. With Gluster, buf_align cannot be detected since the actual I/O is - done on Gluster server, and qemu buffer alignment does not matter. - Since we don't have alignment requirement, buf_align=1 is the best - value. - -2. With local XFS filesystem, buf_align cannot be detected if reading - from unallocated area. In this we must align the buffer, but we don't - know what is the correct size. Using the wrong alignment results in - I/O error. - -3. With Gluster backed by XFS, request_alignment cannot be detected if - reading from unallocated area. In this case we need to use the - correct alignment, and failing to do so results in I/O errors. - -4. With NFS, the server does not use direct I/O, so both buf_align cannot - be detected. In this case we don't need any alignment so we can use - buf_align=1 and request_alignment=1. - -These cases seems to work when storage sector size is 512 bytes, because -the current code starts checking align=512. If the check succeeds -because alignment cannot be detected we use 512. But this does not work -for storage with 4k sector size. - -To determine if we can detect the alignment, we probe first with -align=1. If probing succeeds, maybe there are no alignment requirement -(cases 1, 4) or we are probing unallocated area (cases 2, 3). Since we -don't have any way to tell, we treat this as undetectable alignment. If -probing with align=1 fails with EINVAL, but probing with one of the -expected alignments succeeds, we know that we found a working alignment. - -Practically the alignment requirements are the same for buffer -alignment, buffer length, and offset in file. So in case we cannot -detect buf_align, we can use request alignment. If we cannot detect -request alignment, we can fallback to a safe value. To use this logic, -we probe first request alignment instead of buf_align. - -Here is a table showing the behaviour with current code (the value in -parenthesis is the optimal value). - -Case Sector buf_align (opt) request_alignment (opt) result -====================================================================== -1 512 512 (1) 512 (512) OK -1 4096 512 (1) 4096 (4096) FAIL ----------------------------------------------------------------------- -2 512 512 (512) 512 (512) OK -2 4096 512 (4096) 4096 (4096) FAIL ----------------------------------------------------------------------- -3 512 512 (1) 512 (512) OK -3 4096 512 (1) 512 (4096) FAIL ----------------------------------------------------------------------- -4 512 512 (1) 512 (1) OK -4 4096 512 (1) 512 (1) OK - -Same cases with this change: - -Case Sector buf_align (opt) request_alignment (opt) result -====================================================================== -1 512 512 (1) 512 (512) OK -1 4096 4096 (1) 4096 (4096) OK ----------------------------------------------------------------------- -2 512 512 (512) 512 (512) OK -2 4096 4096 (4096) 4096 (4096) OK ----------------------------------------------------------------------- -3 512 4096 (1) 4096 (512) OK -3 4096 4096 (1) 4096 (4096) OK ----------------------------------------------------------------------- -4 512 4096 (1) 4096 (1) OK -4 4096 4096 (1) 4096 (1) OK - -I tested that provisioning VMs and copying disks on local XFS and -Gluster with 4k bytes sector size work now, resolving bugs [1],[2]. -I tested also on XFS, NFS, Gluster with 512 bytes sector size. - -[1] https://bugzilla.redhat.com/1737256 -[2] https://bugzilla.redhat.com/1738657 - -Signed-off-by: Nir Soffer -Signed-off-by: Kevin Wolf - -(cherry picked from commit a6b257a08e3d72219f03e461a52152672fec0612) - -Signed-off-by: Michael Roth ---- - block/file-posix.c | 36 +++++++++++++++++++++++++----------- - 1 file changed, 25 insertions(+), 11 deletions(-) - -diff --git a/block/file-posix.c b/block/file-posix.c -index c185f34..d5065c6 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -321,6 +321,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) - BDRVRawState *s = bs->opaque; - char *buf; - size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); -+ size_t alignments[] = {1, 512, 1024, 2048, 4096}; - - /* For SCSI generic devices the alignment is not really used. - With buffered I/O, we don't have any restrictions. */ -@@ -347,25 +348,38 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) - } - #endif - -- /* If we could not get the sizes so far, we can only guess them */ -- if (!s->buf_align) { -+ /* -+ * If we could not get the sizes so far, we can only guess them. First try -+ * to detect request alignment, since it is more likely to succeed. Then -+ * try to detect buf_align, which cannot be detected in some cases (e.g. -+ * Gluster). If buf_align cannot be detected, we fallback to the value of -+ * request_alignment. -+ */ -+ -+ if (!bs->bl.request_alignment) { -+ int i; - size_t align; -- buf = qemu_memalign(max_align, 2 * max_align); -- for (align = 512; align <= max_align; align <<= 1) { -- if (raw_is_io_aligned(fd, buf + align, max_align)) { -- s->buf_align = align; -+ buf = qemu_memalign(max_align, max_align); -+ for (i = 0; i < ARRAY_SIZE(alignments); i++) { -+ align = alignments[i]; -+ if (raw_is_io_aligned(fd, buf, align)) { -+ /* Fallback to safe value. */ -+ bs->bl.request_alignment = (align != 1) ? align : max_align; - break; - } - } - qemu_vfree(buf); - } - -- if (!bs->bl.request_alignment) { -+ if (!s->buf_align) { -+ int i; - size_t align; -- buf = qemu_memalign(s->buf_align, max_align); -- for (align = 512; align <= max_align; align <<= 1) { -- if (raw_is_io_aligned(fd, buf, align)) { -- bs->bl.request_alignment = align; -+ buf = qemu_memalign(max_align, 2 * max_align); -+ for (i = 0; i < ARRAY_SIZE(alignments); i++) { -+ align = alignments[i]; -+ if (raw_is_io_aligned(fd, buf + align, max_align)) { -+ /* Fallback to request_aligment. */ -+ s->buf_align = (align != 1) ? align : bs->bl.request_alignment; - break; - } - } --- -1.8.3.1 - diff --git a/fix-compilation-errors-of-sw64-architecture-on-x86-p.patch b/fix-compilation-errors-of-sw64-architecture-on-x86-p.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f2cdc1e05db186c75495d919353fb794f1c3755 --- /dev/null +++ b/fix-compilation-errors-of-sw64-architecture-on-x86-p.patch @@ -0,0 +1,25 @@ +From 58471cd8dcf8e6a66113ddf9bb4ac45c89bbd57b Mon Sep 17 00:00:00 2001 +From: lifeng 71117973 +Date: Wed, 2 Nov 2022 11:19:55 +0800 +Subject: [PATCH 1/2] fix compilation errors of sw64 architecture on x86 + platform + +--- + target/sw64/float_helper.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/target/sw64/float_helper.c b/target/sw64/float_helper.c +index ad1c3cce48..c8e0845afc 100644 +--- a/target/sw64/float_helper.c ++++ b/target/sw64/float_helper.c +@@ -653,7 +653,6 @@ void helper_ieee_input(CPUSW64State *env, uint64_t val) + { + #ifndef CONFIG_USER_ONLY + uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; +- uint64_t frac = val & 0xfffffffffffffull; + + if (exp == 0x7ff) { + /* Infinity or NaN. */ +-- +2.27.0 + diff --git a/fix-qemu-core-when-vhost-user-net-config-with-server.patch b/fix-qemu-core-when-vhost-user-net-config-with-server.patch new file mode 100644 index 0000000000000000000000000000000000000000..a5253016a612d1faf009a6245a1288e7ec659817 --- /dev/null +++ b/fix-qemu-core-when-vhost-user-net-config-with-server.patch @@ -0,0 +1,46 @@ +From 228609b7d942639a1ac8a9ba2816b6bb7cbc5ab8 Mon Sep 17 00:00:00 2001 +From: caojinhuahw +Date: Mon, 19 Dec 2022 12:35:50 +0000 +Subject: [PATCH 2/2] fix qemu-core when vhost-user-net config with server mode + +commit 3a223111d7 set default reconnect for vhost-user-net +device, if vhost-user-net config with server mode will +casuse the core when ovs client stop. +tcp_chr_disconnect ---> set tcp_char state disconnect +tcp_chr start reconnect ---> set tcp_char state connecting +tcp_char is listen ---> call tcp_chr_accept() +fun tcp_char_accept() set tcp_char state to connecting, but +current tcp_char state already is connecting, assert failed +in tcp_char_change_state() raise qemu core + assert(s->state == TCP_CHARDEV_STATE_DISCONNECTED) + +this commit check tcp_char mode, if tcp_char config with server +mode, dont set reconnect time for tcp_chr. + +fix: 3a223111d7 vhost-user: Add support reconnect vhost-user socket + +Signed-off-by: caojinhuahw +--- + chardev/char-socket.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index b1e9f43ec6..57ae53304a 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -403,6 +403,12 @@ static void tcp_chr_set_reconnect_time(Chardev *chr, + void qemu_chr_set_reconnect_time(Chardev *chr, int64_t reconnect_time) + { + ChardevClass *cc = CHARDEV_GET_CLASS(chr); ++ SocketChardev *s = SOCKET_CHARDEV(chr); ++ ++ /* if sock dev is listen, dont set reconnect time */ ++ if (s->is_listen) { ++ return; ++ } + + if (cc->chr_set_reconnect_time) { + cc->chr_set_reconnect_time(chr, reconnect_time); +-- +2.27.0 + diff --git a/fix-qmp-command-migrate-set-parameters.patch b/fix-qmp-command-migrate-set-parameters.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab7fb31af146319002d90ab407b35c099e4647e9 --- /dev/null +++ b/fix-qmp-command-migrate-set-parameters.patch @@ -0,0 +1,31 @@ +From 05526b64c8201bb7395927a81ceef3723c1ce57e Mon Sep 17 00:00:00 2001 +From: mayunlong +Date: Fri, 23 Dec 2022 10:43:46 +0800 +Subject: [PATCH] fix qmp command migrate-set-parameters + +params didn't apply after excute qmp command migrate-set-parameters, +this resulted in another qmp command(query-migrate-parameters) error. + +Signed-off-by:mayunlong +--- + migration/migration.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/migration/migration.c b/migration/migration.c +index 33d5832e47..2ec116f901 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1621,6 +1621,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) + s->parameters.decompress_threads = params->decompress_threads; + } + ++ if (params->has_compress_method) { ++ s->parameters.compress_method = params->compress_method; ++ } ++ + if (params->has_throttle_trigger_threshold) { + s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold; + } +-- +2.27.0 + diff --git a/fix-vhost_user_blk_watch-crash.patch b/fix-vhost_user_blk_watch-crash.patch deleted file mode 100644 index 905cbe3c2542b7d59f8d69da720bf0639a4be9bb..0000000000000000000000000000000000000000 --- a/fix-vhost_user_blk_watch-crash.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0b77995819a596f96c621697643e83624126e668 Mon Sep 17 00:00:00 2001 -From: Li Feng -Date: Mon, 23 Mar 2020 13:29:24 +0800 -Subject: [PATCH 13/14] fix vhost_user_blk_watch crash - -the G_IO_HUP is watched in tcp_chr_connect, and the callback -vhost_user_blk_watch is not needed, because tcp_chr_hup is registered as -callback. And it will close the tcp link. - -Signed-off-by: Li Feng -Message-Id: <20200323052924.29286-1-fengli@smartx.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Peng Liang ---- - hw/block/vhost-user-blk.c | 19 ------------------- - include/hw/virtio/vhost-user-blk.h | 1 - - 2 files changed, 20 deletions(-) - -diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c -index 85bc4017e7e9..dc66f8a5febd 100644 ---- a/hw/block/vhost-user-blk.c -+++ b/hw/block/vhost-user-blk.c -@@ -346,18 +346,6 @@ static void vhost_user_blk_disconnect(DeviceState *dev) - vhost_dev_cleanup(&s->dev); - } - --static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond, -- void *opaque) --{ -- DeviceState *dev = opaque; -- VirtIODevice *vdev = VIRTIO_DEVICE(dev); -- VHostUserBlk *s = VHOST_USER_BLK(vdev); -- -- qemu_chr_fe_disconnect(&s->chardev); -- -- return true; --} -- - static void vhost_user_blk_event(void *opaque, int event) - { - DeviceState *dev = opaque; -@@ -370,15 +358,9 @@ static void vhost_user_blk_event(void *opaque, int event) - qemu_chr_fe_disconnect(&s->chardev); - return; - } -- s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP, -- vhost_user_blk_watch, dev); - break; - case CHR_EVENT_CLOSED: - vhost_user_blk_disconnect(dev); -- if (s->watch) { -- g_source_remove(s->watch); -- s->watch = 0; -- } - break; - } - } -@@ -419,7 +401,6 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) - - s->inflight = g_new0(struct vhost_inflight, 1); - s->vqs = g_new(struct vhost_virtqueue, s->num_queues); -- s->watch = 0; - s->connected = false; - - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, -diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h -index 8dbf11c6f071..ad9b742a644c 100644 ---- a/include/hw/virtio/vhost-user-blk.h -+++ b/include/hw/virtio/vhost-user-blk.h -@@ -38,7 +38,6 @@ typedef struct VHostUserBlk { - struct vhost_inflight *inflight; - VhostUserState vhost_user; - struct vhost_virtqueue *vqs; -- guint watch; - bool connected; - } VHostUserBlk; - --- -2.26.2 - diff --git a/fixed-the-error-that-no-bios-file-soft-link-was-crea.patch b/fixed-the-error-that-no-bios-file-soft-link-was-crea.patch new file mode 100644 index 0000000000000000000000000000000000000000..4bc85c4d97a838a18ebe4f209b17d6009161c955 --- /dev/null +++ b/fixed-the-error-that-no-bios-file-soft-link-was-crea.patch @@ -0,0 +1,28 @@ +From cf6be03a1f5b7595a2ecada71fa8aa30de744703 Mon Sep 17 00:00:00 2001 +From: lifeng 71117973 +Date: Wed, 2 Nov 2022 17:20:50 +0800 +Subject: [PATCH 2/2] fixed the error that no bios file soft link was created + in the build directory when compiling the sw64 architecture + +--- + configure | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index 9569d7a3d0..0ae7bcf065 100755 +--- a/configure ++++ b/configure +@@ -3861,7 +3861,9 @@ for bios_file in \ + $source_path/pc-bios/u-boot.* \ + $source_path/pc-bios/edk2-*.fd.bz2 \ + $source_path/pc-bios/palcode-* \ +- $source_path/pc-bios/qemu_vga.ndrv ++ $source_path/pc-bios/qemu_vga.ndrv \ ++ $source_path/pc-bios/core* \ ++ $source_path/pc-bios/uefi-bios-sw + + do + LINKS="$LINKS pc-bios/$(basename $bios_file)" +-- +2.27.0 + diff --git a/fixup-compile-on-loongarch64-machine.patch b/fixup-compile-on-loongarch64-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..1dfe04895207aef9a2da3dc3fc3d9557b4e9814c --- /dev/null +++ b/fixup-compile-on-loongarch64-machine.patch @@ -0,0 +1,26 @@ +From c952962cda3daf05323b383485d834ffc8e16f4f Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Wed, 29 Mar 2023 02:48:04 -0400 +Subject: [PATCH] fixup compile on loongarch64 machine. + +Add function kvm_arch_accel_class_init definition on loongarch64 machine. + +Signed-off-by: lixianglai +--- + target/loongarch64/kvm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c +index 2b0159bb32..21f6d5695f 100644 +--- a/target/loongarch64/kvm.c ++++ b/target/loongarch64/kvm.c +@@ -1364,3 +1364,6 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) + { + abort(); + } ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +-- +2.27.0 + diff --git a/freeclock-add-qmp-command-to-get-time-offset-of-vm-i.patch b/freeclock-add-qmp-command-to-get-time-offset-of-vm-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..e16b514e4f0d8db9fe55a393ed1c9ce434228334 --- /dev/null +++ b/freeclock-add-qmp-command-to-get-time-offset-of-vm-i.patch @@ -0,0 +1,125 @@ +From 124d427a1fdae2d1eeed433093ec4ab78b81237e Mon Sep 17 00:00:00 2001 +From: "shenghualong@huawei.com" +Date: Thu, 10 Feb 2022 11:11:37 +0800 +Subject: [PATCH] freeclock: add qmp command to get time offset of vm in + seconds + +When setting the system time in VM, a RTC_CHANGE event will be reported. +However, if libvirt is restarted while the event is be reporting, the +event will be lost and we will get the old time (not the time we set in +VM) after rebooting the VM. + +We save the delta time in QEMU and add a rtc-date-diff qmp to get the +delta time so that libvirt can get the latest time in VM according to +the qmp after libvirt is restarted. + +Signed-off-by: Peng Liang +Signed-off-by: zhangxinhao +--- + include/qemu-common.h | 4 +++- + monitor/qmp-cmds.c | 5 +++++ + qapi/misc.json | 9 +++++++++ + qapi/pragma.json | 3 ++- + softmmu/rtc.c | 13 ++++++++++++- + 5 files changed, 31 insertions(+), 3 deletions(-) + +diff --git a/include/qemu-common.h b/include/qemu-common.h +index 73bcf763ed..9ed8832152 100644 +--- a/include/qemu-common.h ++++ b/include/qemu-common.h +@@ -27,7 +27,9 @@ int qemu_main(int argc, char **argv, char **envp); + #endif + + void qemu_get_timedate(struct tm *tm, int offset); +-int qemu_timedate_diff(struct tm *tm); ++time_t qemu_timedate_diff(struct tm *tm); ++time_t get_rtc_date_diff(void); ++void set_rtc_date_diff(time_t diff); + + void *qemu_oom_check(void *ptr); + +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index 343353e27a..98868cee03 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -466,3 +466,8 @@ HumanReadableText *qmp_x_query_irq(Error **errp) + + return human_readable_text_from_str(buf); + } ++ ++int64_t qmp_query_rtc_date_diff(Error **errp) ++{ ++ return get_rtc_date_diff(); ++} +diff --git a/qapi/misc.json b/qapi/misc.json +index 358548abe1..5b6d653682 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -527,3 +527,12 @@ + 'data': { '*option': 'str' }, + 'returns': ['CommandLineOptionInfo'], + 'allow-preconfig': true } ++ ++## ++# @query-rtc-date-diff: ++# ++# get vm's time offset ++# ++# Since: 2.8 ++## ++{ 'command': 'query-rtc-date-diff', 'returns': 'int64' } +diff --git a/qapi/pragma.json b/qapi/pragma.json +index 3bc0335d1f..b37f6de445 100644 +--- a/qapi/pragma.json ++++ b/qapi/pragma.json +@@ -26,7 +26,8 @@ + 'qom-get', + 'query-tpm-models', + 'query-tpm-types', +- 'ringbuf-read' ], ++ 'ringbuf-read', ++ 'query-rtc-date-diff' ], + # Externally visible types whose member names may use uppercase + 'member-name-exceptions': [ # visible in: + 'ACPISlotType', # query-acpi-ospm-status +diff --git a/softmmu/rtc.c b/softmmu/rtc.c +index 5632684fc9..57bb8bba7c 100644 +--- a/softmmu/rtc.c ++++ b/softmmu/rtc.c +@@ -43,6 +43,7 @@ static time_t rtc_ref_start_datetime; + static int rtc_realtime_clock_offset; /* used only with QEMU_CLOCK_REALTIME */ + static int rtc_host_datetime_offset = -1; /* valid & used only with + RTC_BASE_DATETIME */ ++static time_t rtc_date_diff = 0; + QEMUClockType rtc_clock; + /***********************************************************/ + /* RTC reference time/date access */ +@@ -84,7 +85,7 @@ void qemu_get_timedate(struct tm *tm, int offset) + } + } + +-int qemu_timedate_diff(struct tm *tm) ++time_t qemu_timedate_diff(struct tm *tm) + { + time_t seconds; + +@@ -107,6 +108,16 @@ int qemu_timedate_diff(struct tm *tm) + return seconds - qemu_ref_timedate(QEMU_CLOCK_HOST); + } + ++time_t get_rtc_date_diff(void) ++{ ++ return rtc_date_diff; ++} ++ ++void set_rtc_date_diff(time_t diff) ++{ ++ rtc_date_diff = diff; ++} ++ + static void configure_rtc_base_datetime(const char *startdate) + { + time_t rtc_start_datetime; +-- +2.27.0 + diff --git a/freeclock-set-rtc_date_diff-for-X86.patch b/freeclock-set-rtc_date_diff-for-X86.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab4e9d237bbb8c3f4e90808e45bbe6eeaa8c7f20 --- /dev/null +++ b/freeclock-set-rtc_date_diff-for-X86.patch @@ -0,0 +1,30 @@ +From 3d0846d864384be3d08a54ca6e2ce247a5cee952 Mon Sep 17 00:00:00 2001 +From: liuxiangdong +Date: Thu, 10 Feb 2022 14:25:30 +0800 +Subject: [PATCH] freeclock: set rtc_date_diff for X86 + +Set rtc_date_diff in mc146818rtc. + +Signed-off-by: liuxiangdong +Signed-off-by: zhangxinhao +--- + hw/rtc/mc146818rtc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c +index 4fbafddb22..af1df9aaeb 100644 +--- a/hw/rtc/mc146818rtc.c ++++ b/hw/rtc/mc146818rtc.c +@@ -616,7 +616,8 @@ static void rtc_set_time(RTCState *s) + s->base_rtc = mktimegm(&tm); + s->last_update = qemu_clock_get_ns(rtc_clock); + +- qapi_event_send_rtc_change(qemu_timedate_diff(&tm)); ++ set_rtc_date_diff(qemu_timedate_diff(&tm)); ++ qapi_event_send_rtc_change(get_rtc_date_diff()); + } + + static void rtc_set_cmos(RTCState *s, const struct tm *tm) +-- +2.27.0 + diff --git a/freeclock-set-rtc_date_diff-for-arm.patch b/freeclock-set-rtc_date_diff-for-arm.patch new file mode 100644 index 0000000000000000000000000000000000000000..6156fe13bd9406dcc0d38d37d8005c5ea6dada45 --- /dev/null +++ b/freeclock-set-rtc_date_diff-for-arm.patch @@ -0,0 +1,30 @@ +From 1e6bae1d13302594b6e63d88e8627fa477966cf4 Mon Sep 17 00:00:00 2001 +From: "shenghualong@huawei.com" +Date: Thu, 10 Feb 2022 14:23:28 +0800 +Subject: [PATCH] freeclock: set rtc_date_diff for arm + +Set rtc_date_diff in pl031. + +Signed-off-by: Peng Liang +Signed-off-by: zhangxinhao +--- + hw/rtc/pl031.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c +index e7ced90b02..da8b061e91 100644 +--- a/hw/rtc/pl031.c ++++ b/hw/rtc/pl031.c +@@ -143,7 +143,8 @@ static void pl031_write(void * opaque, hwaddr offset, + s->tick_offset += value - pl031_get_count(s); + + qemu_get_timedate(&tm, s->tick_offset); +- qapi_event_send_rtc_change(qemu_timedate_diff(&tm)); ++ set_rtc_date_diff(qemu_timedate_diff(&tm)); ++ qapi_event_send_rtc_change(get_rtc_date_diff()); + + pl031_set_alarm(s); + break; +-- +2.27.0 + diff --git a/gdb-xml-Fix-size-of-EFER-register-on-i386-architectu.patch b/gdb-xml-Fix-size-of-EFER-register-on-i386-architectu.patch new file mode 100644 index 0000000000000000000000000000000000000000..129b51edac31d41d51f494a077e9e58ee8978223 --- /dev/null +++ b/gdb-xml-Fix-size-of-EFER-register-on-i386-architectu.patch @@ -0,0 +1,49 @@ +From 9fd0035ff518ab3d2d4ee2578176fb562f9eb161 Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Wed, 23 Nov 2022 06:05:06 +0000 +Subject: [PATCH 06/29] gdb-xml: Fix size of EFER register on i386 architecture + when debugged by GDB mainline inclusion from mainline-v7.2.0-rc2 commit + 75ac231c67cdb13f0609943fab5499963858b587 category: bugfix + +-------------------------------------------- + +Before this commit, there were contradictory descriptions about size of EFER +register. +Line 113 says the size is 8 bytes. +Line 129 says the size is 4 bytes. + +As a result, when GDB is debugging an OS running on QEMU, the GDB cannot +read 'g' packets correctly. This 'g' packet transmits values of each +registers of machine emulated by QEMU to GDB. QEMU, the packet sender, +assign 4 bytes for EFER in 'g' packet based on the line 113. +GDB, the packet receiver, extract 8 bytes for EFER in 'g' packet based on +the line 129. Therefore, all registers located behind EFER in 'g' packet +has been shifted 4 bytes in GDB. + +After this commit, GDB can read 'g' packets correctly. + +Signed-off-by: TaiseiIto +Message-Id: +Signed-off-by: Paolo Bonzini + +Signed-off-by: cmss_dx +--- + gdb-xml/i386-32bit.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gdb-xml/i386-32bit.xml b/gdb-xml/i386-32bit.xml +index 872fcea9c2..7a66a02b67 100644 +--- a/gdb-xml/i386-32bit.xml ++++ b/gdb-xml/i386-32bit.xml +@@ -110,7 +110,7 @@ + + + +- ++ + + + +-- +2.27.0 + diff --git a/gdb-xml-fix-duplicate-register-in-arm-neon.xml.patch b/gdb-xml-fix-duplicate-register-in-arm-neon.xml.patch new file mode 100644 index 0000000000000000000000000000000000000000..792af946a3d03eea07bb7333f55298b3c624c8a4 --- /dev/null +++ b/gdb-xml-fix-duplicate-register-in-arm-neon.xml.patch @@ -0,0 +1,36 @@ +From 7010b0dd1b6f27b14a0c02c81944513fbd60deab Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 09:58:38 +0000 +Subject: [PATCH] gdb-xml: fix duplicate register in arm-neon.xml +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 940bb5fa9ca9f71fcc0d06e9de9ac3ab7415d0f2 + +Signed-off-by: jipengfei_yewu +Reviewed-by: Richard Henderson +Fixes: 56aebc8916 ("Add GDB XML register description support") +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Alex Bennée +Message-Id: <20231106185112.2755262-3-alex.bennee@linaro.org> +--- + gdb-xml/arm-neon.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gdb-xml/arm-neon.xml b/gdb-xml/arm-neon.xml +index 9dce0a996f..d61f6b8549 100644 +--- a/gdb-xml/arm-neon.xml ++++ b/gdb-xml/arm-neon.xml +@@ -76,7 +76,7 @@ + + + +- ++ + + + +-- +2.27.0 + diff --git a/gitlab-Disable-plugins-for-cross-i386-tci.patch b/gitlab-Disable-plugins-for-cross-i386-tci.patch new file mode 100644 index 0000000000000000000000000000000000000000..a2960a0e6646b4f2e4088e6a1d714f20ab7c3c49 --- /dev/null +++ b/gitlab-Disable-plugins-for-cross-i386-tci.patch @@ -0,0 +1,34 @@ +From d301917340f0d0196fb8e346a5d489e9be329a0a Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Fri, 30 Jun 2023 21:33:34 +0800 +Subject: [PATCH] gitlab: Disable plugins for cross-i386-tci + +There are timeouts in the cross-i386-tci job that are related to plugins. +Restrict this job to basic TCI testing. + +cheery-pick from 0cc889c8826cefa5b80110d31a62273b56aa1832 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Richard Henderson +Acked-by: Thomas Huth +Message-Id: <20230629130844.151453-1-richard.henderson@linaro.org> +--- + .gitlab-ci.d/crossbuilds.yml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml +index 17d6cb3e45..d06bf5f57d 100644 +--- a/.gitlab-ci.d/crossbuilds.yml ++++ b/.gitlab-ci.d/crossbuilds.yml +@@ -65,7 +65,7 @@ cross-i386-tci: + variables: + IMAGE: fedora-i386-cross + ACCEL: tcg-interpreter +- EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user ++ EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user --disable-plugins + MAKE_CHECK_ARGS: check check-tcg + + cross-mips-system: +-- +2.41.0.windows.1 + diff --git a/hbitmap-handle-set-reset-with-zero-length.patch b/hbitmap-handle-set-reset-with-zero-length.patch deleted file mode 100644 index b346a970d8594e2fae6a730c8c66370dc66af0da..0000000000000000000000000000000000000000 --- a/hbitmap-handle-set-reset-with-zero-length.patch +++ /dev/null @@ -1,50 +0,0 @@ -From c0b35d87de345bd3b59a44c604b247a0497f2fc0 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Fri, 11 Oct 2019 12:07:07 +0300 -Subject: [PATCH] hbitmap: handle set/reset with zero length - -Passing zero length to these functions leads to unpredicted results. -Zero-length set/reset may occur in active-mirror, on zero-length write -(which is unlikely, but not guaranteed to never happen). - -Let's just do nothing on zero-length request. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-id: 20191011090711.19940-2-vsementsov@virtuozzo.com -Reviewed-by: Max Reitz -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -(cherry picked from commit fed33bd175f663cc8c13f8a490a4f35a19756cfe) -Signed-off-by: Michael Roth ---- - util/hbitmap.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/util/hbitmap.c b/util/hbitmap.c -index 71c6ba2c52..c059313b9e 100644 ---- a/util/hbitmap.c -+++ b/util/hbitmap.c -@@ -387,6 +387,10 @@ void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count) - uint64_t first, n; - uint64_t last = start + count - 1; - -+ if (count == 0) { -+ return; -+ } -+ - trace_hbitmap_set(hb, start, count, - start >> hb->granularity, last >> hb->granularity); - -@@ -478,6 +482,10 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count) - uint64_t last = start + count - 1; - uint64_t gran = 1ULL << hb->granularity; - -+ if (count == 0) { -+ return; -+ } -+ - assert(QEMU_IS_ALIGNED(start, gran)); - assert(QEMU_IS_ALIGNED(count, gran) || (start + count == hb->orig_size)); - --- -2.23.0 diff --git a/hmp-Improve-sync-profile-error-message.patch b/hmp-Improve-sync-profile-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..703bbe85f458193426476cdd1d7dcf13d6809ee5 --- /dev/null +++ b/hmp-Improve-sync-profile-error-message.patch @@ -0,0 +1,52 @@ +From 3860a3a40673bdbcf8f8fde9017e9e1ecbd82b36 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 16:09:24 +0800 +Subject: [PATCH] hmp: Improve sync-profile error message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 7200fb211ef306c36d5e9060263b2a4d2f6d4700 + +Improve + + (qemu) sync-profile of + Error: Invalid parameter 'of' + +to + + Error: invalid parameter 'of', expecting 'on', 'off', or 'reset' + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-3-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Dr. David Alan Gilbert +--- + monitor/hmp-cmds.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 9570011232..5246c82e14 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -46,7 +46,6 @@ + #include "qapi/qapi-visit-migration.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qapi-visit-migration.h" +-#include "qapi/qmp/qerror.h" + #include "qapi/string-input-visitor.h" + #include "qapi/string-output-visitor.h" + #include "qom/object_interfaces.h" +@@ -920,7 +919,8 @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict) + } else { + Error *err = NULL; + +- error_setg(&err, QERR_INVALID_PARAMETER, op); ++ error_setg(&err, "invalid parameter '%s'," ++ " expecting 'on', 'off', or 'reset'", op); + hmp_handle_error(mon, err); + } + } +-- +2.27.0 + diff --git a/hmp-vnc-Fix-info-vnc-list-leak.patch b/hmp-vnc-Fix-info-vnc-list-leak.patch deleted file mode 100644 index ccc4e1db511a18c5da864a1d8b2732e9a4cd8a1f..0000000000000000000000000000000000000000 --- a/hmp-vnc-Fix-info-vnc-list-leak.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 6cb599f75b7844aefd7823ad97fc3bae70eff11f Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Mon, 23 Mar 2020 12:08:22 +0000 -Subject: [PATCH 06/14] hmp/vnc: Fix info vnc list leak - -We're iterating the list, and then freeing the iteration pointer rather -than the list head. - -Fixes: 0a9667ecdb6d ("hmp: Update info vnc") -Reported-by: Coverity (CID 1421932) -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20200323120822.51266-1-dgilbert@redhat.com> -Reviewed-by: Peter Maydell -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Peng Liang ---- - monitor/hmp-cmds.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c -index 5ca3ebe94272..fc5d6b92c4b6 100644 ---- a/monitor/hmp-cmds.c -+++ b/monitor/hmp-cmds.c -@@ -745,10 +745,11 @@ static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server) - - void hmp_info_vnc(Monitor *mon, const QDict *qdict) - { -- VncInfo2List *info2l; -+ VncInfo2List *info2l, *info2l_head; - Error *err = NULL; - - info2l = qmp_query_vnc_servers(&err); -+ info2l_head = info2l; - if (err) { - hmp_handle_error(mon, &err); - return; -@@ -777,7 +778,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) - info2l = info2l->next; - } - -- qapi_free_VncInfo2List(info2l); -+ qapi_free_VncInfo2List(info2l_head); - - } - #endif --- -2.26.2 - diff --git a/host-vdpa-make-notifiers-_init-_uninit-symmetric.patch b/host-vdpa-make-notifiers-_init-_uninit-symmetric.patch new file mode 100644 index 0000000000000000000000000000000000000000..5cfe9aa9455b9e6d982e5064ace7c28979c37723 --- /dev/null +++ b/host-vdpa-make-notifiers-_init-_uninit-symmetric.patch @@ -0,0 +1,79 @@ +From 8bba9208da0aa994b91d9568b58241e94b5d46fc Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 26 Jul 2023 02:21:47 +0000 +Subject: [PATCH] host-vdpa: make notifiers _init()/_uninit() symmetric + mainline inclusion commit b1f030a0a2e281193b09350c0281c0084e84bcf4 category: + bugfix + +--------------------------------------------------------------- + +vhost_vdpa_host_notifiers_init() initializes queue notifiers +for queues "dev->vq_index" to queue "dev->vq_index + dev->nvqs", +whereas vhost_vdpa_host_notifiers_uninit() uninitializes the +same notifiers for queue "0" to queue "dev->nvqs". + +This asymmetry seems buggy, fix that by using dev->vq_index +as the base for both. + +Fixes: d0416d487bd5 ("vhost-vdpa: map virtqueue notification area if possible") +Cc: jasowang@redhat.com +Signed-off-by: Laurent Vivier +Message-Id: <20220211161309.1385839-1-lvivier@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Stefano Garzarella +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + hw/virtio/vhost-vdpa.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 225c9b1730..287025ef93 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -381,15 +381,6 @@ static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, + } + } + +-static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) +-{ +- int i; +- +- for (i = 0; i < n; i++) { +- vhost_vdpa_host_notifier_uninit(dev, i); +- } +-} +- + static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index) + { + size_t page_size = qemu_real_host_page_size; +@@ -429,6 +420,15 @@ err: + return -1; + } + ++static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) ++{ ++ int i; ++ ++ for (i = dev->vq_index; i < dev->vq_index + n; i++) { ++ vhost_vdpa_host_notifier_uninit(dev, i); ++ } ++} ++ + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + { + int i; +@@ -442,7 +442,7 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + return; + + err: +- vhost_vdpa_host_notifiers_uninit(dev, i); ++ vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); + return; + } + +-- +2.41.0.windows.1 + diff --git a/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch b/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch deleted file mode 100644 index 0cbda2bf538fdf6eccab11faa319bc9a31be12f9..0000000000000000000000000000000000000000 --- a/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch +++ /dev/null @@ -1,61 +0,0 @@ -From f14505f7f91edbce738202a6f658806d1074116c Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Fri, 11 Dec 2020 17:28:39 +0800 -Subject: [PATCH] hostmem: Fix up free host_nodes list right after visited - -In host_memory_backend_get_host_nodes, we build host_nodes -list and output it to v (a StringOutputVisitor) but forget -to free the list. This fixes the memory leak. - -The memory leak stack: - -Direct leak of 32 byte(s) in 2 object(s) allocated from: - #0 0xfffda30b3393 in __interceptor_calloc (/usr/lib64/libasan.so.4+0xd3393) - #1 0xfffda1d28b9b in g_malloc0 (/usr/lib64/libglib-2.0.so.0+0x58b9b) - #2 0xaaab05ca6e43 in host_memory_backend_get_host_nodes backends/hostmem.c:94 - #3 0xaaab061ddf83 in object_property_get_uint16List qom/object.c:1478 - #4 0xaaab05866513 in query_memdev hw/core/machine-qmp-cmds.c:312 - #5 0xaaab061d980b in do_object_child_foreach qom/object.c:1001 - #6 0xaaab0586779b in qmp_query_memdev hw/core/machine-qmp-cmds.c:328 - #7 0xaaab0615ed3f in qmp_marshal_query_memdev qapi/qapi-commands-machine.c:327 - #8 0xaaab0632d647 in do_qmp_dispatch qapi/qmp-dispatch.c:147 - #9 0xaaab0632d647 in qmp_dispatch qapi/qmp-dispatch.c:190 - #10 0xaaab0610f74b in monitor_qmp_dispatch monitor/qmp.c:120 - #11 0xaaab0611074b in monitor_qmp_bh_dispatcher monitor/qmp.c:209 - #12 0xaaab063caefb in aio_bh_poll util/async.c:117 - #13 0xaaab063d30fb in aio_dispatch util/aio-posix.c:459 - #14 0xaaab063cac8f in aio_ctx_dispatch util/async.c:268 - #15 0xfffda1d22a6b in g_main_context_dispatch (/usr/lib64/libglib-2.0.so.0+0x52a6b) - #16 0xaaab063d0e97 in glib_pollfds_poll util/main-loop.c:218 - #17 0xaaab063d0e97 in os_host_main_loop_wait util/main-loop.c:241 - #18 0xaaab063d0e97 in main_loop_wait util/main-loop.c:517 - #19 0xaaab05c8bfa7 in main_loop /root/rpmbuild/BUILD/qemu-4.1.0/vl.c:1791 - #20 0xaaab05713bc3 in main /root/rpmbuild/BUILD/qemu-4.1.0/vl.c:4473 - #21 0xfffda0a83ebf in __libc_start_main (/usr/lib64/libc.so.6+0x23ebf) - #22 0xaaab0571ed5f (aarch64-softmmu/qemu-system-aarch64+0x88ed5f) -SUMMARY: AddressSanitizer: 32 byte(s) leaked in 2 allocation(s). - -Fixes: 4cf1b76bf1e2 (hostmem: add properties for NUMA memory policy) -Reported-by: Euler Robot -Tested-by: Chen Qun -Reviewed-by: Igor Mammedov -Signed-off-by: Keqian Zhu ---- - backends/hostmem.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/backends/hostmem.c b/backends/hostmem.c -index 463102aa15..9e1b3a0afc 100644 ---- a/backends/hostmem.c -+++ b/backends/hostmem.c -@@ -108,6 +108,7 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name, - - ret: - visit_type_uint16List(v, name, &host_nodes, errp); -+ qapi_free_uint16List(host_nodes); - } - - static void --- -2.27.0 - diff --git a/hostmem-default-the-amount-of-prealloc-threads-to-sm.patch b/hostmem-default-the-amount-of-prealloc-threads-to-sm.patch new file mode 100644 index 0000000000000000000000000000000000000000..a37cb4d42de22761115980357769461fdb912fc7 --- /dev/null +++ b/hostmem-default-the-amount-of-prealloc-threads-to-sm.patch @@ -0,0 +1,45 @@ +From 1a1ea4307536f142aff5ea17b9dc73ffe3a35c79 Mon Sep 17 00:00:00 2001 +From: Jaroslav Jindrak +Date: Tue, 17 May 2022 14:38:58 +0200 +Subject: [PATCH 3/3] hostmem: default the amount of prealloc-threads to + smp-cpus + +Prior to the introduction of the prealloc-threads property, the amount +of threads used to preallocate memory was derived from the value of +smp-cpus passed to qemu, the amount of physical cpus of the host +and a hardcoded maximum value. When the prealloc-threads property +was introduced, it included a default of 1 in backends/hostmem.c and +a default of smp-cpus using the sugar API for the property itself. The +latter default is not used when the property is not specified on qemu's +command line, so guests that were not adjusted for this change suddenly +started to use the default of 1 thread to preallocate memory, which +resulted in observable slowdowns in guest boots for guests with large +memory (e.g. when using libvirt <8.2.0 or managing guests manually). + +This commit restores the original behavior for these cases while not +impacting guests started with the prealloc-threads property in any way. + +Fixes: 220c1fd864e9d ("hostmem: introduce "prealloc-threads" property") +Signed-off-by: Jaroslav Jindrak +Message-Id: <20220517123858.7933-1-dzejrou@gmail.com> +Signed-off-by: Paolo Bonzini +--- + backends/hostmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/backends/hostmem.c b/backends/hostmem.c +index 4c05862ed5..c9ddaec849 100644 +--- a/backends/hostmem.c ++++ b/backends/hostmem.c +@@ -273,7 +273,7 @@ static void host_memory_backend_init(Object *obj) + backend->merge = machine_mem_merge(machine); + backend->dump = machine_dump_guest_core(machine); + backend->reserve = true; +- backend->prealloc_threads = 1; ++ backend->prealloc_threads = machine->smp.cpus; + } + + static void host_memory_backend_post_init(Object *obj) +-- +2.27.0 + diff --git a/hppa-fix-leak-from-g_strdup_printf.patch b/hppa-fix-leak-from-g_strdup_printf.patch deleted file mode 100644 index b04193e380fe58ef14e91cb56d162abc264dce9b..0000000000000000000000000000000000000000 --- a/hppa-fix-leak-from-g_strdup_printf.patch +++ /dev/null @@ -1,54 +0,0 @@ -From b7ef7e6fb5a2b08268f4b19c07c07abd4fbb2064 Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 14:48:49 +0800 -Subject: [PATCH] hppa: fix leak from g_strdup_printf -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -memory_region_init_* takes care of copying the name into memory it owns. -Free it in the caller. - -Signed-off-by: Paolo Bonzini -Reviewed-by: Philippe Mathieu-Daudé ---- - hw/hppa/dino.c | 1 + - hw/hppa/machine.c | 4 +++- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c -index e94614ab..ef923b49 100644 ---- a/hw/hppa/dino.c -+++ b/hw/hppa/dino.c -@@ -485,6 +485,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, - memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), - name, &s->pci_mem, addr, - DINO_MEM_CHUNK_SIZE); -+ g_free(name); - } - - /* Set up PCI view of memory: Bus master address space. */ -diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c -index 662838d8..9e25660e 100644 ---- a/hw/hppa/machine.c -+++ b/hw/hppa/machine.c -@@ -78,13 +78,15 @@ static void machine_hppa_init(MachineState *machine) - - /* Create CPUs. */ - for (i = 0; i < smp_cpus; i++) { -+ char *name = g_strdup_printf("cpu%ld-io-eir", i); - cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type)); - - cpu_region = g_new(MemoryRegion, 1); - memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops, -- cpu[i], g_strdup_printf("cpu%ld-io-eir", i), 4); -+ cpu[i], name, 4); - memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000, - cpu_region); -+ g_free(name); - } - - /* Limit main memory. */ --- -2.19.1 - diff --git a/hugepages-hugepages-files-maybe-leftover.patch b/hugepages-hugepages-files-maybe-leftover.patch new file mode 100644 index 0000000000000000000000000000000000000000..611f1eace32aebf33917851b1a3833984efab124 --- /dev/null +++ b/hugepages-hugepages-files-maybe-leftover.patch @@ -0,0 +1,99 @@ +From 3cb1b0ce091998532a30793e3272925da4e6f3aa Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Mon, 7 Feb 2022 14:31:34 +0800 +Subject: [PATCH 1/2] hugepages: hugepages files maybe leftover + +Before qemu uses the hugepage memory directory /dev/hugepages/libvirt/qemu/xxx, +The directory may be deleted because of the destroy virtual machine. +Cause qemu to create files directly under /dev/hugepages/libvirt/qemu/. +After the file is created, the file is not cleaned up by unlink, +and when the virtual machine is destroyed, libvirt will only clean up +/dev/hugepages/libvirt/qemu/xxx directory. After creating the hugepage file, +execute unlink to clean up the file to fix the problem. + +Signed-off-by: Jinhua Cao +Signed-off-by: Jiajie Li +--- + include/qemu/mmap-alloc.h | 3 +++ + softmmu/physmem.c | 10 +++++++++- + util/mmap-alloc.c | 22 ++++++++++++++++++++++ + 3 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h +index 90d0eee705..707202e5be 100644 +--- a/include/qemu/mmap-alloc.h ++++ b/include/qemu/mmap-alloc.h +@@ -1,6 +1,9 @@ + #ifndef QEMU_MMAP_ALLOC_H + #define QEMU_MMAP_ALLOC_H + ++#define HUGETLBFS_MAGIC 0x958458f6 ++ ++size_t qemu_fd_getfiletype(int fd); + + size_t qemu_fd_getpagesize(int fd); + +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index 3524c04c2a..3b9a61448c 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -1496,7 +1496,14 @@ static int file_ram_open(const char *path, + /* @path names a file that doesn't exist, create it */ + fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (fd >= 0) { +- *created = true; ++ info_report("open %s success \n", path); ++ /* if fd file type is HUGETLBFS_MAGIC, unlink it, */ ++ /* in case to prevent residue after qemu killed */ ++ if (qemu_fd_getfiletype(fd) == HUGETLBFS_MAGIC) { ++ unlink(path); ++ } else { ++ *created = true; ++ } + break; + } + } else if (errno == EISDIR) { +@@ -1515,6 +1522,7 @@ static int file_ram_open(const char *path, + + fd = mkstemp(filename); + if (fd >= 0) { ++ info_report("mkstemp %s success \n", filename); + unlink(filename); + g_free(filename); + break; +diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c +index 893d864354..4993dd5bfa 100644 +--- a/util/mmap-alloc.c ++++ b/util/mmap-alloc.c +@@ -29,6 +29,28 @@ + #include + #endif + ++size_t qemu_fd_getfiletype(int fd) ++{ ++ struct statfs fs; ++ int ret; ++ ++ if (fd != -1) { ++ do { ++ ret = fstatfs(fd, &fs); ++ } while (ret != 0 && errno == EINTR); ++ ++ if (ret != 0) { ++ fprintf(stderr, "Couldn't fstatfs() fd: %s\n", ++ strerror(errno)); ++ return -1; ++ } ++ return fs.f_type; ++ } else { ++ fprintf(stderr, "fd is invalid \n"); ++ return -1; ++ } ++} ++ + size_t qemu_fd_getpagesize(int fd) + { + #ifdef CONFIG_LINUX +-- +2.27.0 + diff --git a/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch b/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch deleted file mode 100644 index dc57aa64dd12427afc1e59af0476206317065d1b..0000000000000000000000000000000000000000 --- a/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch +++ /dev/null @@ -1,478 +0,0 @@ -From b12d9edd0079d4ee136c25e95333918b0c6d3cd9 Mon Sep 17 00:00:00 2001 -From: Samuel Ortiz -Date: Wed, 18 Sep 2019 14:06:25 +0100 -Subject: [PATCH] hw/acpi: Add ACPI Generic Event Device Support - -The ACPI Generic Event Device (GED) is a hardware-reduced specific -device[ACPI v6.1 Section 5.6.9] that handles all platform events, -including the hotplug ones. This patch generates the AML code that -defines GEDs. - -Platforms need to specify their own GED Event bitmap to describe -what kind of events they want to support through GED. Also this -uses a a single interrupt for the GED device, relying on IO -memory region to communicate the type of device affected by the -interrupt. This way, we can support up to 32 events with a unique -interrupt. - -This supports only memory hotplug for now. - -Signed-off-by: Samuel Ortiz -Signed-off-by: Sebastien Boeuf -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Message-Id: <20190918130633.4872-4-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Igor Mammedov ---- - hw/acpi/Kconfig | 4 + - hw/acpi/Makefile.objs | 1 + - hw/acpi/generic_event_device.c | 303 +++++++++++++++++++++++++ - include/hw/acpi/generic_event_device.h | 100 ++++++++ - 4 files changed, 408 insertions(+) - create mode 100644 hw/acpi/generic_event_device.c - create mode 100644 include/hw/acpi/generic_event_device.h - -diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig -index 7c59cf900b..12e3f1e86e 100644 ---- a/hw/acpi/Kconfig -+++ b/hw/acpi/Kconfig -@@ -31,3 +31,7 @@ config ACPI_VMGENID - bool - default y - depends on PC -+ -+config ACPI_HW_REDUCED -+ bool -+ depends on ACPI -diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs -index 1a720c381e..e4b5d101a4 100644 ---- a/hw/acpi/Makefile.objs -+++ b/hw/acpi/Makefile.objs -@@ -6,6 +6,7 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o - common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o - common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o - common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o -+common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o - common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o - - common-obj-y += acpi_interface.o -diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c -new file mode 100644 -index 0000000000..b94500b08d ---- /dev/null -+++ b/hw/acpi/generic_event_device.c -@@ -0,0 +1,303 @@ -+/* -+ * -+ * Copyright (c) 2018 Intel Corporation -+ * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd -+ * Written by Samuel Ortiz, Shameer Kolothum -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "exec/address-spaces.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/generic_event_device.h" -+#include "hw/irq.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/qdev-properties.h" -+#include "migration/vmstate.h" -+#include "qemu/error-report.h" -+ -+static const uint32_t ged_supported_events[] = { -+ ACPI_GED_MEM_HOTPLUG_EVT, -+}; -+ -+/* -+ * The ACPI Generic Event Device (GED) is a hardware-reduced specific -+ * device[ACPI v6.1 Section 5.6.9] that handles all platform events, -+ * including the hotplug ones. Platforms need to specify their own -+ * GED Event bitmap to describe what kind of events they want to support -+ * through GED. This routine uses a single interrupt for the GED device, -+ * relying on IO memory region to communicate the type of device -+ * affected by the interrupt. This way, we can support up to 32 events -+ * with a unique interrupt. -+ */ -+void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, -+ uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base) -+{ -+ AcpiGedState *s = ACPI_GED(hotplug_dev); -+ Aml *crs = aml_resource_template(); -+ Aml *evt, *field; -+ Aml *dev = aml_device("%s", name); -+ Aml *evt_sel = aml_local(0); -+ Aml *esel = aml_name(AML_GED_EVT_SEL); -+ -+ /* _CRS interrupt */ -+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH, -+ AML_EXCLUSIVE, &ged_irq, 1)); -+ -+ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013"))); -+ aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE))); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ -+ /* Append IO region */ -+ aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs, -+ aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET), -+ ACPI_GED_EVT_SEL_LEN)); -+ field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK, -+ AML_WRITE_AS_ZEROS); -+ aml_append(field, aml_named_field(AML_GED_EVT_SEL, -+ ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE)); -+ aml_append(dev, field); -+ -+ /* -+ * For each GED event we: -+ * - Add a conditional block for each event, inside a loop. -+ * - Call a method for each supported GED event type. -+ * -+ * The resulting ASL code looks like: -+ * -+ * Local0 = ESEL -+ * If ((Local0 & One) == One) -+ * { -+ * MethodEvent0() -+ * } -+ * -+ * If ((Local0 & 0x2) == 0x2) -+ * { -+ * MethodEvent1() -+ * } -+ * ... -+ */ -+ evt = aml_method("_EVT", 1, AML_SERIALIZED); -+ { -+ Aml *if_ctx; -+ uint32_t i; -+ uint32_t ged_events = ctpop32(s->ged_event_bitmap); -+ -+ /* Local0 = ESEL */ -+ aml_append(evt, aml_store(esel, evt_sel)); -+ -+ 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; -+ } -+ -+ if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL), -+ aml_int(event))); -+ switch (event) { -+ case ACPI_GED_MEM_HOTPLUG_EVT: -+ aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." -+ MEMORY_SLOT_SCAN_METHOD)); -+ break; -+ default: -+ /* -+ * Please make sure all the events in ged_supported_events[] -+ * are handled above. -+ */ -+ g_assert_not_reached(); -+ } -+ -+ aml_append(evt, if_ctx); -+ ged_events--; -+ } -+ -+ if (ged_events) { -+ error_report("Unsupported events specified"); -+ abort(); -+ } -+ } -+ -+ /* Append _EVT method */ -+ aml_append(dev, evt); -+ -+ aml_append(table, dev); -+} -+ -+/* Memory read by the GED _EVT AML dynamic method */ -+static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ uint64_t val = 0; -+ GEDState *ged_st = opaque; -+ -+ switch (addr) { -+ case ACPI_GED_EVT_SEL_OFFSET: -+ /* Read the selector value and reset it */ -+ val = ged_st->sel; -+ ged_st->sel = 0; -+ break; -+ default: -+ break; -+ } -+ -+ return val; -+} -+ -+/* Nothing is expected to be written to the GED memory region */ -+static void ged_write(void *opaque, hwaddr addr, uint64_t data, -+ unsigned int size) -+{ -+} -+ -+static const MemoryRegionOps ged_ops = { -+ .read = ged_read, -+ .write = ged_write, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 4, -+ }, -+}; -+ -+static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ AcpiGedState *s = ACPI_GED(hotplug_dev); -+ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); -+ } else { -+ error_setg(errp, "virt: device plug request for unsupported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -+{ -+ AcpiGedState *s = ACPI_GED(adev); -+ GEDState *ged_st = &s->ged_state; -+ uint32_t sel; -+ -+ if (ev & ACPI_MEMORY_HOTPLUG_STATUS) { -+ sel = ACPI_GED_MEM_HOTPLUG_EVT; -+ } else { -+ /* Unknown event. Return without generating interrupt. */ -+ warn_report("GED: Unsupported event %d. No irq injected", ev); -+ return; -+ } -+ -+ /* -+ * Set the GED selector field to communicate the event type. -+ * This will be read by GED aml code to select the appropriate -+ * event method. -+ */ -+ ged_st->sel |= sel; -+ -+ /* Trigger the event by sending an interrupt to the guest. */ -+ qemu_irq_pulse(s->irq); -+} -+ -+static Property acpi_ged_properties[] = { -+ DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static const VMStateDescription vmstate_memhp_state = { -+ .name = "acpi-ged/memhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_ged_state = { -+ .name = "acpi-ged-state", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(sel, GEDState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_acpi_ged = { -+ .name = "acpi-ged", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState), -+ VMSTATE_END_OF_LIST(), -+ }, -+ .subsections = (const VMStateDescription * []) { -+ &vmstate_memhp_state, -+ NULL -+ } -+}; -+ -+static void acpi_ged_initfn(Object *obj) -+{ -+ DeviceState *dev = DEVICE(obj); -+ AcpiGedState *s = ACPI_GED(dev); -+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); -+ GEDState *ged_st = &s->ged_state; -+ -+ memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st, -+ TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); -+ sysbus_init_mmio(sbd, &ged_st->io); -+ -+ sysbus_init_irq(sbd, &s->irq); -+ -+ s->memhp_state.is_enabled = true; -+ /* -+ * GED handles memory hotplug event and acpi-mem-hotplug -+ * memory region gets initialized here. Create an exclusive -+ * container for memory hotplug IO and expose it as GED sysbus -+ * MMIO so that boards can map it separately. -+ */ -+ memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container", -+ MEMORY_HOTPLUG_IO_LEN); -+ sysbus_init_mmio(sbd, &s->container_memhp); -+ acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), -+ &s->memhp_state, 0); -+} -+ -+static void acpi_ged_class_init(ObjectClass *class, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(class); -+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); -+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); -+ -+ dc->desc = "ACPI Generic Event Device"; -+ dc->props = acpi_ged_properties; -+ dc->vmsd = &vmstate_acpi_ged; -+ -+ hc->plug = acpi_ged_device_plug_cb; -+ -+ adevc->send_event = acpi_ged_send_event; -+} -+ -+static const TypeInfo acpi_ged_info = { -+ .name = TYPE_ACPI_GED, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(AcpiGedState), -+ .instance_init = acpi_ged_initfn, -+ .class_init = acpi_ged_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { TYPE_ACPI_DEVICE_IF }, -+ { } -+ } -+}; -+ -+static void acpi_ged_register_types(void) -+{ -+ type_register_static(&acpi_ged_info); -+} -+ -+type_init(acpi_ged_register_types) -diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h -new file mode 100644 -index 0000000000..2049e8d873 ---- /dev/null -+++ b/include/hw/acpi/generic_event_device.h -@@ -0,0 +1,100 @@ -+/* -+ * -+ * Copyright (c) 2018 Intel Corporation -+ * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd -+ * Written by Samuel Ortiz, Shameer Kolothum -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * The ACPI Generic Event Device (GED) is a hardware-reduced specific -+ * device[ACPI v6.1 Section 5.6.9] that handles all platform events, -+ * including the hotplug ones. Generic Event Device allows platforms -+ * to handle interrupts in ACPI ASL statements. It follows a very -+ * similar approach like the _EVT method from GPIO events. All -+ * interrupts are listed in _CRS and the handler is written in _EVT -+ * method. Here, we use a single interrupt for the GED device, relying -+ * on IO memory region to communicate the type of device affected by -+ * the interrupt. This way, we can support up to 32 events with a -+ * unique interrupt. -+ * -+ * Here is an example. -+ * -+ * Device (\_SB.GED) -+ * { -+ * Name (_HID, "ACPI0013") -+ * Name (_UID, Zero) -+ * Name (_CRS, ResourceTemplate () -+ * { -+ * Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) -+ * { -+ * 0x00000029, -+ * } -+ * }) -+ * OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) -+ * Field (EREG, DWordAcc, NoLock, WriteAsZeros) -+ * { -+ * ESEL, 32 -+ * } -+ * -+ * Method (_EVT, 1, Serialized) // _EVT: Event -+ * { -+ * Local0 = ESEL // ESEL = IO memory region which specifies the -+ * // device type. -+ * If (((Local0 & One) == One)) -+ * { -+ * MethodEvent1() -+ * } -+ * If ((Local0 & 0x2) == 0x2) -+ * { -+ * MethodEvent2() -+ * } -+ * ... -+ * } -+ * } -+ * -+ */ -+ -+#ifndef HW_ACPI_GED_H -+#define HW_ACPI_GED_H -+ -+#include "hw/sysbus.h" -+#include "hw/acpi/memory_hotplug.h" -+ -+#define TYPE_ACPI_GED "acpi-ged" -+#define ACPI_GED(obj) \ -+ OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED) -+ -+#define ACPI_GED_EVT_SEL_OFFSET 0x0 -+#define ACPI_GED_EVT_SEL_LEN 0x4 -+ -+#define GED_DEVICE "GED" -+#define AML_GED_EVT_REG "EREG" -+#define AML_GED_EVT_SEL "ESEL" -+ -+/* -+ * Platforms need to specify the GED event bitmap -+ * to describe what kind of events they want to support -+ * through GED. -+ */ -+#define ACPI_GED_MEM_HOTPLUG_EVT 0x1 -+ -+typedef struct GEDState { -+ MemoryRegion io; -+ uint32_t sel; -+} GEDState; -+ -+typedef struct AcpiGedState { -+ SysBusDevice parent_obj; -+ MemHotplugState memhp_state; -+ MemoryRegion container_memhp; -+ GEDState ged_state; -+ uint32_t ged_event_bitmap; -+ qemu_irq irq; -+} AcpiGedState; -+ -+void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, -+ uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base); -+ -+#endif --- -2.19.1 diff --git a/hw-acpi-Add-ospm_status-hook-implementation-for-acpi.patch b/hw-acpi-Add-ospm_status-hook-implementation-for-acpi.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d917c601aada976bd645909de6b1b370ee18262 --- /dev/null +++ b/hw-acpi-Add-ospm_status-hook-implementation-for-acpi.patch @@ -0,0 +1,60 @@ +From fa15ed1690bbfd95e2df6efafcb034198e9b637a Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Tue, 16 Aug 2022 17:49:57 +0800 +Subject: [PATCH] hw/acpi: Add ospm_status hook implementation for acpi-ged + +Setup an ARM virtual machine of machine virt and execute qmp "query-acpi-ospm-status" +causes segmentation fault with following dumpstack: + #1 0x0000aaaaab64235c in qmp_query_acpi_ospm_status (errp=errp@entry=0xfffffffff030) at ../monitor/qmp-cmds.c:312 + #2 0x0000aaaaabfc4e20 in qmp_marshal_query_acpi_ospm_status (args=, ret=0xffffea4ffe90, errp=0xffffea4ffe88) at qapi/qapi-commands-acpi.c:63 + #3 0x0000aaaaabff8ba0 in do_qmp_dispatch_bh (opaque=0xffffea4ffe98) at ../qapi/qmp-dispatch.c:128 + #4 0x0000aaaaac02e594 in aio_bh_call (bh=0xffffe0004d80) at ../util/async.c:150 + #5 aio_bh_poll (ctx=ctx@entry=0xaaaaad0f6040) at ../util/async.c:178 + #6 0x0000aaaaac00bd40 in aio_dispatch (ctx=ctx@entry=0xaaaaad0f6040) at ../util/aio-posix.c:421 + #7 0x0000aaaaac02e010 in aio_ctx_dispatch (source=0xaaaaad0f6040, callback=, user_data=) at ../util/async.c:320 + #8 0x0000fffff76f6884 in g_main_context_dispatch () at /usr/lib64/libglib-2.0.so.0 + #9 0x0000aaaaac0452d4 in glib_pollfds_poll () at ../util/main-loop.c:297 + #10 os_host_main_loop_wait (timeout=0) at ../util/main-loop.c:320 + #11 main_loop_wait (nonblocking=nonblocking@entry=0) at ../util/main-loop.c:596 + #12 0x0000aaaaab5c9e50 in qemu_main_loop () at ../softmmu/runstate.c:734 + #13 0x0000aaaaab185370 in qemu_main (argc=argc@entry=47, argv=argv@entry=0xfffffffff518, envp=envp@entry=0x0) at ../softmmu/main.c:38 + #14 0x0000aaaaab16f99c in main (argc=47, argv=0xfffffffff518) at ../softmmu/main.c:47 + +Fixes: ebb62075021a ("hw/acpi: Add ACPI Generic Event Device Support") +Signed-off-by: Keqian Zhu +Reviewed-by: Igor Mammedov +Message-id: 20220816094957.31700-1-zhukeqian1@huawei.com +Signed-off-by: Peter Maydell +--- + hw/acpi/generic_event_device.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 042a8ef8a5..53e9112d9f 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -273,6 +273,13 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, + } + } + ++static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) ++{ ++ AcpiGedState *s = ACPI_GED(adev); ++ ++ acpi_memory_ospm_status(&s->memhp_state, list); ++} ++ + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + { + AcpiGedState *s = ACPI_GED(adev); +@@ -444,6 +451,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + hc->unplug_request = acpi_ged_unplug_request_cb; + hc->unplug = acpi_ged_unplug_cb; + ++ adevc->ospm_status = acpi_ged_ospm_status; + adevc->send_event = acpi_ged_send_event; + } + +-- +2.27.0 + diff --git a/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch b/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch deleted file mode 100644 index 292687199fbe797b86b25ac2fb56063f7080a0f0..0000000000000000000000000000000000000000 --- a/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 7a08983315bf4d624966a89112259e2b4949de91 Mon Sep 17 00:00:00 2001 -From: Samuel Ortiz -Date: Wed, 18 Sep 2019 14:06:24 +0100 -Subject: [PATCH] hw/acpi: Do not create memory hotplug method when handler is - not defined - -With Hardware-reduced ACPI, the GED device will manage ACPI -hotplug entirely. As a consequence, make the memory specific -events AML generation optional. The code will only be added -when the method name is not NULL. - -Signed-off-by: Samuel Ortiz -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-3-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/acpi/memory_hotplug.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c -index 9a515c0484..8b30356c1a 100644 ---- a/hw/acpi/memory_hotplug.c -+++ b/hw/acpi/memory_hotplug.c -@@ -711,10 +711,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - } - aml_append(table, dev_container); - -- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); -- aml_append(method, -- aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD)); -- aml_append(table, method); -+ if (event_handler_method) { -+ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); -+ aml_append(method, aml_call0(MEMORY_DEVICES_CONTAINER "." -+ MEMORY_SLOT_SCAN_METHOD)); -+ aml_append(table, method); -+ } - - g_free(mhp_res_path); - } --- -2.19.1 diff --git a/hw-acpi-Make-ACPI-IO-address-space-configurable.patch b/hw-acpi-Make-ACPI-IO-address-space-configurable.patch deleted file mode 100644 index cdf597b51566400b17ddac3e27dc93cb65a61bd6..0000000000000000000000000000000000000000 --- a/hw-acpi-Make-ACPI-IO-address-space-configurable.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 6cd7281c73ca462b2f27969f1e28f1afd3ebe82d Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:23 +0100 -Subject: [PATCH] hw/acpi: Make ACPI IO address space configurable - -This is in preparation for adding support for ARM64 platforms -where it doesn't use port mapped IO for ACPI IO space. We are -making changes so that MMIO region can be accommodated -and board can pass the base address into the aml build function. - -Also move few MEMORY_* definitions to header so that other memory -hotplug event signalling mechanisms (eg. Generic Event Device on -HW-reduced acpi platforms) can use the same from their respective -event handler code. - -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-2-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/acpi/memory_hotplug.c | 33 ++++++++++++++------------------ - hw/i386/acpi-build.c | 7 ++++++- - hw/i386/pc.c | 3 +++ - include/hw/acpi/memory_hotplug.h | 9 +++++++-- - include/hw/i386/pc.h | 3 +++ - 5 files changed, 33 insertions(+), 22 deletions(-) - -diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c -index 297812d5f7..9a515c0484 100644 ---- a/hw/acpi/memory_hotplug.c -+++ b/hw/acpi/memory_hotplug.c -@@ -29,12 +29,7 @@ - #define MEMORY_SLOT_PROXIMITY_METHOD "MPXM" - #define MEMORY_SLOT_EJECT_METHOD "MEJ0" - #define MEMORY_SLOT_NOTIFY_METHOD "MTFY" --#define MEMORY_SLOT_SCAN_METHOD "MSCN" - #define MEMORY_HOTPLUG_DEVICE "MHPD" --#define MEMORY_HOTPLUG_IO_LEN 24 --#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC" -- --static uint16_t memhp_io_base; - - static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) - { -@@ -209,7 +204,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = { - }; - - void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, -- MemHotplugState *state, uint16_t io_base) -+ MemHotplugState *state, hwaddr io_base) - { - MachineState *machine = MACHINE(qdev_get_machine()); - -@@ -218,12 +213,10 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, - return; - } - -- assert(!memhp_io_base); -- memhp_io_base = io_base; - state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); - memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, - "acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN); -- memory_region_add_subregion(as, memhp_io_base, &state->io); -+ memory_region_add_subregion(as, io_base, &state->io); - } - - /** -@@ -342,7 +335,8 @@ const VMStateDescription vmstate_memory_hotplug = { - - void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - const char *res_root, -- const char *event_handler_method) -+ const char *event_handler_method, -+ AmlRegionSpace rs, hwaddr memhp_io_base) - { - int i; - Aml *ifctx; -@@ -351,10 +345,6 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - Aml *mem_ctrl_dev; - char *mhp_res_path; - -- if (!memhp_io_base) { -- return; -- } -- - mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root); - mem_ctrl_dev = aml_device("%s", mhp_res_path); - { -@@ -365,14 +355,19 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - aml_name_decl("_UID", aml_string("Memory hotplug resources"))); - - crs = aml_resource_template(); -- aml_append(crs, -- aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, -- MEMORY_HOTPLUG_IO_LEN) -- ); -+ if (rs == AML_SYSTEM_IO) { -+ aml_append(crs, -+ aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, -+ MEMORY_HOTPLUG_IO_LEN) -+ ); -+ } else { -+ aml_append(crs, aml_memory32_fixed(memhp_io_base, -+ MEMORY_HOTPLUG_IO_LEN, AML_READ_WRITE)); -+ } - aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs)); - - aml_append(mem_ctrl_dev, aml_operation_region( -- MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, -+ MEMORY_HOTPLUG_IO_REGION, rs, - aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN) - ); - -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index f3fdfefcd5..749218561a 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -1871,7 +1871,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, - "\\_SB.PCI0", "\\_GPE._E02"); - } -- build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03"); -+ -+ if (pcms->memhp_io_base && nr_mem) { -+ build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", -+ "\\_GPE._E03", AML_SYSTEM_IO, -+ pcms->memhp_io_base); -+ } - - scope = aml_scope("_GPE"); - { -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index d011733ff7..8a914130b0 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -1936,6 +1936,9 @@ void pc_memory_init(PCMachineState *pcms, - - /* Init default IOAPIC address space */ - pcms->ioapic_as = &address_space_memory; -+ -+ /* Init ACPI memory hotplug IO base address */ -+ pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE; - } - - /* -diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h -index 77c65765d6..dfe9cf3fde 100644 ---- a/include/hw/acpi/memory_hotplug.h -+++ b/include/hw/acpi/memory_hotplug.h -@@ -5,6 +5,10 @@ - #include "hw/acpi/acpi.h" - #include "hw/acpi/aml-build.h" - -+#define MEMORY_SLOT_SCAN_METHOD "MSCN" -+#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC" -+#define MEMORY_HOTPLUG_IO_LEN 24 -+ - /** - * MemStatus: - * @is_removing: the memory device in slot has been requested to be ejected. -@@ -29,7 +33,7 @@ typedef struct MemHotplugState { - } MemHotplugState; - - void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, -- MemHotplugState *state, uint16_t io_base); -+ MemHotplugState *state, hwaddr io_base); - - void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, - DeviceState *dev, Error **errp); -@@ -48,5 +52,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); - - void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - const char *res_root, -- const char *event_handler_method); -+ const char *event_handler_method, -+ AmlRegionSpace rs, hwaddr memhp_io_base); - #endif -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 859b64c51d..49b47535cf 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -69,6 +69,9 @@ struct PCMachineState { - /* Address space used by IOAPIC device. All IOAPIC interrupts - * will be translated to MSI messages in the address space. */ - AddressSpace *ioapic_as; -+ -+ /* ACPI Memory hotplug IO base address */ -+ hwaddr memhp_io_base; - }; - - #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" --- -2.19.1 diff --git a/hw-acpi-Support-acpi-ged-to-report-CPU-s-OST-info.patch b/hw-acpi-Support-acpi-ged-to-report-CPU-s-OST-info.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b48446f091a79bc91de8327878adf6252c52cfa --- /dev/null +++ b/hw-acpi-Support-acpi-ged-to-report-CPU-s-OST-info.patch @@ -0,0 +1,28 @@ +From 9e8ccc2a868e719233a34946106859461c057ade Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Tue, 14 Feb 2023 20:28:11 +0800 +Subject: [PATCH] hw/acpi: Support acpi-ged to report CPU's OST info + +Setup an ARM virtual machine of machine virt and execute qmp +"query-acpi-ospm-status" but can not get the CPU's OST info. + +Signed-off-by: Kunkun Jiang +--- + hw/acpi/generic_event_device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 53e9112d9f..9118681662 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -278,6 +278,7 @@ static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) + AcpiGedState *s = ACPI_GED(adev); + + acpi_memory_ospm_status(&s->memhp_state, list); ++ acpi_cpu_ospm_status(&s->cpuhp_state, list); + } + + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) +-- +2.27.0 + diff --git a/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch b/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch new file mode 100644 index 0000000000000000000000000000000000000000..0525989485e8ce7ea6180b3d8b933ab70dfe74ef --- /dev/null +++ b/hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch @@ -0,0 +1,113 @@ +From 66c935b435d90ef9c1ae4446c5edc07cbd8ba0ed Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:29 +0800 +Subject: [PATCH 17/24] hw/acpi/aml-build: Improve scalability of PPTT + generation + +Use g_queue APIs to reduce the nested loops and code indentation +with the processor hierarchy levels increasing. Consenquently, +it's more scalable to add new topology level to build_pptt. + +No functional change intended. + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-4-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/acpi/aml-build.c | 50 +++++++++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 18 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index b3b3310df3..6aaedca2e5 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2001,7 +2001,10 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + const char *oem_id, const char *oem_table_id) + { +- int pptt_start = table_data->len; ++ 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, +@@ -2010,9 +2013,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + acpi_table_begin(&table, table_data); + + for (socket = 0; socket < ms->smp.sockets; socket++) { +- uint32_t socket_offset = table_data->len - pptt_start; +- int core; +- ++ g_queue_push_tail(list, ++ GUINT_TO_POINTER(table_data->len - pptt_start)); + build_processor_hierarchy_node( + table_data, + /* +@@ -2021,35 +2023,47 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + */ + (1 << 0), + 0, socket, NULL, 0); ++ } + +- for (core = 0; core < ms->smp.cores; core++) { +- uint32_t core_offset = table_data->len - pptt_start; +- int thread; ++ 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++) { + 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 */ +- socket_offset, core, NULL, 0); +- +- 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 */ +- core_offset, uid++, NULL, 0); +- } ++ parent_offset, core, NULL, 0); + } else { + build_processor_hierarchy_node( + table_data, + (1 << 1) | /* ACPI Processor ID valid */ + (1 << 3), /* Node is a Leaf */ +- socket_offset, uid++, NULL, 0); ++ parent_offset, uid++, NULL, 0); + } + } + } + ++ 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); + } + +-- +2.27.0 + diff --git a/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch b/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch new file mode 100644 index 0000000000000000000000000000000000000000..17542a05a23ab3037961b1d4e970d9b1d32efd34 --- /dev/null +++ b/hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch @@ -0,0 +1,56 @@ +From 9c16924ba0a77c34246b69e8b1faee219f266445 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:31 +0800 +Subject: [PATCH 19/24] hw/acpi/aml-build: Support cluster level in PPTT + generation + +Support CPU cluster topology level in generation of ACPI +Processor Properties Topology Table (PPTT). + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-6-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/acpi/aml-build.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index 6aaedca2e5..bb2cad63b5 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2001,6 +2001,7 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + void build_pptt(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; +@@ -2025,6 +2026,23 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + 0, socket, NULL, 0); + } + ++ 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; +-- +2.27.0 + diff --git a/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch b/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch deleted file mode 100644 index f2c0f3900d05652a977be13df0babb8210c65b1b..0000000000000000000000000000000000000000 --- a/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch +++ /dev/null @@ -1,72 +0,0 @@ -From e6b1fd7bfbfe116e9d5df590f7069336c1eb1983 Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:29 +0100 -Subject: [PATCH] hw/arm: Factor out powerdown notifier from GPIO - -This is in preparation of using GED device for -system_powerdown event. Make the powerdown notifier -registration independent of create_gpio() fn. - -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-8-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/arm/virt.c | 12 ++++-------- - include/hw/arm/virt.h | 1 + - 2 files changed, 5 insertions(+), 8 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index ab33cce4b3..aaefa5578e 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -910,10 +910,6 @@ static void virt_powerdown_req(Notifier *n, void *opaque) - qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); - } - --static Notifier virt_system_powerdown_notifier = { -- .notify = virt_powerdown_req --}; -- - static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) - { - char *nodename; -@@ -954,10 +950,6 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) - KEY_POWER); - qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff", - "gpios", phandle, 3, 0); -- -- /* connect powerdown request */ -- qemu_register_powerdown_notifier(&virt_system_powerdown_notifier); -- - g_free(nodename); - } - -@@ -1856,6 +1848,10 @@ static void machvirt_init(MachineState *machine) - vms->acpi_dev = create_acpi_ged(vms, pic); - } - -+ /* connect powerdown request */ -+ vms->powerdown_notifier.notify = virt_powerdown_req; -+ qemu_register_powerdown_notifier(&vms->powerdown_notifier); -+ - /* Create mmio transports, so the user can create virtio backends - * (which will be automatically plugged in to the transports). If - * no backend is created the transport will just sit harmlessly idle. -diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 0350285136..dcceb9c615 100644 ---- a/include/hw/arm/virt.h -+++ b/include/hw/arm/virt.h -@@ -139,6 +139,7 @@ typedef struct { - int psci_conduit; - hwaddr highest_gpa; - DeviceState *acpi_dev; -+ Notifier powerdown_notifier; - } VirtMachineState; - - #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) --- -2.19.1 diff --git a/hw-arm-Use-GED-for-system_powerdown-event.patch b/hw-arm-Use-GED-for-system_powerdown-event.patch deleted file mode 100644 index 140f59a2c71da40f47a2edd2bd2dd529227c3ddc..0000000000000000000000000000000000000000 --- a/hw-arm-Use-GED-for-system_powerdown-event.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 0b77f242b180f1ae40b9752999cef4894113df8e Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:30 +0100 -Subject: [PATCH] hw/arm: Use GED for system_powerdown event - -For machines 4.2 or higher with ACPI boot use GED for system_powerdown -event instead of GPIO. Guest boot with DT still uses GPIO. - -Signed-off-by: Shameer Kolothum -Reviewed-by: Eric Auger -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-9-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/acpi/generic_event_device.c | 8 ++++++++ - hw/arm/virt-acpi-build.c | 6 +++--- - hw/arm/virt.c | 18 ++++++++++++------ - include/hw/acpi/acpi_dev_interface.h | 1 + - include/hw/acpi/generic_event_device.h | 3 +++ - 5 files changed, 27 insertions(+), 9 deletions(-) - -diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c -index b94500b08d..9cee90cc70 100644 ---- a/hw/acpi/generic_event_device.c -+++ b/hw/acpi/generic_event_device.c -@@ -22,6 +22,7 @@ - - static const uint32_t ged_supported_events[] = { - ACPI_GED_MEM_HOTPLUG_EVT, -+ ACPI_GED_PWR_DOWN_EVT, - }; - - /* -@@ -104,6 +105,11 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, - aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." - MEMORY_SLOT_SCAN_METHOD)); - break; -+ case ACPI_GED_PWR_DOWN_EVT: -+ aml_append(if_ctx, -+ aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), -+ aml_int(0x80))); -+ break; - default: - /* - * Please make sure all the events in ged_supported_events[] -@@ -184,6 +190,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) - - if (ev & ACPI_MEMORY_HOTPLUG_STATUS) { - sel = ACPI_GED_MEM_HOTPLUG_EVT; -+ } else if (ev & ACPI_POWER_DOWN_STATUS) { -+ sel = ACPI_GED_PWR_DOWN_EVT; - } else { - /* Unknown event. Return without generating interrupt. */ - warn_report("GED: Unsupported event %d. No irq injected", ev); -diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 9622994e50..f48733d9f2 100644 ---- a/hw/arm/virt-acpi-build.c -+++ b/hw/arm/virt-acpi-build.c -@@ -50,7 +50,6 @@ - #include "hw/acpi/acpi-defs.h" - - #define ARM_SPI_BASE 32 --#define ACPI_POWER_BUTTON_DEVICE "PWRB" - - static void acpi_dsdt_add_psd(Aml *dev, int cpus) - { -@@ -813,13 +812,14 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); - acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), - vms->highmem, vms->highmem_ecam); -- acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], -- (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); - if (vms->acpi_dev) { - build_ged_aml(scope, "\\_SB."GED_DEVICE, - HOTPLUG_HANDLER(vms->acpi_dev), - irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, - memmap[VIRT_ACPI_GED].base); -+ } else { -+ acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], -+ (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); - } - - if (vms->acpi_dev) { -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index aaefa5578e..18321e522b 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -639,10 +639,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) - DeviceState *dev; - MachineState *ms = MACHINE(vms); - int irq = vms->irqmap[VIRT_ACPI_GED]; -- uint32_t event = 0; -+ uint32_t event = ACPI_GED_PWR_DOWN_EVT; - - if (ms->ram_slots) { -- event = ACPI_GED_MEM_HOTPLUG_EVT; -+ event |= ACPI_GED_MEM_HOTPLUG_EVT; - } - - dev = qdev_create(NULL, TYPE_ACPI_GED); -@@ -906,8 +906,14 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) - static DeviceState *gpio_key_dev; - static void virt_powerdown_req(Notifier *n, void *opaque) - { -- /* use gpio Pin 3 for power button event */ -- qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); -+ VirtMachineState *s = container_of(n, VirtMachineState, powerdown_notifier); -+ -+ if (s->acpi_dev) { -+ acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS); -+ } else { -+ /* use gpio Pin 3 for power button event */ -+ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); -+ } - } - - static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) -@@ -1842,10 +1848,10 @@ static void machvirt_init(MachineState *machine) - - create_pcie(vms, pic); - -- create_gpio(vms, pic); -- - if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { - vms->acpi_dev = create_acpi_ged(vms, pic); -+ } else { -+ create_gpio(vms, pic); - } - - /* connect powerdown request */ -diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h -index 43ff119179..adcb3a816c 100644 ---- a/include/hw/acpi/acpi_dev_interface.h -+++ b/include/hw/acpi/acpi_dev_interface.h -@@ -11,6 +11,7 @@ typedef enum { - ACPI_MEMORY_HOTPLUG_STATUS = 8, - ACPI_NVDIMM_HOTPLUG_STATUS = 16, - ACPI_VMGENID_CHANGE_STATUS = 32, -+ ACPI_POWER_DOWN_STATUS = 64, - } AcpiEventStatusBits; - - #define TYPE_ACPI_DEVICE_IF "acpi-device-interface" -diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h -index 2049e8d873..d157eac088 100644 ---- a/include/hw/acpi/generic_event_device.h -+++ b/include/hw/acpi/generic_event_device.h -@@ -62,6 +62,8 @@ - #include "hw/sysbus.h" - #include "hw/acpi/memory_hotplug.h" - -+#define ACPI_POWER_BUTTON_DEVICE "PWRB" -+ - #define TYPE_ACPI_GED "acpi-ged" - #define ACPI_GED(obj) \ - OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED) -@@ -79,6 +81,7 @@ - * through GED. - */ - #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 -+#define ACPI_GED_PWR_DOWN_EVT 0x2 - - typedef struct GEDState { - MemoryRegion io; --- -2.19.1 diff --git a/hw-arm-acpi-enable-SHPC-native-hot-plug.patch b/hw-arm-acpi-enable-SHPC-native-hot-plug.patch deleted file mode 100644 index 2b2e530bb8e3555b4f9cf2a807b060ac62ccd9de..0000000000000000000000000000000000000000 --- a/hw-arm-acpi-enable-SHPC-native-hot-plug.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 1ad2e774f4fd3f720d5db07e86fe60df13f21a6d Mon Sep 17 00:00:00 2001 -From: Heyi Guo -Date: Mon, 9 Dec 2019 14:37:19 +0800 -Subject: [PATCH] hw/arm/acpi: enable SHPC native hot plug - -After the introduction of generic PCIe root port and PCIe-PCI bridge, -we will also have SHPC controller on ARM, so just enable SHPC native -hot plug. - -Also update tests/data/acpi/virt/DSDT* to pass "make check". - -Cc: Shannon Zhao -Cc: Peter Maydell -Cc: "Michael S. Tsirkin" -Cc: Igor Mammedov -Reviewed-by: Michael S. Tsirkin -Reviewed-by: Igor Mammedov -Signed-off-by: Heyi Guo -Message-id: 20191209063719.23086-3-guoheyi@huawei.com -Signed-off-by: Peter Maydell ---- - hw/arm/virt-acpi-build.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 2cfac7b84f..588e7f2680 100644 ---- a/hw/arm/virt-acpi-build.c -+++ b/hw/arm/virt-acpi-build.c -@@ -347,7 +347,12 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, - aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); - aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); - aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); -- aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL), -+ -+ /* -+ * Allow OS control for all 5 features: -+ * PCIeHotplug SHPCHotplug PME AER PCIeCapability. -+ */ -+ aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1F), NULL), - aml_name("CTRL"))); - - ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); --- -2.23.0 - diff --git a/hw-arm-ast2600-Fix-address-mapping-of-second-SPI-con.patch b/hw-arm-ast2600-Fix-address-mapping-of-second-SPI-con.patch new file mode 100644 index 0000000000000000000000000000000000000000..9935b5e9a54dc36340f77f73771a39798be3ac7b --- /dev/null +++ b/hw-arm-ast2600-Fix-address-mapping-of-second-SPI-con.patch @@ -0,0 +1,40 @@ +From 13a37e4130fbdfcd9a5027b4339eee592ee76889 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 11:01:29 +0800 +Subject: [PATCH] hw/arm: ast2600: Fix address mapping of second SPI controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 08048cbd5e7dc0a0359ccb8c7968e4d011174801 + +Address should be 0x1E631000 and not 0x1E641000 as initially introduced. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/838 +Fixes: f25c0ae1079d ("aspeed/soc: Add AST2600 support") +Suggested-by: Troy Lee +Signed-off-by: Cédric Le Goater +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20220126083520.4135713-1-clg@kaod.org +Signed-off-by: Peter Maydell +Signed-off-by: Luo Yifan +--- + hw/arm/aspeed_ast2600.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c +index 0384357a95..d83a70300e 100644 +--- a/hw/arm/aspeed_ast2600.c ++++ b/hw/arm/aspeed_ast2600.c +@@ -27,7 +27,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { + [ASPEED_DEV_PWM] = 0x1E610000, + [ASPEED_DEV_FMC] = 0x1E620000, + [ASPEED_DEV_SPI1] = 0x1E630000, +- [ASPEED_DEV_SPI2] = 0x1E641000, ++ [ASPEED_DEV_SPI2] = 0x1E631000, + [ASPEED_DEV_EHCI1] = 0x1E6A1000, + [ASPEED_DEV_EHCI2] = 0x1E6A3000, + [ASPEED_DEV_MII1] = 0x1E650000, +-- +2.27.0 + diff --git a/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch index 95abd07e5a2b62acd14c1a45e61ce471707f173e..0055d3b37ec334de1912824a8c78e9d81321a6cd 100644 --- a/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch +++ b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch @@ -1,4 +1,4 @@ -From de86ba0ff72a51b0c1cdbebf790869aea73ae9d3 Mon Sep 17 00:00:00 2001 +From 9dc22ff87eb61a8b2bcc5892961ec432986893c9 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 9 Apr 2020 09:31:22 +0800 Subject: [PATCH] hw/arm/boot: Add manually register and trigger of CPU reset @@ -17,13 +17,13 @@ Signed-off-by: Salil Mehta 4 files changed, 50 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c -index fc4e021a38..3ab9de6456 100644 +index 21024f7999..3d45de1772 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c -@@ -789,6 +789,24 @@ static void do_cpu_reset(void *opaque) +@@ -814,6 +814,24 @@ static void do_cpu_reset(void *opaque) } } - + +void cpu_hotplug_register_reset(int ncpu) +{ + CPUState *cpu_0 = qemu_get_cpu(0); @@ -46,13 +46,13 @@ index fc4e021a38..3ab9de6456 100644 * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified * by key. diff --git a/hw/core/reset.c b/hw/core/reset.c -index 9c477f2bf5..0efaf2d76c 100644 +index e923723d38..314d332111 100644 --- a/hw/core/reset.c +++ b/hw/core/reset.c -@@ -47,6 +47,31 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) +@@ -48,6 +48,31 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); } - + +QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func, + void *opaque) +{ @@ -82,13 +82,13 @@ index 9c477f2bf5..0efaf2d76c 100644 { QEMUResetEntry *re; diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h -index c48cc4c2bc..9452ccd1fa 100644 +index ce2b48b88b..c3c4d3ea79 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h -@@ -118,6 +118,9 @@ struct arm_boot_info { +@@ -119,6 +119,9 @@ struct arm_boot_info { arm_endianness endianness; }; - + +void cpu_hotplug_register_reset(int ncpu); +void cpu_hotplug_reset_manually(int ncpu); + @@ -101,15 +101,16 @@ index 0b0d6d7598..f3ff26c637 100644 +++ b/include/sysemu/reset.h @@ -2,7 +2,11 @@ #define QEMU_SYSEMU_RESET_H - + typedef void QEMUResetHandler(void *opaque); +typedef struct QEMUResetEntry QEMUResetEntry; - + +QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func, void *opaque); +void qemu_register_reset_after(QEMUResetEntry *entry, + QEMUResetHandler *func, void *opaque); void qemu_register_reset(QEMUResetHandler *func, void *opaque); void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); void qemu_devices_reset(void); --- -2.19.1 +-- +2.27.0 + diff --git a/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch b/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch deleted file mode 100644 index e7ca51a5deb7146de6d6b05aa1d8391b0c08adac..0000000000000000000000000000000000000000 --- a/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 220816989c1e3d490d293b8d7ac85dbc41a4c321 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 20 Sep 2019 18:40:39 +0100 -Subject: [PATCH] hw/arm/boot.c: Set NSACR.{CP11,CP10} for NS kernel boots - -If we're booting a Linux kernel directly into Non-Secure -state on a CPU which has Secure state, then make sure we -set the NSACR CP11 and CP10 bits, so that Non-Secure is allowed -to access the FPU. Otherwise an AArch32 kernel will UNDEF as -soon as it tries to use the FPU. - -It used to not matter that we didn't do this until commit -fc1120a7f5f2d4b6, where we implemented actually honouring -these NSACR bits. - -The problem only exists for CPUs where EL3 is AArch32; the -equivalent AArch64 trap bits are in CPTR_EL3 and are "0 to -not trap, 1 to trap", so the reset value of the register -permits NS access, unlike NSACR. - -Fixes: fc1120a7f5 -Fixes: https://bugs.launchpad.net/qemu/+bug/1844597 -Cc: qemu-stable@nongnu.org -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Message-id: 20190920174039.3916-1-peter.maydell@linaro.org -(cherry picked from commit ece628fcf69cbbd4b3efb6fbd203af07609467a2) -Signed-off-by: Michael Roth ---- - hw/arm/boot.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/arm/boot.c b/hw/arm/boot.c -index c2b89b3bb9..fc4e021a38 100644 ---- a/hw/arm/boot.c -+++ b/hw/arm/boot.c -@@ -754,6 +754,8 @@ static void do_cpu_reset(void *opaque) - (cs != first_cpu || !info->secure_board_setup)) { - /* Linux expects non-secure state */ - env->cp15.scr_el3 |= SCR_NS; -+ /* Set NSACR.{CP11,CP10} so NS can access the FPU */ -+ env->cp15.nsacr |= 3 << 10; - } - } - --- -2.23.0 diff --git a/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch b/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..8cc37891158df31ef5a281fba9921968b07ecd59 --- /dev/null +++ b/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch @@ -0,0 +1,62 @@ +From 81c2b665d9ea6670677f35aa1ab2ad68d6e73aa4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 20 Nov 2023 12:51:15 +0100 +Subject: [PATCH] hw/arm/fsl-imx: Do not ignore Error argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit 0cbb56c236a4a28f5149eed227d74bb737321cfc +category: bugfix + +-------------------------------------------------------- + +Both i.MX25 and i.MX6 SoC models ignore the Error argument when +setting the PHY number. Pick &error_abort which is the error +used by the i.MX7 SoC (see commit 1f7197deb0 "ability to change +the FEC PHY on i.MX7 processor"). + +Fixes: 74c1330582 ("ability to change the FEC PHY on i.MX25 processor") +Fixes: a9c167a3c4 ("ability to change the FEC PHY on i.MX6 processor") +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20231120115116.76858-1-philmd@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: zhujun2 +--- + hw/arm/fsl-imx25.c | 3 ++- + hw/arm/fsl-imx6.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c +index 24c4374590..9aabbf7f58 100644 +--- a/hw/arm/fsl-imx25.c ++++ b/hw/arm/fsl-imx25.c +@@ -169,7 +169,8 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) + epit_table[i].irq)); + } + +- object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err); ++ object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, ++ &error_abort); + qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) { +diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c +index 00dafe3f62..c4b95dc7a7 100644 +--- a/hw/arm/fsl-imx6.c ++++ b/hw/arm/fsl-imx6.c +@@ -377,7 +377,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) + spi_table[i].irq)); + } + +- object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &err); ++ object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, ++ &error_abort); + qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) { + return; +-- +2.27.0 + diff --git a/hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch b/hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch index 1824b8e4fd0fa31603df903bb640065c70858907..d92b5edd5a76cec878d9d7ddb1af9698360280b8 100644 --- a/hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch +++ b/hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch @@ -1,4 +1,4 @@ -From 8bf9d1dc67335c1fb921a56825f6bf198a568091 Mon Sep 17 00:00:00 2001 +From 876d18c962f0ead31d8458cd7ac19178be78455c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 19 Mar 2021 12:22:48 -0400 Subject: [PATCH] hw/arm/smmu-common: Allow domain invalidation for @@ -17,16 +17,16 @@ Signed-off-by: Kunkun Jiang 1 file changed, 1 insertion(+) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c -index 717d22bcbe..de9468d33f 100644 +index 3a1ecf81d6..2ec4222c93 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c -@@ -395,6 +395,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) - entry.iova = n->start; - entry.perm = IOMMU_NONE; - entry.addr_mask = n->end - n->start; -+ entry.granularity = IOMMU_INV_GRAN_DOMAIN; +@@ -477,6 +477,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) + event.entry.iova = n->start; + event.entry.perm = IOMMU_NONE; + event.entry.addr_mask = n->end - n->start; ++ event.entry.granularity = IOMMU_INV_GRAN_DOMAIN; - memory_region_notify_one(n, &entry); + memory_region_notify_iommu_one(n, &event); } -- 2.27.0 diff --git a/hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch b/hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch index 89f9292287246e65a25587df2da43f2765457312..e8d397824f80fff77c7260bfb4dcec67e410b250 100644 --- a/hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch +++ b/hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch @@ -1,4 +1,4 @@ -From bc602a4d1355774a0a44e8fbf6dd842049dd63f3 Mon Sep 17 00:00:00 2001 +From 5a759ab19d508361053e388694546216705d173b Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 28 Aug 2018 09:21:53 -0400 Subject: [PATCH] hw/arm/smmuv3: Advertise MSI_TRANSLATE attribute @@ -14,10 +14,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 3 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 55eed5189e..83d59b6d28 100644 +index 9b87d16217..12f354a0d5 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -1538,6 +1538,9 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, +@@ -1596,6 +1596,9 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, if (attr == IOMMU_ATTR_VFIO_NESTED) { *(bool *) data = true; return 0; diff --git a/hw-arm-smmuv3-Allow-MAP-notifiers.patch b/hw-arm-smmuv3-Allow-MAP-notifiers.patch index ec050121fcd57a2e942774ce76fceb8ed5039cf2..1d82532d1262f420e3d4bb39f27579d85f437026 100644 --- a/hw-arm-smmuv3-Allow-MAP-notifiers.patch +++ b/hw-arm-smmuv3-Allow-MAP-notifiers.patch @@ -1,4 +1,4 @@ -From 965729b4875f637dacdbf82960347beb65512d12 Mon Sep 17 00:00:00 2001 +From dc126664134989975ce9ab9e7d5d2c8916628bf6 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 18 Mar 2020 11:17:36 +0100 Subject: [PATCH] hw/arm/smmuv3: Allow MAP notifiers @@ -14,19 +14,19 @@ Signed-off-by: Kunkun Jiang 1 file changed, 8 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 931d6eae57..c26fba118c 100644 +index 9aeb420428..45f21c53fe 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -1563,14 +1563,6 @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, - SMMUv3State *s3 = sdev->smmu; - SMMUState *s = &(s3->smmu_state); +@@ -1628,14 +1628,6 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + return -EINVAL; + } - if (new & IOMMU_NOTIFIER_MAP) { -- int bus_num = pci_bus_num(sdev->bus); -- PCIDevice *pcidev = pci_find_device(sdev->bus, bus_num, sdev->devfn); -- -- warn_report("SMMUv3 does not support notification on MAP: " -- "device %s will not function properly", pcidev->name); +- error_setg(errp, +- "device %02x.%02x.%x requires iommu MAP notifier which is " +- "not currently supported", pci_bus_num(sdev->bus), +- PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn)); +- return -EINVAL; - } - if (old == IOMMU_NOTIFIER_NONE) { diff --git a/hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch b/hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch index 1f3425e7eddae1fee87d0cb8d86587f4e6011ee5..646a95bd19bab7b28a797433b0321edc45512657 100644 --- a/hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch +++ b/hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch @@ -1,4 +1,4 @@ -From 8108317641b3cb378bf1862dc3c0a73d1e0976ce Mon Sep 17 00:00:00 2001 +From dcda615b3d9b1acffee3d31d57974cc9e4bd0dee Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 4 Sep 2018 08:48:33 -0400 Subject: [PATCH] hw/arm/smmuv3: Fill the IOTLBEntry arch_id on NH_VA @@ -17,17 +17,17 @@ Signed-off-by: Kunkun Jiang 1 file changed, 2 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index f8e721f949..c6b950af35 100644 +index 3416f6a639..696c588f08 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -824,6 +824,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - entry.iova = iova; - entry.addr_mask = (1 << tt->granule_sz) - 1; - entry.perm = IOMMU_NONE; -+ entry.flags = IOMMU_INV_FLAGS_ARCHID; -+ entry.arch_id = asid; +@@ -833,6 +833,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + event.entry.iova = iova; + event.entry.addr_mask = num_pages * (1 << granule) - 1; + event.entry.perm = IOMMU_NONE; ++ event.entry.flags = IOMMU_INV_FLAGS_ARCHID; ++ event.entry.arch_id = asid; - memory_region_notify_one(n, &entry); + memory_region_notify_iommu_one(n, &event); } -- 2.27.0 diff --git a/hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch b/hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch index febaffaa655ecbe70419d692e586e56b1561f330..f5f3db19ea9ca70944d1da3be402ce800226d08c 100644 --- a/hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch +++ b/hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch @@ -1,4 +1,4 @@ -From 6393ad5c1ba6a04b038d80ecc1e663ad91ed0d21 Mon Sep 17 00:00:00 2001 +From c219274b7b6a472d7340a4f72a052ba33ed19659 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 14 Mar 2019 09:55:13 -0400 Subject: [PATCH] hw/arm/smmuv3: Fill the IOTLBEntry leaf field on NH_VA @@ -12,70 +12,66 @@ penalties in nested mode. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - hw/arm/smmuv3.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) + hw/arm/smmuv3.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index c6b950af35..c1caa6bc3a 100644 +index 696c588f08..ad816e850c 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -795,7 +795,7 @@ epilogue: +@@ -800,7 +800,7 @@ epilogue: static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, IOMMUNotifier *n, - int asid, -- dma_addr_t iova) -+ dma_addr_t iova, bool leaf) + int asid, dma_addr_t iova, +- uint8_t tg, uint64_t num_pages) ++ uint8_t tg, uint64_t num_pages, bool leaf) { SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); - SMMUEventInfo event = {}; -@@ -826,6 +826,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - entry.perm = IOMMU_NONE; - entry.flags = IOMMU_INV_FLAGS_ARCHID; - entry.arch_id = asid; -+ entry.leaf = leaf; + IOMMUTLBEvent event = {}; +@@ -835,6 +835,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + event.entry.perm = IOMMU_NONE; + event.entry.flags = IOMMU_INV_FLAGS_ARCHID; + event.entry.arch_id = asid; ++ event.entry.leaf = leaf; - memory_region_notify_one(n, &entry); - } -@@ -854,7 +855,8 @@ static void smmuv3_notify_asid(IOMMUMemoryRegion *mr, + memory_region_notify_iommu_one(n, &event); } +@@ -866,7 +867,7 @@ static void smmuv3_notify_asid(IOMMUMemoryRegion *mr, - /* invalidate an asid/iova tuple in all mr's */ --static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova) -+static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, -+ bool leaf) + /* invalidate an asid/iova range tuple in all mr's */ + static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, +- uint8_t tg, uint64_t num_pages) ++ uint8_t tg, uint64_t num_pages, bool leaf) { SMMUDevice *sdev; -@@ -865,7 +867,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova) - trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova); +@@ -878,7 +879,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, + tg, num_pages); IOMMU_NOTIFIER_FOREACH(n, mr) { -- smmuv3_notify_iova(mr, n, asid, iova); -+ smmuv3_notify_iova(mr, n, asid, iova, leaf); +- smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages); ++ smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages, leaf); } } } -@@ -1018,9 +1020,10 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) - { - dma_addr_t addr = CMD_ADDR(&cmd); - uint16_t vmid = CMD_VMID(&cmd); -+ bool leaf = CMD_LEAF(&cmd); +@@ -903,7 +904,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) - trace_smmuv3_cmdq_tlbi_nh_vaa(vmid, addr); -- smmuv3_inv_notifiers_iova(bs, -1, addr); -+ smmuv3_inv_notifiers_iova(bs, -1, addr, leaf); - smmu_iotlb_inv_all(bs); - break; - } -@@ -1032,7 +1035,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) - bool leaf = CMD_LEAF(&cmd); + if (!tg) { + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, 1, ttl, leaf); +- smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1); ++ smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1, leaf); + smmu_iotlb_inv_iova(s, asid, addr, tg, 1, ttl); + return; + } +@@ -921,7 +922,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) - trace_smmuv3_cmdq_tlbi_nh_va(vmid, asid, addr, leaf); -- smmuv3_inv_notifiers_iova(bs, asid, addr); -+ smmuv3_inv_notifiers_iova(bs, asid, addr, leaf); - smmu_iotlb_inv_iova(bs, asid, addr); - break; - } + num_pages = (mask + 1) >> granule; + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf); +- smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages); ++ smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages, leaf); + smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl); + addr += mask + 1; + } -- 2.27.0 diff --git a/hw-arm-smmuv3-Implement-fault-injection.patch b/hw-arm-smmuv3-Implement-fault-injection.patch index 0260e28a05e7d30ec2b637eadb2251890c7e3701..5ecb6da751ece0b759505e47ea49e254234787ef 100644 --- a/hw-arm-smmuv3-Implement-fault-injection.patch +++ b/hw-arm-smmuv3-Implement-fault-injection.patch @@ -1,4 +1,4 @@ -From 55bfd18b7671c82705d83d543281add0afcda31f Mon Sep 17 00:00:00 2001 +From d31c754470b4b651d0e19c66738fbcc8fc6abf3c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 13 Sep 2018 14:24:45 +0200 Subject: [PATCH] hw/arm/smmuv3: Implement fault injection @@ -14,10 +14,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 71 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 3d2151857d..931d6eae57 100644 +index 58139f707d..9aeb420428 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -1594,6 +1594,76 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, +@@ -1660,6 +1660,76 @@ static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, return -EINVAL; } @@ -94,7 +94,7 @@ index 3d2151857d..931d6eae57 100644 static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, void *data) { -@@ -1602,6 +1672,7 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, +@@ -1668,6 +1738,7 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, imrc->translate = smmuv3_translate; imrc->notify_flag_changed = smmuv3_notify_flag_changed; imrc->get_attr = smmuv3_get_attr; diff --git a/hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch b/hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch index 10639e89f957b970b78f2c0de930ad8b92032d0f..505bec39045c01a65e90863f940dc28011f7b400 100644 --- a/hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch +++ b/hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch @@ -1,4 +1,4 @@ -From c0027c2e744c8ed99e937d3cbc88f400ab63a316 Mon Sep 17 00:00:00 2001 +From de53feaa37a267a21ed30a642e1e64c5fcfbc4a4 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Sun, 14 Feb 2021 12:30:57 -0500 Subject: [PATCH] hw/arm/smmuv3: Improve stage1 ASID invalidation @@ -17,16 +17,16 @@ do not support the new fields, like VHOST. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - hw/arm/smmuv3.c | 42 ++++++++++++++++++++++++++++++++++++++++-- + hw/arm/smmuv3.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- hw/arm/trace-events | 1 + - 2 files changed, 41 insertions(+), 2 deletions(-) + 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 3b5723e1e1..0ef1ca376c 100644 +index 94e2c658f8..da5dac1ba5 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -827,6 +827,29 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - memory_region_notify_one(n, &entry); +@@ -836,6 +836,31 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + memory_region_notify_iommu_one(n, &event); } +/** @@ -39,24 +39,26 @@ index 3b5723e1e1..0ef1ca376c 100644 +static void smmuv3_notify_asid(IOMMUMemoryRegion *mr, + IOMMUNotifier *n, int asid) +{ -+ IOMMUTLBEntry entry; ++ IOMMUTLBEvent event = {}; + -+ entry.target_as = &address_space_memory; -+ entry.perm = IOMMU_NONE; -+ entry.granularity = IOMMU_INV_GRAN_PASID; -+ entry.flags = IOMMU_INV_FLAGS_ARCHID; -+ entry.arch_id = asid; -+ entry.iova = n->start; -+ entry.addr_mask = n->end - n->start; ++ event.type = IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.perm = IOMMU_NONE; ++ event.entry.granularity = IOMMU_INV_GRAN_PASID; ++ event.entry.flags = IOMMU_INV_FLAGS_ARCHID; ++ event.entry.arch_id = asid; ++ event.entry.iova = n->start; ++ event.entry.addr_mask = n->end - n->start; + -+ memory_region_notify_one(n, &entry); ++ memory_region_notify_iommu_one(n, &event); +} + - /* invalidate an asid/iova tuple in all mr's */ - static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova) - { -@@ -844,6 +867,22 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova) - } ++ + /* invalidate an asid/iova range tuple in all mr's */ + static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, + uint8_t tg, uint64_t num_pages) +@@ -913,6 +938,22 @@ smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + return true; } +static void smmuv3_s1_asid_inval(SMMUState *s, uint16_t asid) @@ -78,7 +80,7 @@ index 3b5723e1e1..0ef1ca376c 100644 static int smmuv3_cmdq_consume(SMMUv3State *s) { SMMUState *bs = ARM_SMMU(s); -@@ -963,8 +1002,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) +@@ -1027,8 +1068,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) uint16_t asid = CMD_ASID(&cmd); trace_smmuv3_cmdq_tlbi_nh_asid(asid); @@ -89,17 +91,17 @@ index 3b5723e1e1..0ef1ca376c 100644 } case SMMU_CMD_TLBI_NH_ALL: diff --git a/hw/arm/trace-events b/hw/arm/trace-events -index 0acedcedc6..4512d20115 100644 +index 2dee296c8f..1447ad5a90 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events -@@ -44,6 +44,7 @@ smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t p - smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)" - smmuv3_cmdq_tlbi_nh_va(int vmid, int asid, uint64_t addr, bool leaf) "vmid =%d asid =%d addr=0x%"PRIx64" leaf=%d" - smmuv3_cmdq_tlbi_nh_vaa(int vmid, uint64_t addr) "vmid =%d addr=0x%"PRIx64 +@@ -46,6 +46,7 @@ smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x" + smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)" + smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)" + smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d" +smmuv3_s1_asid_inval(int asid) "asid=%d" smmuv3_cmdq_tlbi_nh(void) "" smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d" - smmu_iotlb_cache_hit(uint16_t asid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d" + smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x" -- 2.27.0 diff --git a/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch b/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch index a615b8664bd6b9c3603073bfd7ec0bb505e70ef8..012c5d0071dc9f1bce50e706958e55fb443230d2 100644 --- a/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch +++ b/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch @@ -1,4 +1,4 @@ -From d0a1ce3c46246b6ef5510ac1d5c18308417ed525 Mon Sep 17 00:00:00 2001 +From 2e5929ec2a35a7a227dc7ba70a557a84993a366d Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 9 Aug 2018 21:04:19 +0200 Subject: [PATCH] hw/arm/smmuv3: Pass stage 1 configurations to the host @@ -12,12 +12,25 @@ to the host and apply it at physical level. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - hw/arm/smmuv3.c | 77 +++++++++++++++++++++++++++++++++++---------- - hw/arm/trace-events | 2 +- - 2 files changed, 61 insertions(+), 18 deletions(-) + hw/arm/smmu-internal.h | 1 + + hw/arm/smmuv3.c | 71 ++++++++++++++++++++++++++++++++++++------ + hw/arm/trace-events | 1 + + 3 files changed, 64 insertions(+), 9 deletions(-) +diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h +index 2d75b31953..5ef8c598c6 100644 +--- a/hw/arm/smmu-internal.h ++++ b/hw/arm/smmu-internal.h +@@ -105,6 +105,7 @@ typedef struct SMMUIOTLBPageInvInfo { + } SMMUIOTLBPageInvInfo; + + typedef struct SMMUSIDRange { ++ SMMUState *state; + uint32_t start; + uint32_t end; + } SMMUSIDRange; diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index c1caa6bc3a..3d2151857d 100644 +index ad816e850c..58139f707d 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -16,6 +16,10 @@ @@ -29,9 +42,9 @@ index c1caa6bc3a..3d2151857d 100644 +#endif + #include "qemu/osdep.h" - #include "hw/boards.h" - #include "sysemu/sysemu.h" -@@ -872,6 +876,60 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, + #include "qemu/bitops.h" + #include "hw/irq.h" +@@ -928,6 +932,61 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) } } @@ -39,7 +52,8 @@ index c1caa6bc3a..3d2151857d 100644 +{ +#ifdef __linux__ + IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); -+ SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid}; ++ SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid, ++ .inval_ste_allowed = true}; + IOMMUConfig iommu_config = {}; + SMMUTransCfg *cfg; + SMMUDevice *sdev; @@ -89,10 +103,18 @@ index c1caa6bc3a..3d2151857d 100644 +#endif +} + - static void smmuv3_s1_asid_inval(SMMUState *s, uint16_t asid) + static gboolean + smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) { - SMMUDevice *sdev; -@@ -938,22 +996,14 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) +@@ -938,6 +997,7 @@ smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + if (sid < sid_range->start || sid > sid_range->end) { + return false; + } ++ smmuv3_notify_config_change(sid_range->state, sid); + trace_smmuv3_config_cache_inv(sid); + return true; + } +@@ -1008,22 +1068,14 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) case SMMU_CMD_CFGI_STE: { uint32_t sid = CMD_SID(&cmd); @@ -116,32 +138,24 @@ index c1caa6bc3a..3d2151857d 100644 break; } case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ -@@ -970,14 +1020,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) - trace_smmuv3_cmdq_cfgi_ste_range(start, end); - - for (i = start; i <= end; i++) { -- IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, i); -- SMMUDevice *sdev; -- -- if (!mr) { -- continue; -- } -- sdev = container_of(mr, SMMUDevice, iommu); -- smmuv3_flush_config(sdev); -+ smmuv3_notify_config_change(bs, i); +@@ -1038,6 +1090,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) } - break; - } + + mask = (1ULL << (range + 1)) - 1; ++ sid_range.state = bs; + sid_range.start = sid & ~mask; + sid_range.end = sid_range.start + mask; + diff --git a/hw/arm/trace-events b/hw/arm/trace-events -index 4512d20115..cbbe2ccafd 100644 +index 1447ad5a90..d9851d663e 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events -@@ -53,4 +53,4 @@ smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid %d" +@@ -53,4 +53,5 @@ smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x" smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s" smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" - smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova) "iommu mr=%s asid=%d iova=0x%"PRIx64 -- + smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 +smmuv3_notify_config_change(const char *name, uint8_t config, uint64_t s1ctxptr) "iommu mr=%s config=%d s1ctxptr=0x%"PRIx64 + -- 2.27.0 diff --git a/hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch b/hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch index c363acb60c0fce72a986b6056aa74bb578b7a992..0fc5f84460a60655713b48766bed2b7599042431 100644 --- a/hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch +++ b/hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch @@ -1,4 +1,4 @@ -From 06e43bc658aa80bb5f4da3e43c1c13d4cab6ebdd Mon Sep 17 00:00:00 2001 +From 1b95c995f032c21bf6607dda8ede0f5856bb190a Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 11 May 2021 10:08:16 +0800 Subject: [PATCH] hw/arm/smmuv3: Post-load stage 1 configurations to the host @@ -17,10 +17,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index c26fba118c..f383143db1 100644 +index 45f21c53fe..291e3a12e8 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -876,7 +876,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, +@@ -932,7 +932,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) } } @@ -29,7 +29,7 @@ index c26fba118c..f383143db1 100644 { #ifdef __linux__ IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); -@@ -884,9 +884,10 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) +@@ -941,9 +941,10 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) IOMMUConfig iommu_config = {}; SMMUTransCfg *cfg; SMMUDevice *sdev; @@ -41,7 +41,7 @@ index c26fba118c..f383143db1 100644 } sdev = container_of(mr, SMMUDevice, iommu); -@@ -895,13 +896,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) +@@ -952,13 +953,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) smmuv3_flush_config(sdev); if (!pci_device_is_pasid_ops_set(sdev->bus, sdev->devfn)) { @@ -57,7 +57,7 @@ index c26fba118c..f383143db1 100644 } iommu_config.pasid_cfg.argsz = sizeof(struct iommu_pasid_table_config); -@@ -923,10 +924,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) +@@ -980,10 +981,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) iommu_config.pasid_cfg.config, iommu_config.pasid_cfg.base_ptr); @@ -72,7 +72,7 @@ index c26fba118c..f383143db1 100644 #endif } -@@ -1494,6 +1498,24 @@ static void smmu_realize(DeviceState *d, Error **errp) +@@ -1553,6 +1557,24 @@ static void smmu_realize(DeviceState *d, Error **errp) smmu_init_irq(s, dev); } @@ -97,7 +97,7 @@ index c26fba118c..f383143db1 100644 static const VMStateDescription vmstate_smmuv3_queue = { .name = "smmuv3_queue", .version_id = 1, -@@ -1512,6 +1534,7 @@ static const VMStateDescription vmstate_smmuv3 = { +@@ -1571,6 +1593,7 @@ static const VMStateDescription vmstate_smmuv3 = { .version_id = 1, .minimum_version_id = 1, .priority = MIG_PRI_IOMMU, diff --git a/hw-arm-smmuv3-Set-the-restoration-priority-of-the-vS.patch b/hw-arm-smmuv3-Set-the-restoration-priority-of-the-vS.patch deleted file mode 100644 index 1139feaed62705a6baebbecba25ad0355b761daf..0000000000000000000000000000000000000000 --- a/hw-arm-smmuv3-Set-the-restoration-priority-of-the-vS.patch +++ /dev/null @@ -1,33 +0,0 @@ -From eceb9213e23d15d5b4342b6a6a8368f4fec60c2f Mon Sep 17 00:00:00 2001 -From: Zenghui Yu -Date: Mon, 19 Oct 2020 17:15:08 +0800 -Subject: [PATCH] hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 - explicitly - -Ensure the vSMMUv3 will be restored before all PCIe devices so that DMA -translation can work properly during migration. - -Signed-off-by: Zenghui Yu -Message-id: 20201019091508.197-1-yuzenghui@huawei.com -Acked-by: Eric Auger -Signed-off-by: Peter Maydell -Signed-off-by: Kunkun Jiang ---- - hw/arm/smmuv3.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 7911944c59..3b5723e1e1 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -1424,6 +1424,7 @@ static const VMStateDescription vmstate_smmuv3 = { - .name = "smmuv3", - .version_id = 1, - .minimum_version_id = 1, -+ .priority = MIG_PRI_IOMMU, - .fields = (VMStateField[]) { - VMSTATE_UINT32(features, SMMUv3State), - VMSTATE_UINT8(sid_size, SMMUv3State), --- -2.27.0 - diff --git a/hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch b/hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch index 8ed3590b6e3c3863486db0082be983a7b7d4968c..3bbf1dadc18e41dbfe5859f337c79d42ef557c0b 100644 --- a/hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch +++ b/hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch @@ -1,4 +1,4 @@ -From 6fc85d8a6022d94ffec4cc118472cde583706bfb Mon Sep 17 00:00:00 2001 +From f937ce4124d57eea27d516957a2efa0e7fbdf198 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 9 Aug 2018 20:56:44 +0200 Subject: [PATCH] hw/arm/smmuv3: Store the PASID table GPA in the translation @@ -17,10 +17,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 2 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 83d59b6d28..f8e721f949 100644 +index 12f354a0d5..3416f6a639 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -352,6 +352,7 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg, +@@ -358,6 +358,7 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg, "SMMUv3 S1 stalling fault model not allowed yet\n"); goto bad_ste; } @@ -29,10 +29,10 @@ index 83d59b6d28..f8e721f949 100644 bad_ste: diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h -index 1f37844e5c..353668f4ea 100644 +index 706be3c6d0..d578339935 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h -@@ -68,6 +68,7 @@ typedef struct SMMUTransCfg { +@@ -76,6 +76,7 @@ typedef struct SMMUTransCfg { uint8_t tbi; /* Top Byte Ignore */ uint16_t asid; SMMUTransTableInfo tt[2]; diff --git a/hw-arm-smmuv3-Support-16K-translation-granule.patch b/hw-arm-smmuv3-Support-16K-translation-granule.patch deleted file mode 100644 index 08c4bc5603401f6e5735daa6767dfa2aa2785255..0000000000000000000000000000000000000000 --- a/hw-arm-smmuv3-Support-16K-translation-granule.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 008dec30dea19950ff48a34c54441d065c1f228b Mon Sep 17 00:00:00 2001 -From: Kunkun Jiang -Date: Wed, 31 Mar 2021 14:47:13 +0800 -Subject: [PATCH] hw/arm/smmuv3: Support 16K translation granule - -The driver can query some bits in SMMUv3 IDR5 to learn which -translation granules are supported. Arm recommends that SMMUv3 -implementations support at least 4K and 64K granules. But in -the vSMMUv3, there seems to be no reason not to support 16K -translation granule. In addition, if 16K is not supported, -vSVA will failed to be enabled in the future for 16K guest -kernel. So it'd better to support it. - -Signed-off-by: Kunkun Jiang -Reviewed-by: Eric Auger -Tested-by: Eric Auger -Signed-off-by: Peter Maydell ---- - hw/arm/smmuv3.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index e96d5beb9a..7911944c59 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -254,8 +254,9 @@ static void smmuv3_init_regs(SMMUv3State *s) - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS); - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS); - -- /* 4K and 64K granule support */ -+ /* 4K, 16K and 64K granule support */ - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); -+ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1); - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1); - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */ - -@@ -480,7 +481,8 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event) - - tg = CD_TG(cd, i); - tt->granule_sz = tg2granule(tg, i); -- if ((tt->granule_sz != 12 && tt->granule_sz != 16) || CD_ENDI(cd)) { -+ if ((tt->granule_sz != 12 && tt->granule_sz != 14 && -+ tt->granule_sz != 16) || CD_ENDI(cd)) { - goto bad_cd; - } - --- -2.27.0 - diff --git a/hw-arm-virt-Add-memory-hotplug-framework.patch b/hw-arm-virt-Add-memory-hotplug-framework.patch deleted file mode 100644 index dcb0f21f5b63e10636d889f6cae99a4d738d1d0e..0000000000000000000000000000000000000000 --- a/hw-arm-virt-Add-memory-hotplug-framework.patch +++ /dev/null @@ -1,130 +0,0 @@ -From e14fadc66d488ad10a10a2076721b72cc239ded9 Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Wed, 18 Sep 2019 14:06:26 +0100 -Subject: [PATCH] hw/arm/virt: Add memory hotplug framework - -This patch adds the memory hot-plug/hot-unplug infrastructure -in machvirt. The device memory is not yet exposed to the Guest -either through DT or ACPI and hence both cold/hot plug of memory -is explicitly disabled for now. - -Signed-off-by: Eric Auger -Signed-off-by: Kwangwoo Lee -Signed-off-by: Shameer Kolothum -Reviewed-by: Peter Maydell -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-5-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/arm/Kconfig | 2 ++ - hw/arm/virt.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 54 insertions(+), 1 deletion(-) - -diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig -index ab65ecd216..84961c17ab 100644 ---- a/hw/arm/Kconfig -+++ b/hw/arm/Kconfig -@@ -20,6 +20,8 @@ config ARM_VIRT - select SMBIOS - select VIRTIO_MMIO - select ACPI_PCI -+ select MEM_DEVICE -+ select DIMM - - config CHEETAH - bool -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 23d72aed97..c7c07fe3ac 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -65,6 +65,8 @@ - #include "hw/arm/smmuv3.h" - #include "hw/acpi/acpi.h" - #include "target/arm/internals.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/mem/nvdimm.h" - - #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ - static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ -@@ -1998,6 +2000,42 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) - return ms->possible_cpus; - } - -+static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ -+ /* -+ * The device memory is not yet exposed to the Guest either through -+ * DT or ACPI and hence both cold/hot plug of memory is explicitly -+ * disabled for now. -+ */ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ error_setg(errp, "memory cold/hot plug is not yet supported"); -+ return; -+ } -+ -+ pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); -+} -+ -+static void virt_memory_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); -+ Error *local_err = NULL; -+ -+ pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err); -+ -+ error_propagate(errp, local_err); -+} -+ -+static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ virt_memory_pre_plug(hotplug_dev, dev, errp); -+ } -+} -+ - static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -@@ -2009,12 +2047,23 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, - SYS_BUS_DEVICE(dev)); - } - } -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ virt_memory_plug(hotplug_dev, dev, errp); -+ } -+} -+ -+static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ error_setg(errp, "device unplug request for unsupported device" -+ " type: %s", object_get_typename(OBJECT(dev))); - } - - static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, - DeviceState *dev) - { -- if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) { -+ if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) || -+ (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { - return HOTPLUG_HANDLER(machine); - } - -@@ -2078,7 +2127,9 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) - mc->kvm_type = virt_kvm_type; - assert(!mc->get_hotplug_handler); - mc->get_hotplug_handler = virt_machine_get_hotplug_handler; -+ hc->pre_plug = virt_machine_device_pre_plug_cb; - hc->plug = virt_machine_device_plug_cb; -+ hc->unplug_request = virt_machine_device_unplug_request_cb; - mc->numa_mem_supported = true; - } - --- -2.19.1 diff --git a/hw-arm-virt-Assign-virt_madt_cpu_entry-to-acpi_ged-m.patch b/hw-arm-virt-Assign-virt_madt_cpu_entry-to-acpi_ged-m.patch new file mode 100644 index 0000000000000000000000000000000000000000..71aea39369b48af8680a8071e2234860adfb77a1 --- /dev/null +++ b/hw-arm-virt-Assign-virt_madt_cpu_entry-to-acpi_ged-m.patch @@ -0,0 +1,40 @@ +From ae74dda87e172ce82a8180d1a2e9c62904390f91 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 10:05:54 +0800 +Subject: [PATCH] hw/arm/virt: Assign virt_madt_cpu_entry to acpi_ged madt_cpu + hook + +In build_cpus_aml, we will invoke this hook to build _MAT +aml mehtod for cpus. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 47e98f09e8..44c29070c4 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -684,6 +684,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) + static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + { + DeviceState *dev; ++ AcpiDeviceIfClass *adevc; + MachineState *ms = MACHINE(vms); + int irq = vms->irqmap[VIRT_ACPI_GED]; + uint32_t event = ACPI_GED_PWR_DOWN_EVT; +@@ -699,6 +700,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + dev = qdev_new(TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); + ++ adevc = ACPI_DEVICE_IF_GET_CLASS(dev); ++ adevc->madt_cpu = virt_madt_cpu_entry; ++ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); +-- +2.27.0 + diff --git a/hw-arm-virt-Check-for-attempt-to-use-TrustZone-with-.patch b/hw-arm-virt-Check-for-attempt-to-use-TrustZone-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..f395c38dea1247a63e682d8e0e2bb91051c1ab50 --- /dev/null +++ b/hw-arm-virt-Check-for-attempt-to-use-TrustZone-with-.patch @@ -0,0 +1,57 @@ +From fd9cd16407e9d98807c631521ff1fcb83bfefac4 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 21 Aug 2023 06:21:27 +0000 +Subject: [PATCH] hw/arm/virt: Check for attempt to use TrustZone with KVM or + HVF mainline inclusion commit 78255ce392dc8596f9886476ad1e5c3c67f1c10a + category: bugfix + +--------------------------------------------------------------- + +It's not possible to provide the guest with the Security extensions +(TrustZone) when using KVM or HVF, because the hardware +virtualization extensions don't permit running EL3 guest code. +However, we weren't checking for this combination, with the result +that QEMU would assert if you tried it: + +$ qemu-system-aarch64 -enable-kvm -machine virt,secure=on -cpu host -display none +Unexpected error in object_property_find_err() at ../../qom/object.c:1304: +qemu-system-aarch64: Property 'host-arm-cpu.secure-memory' not found +Aborted + +Check for this combination of options and report an error, in the +same way we already do for attempts to give a KVM or HVF guest the +Virtualization or MTE extensions. Now we will report: + +qemu-system-aarch64: mach-virt: KVM does not support providing Security extensions (TrustZone) to the guest CPU + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/961 +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20220404155301.566542-1-peter.maydell@linaro.org + +Signed-off-by: tangbinzy +--- + hw/arm/virt.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 4c876fcf16..93554cccf1 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2097,6 +2097,13 @@ static void machvirt_init(MachineState *machine) + exit(1); + } + ++ if (vms->secure && (kvm_enabled() || hvf_enabled())) { ++ error_report("mach-virt: %s does not support providing " ++ "Security extensions (TrustZone) to the guest CPU", ++ kvm_enabled() ? "KVM" : "HVF"); ++ exit(1); ++ } ++ + if (vms->virt && (kvm_enabled() || hvf_enabled())) { + error_report("mach-virt: %s does not support providing " + "Virtualization extensions to the guest CPU", +-- +2.41.0.windows.1 + diff --git a/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch b/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch deleted file mode 100644 index b32b2a01929189ff6f89e94f011d4d9cc3811a3b..0000000000000000000000000000000000000000 --- a/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch +++ /dev/null @@ -1,252 +0,0 @@ -From ce813d8daa2e01df52509f4bb52b9ab774408706 Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:27 +0100 -Subject: [PATCH] hw/arm/virt: Enable device memory cold/hot plug with ACPI - boot - -This initializes the GED device with base memory and irq, configures -ged memory hotplug event and builds the corresponding aml code. With -this, both hot and cold plug of device memory is enabled now for Guest -with ACPI boot. Memory cold plug support with Guest DT boot is not yet -supported. - -As DSDT table gets changed by this, update bios-tables-test-allowed-diff.h -to avoid "make check" failure. - -Signed-off-by: Shameer Kolothum -Message-Id: <20190918130633.4872-6-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Igor Mammedov ---- - hw/arm/Kconfig | 2 ++ - hw/arm/virt-acpi-build.c | 21 ++++++++++++++ - hw/arm/virt.c | 59 +++++++++++++++++++++++++++++++++++----- - include/hw/arm/virt.h | 4 +++ - 4 files changed, 79 insertions(+), 7 deletions(-) - -diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig -index 84961c17ab..ad7f7c089b 100644 ---- a/hw/arm/Kconfig -+++ b/hw/arm/Kconfig -@@ -22,6 +22,8 @@ config ARM_VIRT - select ACPI_PCI - select MEM_DEVICE - select DIMM -+ select ACPI_MEMORY_HOTPLUG -+ select ACPI_HW_REDUCED - - config CHEETAH - bool -diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index fe54411f6a..fca53ae01f 100644 ---- a/hw/arm/virt-acpi-build.c -+++ b/hw/arm/virt-acpi-build.c -@@ -40,6 +40,8 @@ - #include "hw/acpi/aml-build.h" - #include "hw/acpi/utils.h" - #include "hw/acpi/pci.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "hw/acpi/generic_event_device.h" - #include "hw/pci/pcie_host.h" - #include "hw/pci/pci.h" - #include "hw/arm/virt.h" -@@ -779,6 +781,7 @@ static void - build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - { - Aml *scope, *dsdt; -+ MachineState *ms = MACHINE(vms); - const MemMapEntry *memmap = vms->memmap; - const int *irqmap = vms->irqmap; - -@@ -803,6 +806,24 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - vms->highmem, vms->highmem_ecam); - acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], - (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); -+ if (vms->acpi_dev) { -+ build_ged_aml(scope, "\\_SB."GED_DEVICE, -+ HOTPLUG_HANDLER(vms->acpi_dev), -+ irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, -+ memmap[VIRT_ACPI_GED].base); -+ } -+ -+ if (vms->acpi_dev) { -+ uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev), -+ "ged-event", &error_abort); -+ -+ if (event & ACPI_GED_MEM_HOTPLUG_EVT) { -+ build_memory_hotplug_aml(scope, ms->ram_slots, "\\_SB", NULL, -+ AML_SYSTEM_MEMORY, -+ memmap[VIRT_PCDIMM_ACPI].base); -+ } -+ } -+ - acpi_dsdt_add_power_button(scope); - - aml_append(dsdt, scope); -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index c7c07fe3ac..8ccabd5159 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -67,6 +67,7 @@ - #include "target/arm/internals.h" - #include "hw/mem/pc-dimm.h" - #include "hw/mem/nvdimm.h" -+#include "hw/acpi/generic_event_device.h" - - #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ - static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ -@@ -137,6 +138,8 @@ static const MemMapEntry base_memmap[] = { - [VIRT_GPIO] = { 0x09030000, 0x00001000 }, - [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, - [VIRT_SMMU] = { 0x09050000, 0x00020000 }, -+ [VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN }, -+ [VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN }, - [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, - [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, - /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ -@@ -173,6 +176,7 @@ static const int a15irqmap[] = { - [VIRT_PCIE] = 3, /* ... to 6 */ - [VIRT_GPIO] = 7, - [VIRT_SECURE_UART] = 8, -+ [VIRT_ACPI_GED] = 9, - [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ - [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ - [VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */ -@@ -630,6 +634,29 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) - } - } - -+static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) -+{ -+ DeviceState *dev; -+ MachineState *ms = MACHINE(vms); -+ int irq = vms->irqmap[VIRT_ACPI_GED]; -+ uint32_t event = 0; -+ -+ if (ms->ram_slots) { -+ event = ACPI_GED_MEM_HOTPLUG_EVT; -+ } -+ -+ dev = qdev_create(NULL, TYPE_ACPI_GED); -+ qdev_prop_set_uint32(dev, "ged-event", event); -+ -+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); -+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); -+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]); -+ -+ qdev_init_nofail(dev); -+ -+ return dev; -+} -+ - static void create_its(VirtMachineState *vms, DeviceState *gicdev) - { - const char *itsclass = its_class_name(); -@@ -1603,6 +1630,7 @@ static void machvirt_init(MachineState *machine) - MemoryRegion *ram = g_new(MemoryRegion, 1); - bool firmware_loaded; - bool aarch64 = true; -+ bool has_ged = !vmc->no_ged; - unsigned int smp_cpus = machine->smp.cpus; - unsigned int max_cpus = machine->smp.max_cpus; - -@@ -1824,6 +1852,10 @@ static void machvirt_init(MachineState *machine) - - create_gpio(vms, pic); - -+ if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { -+ vms->acpi_dev = create_acpi_ged(vms, pic); -+ } -+ - /* Create mmio transports, so the user can create virtio backends - * (which will be automatically plugged in to the transports). If - * no backend is created the transport will just sit harmlessly idle. -@@ -2003,14 +2035,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) - static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) - { -+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); -+ const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); - -- /* -- * The device memory is not yet exposed to the Guest either through -- * DT or ACPI and hence both cold/hot plug of memory is explicitly -- * disabled for now. -- */ -- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -- error_setg(errp, "memory cold/hot plug is not yet supported"); -+ if (is_nvdimm) { -+ error_setg(errp, "nvdimm is not yet supported"); -+ return; -+ } -+ -+ if (!vms->acpi_dev) { -+ error_setg(errp, -+ "memory hotplug is not enabled: missing acpi-ged device"); - return; - } - -@@ -2020,11 +2055,18 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - static void virt_memory_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -+ HotplugHandlerClass *hhc; - VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); - Error *local_err = NULL; - - pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err); -+ if (local_err) { -+ goto out; -+ } - -+ hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev); -+ hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort); -+out: - error_propagate(errp, local_err); - } - -@@ -2231,8 +2273,11 @@ DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) - - static void virt_machine_4_0_options(MachineClass *mc) - { -+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); -+ - virt_machine_4_1_options(mc); - compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); -+ vmc->no_ged = true; - } - DEFINE_VIRT_MACHINE(4, 0) - -diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index a9d6977afc..0350285136 100644 ---- a/include/hw/arm/virt.h -+++ b/include/hw/arm/virt.h -@@ -78,6 +78,8 @@ enum { - VIRT_GPIO, - VIRT_SECURE_UART, - VIRT_SECURE_MEM, -+ VIRT_PCDIMM_ACPI, -+ VIRT_ACPI_GED, - VIRT_LOWMEMMAP_LAST, - }; - -@@ -107,6 +109,7 @@ typedef struct { - bool claim_edge_triggered_timers; - bool smbios_old_sys_ver; - bool no_highmem_ecam; -+ bool no_ged; /* Machines < 4.1 has no support for ACPI GED device */ - bool kvm_no_adjvtime; - } VirtMachineClass; - -@@ -135,6 +138,7 @@ typedef struct { - uint32_t iommu_phandle; - int psci_conduit; - hwaddr highest_gpa; -+ DeviceState *acpi_dev; - } VirtMachineState; - - #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) --- -2.19.1 diff --git a/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch b/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch index 1e3befaf62920ca12cae4c8ead6d731800ef79a8..fe733c62e37890f92821268c623da3adf22b7499 100644 --- a/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch +++ b/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch @@ -1,4 +1,4 @@ -From 3a0af1446395e74476a763ca12713b28c099a144 Mon Sep 17 00:00:00 2001 +From 7838609e9a7743af03c58ae46afd26070b2feea6 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 6 Apr 2020 12:50:54 +0800 Subject: [PATCH] hw/arm/virt: Factor out some CPU init codes to pre_plug hook @@ -10,90 +10,137 @@ let them be shared by all CPUs. Signed-off-by: Keqian Zhu Signed-off-by: Salil Mehta --- - hw/arm/virt.c | 108 +++++++++++++++++++++++++++----------------------- - 1 file changed, 58 insertions(+), 50 deletions(-) + hw/arm/virt.c | 197 ++++++++++++++++++++++++++------------------------ + 1 file changed, 103 insertions(+), 94 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 64532b61b2..83f4887e57 100644 +index a12e718686..149e0245d7 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -196,6 +196,8 @@ static const char *valid_cpus[] = { +@@ -213,6 +213,10 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("max"), }; - + +static MemoryRegion *secure_sysmem; ++static MemoryRegion *tag_sysmem; ++static MemoryRegion *secure_tag_sysmem; + static bool cpu_type_valid(const char *cpu) { int i; -@@ -1629,7 +1631,6 @@ static void machvirt_init(MachineState *machine) +@@ -1990,9 +1994,6 @@ static void machvirt_init(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); const CPUArchIdList *possible_cpus; MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *secure_sysmem = NULL; +- MemoryRegion *tag_sysmem = NULL; +- MemoryRegion *secure_tag_sysmem = NULL; int n, virt_max_cpus; - MemoryRegion *ram = g_new(MemoryRegion, 1); bool firmware_loaded; -@@ -1752,57 +1753,10 @@ static void machvirt_init(MachineState *machine) + bool aarch64 = true; +@@ -2099,100 +2100,11 @@ static void machvirt_init(MachineState *machine) } - + cpuobj = object_new(possible_cpus->cpus[n].type); -- object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, -- "mp-affinity", NULL); +- object_property_set_int(cpuobj, "mp-affinity", +- possible_cpus->cpus[n].arch_id, NULL); + aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); - + cs = CPU(cpuobj); cs->cpu_index = n; -- + - numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), - &error_fatal); - - aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); - - if (!vms->secure) { -- object_property_set_bool(cpuobj, false, "has_el3", NULL); +- object_property_set_bool(cpuobj, "has_el3", false, NULL); - } - -- if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { -- object_property_set_bool(cpuobj, false, "has_el2", NULL); +- if (!vms->virt && object_property_find(cpuobj, "has_el2")) { +- object_property_set_bool(cpuobj, "has_el2", false, NULL); - } - - if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { -- object_property_set_int(cpuobj, vms->psci_conduit, -- "psci-conduit", NULL); +- object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, +- NULL); - - /* Secondary CPUs start in PSCI powered-down state */ - if (n > 0) { -- object_property_set_bool(cpuobj, true, -- "start-powered-off", NULL); +- object_property_set_bool(cpuobj, "start-powered-off", true, +- NULL); - } - } - - if (vmc->kvm_no_adjvtime && -- object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { -- object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); +- object_property_find(cpuobj, "kvm-no-adjvtime")) { +- object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); - } - -- if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { -- object_property_set_bool(cpuobj, false, "pmu", NULL); +- if (vmc->no_kvm_steal_time && +- object_property_find(cpuobj, "kvm-steal-time")) { +- object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL); - } - -- if (object_property_find(cpuobj, "reset-cbar", NULL)) { -- object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, -- "reset-cbar", &error_abort); +- if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) { +- object_property_set_bool(cpuobj, "pmu", false, NULL); - } - -- object_property_set_link(cpuobj, OBJECT(sysmem), "memory", +- if (object_property_find(cpuobj, "reset-cbar")) { +- object_property_set_int(cpuobj, "reset-cbar", +- vms->memmap[VIRT_CPUPERIPHS].base, +- &error_abort); +- } +- +- object_property_set_link(cpuobj, "memory", OBJECT(sysmem), - &error_abort); - if (vms->secure) { -- object_property_set_link(cpuobj, OBJECT(secure_sysmem), -- "secure-memory", &error_abort); +- object_property_set_link(cpuobj, "secure-memory", +- OBJECT(secure_sysmem), &error_abort); +- } +- +- if (vms->mte) { +- /* Create the memory region only once, but link to all cpus. */ +- if (!tag_sysmem) { +- /* +- * The property exists only if MemTag is supported. +- * If it is, we must allocate the ram to back that up. +- */ +- if (!object_property_find(cpuobj, "tag-memory")) { +- error_report("MTE requested, but not supported " +- "by the guest CPU"); +- exit(1); +- } +- +- tag_sysmem = g_new(MemoryRegion, 1); +- memory_region_init(tag_sysmem, OBJECT(machine), +- "tag-memory", UINT64_MAX / 32); +- +- if (vms->secure) { +- secure_tag_sysmem = g_new(MemoryRegion, 1); +- memory_region_init(secure_tag_sysmem, OBJECT(machine), +- "secure-tag-memory", UINT64_MAX / 32); +- +- /* As with ram, secure-tag takes precedence over tag. */ +- memory_region_add_subregion_overlap(secure_tag_sysmem, 0, +- tag_sysmem, -1); +- } +- } +- +- object_property_set_link(cpuobj, "tag-memory", OBJECT(tag_sysmem), +- &error_abort); +- if (vms->secure) { +- object_property_set_link(cpuobj, "secure-tag-memory", +- OBJECT(secure_tag_sysmem), +- &error_abort); +- } - } - - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); object_unref(cpuobj); } -@@ -2089,10 +2043,16 @@ out: +@@ -2600,10 +2512,16 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -108,63 +155,107 @@ index 64532b61b2..83f4887e57 100644 + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + MemoryRegion *sysmem = get_system_memory(); + int smp_clusters = ms->smp.clusters; int smp_cores = ms->smp.cores; int smp_threads = ms->smp.threads; - -@@ -2145,6 +2105,54 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, +@@ -2673,6 +2591,97 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, return; } cpu->thread_id = topo.smt_id; + + /* Init some properties */ + -+ object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id, -+ "mp-affinity", NULL); ++ object_property_set_int(cpuobj, "mp-affinity", ++ possible_cpus->cpus[cs->cpu_index].arch_id, NULL); + + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), + &error_fatal); + + if (!vms->secure) { -+ object_property_set_bool(cpuobj, false, "has_el3", NULL); ++ object_property_set_bool(cpuobj, "has_el3", false, NULL); + } + -+ if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { -+ object_property_set_bool(cpuobj, false, "has_el2", NULL); ++ if (!vms->virt && object_property_find(cpuobj, "has_el2")) { ++ object_property_set_bool(cpuobj, "has_el2", false, NULL); + } + + if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { -+ object_property_set_int(cpuobj, vms->psci_conduit, -+ "psci-conduit", NULL); ++ object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, ++ NULL); + + /* Secondary CPUs start in PSCI powered-down state */ + if (cs->cpu_index > 0) { -+ object_property_set_bool(cpuobj, true, -+ "start-powered-off", NULL); ++ object_property_set_bool(cpuobj, "start-powered-off", true, ++ NULL); + } + } + + if (vmc->kvm_no_adjvtime && -+ object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { -+ object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); ++ object_property_find(cpuobj, "kvm-no-adjvtime")) { ++ object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); ++ } ++ ++ if (vmc->no_kvm_steal_time && ++ object_property_find(cpuobj, "kvm-steal-time")) { ++ object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL); + } + -+ if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { -+ object_property_set_bool(cpuobj, false, "pmu", NULL); ++ if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) { ++ object_property_set_bool(cpuobj, "pmu", false, NULL); + } + -+ if (object_property_find(cpuobj, "reset-cbar", NULL)) { -+ object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, -+ "reset-cbar", &error_abort); ++ if (object_property_find(cpuobj, "reset-cbar")) { ++ object_property_set_int(cpuobj, "reset-cbar", ++ vms->memmap[VIRT_CPUPERIPHS].base, ++ &error_abort); + } + -+ object_property_set_link(cpuobj, OBJECT(sysmem), "memory", ++ object_property_set_link(cpuobj, "memory", OBJECT(sysmem), + &error_abort); + if (vms->secure) { -+ object_property_set_link(cpuobj, OBJECT(secure_sysmem), -+ "secure-memory", &error_abort); ++ object_property_set_link(cpuobj, "secure-memory", ++ OBJECT(secure_sysmem), &error_abort); ++ } ++ ++ if (vms->mte) { ++ /* Create the memory region only once, but link to all cpus. */ ++ if (!tag_sysmem) { ++ /* ++ * The property exists only if MemTag is supported. ++ * If it is, we must allocate the ram to back that up. ++ */ ++ if (!object_property_find(cpuobj, "tag-memory")) { ++ error_report("MTE requested, but not supported " ++ "by the guest CPU"); ++ exit(1); ++ } ++ ++ tag_sysmem = g_new(MemoryRegion, 1); ++ memory_region_init(tag_sysmem, OBJECT(ms), ++ "tag-memory", UINT64_MAX / 32); ++ ++ if (vms->secure) { ++ secure_tag_sysmem = g_new(MemoryRegion, 1); ++ memory_region_init(secure_tag_sysmem, OBJECT(ms), ++ "secure-tag-memory", UINT64_MAX / 32); ++ ++ /* As with ram, secure-tag takes precedence over tag. */ ++ memory_region_add_subregion_overlap(secure_tag_sysmem, 0, ++ tag_sysmem, -1); ++ } ++ } ++ ++ object_property_set_link(cpuobj, "tag-memory", OBJECT(tag_sysmem), ++ &error_abort); ++ if (vms->secure) { ++ object_property_set_link(cpuobj, "secure-tag-memory", ++ OBJECT(secure_tag_sysmem), ++ &error_abort); ++ } + } } - + static void virt_cpu_plug(HotplugHandler *hotplug_dev, --- -2.19.1 +-- +2.27.0 + diff --git a/hw-arm-virt-Fix-devicetree-warnings-about-the-virtio.patch b/hw-arm-virt-Fix-devicetree-warnings-about-the-virtio.patch new file mode 100644 index 0000000000000000000000000000000000000000..7c10bc0991de50b11b968b53d4bb1fee8ec1696d --- /dev/null +++ b/hw-arm-virt-Fix-devicetree-warnings-about-the-virtio.patch @@ -0,0 +1,62 @@ +From 9fdae653dc60c96fad416abb1b5294f767fcb3c5 Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Wed, 23 Nov 2022 08:10:00 +0000 +Subject: [PATCH 11/29] hw/arm/virt: Fix devicetree warnings about the + virtio-iommu node mainline inclusion from mainline-v7.2.0-rc1 commit + 7cd5d384bb298ce3c595a3774213b5b478881ac8 category: bugfix + +-------------------------------- + +The "PCI Bus Binding to: IEEE Std 1275-1994" defines the compatible +string for a PCIe bus or endpoint as "pci," or +similar. Since the initial binding for PCI virtio-iommu didn't follow +this rule, it was modified to accept both strings and ensure backward +compatibility. Also, the unit-name for the node should be +"device,function". + +Fix corresponding dt-validate and dtc warnings: + + pcie@10000000: virtio_iommu@16:compatible: ['virtio,pci-iommu'] does not contain items matching the given schema + pcie@10000000: Unevaluated properties are not allowed (... 'virtio_iommu@16' were unexpected) + From schema: linux/Documentation/devicetree/bindings/pci/host-generic-pci.yaml + virtio_iommu@16: compatible: 'oneOf' conditional failed, one must be fixed: + ['virtio,pci-iommu'] is too short + 'pci1af4,1057' was expected + From schema: dtschema/schemas/pci/pci-bus.yaml + + Warning (pci_device_reg): /pcie@10000000/virtio_iommu@16: PCI unit address format error, expected "2,0" + +Signed-off-by: Jean-Philippe Brucker +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell + +Signed-off-by: cmss_dx +--- + hw/arm/virt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index b81d22d68f..4716f9baaa 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1470,14 +1470,15 @@ static void create_smmu(const VirtMachineState *vms, + + static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) + { +- const char compat[] = "virtio,pci-iommu"; ++ const char compat[] = "virtio,pci-iommu\0pci1af4,1057"; + uint16_t bdf = vms->virtio_iommu_bdf; + MachineState *ms = MACHINE(vms); + char *node; + + vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt); + +- node = g_strdup_printf("%s/virtio_iommu@%d", vms->pciehb_nodename, bdf); ++ node = g_strdup_printf("%s/virtio_iommu@%x,%x", vms->pciehb_nodename, ++ PCI_SLOT(bdf), PCI_FUNC(bdf)); + qemu_fdt_add_subnode(ms->fdt, node); + qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", +-- +2.27.0 + diff --git a/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch b/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch deleted file mode 100644 index c124df5394121fdb0415b3b85d04fc3417a747aa..0000000000000000000000000000000000000000 --- a/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch +++ /dev/null @@ -1,73 +0,0 @@ -From acc5162f1d1591ee4830f9b67934fc6d8a9ebbc1 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Tue, 8 Sep 2020 22:09:44 +0800 -Subject: [PATCH] hw/arm/virt: Init PMU for hotplugged vCPU - -Factor out PMU init code from fdt_add_pmu_nodes and -do PMU init for hotplugged vCPU. - -Signed-off-by: Keqian Zhu ---- - hw/arm/virt.c | 29 +++++++++++++++++++++-------- - 1 file changed, 21 insertions(+), 8 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 7afc6c5e..7506d0ff 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -605,6 +605,23 @@ static void fdt_add_gic_node(VirtMachineState *vms) - g_free(nodename); - } - -+static bool virt_cpu_init_pmu(const VirtMachineState *vms, CPUState *cpu) -+{ -+ ARMCPU *armcpu = ARM_CPU(cpu); -+ -+ if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { -+ return false; -+ } -+ if (kvm_enabled()) { -+ if (kvm_irqchip_in_kernel()) { -+ kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); -+ } -+ kvm_arm_pmu_init(cpu); -+ } -+ -+ return true; -+} -+ - static void fdt_add_pmu_nodes(const VirtMachineState *vms) - { - CPUState *cpu; -@@ -612,16 +629,9 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) - uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; - - CPU_FOREACH(cpu) { -- armcpu = ARM_CPU(cpu); -- if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { -+ if (!virt_cpu_init_pmu(vms, cpu)) { - return; - } -- if (kvm_enabled()) { -- if (kvm_irqchip_in_kernel()) { -- kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); -- } -- kvm_arm_pmu_init(cpu); -- } - } - - if (vms->gic_version == 2) { -@@ -2248,6 +2258,9 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, - agcc->cpu_hotplug_realize(gicv3, ncpu); - connect_gic_cpu_irqs(vms, ncpu); - -+ /* Init PMU part */ -+ virt_cpu_init_pmu(vms, cs); -+ - /* Register CPU reset and trigger it manually */ - cpu_synchronize_state(cs); - cpu_hotplug_register_reset(ncpu); --- -2.23.0 - - diff --git a/hw-arm-virt-Introduce-cpu-topology-support.patch b/hw-arm-virt-Introduce-cpu-topology-support.patch deleted file mode 100644 index 932f467fe274453668edf80bac5d023817d6f95b..0000000000000000000000000000000000000000 --- a/hw-arm-virt-Introduce-cpu-topology-support.patch +++ /dev/null @@ -1,236 +0,0 @@ -From 73fc4af05ebe12d77915e6b3c85c48f5e0c432f3 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 22 Apr 2020 19:23:27 +0800 -Subject: [PATCH] hw/arm/virt: Introduce cpu topology support - -Add topology support for guest vcpu by cpu-map in dtb when the guest is booted -with dtb, and by pptt table when the guest is booted with acpi. - -Signed-off-by: Honghao -Signed-off-by: zhanghailiang -(picked-from https://patchwork.ozlabs.org/cover/939301/ which is pushed by -Andrew Jones ) ---- - device_tree.c | 32 ++++++++++++++++++++++ - hw/acpi/aml-build.c | 53 ++++++++++++++++++++++++++++++++++++ - hw/arm/virt-acpi-build.c | 4 +++ - hw/arm/virt.c | 32 +++++++++++++++++++++- - include/hw/acpi/aml-build.h | 2 ++ - include/sysemu/device_tree.h | 1 + - 6 files changed, 123 insertions(+), 1 deletion(-) - -diff --git a/device_tree.c b/device_tree.c -index f8b46b3c..03906a14 100644 ---- a/device_tree.c -+++ b/device_tree.c -@@ -524,6 +524,38 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) - return retval; - } - -+/** -+ * qemu_fdt_add_path -+ * @fdt: Flattened Device Tree -+ * @path: Flattened Device Tree node path -+ * -+ * qemu_fdt_add_path works like qemu_fdt_add_subnode, except it -+ * also recursively adds any missing parent nodes. -+ */ -+int qemu_fdt_add_path(void *fdt, const char *path) -+{ -+ char *parent; -+ int offset; -+ -+ offset = fdt_path_offset(fdt, path); -+ if (offset < 0 && offset != -FDT_ERR_NOTFOUND) { -+ error_report("%s Couldn't find node %s: %s", __func__, path, -+ fdt_strerror(offset)); -+ exit(1); -+ } -+ -+ if (offset != -FDT_ERR_NOTFOUND) { -+ return offset; -+ } -+ -+ parent = g_strdup(path); -+ strrchr(parent, '/')[0] = '\0'; -+ qemu_fdt_add_path(fdt, parent); -+ g_free(parent); -+ -+ return qemu_fdt_add_subnode(fdt, path); -+} -+ - void qemu_fdt_dumpdtb(void *fdt, int size) - { - const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb"); -diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 73f97751..f2c8c28f 100644 ---- a/hw/acpi/aml-build.c -+++ b/hw/acpi/aml-build.c -@@ -25,6 +25,7 @@ - #include "qemu/bswap.h" - #include "qemu/bitops.h" - #include "sysemu/numa.h" -+#include "sysemu/cpus.h" - - static GArray *build_alloc_array(void) - { -@@ -51,6 +52,58 @@ static void build_append_array(GArray *array, GArray *val) - g_array_append_vals(array, val->data, val->len); - } - -+/* -+ * ACPI 6.2 Processor Properties Topology Table (PPTT) -+ */ -+static void build_cpu_hierarchy(GArray *tbl, uint32_t flags, -+ uint32_t parent, uint32_t id) -+{ -+ build_append_byte(tbl, 0); /* Type 0 - processor */ -+ build_append_byte(tbl, 20); /* Length, no private resources */ -+ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ -+ build_append_int_noprefix(tbl, flags, 4); -+ build_append_int_noprefix(tbl, parent, 4); -+ build_append_int_noprefix(tbl, id, 4); -+ build_append_int_noprefix(tbl, 0, 4); /* Num private resources */ -+} -+ -+void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) -+{ -+ int pptt_start = table_data->len; -+ int uid = 0, cpus = 0, socket; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ unsigned int smp_cores = ms->smp.cores; -+ unsigned int smp_threads = ms->smp.threads; -+ -+ acpi_data_push(table_data, sizeof(AcpiTableHeader)); -+ -+ for (socket = 0; cpus < possible_cpus; socket++) { -+ uint32_t socket_offset = table_data->len - pptt_start; -+ int core; -+ -+ build_cpu_hierarchy(table_data, 1, 0, socket); -+ -+ for (core = 0; core < smp_cores; core++) { -+ uint32_t core_offset = table_data->len - pptt_start; -+ int thread; -+ -+ if (smp_threads > 1) { -+ build_cpu_hierarchy(table_data, 0, socket_offset, core); -+ for (thread = 0; thread < smp_threads; thread++) { -+ build_cpu_hierarchy(table_data, 2, core_offset, uid++); -+ } -+ } else { -+ build_cpu_hierarchy(table_data, 2, socket_offset, uid++); -+ } -+ } -+ cpus += smp_cores * smp_threads; -+ } -+ -+ build_header(linker, table_data, -+ (void *)(table_data->data + pptt_start), "PPTT", -+ table_data->len - pptt_start, 1, NULL, NULL); -+} -+ - #define ACPI_NAMESEG_LEN 4 - - static void -diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 29494ebd..fe54411f 100644 ---- a/hw/arm/virt-acpi-build.c -+++ b/hw/arm/virt-acpi-build.c -@@ -848,6 +848,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) - acpi_add_table(table_offsets, tables_blob); - build_fadt_rev5(tables_blob, tables->linker, vms, dsdt); - -+ acpi_add_table(table_offsets, tables_blob); -+ -+ build_pptt(tables_blob, tables->linker, vms->smp_cpus); -+ - acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, vms); - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 0fa355ba..272455bc 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -44,6 +44,7 @@ - #include "net/net.h" - #include "sysemu/device_tree.h" - #include "sysemu/numa.h" -+#include "sysemu/cpus.h" - #include "sysemu/sysemu.h" - #include "sysemu/kvm.h" - #include "hw/loader.h" -@@ -312,7 +313,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) - int cpu; - int addr_cells = 1; - const MachineState *ms = MACHINE(vms); -- -+ unsigned int smp_cores = ms->smp.cores; -+ unsigned int smp_threads = ms->smp.threads; - /* - * From Documentation/devicetree/bindings/arm/cpus.txt - * On ARM v8 64-bit systems value should be set to 2, -@@ -368,8 +370,36 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) - ms->possible_cpus->cpus[cs->cpu_index].props.node_id); - } - -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", -+ qemu_fdt_alloc_phandle(vms->fdt)); -+ - g_free(nodename); - } -+ -+ /* Add vcpu topology by fdt node cpu-map. */ -+ qemu_fdt_add_subnode(vms->fdt, "/cpus/cpu-map"); -+ -+ for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { -+ char *cpu_path = g_strdup_printf("/cpus/cpu@%d", cpu); -+ char *map_path; -+ -+ if (smp_threads > 1) { -+ map_path = g_strdup_printf( -+ "/cpus/cpu-map/%s%d/%s%d/%s%d", -+ "cluster", cpu / (smp_cores * smp_threads), -+ "core", (cpu / smp_threads) % smp_cores, -+ "thread", cpu % smp_threads); -+ } else { -+ map_path = g_strdup_printf( -+ "/cpus/cpu-map/%s%d/%s%d", -+ "cluster", cpu / smp_cores, -+ "core", cpu % smp_cores); -+ } -+ qemu_fdt_add_path(vms->fdt, map_path); -+ qemu_fdt_setprop_phandle(vms->fdt, map_path, "cpu", cpu_path); -+ g_free(map_path); -+ g_free(cpu_path); -+ } - } - - static void fdt_add_its_gic_node(VirtMachineState *vms) -diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h -index 375335ab..bfb0b100 100644 ---- a/include/hw/acpi/aml-build.h -+++ b/include/hw/acpi/aml-build.h -@@ -417,6 +417,8 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s) - void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, - uint64_t len, int node, MemoryAffinityFlags flags); - -+void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus); -+ - void build_slit(GArray *table_data, BIOSLinker *linker); - - void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, -diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h -index c16fd69b..d62fc873 100644 ---- a/include/sysemu/device_tree.h -+++ b/include/sysemu/device_tree.h -@@ -101,6 +101,7 @@ uint32_t qemu_fdt_get_phandle(void *fdt, const char *path); - uint32_t qemu_fdt_alloc_phandle(void *fdt); - int qemu_fdt_nop_node(void *fdt, const char *node_path); - int qemu_fdt_add_subnode(void *fdt, const char *name); -+int qemu_fdt_add_path(void *fdt, const char *path); - - #define qemu_fdt_setprop_cells(fdt, node_path, property, ...) \ - do { \ --- -2.23.0 diff --git a/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch b/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch deleted file mode 100644 index 262cb508bcb8ba48bf93a3875957f2c9ace7698d..0000000000000000000000000000000000000000 --- a/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch +++ /dev/null @@ -1,402 +0,0 @@ -From 5d1be90750551f1debf5767d7a6e2b9c50054c05 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Mon, 9 Dec 2019 10:03:06 +0100 -Subject: [PATCH] hw/arm/virt: Simplify by moving the gic in the machine state -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Make the gic a field in the machine state, and instead of filling -an array of qemu_irq and passing it around, directly call -qdev_get_gpio_in() on the gic field. - -Signed-off-by: Philippe Mathieu-Daudé -Reviewed-by: Luc Michel -Message-id: 20191209090306.20433-1-philmd@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell ---- - hw/arm/virt.c | 109 +++++++++++++++++++++--------------------- - include/hw/arm/virt.h | 1 + - 2 files changed, 55 insertions(+), 55 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 18321e522b..8638aeedb7 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -634,7 +634,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) - } - } - --static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) -+static inline DeviceState *create_acpi_ged(VirtMachineState *vms) - { - DeviceState *dev; - MachineState *ms = MACHINE(vms); -@@ -650,14 +650,14 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) - - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); -- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]); -+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - - qdev_init_nofail(dev); - - return dev; - } - --static void create_its(VirtMachineState *vms, DeviceState *gicdev) -+static void create_its(VirtMachineState *vms) - { - const char *itsclass = its_class_name(); - DeviceState *dev; -@@ -669,7 +669,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev) - - dev = qdev_create(NULL, itsclass); - -- object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3", -+ object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3", - &error_abort); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); -@@ -677,7 +677,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev) - fdt_add_its_gic_node(vms); - } - --static void create_v2m(VirtMachineState *vms, qemu_irq *pic) -+static void create_v2m(VirtMachineState *vms) - { - int i; - int irq = vms->irqmap[VIRT_GIC_V2M]; -@@ -690,17 +690,17 @@ static void create_v2m(VirtMachineState *vms, qemu_irq *pic) - qdev_init_nofail(dev); - - for (i = 0; i < NUM_GICV2M_SPIS; i++) { -- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); -+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, -+ qdev_get_gpio_in(vms->gic, irq + i)); - } - - fdt_add_v2m_gic_node(vms); - } - --static void create_gic(VirtMachineState *vms, qemu_irq *pic) -+static void create_gic(VirtMachineState *vms) - { - MachineState *ms = MACHINE(vms); - /* We create a standalone GIC */ -- DeviceState *gicdev; - SysBusDevice *gicbusdev; - const char *gictype; - int type = vms->gic_version, i; -@@ -709,15 +709,15 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) - - gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); - -- gicdev = qdev_create(NULL, gictype); -- qdev_prop_set_uint32(gicdev, "revision", type); -- qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); -+ vms->gic = qdev_create(NULL, gictype); -+ qdev_prop_set_uint32(vms->gic, "revision", type); -+ qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); - /* Note that the num-irq property counts both internal and external - * interrupts; there are always 32 of the former (mandated by GIC spec). - */ -- qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); -+ qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32); - if (!kvm_irqchip_in_kernel()) { -- qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure); -+ qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure); - } - - if (type == 3) { -@@ -727,25 +727,25 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) - - nb_redist_regions = virt_gicv3_redist_region_count(vms); - -- qdev_prop_set_uint32(gicdev, "len-redist-region-count", -+ qdev_prop_set_uint32(vms->gic, "len-redist-region-count", - nb_redist_regions); -- qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count); -+ qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count); - - if (nb_redist_regions == 2) { - uint32_t redist1_capacity = - vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; - -- qdev_prop_set_uint32(gicdev, "redist-region-count[1]", -+ qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", - MIN(smp_cpus - redist0_count, redist1_capacity)); - } - } else { - if (!kvm_irqchip_in_kernel()) { -- qdev_prop_set_bit(gicdev, "has-virtualization-extensions", -+ qdev_prop_set_bit(vms->gic, "has-virtualization-extensions", - vms->virt); - } - } -- qdev_init_nofail(gicdev); -- gicbusdev = SYS_BUS_DEVICE(gicdev); -+ qdev_init_nofail(vms->gic); -+ gicbusdev = SYS_BUS_DEVICE(vms->gic); - sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); - if (type == 3) { - sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); -@@ -781,23 +781,23 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) - - for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { - qdev_connect_gpio_out(cpudev, irq, -- qdev_get_gpio_in(gicdev, -+ qdev_get_gpio_in(vms->gic, - ppibase + timer_irq[irq])); - } - - if (type == 3) { -- qemu_irq irq = qdev_get_gpio_in(gicdev, -+ qemu_irq irq = qdev_get_gpio_in(vms->gic, - ppibase + ARCH_GIC_MAINT_IRQ); - qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", - 0, irq); - } else if (vms->virt) { -- qemu_irq irq = qdev_get_gpio_in(gicdev, -+ qemu_irq irq = qdev_get_gpio_in(vms->gic, - ppibase + ARCH_GIC_MAINT_IRQ); - sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq); - } - - qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, -- qdev_get_gpio_in(gicdev, ppibase -+ qdev_get_gpio_in(vms->gic, ppibase - + VIRTUAL_PMU_IRQ)); - - sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); -@@ -809,20 +809,16 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) - qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); - } - -- for (i = 0; i < NUM_IRQS; i++) { -- pic[i] = qdev_get_gpio_in(gicdev, i); -- } -- - fdt_add_gic_node(vms); - - if (type == 3 && vms->its) { -- create_its(vms, gicdev); -+ create_its(vms); - } else if (type == 2) { -- create_v2m(vms, pic); -+ create_v2m(vms); - } - } - --static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, -+static void create_uart(const VirtMachineState *vms, int uart, - MemoryRegion *mem, Chardev *chr) - { - char *nodename; -@@ -838,7 +834,7 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, - qdev_init_nofail(dev); - memory_region_add_subregion(mem, base, - sysbus_mmio_get_region(s, 0)); -- sysbus_connect_irq(s, 0, pic[irq]); -+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); - - nodename = g_strdup_printf("/pl011@%" PRIx64, base); - qemu_fdt_add_subnode(vms->fdt, nodename); -@@ -880,7 +876,7 @@ static void create_cpufreq(const VirtMachineState *vms, MemoryRegion *mem) - memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); - } - --static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) -+static void create_rtc(const VirtMachineState *vms) - { - char *nodename; - hwaddr base = vms->memmap[VIRT_RTC].base; -@@ -888,7 +884,7 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) - int irq = vms->irqmap[VIRT_RTC]; - const char compat[] = "arm,pl031\0arm,primecell"; - -- sysbus_create_simple("pl031", base, pic[irq]); -+ sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq)); - - nodename = g_strdup_printf("/pl031@%" PRIx64, base); - qemu_fdt_add_subnode(vms->fdt, nodename); -@@ -916,7 +912,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque) - } - } - --static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) -+static void create_gpio(const VirtMachineState *vms) - { - char *nodename; - DeviceState *pl061_dev; -@@ -925,7 +921,8 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) - int irq = vms->irqmap[VIRT_GPIO]; - const char compat[] = "arm,pl061\0arm,primecell"; - -- pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); -+ pl061_dev = sysbus_create_simple("pl061", base, -+ qdev_get_gpio_in(vms->gic, irq)); - - uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt); - nodename = g_strdup_printf("/pl061@%" PRIx64, base); -@@ -959,7 +956,7 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) - g_free(nodename); - } - --static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) -+static void create_virtio_devices(const VirtMachineState *vms) - { - int i; - hwaddr size = vms->memmap[VIRT_MMIO].size; -@@ -995,7 +992,8 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) - int irq = vms->irqmap[VIRT_MMIO] + i; - hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; - -- sysbus_create_simple("virtio-mmio", base, pic[irq]); -+ sysbus_create_simple("virtio-mmio", base, -+ qdev_get_gpio_in(vms->gic, irq)); - } - - /* We add dtb nodes in reverse order so that they appear in the finished -@@ -1244,7 +1242,7 @@ static void create_pcie_irq_map(const VirtMachineState *vms, - 0x7 /* PCI irq */); - } - --static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, -+static void create_smmu(const VirtMachineState *vms, - PCIBus *bus) - { - char *node; -@@ -1267,7 +1265,8 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - for (i = 0; i < NUM_SMMU_IRQS; i++) { -- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); -+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, -+ qdev_get_gpio_in(vms->gic, irq + i)); - } - - node = g_strdup_printf("/smmuv3@%" PRIx64, base); -@@ -1294,7 +1293,7 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, - g_free(node); - } - --static void create_pcie(VirtMachineState *vms, qemu_irq *pic) -+static void create_pcie(VirtMachineState *vms) - { - hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base; - hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size; -@@ -1354,7 +1353,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); - - for (i = 0; i < GPEX_NUM_IRQS; i++) { -- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); -+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, -+ qdev_get_gpio_in(vms->gic, irq + i)); - gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); - } - -@@ -1414,7 +1414,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) - if (vms->iommu) { - vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt); - -- create_smmu(vms, pic, pci->bus); -+ create_smmu(vms, pci->bus); - - qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map", - 0x0, vms->iommu_phandle, 0x0, 0x10000); -@@ -1423,7 +1423,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) - g_free(nodename); - } - --static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) -+static void create_platform_bus(VirtMachineState *vms) - { - DeviceState *dev; - SysBusDevice *s; -@@ -1439,8 +1439,8 @@ static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) - - s = SYS_BUS_DEVICE(dev); - for (i = 0; i < PLATFORM_BUS_NUM_IRQS; i++) { -- int irqn = vms->irqmap[VIRT_PLATFORM_BUS] + i; -- sysbus_connect_irq(s, i, pic[irqn]); -+ int irq = vms->irqmap[VIRT_PLATFORM_BUS] + i; -+ sysbus_connect_irq(s, i, qdev_get_gpio_in(vms->gic, irq)); - } - - memory_region_add_subregion(sysmem, -@@ -1621,7 +1621,6 @@ static void machvirt_init(MachineState *machine) - VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); - MachineClass *mc = MACHINE_GET_CLASS(machine); - const CPUArchIdList *possible_cpus; -- qemu_irq pic[NUM_IRQS]; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *secure_sysmem = NULL; - int n, virt_max_cpus; -@@ -1829,29 +1828,29 @@ static void machvirt_init(MachineState *machine) - - virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem); - -- create_gic(vms, pic); -+ create_gic(vms); - - fdt_add_pmu_nodes(vms); - -- create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); -+ create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); - - create_cpufreq(vms, sysmem); - - if (vms->secure) { - create_secure_ram(vms, secure_sysmem); -- create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); -+ create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); - } - - vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64); - -- create_rtc(vms, pic); -+ create_rtc(vms); - -- create_pcie(vms, pic); -+ create_pcie(vms); - - if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { -- vms->acpi_dev = create_acpi_ged(vms, pic); -+ vms->acpi_dev = create_acpi_ged(vms); - } else { -- create_gpio(vms, pic); -+ create_gpio(vms); - } - - /* connect powerdown request */ -@@ -1862,12 +1861,12 @@ static void machvirt_init(MachineState *machine) - * (which will be automatically plugged in to the transports). If - * no backend is created the transport will just sit harmlessly idle. - */ -- create_virtio_devices(vms, pic); -+ create_virtio_devices(vms); - - vms->fw_cfg = create_fw_cfg(vms, &address_space_memory); - rom_set_fw(vms->fw_cfg); - -- create_platform_bus(vms, pic); -+ create_platform_bus(vms); - - vms->bootinfo.ram_size = machine->ram_size; - vms->bootinfo.kernel_filename = machine->kernel_filename; -diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index dcceb9c615..3dfefca93b 100644 ---- a/include/hw/arm/virt.h -+++ b/include/hw/arm/virt.h -@@ -138,6 +138,7 @@ typedef struct { - uint32_t iommu_phandle; - int psci_conduit; - hwaddr highest_gpa; -+ DeviceState *gic; - DeviceState *acpi_dev; - Notifier powerdown_notifier; - } VirtMachineState; --- -2.19.1 diff --git a/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch b/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd3241f25dc6a437d65bfeb4a3017b189440dd9b --- /dev/null +++ b/hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch @@ -0,0 +1,69 @@ +From 1fab7ee365c8daccedd19d3a1be56babe36afcc6 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:27 +0800 +Subject: [PATCH 15/24] hw/arm/virt: Support CPU cluster on ARM virt machine + +ARM64 machines like Kunpeng Family Server Chips have a level +of hardware topology in which a group of CPU cores share L3 +cache tag or L2 cache. For example, Kunpeng 920 typically +has 6 or 8 clusters in each NUMA node (also represent range +of CPU die), and each cluster has 4 CPU cores. All clusters +share L3 cache data, but CPU cores in each cluster share a +local L3 tag. + +Running a guest kernel with Cluster-Aware Scheduling on the +Hosts which have physical clusters, if we can design a vCPU +topology with cluster level for guest kernel and then have +a dedicated vCPU pinning, the guest will gain scheduling +performance improvement from cache affinity of CPU cluster. + +So let's enable the support for this new parameter on ARM +virt machines. After this patch, we can define a 4-level +CPU hierarchy like: cpus=*,maxcpus=*,sockets=*,clusters=*, +cores=*,threads=*. + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-2-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/arm/virt.c | 1 + + qemu-options.hx | 10 ++++++++++ + 2 files changed, 11 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 3c972fdab0..6ca9cbe2cf 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2704,6 +2704,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + hc->unplug_request = virt_machine_device_unplug_request_cb; + hc->unplug = virt_machine_device_unplug_cb; + mc->nvdimm_supported = true; ++ mc->smp_props.clusters_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; + mc->default_ram_id = "mach-virt.ram"; +diff --git a/qemu-options.hx b/qemu-options.hx +index 0f26f7dad7..74d335e4c3 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -277,6 +277,16 @@ SRST + + -smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16 + ++ The following sub-option defines a CPU topology hierarchy (2 sockets ++ totally on the machine, 2 clusters per socket, 2 cores per cluster, ++ 2 threads per core) for ARM virt machines which support sockets/clusters ++ /cores/threads. Some members of the option can be omitted but their values ++ will be automatically computed: ++ ++ :: ++ ++ -smp 16,sockets=2,clusters=2,cores=2,threads=2,maxcpus=16 ++ + Historically preference was given to the coarsest topology parameters + when computing missing values (ie sockets preferred over cores, which + were preferred over threads), however, this behaviour is considered +-- +2.27.0 + diff --git a/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch b/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d43030f818bee075d09e0403e7e29410f406a92 --- /dev/null +++ b/hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch @@ -0,0 +1,57 @@ +From 38d9ae59b9344f13198e6b4de03b04787bd6b89d Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:28 +0800 +Subject: [PATCH 16/24] hw/arm/virt: Support cluster level in DT cpu-map + +Support one cluster level between core and physical package in the +cpu-map of Arm/virt devicetree. This is also consistent with Linux +Doc "Documentation/devicetree/bindings/cpu/cpu-topology.txt". + +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Message-id: 20220107083232.16256-3-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + hw/arm/virt.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 6ca9cbe2cf..ddcb73f714 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -434,9 +434,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + * can contain several layers of clustering within a single physical + * package and cluster nodes can be contained in parent cluster nodes. + * +- * Given that cluster is not yet supported in the vCPU topology, +- * we currently generate one cluster node within each socket node +- * by default. ++ * Note: currently we only support one layer of clustering within ++ * each physical package. + */ + qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); + +@@ -446,14 +445,16 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + + if (ms->smp.threads > 1) { + map_path = g_strdup_printf( +- "/cpus/cpu-map/socket%d/cluster0/core%d/thread%d", +- cpu / (ms->smp.cores * ms->smp.threads), ++ "/cpus/cpu-map/socket%d/cluster%d/core%d/thread%d", ++ cpu / (ms->smp.clusters * ms->smp.cores * ms->smp.threads), ++ (cpu / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters, + (cpu / ms->smp.threads) % ms->smp.cores, + cpu % ms->smp.threads); + } else { + map_path = g_strdup_printf( +- "/cpus/cpu-map/socket%d/cluster0/core%d", +- cpu / ms->smp.cores, ++ "/cpus/cpu-map/socket%d/cluster%d/core%d", ++ cpu / (ms->smp.clusters * ms->smp.cores), ++ (cpu / ms->smp.cores) % ms->smp.clusters, + cpu % ms->smp.cores); + } + qemu_fdt_add_path(ms->fdt, map_path); +-- +2.27.0 + diff --git a/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch b/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch deleted file mode 100644 index 0602ab8d4d0d7af63f034c9b66c984e5aed627a7..0000000000000000000000000000000000000000 --- a/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 8d287871fd4e1b4654fe9e5011b80614cb44f6d8 Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:28 +0100 -Subject: [PATCH] hw/arm/virt-acpi-build: Add PC-DIMM in SRAT - -Generate Memory Affinity Structures for PC-DIMM ranges. - -Also, Linux and Windows need ACPI SRAT table to make memory hotplug -work properly, however currently QEMU doesn't create SRAT table if -numa options aren't present on CLI. Hence add support(>=4.2) to -create numa node automatically (auto_enable_numa_with_memhp) when -QEMU is started with memory hotplug enabled but without '-numa' -options on CLI. - -Signed-off-by: Shameer Kolothum -Signed-off-by: Eric Auger -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-7-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/arm/virt-acpi-build.c | 9 +++++++++ - hw/arm/virt.c | 2 ++ - 2 files changed, 11 insertions(+) - -diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index fca53ae01f..9622994e50 100644 ---- a/hw/arm/virt-acpi-build.c -+++ b/hw/arm/virt-acpi-build.c -@@ -592,6 +592,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - int i, srat_start; - uint64_t mem_base; - MachineClass *mc = MACHINE_GET_CLASS(vms); -+ MachineState *ms = MACHINE(vms); - const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms)); - - srat_start = table_data->len; -@@ -617,6 +618,14 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) - } - } - -+ if (ms->device_memory) { -+ numamem = acpi_data_push(table_data, sizeof *numamem); -+ build_srat_memory(numamem, ms->device_memory->base, -+ memory_region_size(&ms->device_memory->mr), -+ nb_numa_nodes - 1, -+ MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); -+ } -+ - build_header(linker, table_data, (void *)(table_data->data + srat_start), - "SRAT", table_data->len - srat_start, 3, NULL, NULL); - } -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 8ccabd5159..ab33cce4b3 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -2173,6 +2173,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) - hc->plug = virt_machine_device_plug_cb; - hc->unplug_request = virt_machine_device_unplug_request_cb; - mc->numa_mem_supported = true; -+ mc->auto_enable_numa_with_memhp = true; - } - - static void virt_instance_init(Object *obj) -@@ -2278,6 +2279,7 @@ static void virt_machine_4_0_options(MachineClass *mc) - virt_machine_4_1_options(mc); - compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); - vmc->no_ged = true; -+ mc->auto_enable_numa_with_memhp = false; - } - DEFINE_VIRT_MACHINE(4, 0) - --- -2.19.1 diff --git a/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch b/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch deleted file mode 100644 index 3d711678a6bbd365da89b3039509259f9ffe3c2e..0000000000000000000000000000000000000000 --- a/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch +++ /dev/null @@ -1,25 +0,0 @@ -From fbcb4ffa8648d0aa5be01c11816423a483f245ae Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 26 May 2020 22:39:23 +0800 -Subject: [PATCH] hw/arm/virt: add missing compat for kvm-no-adjvtime - -Machine compatibility for kvm-no-adjvtime is missed, -let's add it for virt machine 4.0 - -Signed-off-by: Ying Fang - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 4c727939..133d36a4 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -2492,6 +2492,7 @@ static void virt_machine_4_0_options(MachineClass *mc) - compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); - vmc->no_ged = true; - mc->auto_enable_numa_with_memhp = false; -+ vmc->kvm_no_adjvtime = true; - } - DEFINE_VIRT_MACHINE(4, 0) - --- -2.23.0 - diff --git a/hw-arm-virt-vTPM-support.patch b/hw-arm-virt-vTPM-support.patch deleted file mode 100644 index cbdc68e62f88981b10ebd459ce101caaf10dba6d..0000000000000000000000000000000000000000 --- a/hw-arm-virt-vTPM-support.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 443ebab9c299b04f020a6873454facb078723141 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Thu, 13 Aug 2020 20:01:10 +0800 -Subject: [PATCH 15/19] hw/arm/virt: vTPM support - -Let the TPM TIS SYSBUS device be dynamically instantiable -in ARM virt. A device tree node is dynamically created -(TPM via MMIO). - -The TPM Physical Presence interface (PPI) is not supported. - -To run with the swtmp TPM emulator, the qemu command line must -be augmented with: - - -chardev socket,id=chrtpm,path=swtpm-sock - -tpmdev emulator,id=tpm0,chardev=chrtpm - -device tpm-tis-device,tpmdev=tpm0 - -swtpm/libtpms command line example: - -swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm ---ctrl type=unixio,path=swtpm-sock - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-7-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - hw/arm/Kconfig | 1 + - hw/arm/sysbus-fdt.c | 33 +++++++++++++++++++++++++++++++++ - hw/arm/virt.c | 7 +++++++ - 3 files changed, 41 insertions(+) - -diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig -index 15e18b0a..06e49f26 100644 ---- a/hw/arm/Kconfig -+++ b/hw/arm/Kconfig -@@ -5,6 +5,7 @@ config ARM_VIRT - imply VFIO_AMD_XGBE - imply VFIO_PLATFORM - imply VFIO_XGMAC -+ imply TPM_TIS_SYSBUS - select A15MPCORE - select ACPI - select ARM_SMMUV3 -diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c -index 57f94e65..c725d325 100644 ---- a/hw/arm/sysbus-fdt.c -+++ b/hw/arm/sysbus-fdt.c -@@ -30,6 +30,7 @@ - #include "hw/arm/sysbus-fdt.h" - #include "qemu/error-report.h" - #include "sysemu/device_tree.h" -+#include "sysemu/tpm.h" - #include "hw/platform-bus.h" - #include "sysemu/sysemu.h" - #include "hw/vfio/vfio-platform.h" -@@ -437,6 +438,37 @@ static bool vfio_platform_match(SysBusDevice *sbdev, - - #endif /* CONFIG_LINUX */ - -+/* -+ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS -+ * -+ * See kernel documentation: -+ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt -+ * Optional interrupt for command completion is not exposed -+ */ -+static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ PlatformBusFDTData *data = opaque; -+ PlatformBusDevice *pbus = data->pbus; -+ void *fdt = data->fdt; -+ const char *parent_node = data->pbus_node_name; -+ char *nodename; -+ uint32_t reg_attr[2]; -+ uint64_t mmio_base; -+ -+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); -+ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); -+ qemu_fdt_add_subnode(fdt, nodename); -+ -+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); -+ -+ reg_attr[0] = cpu_to_be32(mmio_base); -+ reg_attr[1] = cpu_to_be32(0x5000); -+ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); -+ -+ g_free(nodename); -+ return 0; -+} -+ - static int no_fdt_node(SysBusDevice *sbdev, void *opaque) - { - return 0; -@@ -457,6 +489,7 @@ static const BindingEntry bindings[] = { - TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node), - VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node), - #endif -+ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), - TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), - TYPE_BINDING("", NULL), /* last element */ - }; -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 133d36a4..7afc6c5e 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -47,6 +47,7 @@ - #include "sysemu/numa.h" - #include "sysemu/cpus.h" - #include "sysemu/sysemu.h" -+#include "sysemu/tpm.h" - #include "sysemu/kvm.h" - #include "sysemu/cpus.h" - #include "sysemu/hw_accel.h" -@@ -2368,6 +2369,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE); - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM); -+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); - mc->block_default_type = IF_VIRTIO; - mc->no_cdrom = 1; - mc->pci_allow_0_address = true; -@@ -2481,6 +2483,11 @@ type_init(machvirt_machine_init); - - static void virt_machine_4_1_options(MachineClass *mc) - { -+ static GlobalProperty compat[] = { -+ { TYPE_TPM_TIS_SYSBUS, "ppi", "false" }, -+ }; -+ -+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); - } - DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) - --- -2.23.0 - diff --git a/hw-arm-xlnx-zynqmp-fix-unsigned-error-when-checking-.patch b/hw-arm-xlnx-zynqmp-fix-unsigned-error-when-checking-.patch new file mode 100644 index 0000000000000000000000000000000000000000..0968345e28418c949f5c25f680f78db5bbaabd42 --- /dev/null +++ b/hw-arm-xlnx-zynqmp-fix-unsigned-error-when-checking-.patch @@ -0,0 +1,47 @@ +From a1ecbf056603b4fabf8b5ab8a79f70a27fef06ee Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Sun, 24 Sep 2023 19:39:33 +0800 +Subject: [PATCH] hw/arm/xlnx-zynqmp: fix unsigned error when checking the RPUs + number +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When passing --smp with a number lower than XLNX_ZYNQMP_NUM_APU_CPUS, +the expression (ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS) will result +in a positive number as ms->smp.cpus is a unsigned int. +This will raise the following error afterwards, as Qemu will try to +instantiate some additional RPUs. + | $ qemu-system-aarch64 --smp 1 -M xlnx-zcu102 + | ** + | ERROR:../src/tcg/tcg.c:777:tcg_register_thread: + | assertion failed: (n < tcg_max_ctxs) + +cheery-pick from c9ba1c9f02cfede5329f504cdda6fd3a256e0434 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Clément Chigot +Reviewed-by: Francisco Iglesias +Tested-by: Francisco Iglesias +Message-id: 20230524143714.565792-1-chigot@adacore.com +Signed-off-by: Peter Maydell +--- + hw/arm/xlnx-zynqmp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c +index 1c52a575aa..2ffc6df70b 100644 +--- a/hw/arm/xlnx-zynqmp.c ++++ b/hw/arm/xlnx-zynqmp.c +@@ -194,7 +194,7 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, + const char *boot_cpu, Error **errp) + { + int i; +- int num_rpus = MIN(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS, ++ int num_rpus = MIN((int)(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS), + XLNX_ZYNQMP_NUM_RPU_CPUS); + + if (num_rpus <= 0) { +-- +2.41.0.windows.1 + diff --git a/hw-arm64-add-vcpu-cache-info-support.patch b/hw-arm64-add-vcpu-cache-info-support.patch index 79e1dede39def063dc9d8a4f4b87339bcd39c435..3e8c82e626cca3592709f99af77a7092eddc3207 100644 --- a/hw-arm64-add-vcpu-cache-info-support.patch +++ b/hw-arm64-add-vcpu-cache-info-support.patch @@ -1,63 +1,68 @@ -From 5a0ed254f99ca37498bd81994b906b6984b5ffa9 Mon Sep 17 00:00:00 2001 +From c5cd762bb7513b6df07e26f4eb619dccbd1918b7 Mon Sep 17 00:00:00 2001 From: Ying Fang -Date: Wed, 22 Apr 2020 19:25:00 +0800 -Subject: [PATCH] hw/arm64: add vcpu cache info support +Date: Tue, 8 Feb 2022 11:31:15 +0800 +Subject: [PATCH 23/24] hw/arm64: add vcpu cache info support Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. Signed-off-by: zhanghailiang Signed-off-by: Honghao +Signed-off-by: Ying Fang +Signed-off-by: Yanan Wang --- - hw/acpi/aml-build.c | 126 ++++++++++++++++++++++++++++++++++++ - hw/arm/virt.c | 80 ++++++++++++++++++++++- - include/hw/acpi/aml-build.h | 46 +++++++++++++ - 3 files changed, 251 insertions(+), 1 deletion(-) + hw/acpi/aml-build.c | 158 ++++++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 72 ++++++++++++++++ + include/hw/acpi/aml-build.h | 47 +++++++++++ + tests/data/acpi/virt/PPTT | Bin 96 -> 208 bytes + 4 files changed, 277 insertions(+) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index f2c8c28f..74e95005 100644 +index bb2cad63b5..bebf49622b 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c -@@ -55,6 +55,131 @@ static void build_append_array(GArray *array, GArray *val) - /* - * ACPI 6.2 Processor Properties Topology Table (PPTT) - */ +@@ -1994,6 +1994,163 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + } + } + +#ifdef __aarch64__ -+static void build_cache_head(GArray *tbl, uint32_t next_level) ++/* ++ * 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); -+} + -+static void build_cache_tail(GArray *tbl, uint32_t cache_type) -+{ + switch (cache_type) { -+ case ARM_L1D_CACHE: /* L1 dcache info*/ ++ case ARM_L1D_CACHE: /* L1 dcache info */ + build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4); -+ build_append_int_noprefix(tbl, ARM_L1DCACHE_SET, 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*/ ++ case ARM_L1I_CACHE: /* L1 icache info */ + build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4); -+ build_append_int_noprefix(tbl, ARM_L1ICACHE_SET, 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*/ ++ case ARM_L2_CACHE: /* L2 cache info */ + build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4); -+ build_append_int_noprefix(tbl, ARM_L2CACHE_SET, 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*/ ++ case ARM_L3_CACHE: /* L3 cache info */ + build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4); -+ build_append_int_noprefix(tbl, ARM_L3CACHE_SET, 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); @@ -68,208 +73,230 @@ index f2c8c28f..74e95005 100644 + build_append_byte(tbl, 0); + build_append_byte(tbl, 0); + build_append_int_noprefix(tbl, 0, 2); -+ break; + } +} + -+static void build_cache_hierarchy(GArray *tbl, -+ uint32_t next_level, uint32_t cache_type) ++/* ++ * ACPI spec, Revision 6.3 ++ * 5.2.29 Processor Properties Topology Table (PPTT) ++ */ ++void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, ++ const char *oem_id, const char *oem_table_id) +{ -+ build_cache_head(tbl, next_level); -+ build_cache_tail(tbl, cache_type); -+} ++ 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 }; + -+static void build_arm_socket_hierarchy(GArray *tbl, -+ uint32_t offset, uint32_t id) -+{ -+ build_append_byte(tbl, 0); /* Type 0 - processor */ -+ build_append_byte(tbl, 24); /* Length, add private resources */ -+ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ -+ build_append_int_noprefix(tbl, 1, 4); /* Processor boundary and id invalid*/ -+ build_append_int_noprefix(tbl, 0, 4); -+ build_append_int_noprefix(tbl, id, 4); -+ build_append_int_noprefix(tbl, 1, 4); /* Num private resources */ -+ build_append_int_noprefix(tbl, offset, 4); -+} ++ acpi_table_begin(&table, table_data); + -+static void build_arm_cpu_hierarchy(GArray *tbl, -+ struct offset_status *offset, uint32_t id) -+{ -+ if (!offset) { -+ return; ++ 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); + } -+ build_append_byte(tbl, 0); /* Type 0 - processor */ -+ build_append_byte(tbl, 32); /* Length, add private resources */ -+ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ -+ build_append_int_noprefix(tbl, 2, 4); /* Valid id*/ -+ build_append_int_noprefix(tbl, offset->parent, 4); -+ build_append_int_noprefix(tbl, id, 4); -+ build_append_int_noprefix(tbl, 3, 4); /* Num private resources */ -+ build_append_int_noprefix(tbl, offset->l1d_offset, 4); -+ build_append_int_noprefix(tbl, offset->l1i_offset, 4); -+ build_append_int_noprefix(tbl, offset->l2_offset, 4); -+} + -+void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) -+{ -+ int pptt_start = table_data->len; -+ int uid = 0, cpus = 0, socket; -+ struct offset_status offset; -+ const MachineState *ms = MACHINE(qdev_get_machine()); -+ unsigned int smp_cores = ms->smp.cores; ++ if (mc->smp_props.clusters_supported) { ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { ++ int cluster; + -+ acpi_data_push(table_data, sizeof(AcpiTableHeader)); ++ 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); ++ } ++ } ++ } + -+ for (socket = 0; cpus < possible_cpus; socket++) { ++ length = g_queue_get_length(list); ++ for (i = 0; i < length; i++) { + int core; -+ uint32_t l3_offset = table_data->len - pptt_start; -+ build_cache_hierarchy(table_data, 0, ARM_L3_CACHE); -+ -+ offset.parent = table_data->len - pptt_start; -+ build_arm_socket_hierarchy(table_data, l3_offset, socket); -+ -+ for (core = 0; core < smp_cores; core++) { -+ offset.l2_offset = table_data->len - pptt_start; -+ build_cache_hierarchy(table_data, 0, ARM_L2_CACHE); -+ offset.l1d_offset = table_data->len - pptt_start; -+ build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE); -+ offset.l1i_offset = table_data->len - pptt_start; -+ build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE); -+ build_arm_cpu_hierarchy(table_data, &offset, uid++); -+ cpus++; ++ ++ 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); + } + } + -+ build_header(linker, table_data, -+ (void *)(table_data->data + pptt_start), "PPTT", -+ table_data->len - pptt_start, 1, NULL, NULL); ++ g_queue_free(list); ++ acpi_table_end(linker, &table); +} + +#else - static void build_cpu_hierarchy(GArray *tbl, uint32_t flags, - uint32_t parent, uint32_t id) - { -@@ -103,6 +228,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) - (void *)(table_data->data + pptt_start), "PPTT", - table_data->len - pptt_start, 1, NULL, NULL); + /* + * ACPI spec, Revision 6.3 + * 5.2.29 Processor Properties Topology Table (PPTT) +@@ -2084,6 +2241,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, + g_queue_free(list); + acpi_table_end(linker, &table); } +#endif - - #define ACPI_NAMESEG_LEN 4 - + + /* build rev1/rev3/rev5.1 FADT */ + void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 272455bc..9669c70b 100644 +index ddcb73f714..529c0d38b6 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -308,6 +308,81 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) +@@ -350,6 +350,72 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); } - + +static void fdt_add_l3cache_nodes(const VirtMachineState *vms) +{ + int i; -+ const MachineState *ms = MACHINE(qdev_get_machine()); -+ unsigned int smp_cores = ms->smp.cores; -+ unsigned int sockets = vms->smp_cpus / smp_cores; -+ -+ /* If current is not equal to max */ -+ if (vms->smp_cpus % smp_cores) -+ sockets++; ++ const MachineState *ms = MACHINE(vms); ++ int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads; ++ int sockets = (ms->smp.cpus + cpus_per_socket - 1) / cpus_per_socket; + + for (i = 0; i < sockets; i++) { + char *nodename = g_strdup_printf("/cpus/l3-cache%d", i); -+ qemu_fdt_add_subnode(vms->fdt, nodename); -+ qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cache"); -+ qemu_fdt_setprop_string(vms->fdt, nodename, "cache-unified", "true"); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-level", 3); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-size", 0x2000000); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-line-size", 128); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-sets", 2048); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", -+ qemu_fdt_alloc_phandle(vms->fdt)); ++ ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ 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, "phandle", ++ qemu_fdt_alloc_phandle(ms->fdt)); + g_free(nodename); + } +} + -+ +static void fdt_add_l2cache_nodes(const VirtMachineState *vms) +{ -+ int i, j; -+ const MachineState *ms = MACHINE(qdev_get_machine()); -+ unsigned int smp_cores = ms->smp.cores; -+ signed int sockets = vms->smp_cpus / smp_cores; ++ const MachineState *ms = MACHINE(vms); ++ int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads; ++ int cpu; + -+ /* If current is not equal to max */ -+ if (vms->smp_cpus % smp_cores) -+ sockets++; ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ char *next_path = g_strdup_printf("/cpus/l3-cache%d", ++ cpu / cpus_per_socket); ++ char *nodename = g_strdup_printf("/cpus/l2-cache%d", cpu); ++ ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ 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_phandle(ms->fdt, nodename, "next-level-cache", ++ next_path); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", ++ qemu_fdt_alloc_phandle(ms->fdt)); + -+ for (i = 0; i < sockets; i++) { -+ char *next_path = g_strdup_printf("/cpus/l3-cache%d", i); -+ for (j = 0; j < smp_cores; j++) { -+ char *nodename = g_strdup_printf("/cpus/l2-cache%d", -+ i * smp_cores + j); -+ qemu_fdt_add_subnode(vms->fdt, nodename); -+ qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cache"); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-size", 0x80000); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-line-size", 64); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-sets", 1024); -+ qemu_fdt_setprop_phandle(vms->fdt, nodename, -+ "next-level-cache", next_path); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", -+ qemu_fdt_alloc_phandle(vms->fdt)); -+ g_free(nodename); -+ } + g_free(next_path); ++ g_free(nodename); + } +} + +static void fdt_add_l1cache_prop(const VirtMachineState *vms, -+ char *nodename, int cpu) ++ char *nodename, int cpu) +{ ++ const MachineState *ms = MACHINE(vms); + char *cachename = g_strdup_printf("/cpus/l2-cache%d", cpu); + -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-size", 0x10000); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-line-size", 64); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-sets", 256); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-size", 0x10000); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-line-size", 64); -+ qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-sets", 256); -+ qemu_fdt_setprop_phandle(vms->fdt, nodename, -+ "next-level-cache", cachename); ++ 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); +} -+ + static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; -@@ -341,6 +416,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) - qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells); - qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0); - -+ fdt_add_l3cache_nodes(vms); -+ fdt_add_l2cache_nodes(vms); +@@ -384,6 +450,11 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", addr_cells); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + ++ if (!vmc->no_cpu_topology) { ++ fdt_add_l3cache_nodes(vms); ++ fdt_add_l2cache_nodes(vms); ++ } + - for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { + for (cpu = smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); -@@ -369,7 +447,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) - qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", - ms->possible_cpus->cpus[cs->cpu_index].props.node_id); +@@ -413,6 +484,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + } + + if (!vmc->no_cpu_topology) { ++ fdt_add_l1cache_prop(vms, nodename, cpu); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(ms->fdt)); } -- -+ fdt_add_l1cache_prop(vms, nodename, cpu); - qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", - qemu_fdt_alloc_phandle(vms->fdt)); - diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h -index bfb0b100..0be3453a 100644 +index 8346003a22..8e8ad8029e 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h -@@ -223,6 +223,52 @@ struct AcpiBuildTables { +@@ -221,6 +221,53 @@ struct AcpiBuildTables { BIOSLinker *linker; } AcpiBuildTables; - + +#ifdef __aarch64__ +/* Definitions of the hardcoded cache info*/ + @@ -282,28 +309,28 @@ index bfb0b100..0be3453a 100644 + +/* L1 data cache: */ +#define ARM_L1DCACHE_SIZE 65536 -+#define ARM_L1DCACHE_SET 256 ++#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_SET 256 ++#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_SET 1024 ++#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_SET 2048 ++#define ARM_L3CACHE_SETS 2048 +#define ARM_L3CACHE_ASSOCIATIVITY 15 +#define ARM_L3CACHE_ATTRIBUTES 10 +#define ARM_L3CACHE_LINE_SIZE 128 @@ -316,8 +343,11 @@ index bfb0b100..0be3453a 100644 +}; + +#endif - /** - * init_aml_allocator: - * --- -2.23.0 ++ + typedef + struct CrsRangeEntry { + uint64_t base; + +-- +2.27.0 + diff --git a/hw-audio-intel-hda-Do-not-ignore-DMA-overrun-errors.patch b/hw-audio-intel-hda-Do-not-ignore-DMA-overrun-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..40cd09857957336c87f6bd96ed8f9421210b0db9 --- /dev/null +++ b/hw-audio-intel-hda-Do-not-ignore-DMA-overrun-errors.patch @@ -0,0 +1,70 @@ +From 2defe49a69b324499953c9b8c55f18e22ca74631 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Sat, 18 Dec 2021 17:09:10 +0100 +Subject: [PATCH 23/25] hw/audio/intel-hda: Do not ignore DMA overrun errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Per the "High Definition Audio Specification" manual (rev. 1.0a), +section "3.3.30 Offset 5Dh: RIRBSTS - RIRB Status": + + Response Overrun Interrupt Status (RIRBOIS): + + Hardware sets this bit to a 1 when an overrun occurs in the RIRB. + An interrupt may be generated if the Response Overrun Interrupt + Control bit is set. + + This bit will be set if the RIRB DMA engine is not able to write + the incoming responses to memory before additional incoming + responses overrun the internal FIFO. + + When hardware detects an overrun, it will drop the responses which + overrun the buffer and set the RIRBOIS status bit to indicate the + error condition. Optionally, if the RIRBOIC is set, the hardware + will also generate an error to alert software to the problem. + +QEMU emulates the DMA engine with the stl_le_pci_dma() calls. This +function returns a MemTxResult indicating whether the DMA access +was successful. +Handle any MemTxResult error as "DMA engine is not able to write the +incoming responses to memory" and raise the Overrun Interrupt flag +when this case occurs. + +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211218160912.1591633-2-philmd@redhat.com> +Signed-off-by: Thomas Huth +--- + hw/audio/intel-hda.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index 2b55d52150..0c1017edbb 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -350,6 +350,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + hwaddr addr; + uint32_t wp, ex; ++ MemTxResult res = MEMTX_OK; + + if (d->ics & ICH6_IRS_BUSY) { + dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n", +@@ -368,8 +369,12 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res + ex = (solicited ? 0 : (1 << 4)) | dev->cad; + wp = (d->rirb_wp + 1) & 0xff; + addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); +- stl_le_pci_dma(&d->pci, addr + 8 * wp, response, attrs); +- stl_le_pci_dma(&d->pci, addr + 8 * wp + 4, ex, attrs); ++ res |= stl_le_pci_dma(&d->pci, addr + 8 * wp, response, attrs); ++ res |= stl_le_pci_dma(&d->pci, addr + 8 * wp + 4, ex, attrs); ++ if (res != MEMTX_OK && (d->rirb_ctl & ICH6_RBCTL_OVERRUN_EN)) { ++ d->rirb_sts |= ICH6_RBSTS_OVERRUN; ++ intel_hda_update_irq(d); ++ } + d->rirb_wp = wp; + + dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", +-- +2.27.0 + diff --git a/hw-audio-intel-hda-Restrict-DMA-engine-to-memories-n.patch b/hw-audio-intel-hda-Restrict-DMA-engine-to-memories-n.patch new file mode 100644 index 0000000000000000000000000000000000000000..0e2508bdc2b34e7a38089d2bfb3ed74b51b41f5e --- /dev/null +++ b/hw-audio-intel-hda-Restrict-DMA-engine-to-memories-n.patch @@ -0,0 +1,41 @@ +From f8b3b2e8d09320cab4cccab2dcbaab799d2dbd7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Sat, 18 Dec 2021 17:09:11 +0100 +Subject: [PATCH 24/25] hw/audio/intel-hda: Restrict DMA engine to memories + (not MMIO devices) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Issue #542 reports a reentrancy problem when the DMA engine accesses +the HDA controller I/O registers. Fix by restricting the DMA engine +to memories regions (forbidding MMIO devices such the HDA controller). + +Reported-by: OSS-Fuzz (Issue 28435) +Reported-by: Alexander Bulekov +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Thomas Huth +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/542 +CVE: CVE-2021-3611 +Message-Id: <20211218160912.1591633-3-philmd@redhat.com> +Signed-off-by: Thomas Huth +--- + hw/audio/intel-hda.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index 0c1017edbb..3aa57d274e 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -345,7 +345,7 @@ static void intel_hda_corb_run(IntelHDAState *d) + + static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) + { +- const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ const MemTxAttrs attrs = { .memory = true }; + HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + hwaddr addr; +-- +2.27.0 + diff --git a/hw-audio-intel-hda-fix-stream-reset.patch b/hw-audio-intel-hda-fix-stream-reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef80b5d4a0414e2f58539828825890f7bb3a62c6 --- /dev/null +++ b/hw-audio-intel-hda-fix-stream-reset.patch @@ -0,0 +1,47 @@ +From b42ad03f9e1fcdd7cac13789038621173f754294 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Mar 2023 02:38:36 +0000 +Subject: [PATCH] hw/audio/intel-hda: fix stream reset mainline inclusion + commit ecd5f2882fdd10f798984eb52abd00ffc78c2ef7 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +Quote from: +High Definition Audio Specification 1.0a, section 3.3.35 + +Offset 80: {IOB}SDnCTL Stream Reset (SRST): Writing a 1 causes +the corresponding stream to be reset. The Stream Descriptor +registers (except the SRST bit itself) ... are reset. + +Change the code to reset the Stream Descriptor Control and Status +registers except the SRST bit. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/757 +Signed-off-by: Volker Rümelin +Message-Id: <20211226154017.6067-3-vr_qemu@t-online.de> +Signed-off-by: Gerd Hoffmann + +Signed-off-by: tangbinzy +--- + hw/audio/intel-hda.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index 3aa57d274e..78a47bc08c 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -586,7 +586,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 + if (st->ctl & 0x01) { + /* reset */ + dprint(d, 1, "st #%d: reset\n", reg->stream); +- st->ctl = SD_STS_FIFO_READY << 24; ++ st->ctl = SD_STS_FIFO_READY << 24 | SD_CTL_STREAM_RESET; + } + if ((st->ctl & 0x02) != (old & 0x02)) { + uint32_t stnr = (st->ctl >> 20) & 0x0f; +-- +2.27.0 + diff --git a/hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch b/hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..99c174c780c89c4a540935a14fcb3e876c9e707b --- /dev/null +++ b/hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch @@ -0,0 +1,87 @@ +From 4c72f406e3ff02844977fcd8bc696080088d3d08 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 18 Nov 2021 12:57:32 +0100 +Subject: [PATCH 5/6] hw/block/fdc: Prevent end-of-track overrun + (CVE-2021-3507) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Per the 82078 datasheet, if the end-of-track (EOT byte in +the FIFO) is more than the number of sectors per side, the +command is terminated unsuccessfully: + +* 5.2.5 DATA TRANSFER TERMINATION + + The 82078 supports terminal count explicitly through + the TC pin and implicitly through the underrun/over- + run and end-of-track (EOT) functions. For full sector + transfers, the EOT parameter can define the last + sector to be transferred in a single or multisector + transfer. If the last sector to be transferred is a par- + tial sector, the host can stop transferring the data in + mid-sector, and the 82078 will continue to complete + the sector as if a hardware TC was received. The + only difference between these implicit functions and + TC is that they return "abnormal termination" result + status. Such status indications can be ignored if they + were expected. + +* 6.1.3 READ TRACK + + This command terminates when the EOT specified + number of sectors have been read. If the 82078 + does not find an I D Address Mark on the diskette + after the second· occurrence of a pulse on the + INDX# pin, then it sets the IC code in Status Regis- + ter 0 to "01" (Abnormal termination), sets the MA bit + in Status Register 1 to "1", and terminates the com- + mand. + +* 6.1.6 VERIFY + + Refer to Table 6-6 and Table 6-7 for information + concerning the values of MT and EC versus SC and + EOT value. + +* Table 6·6. Result Phase Table + +* Table 6-7. Verify Command Result Phase Table + +Fix by aborting the transfer when EOT > # Sectors Per Side. + +Cc: qemu-stable@nongnu.org +Cc: Hervé Poussineau +Fixes: baca51faff0 ("floppy driver: disk geometry auto detect") +Reported-by: Alexander Bulekov +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/339 +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211118115733.4038610-2-philmd@redhat.com> +Reviewed-by: Hanna Reitz +Signed-off-by: Kevin Wolf +--- + hw/block/fdc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/block/fdc.c b/hw/block/fdc.c +index 21d18ac2e3..24b05406e6 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -1529,6 +1529,14 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) + int tmp; + fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); + tmp = (fdctrl->fifo[6] - ks + 1); ++ if (tmp < 0) { ++ FLOPPY_DPRINTF("invalid EOT: %d\n", tmp); ++ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); ++ fdctrl->fifo[3] = kt; ++ fdctrl->fifo[4] = kh; ++ fdctrl->fifo[5] = ks; ++ return; ++ } + if (fdctrl->fifo[0] & 0x80) + tmp += fdctrl->fifo[6]; + fdctrl->data_len *= tmp; +-- +2.27.0 + diff --git a/hw-block-nvme-fix-pci-doorbell-size-calculation.patch b/hw-block-nvme-fix-pci-doorbell-size-calculation.patch deleted file mode 100644 index f0aa09670e471a344c220ae38b8f5ba43b263eaf..0000000000000000000000000000000000000000 --- a/hw-block-nvme-fix-pci-doorbell-size-calculation.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 1aa42c9269c762ad1b7efa41e92f734b093dce1c Mon Sep 17 00:00:00 2001 -From: Klaus Jensen -Date: Tue, 9 Jun 2020 21:03:12 +0200 -Subject: [PATCH 10/11] hw/block/nvme: fix pci doorbell size calculation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The size of the BAR is 0x1000 (main registers) + 8 bytes for each -queue. Currently, the size of the BAR is calculated like so: - - n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); - -Since the 'num_queues' parameter already accounts for the admin queue, -this should in any case not need to be incremented by one. Also, the -size should be initialized to (0x1000). - - n->reg_size = pow2ceil(0x1000 + 2 * n->num_queues * 4); - -This, with the default value of num_queues (64), we will set aside room -for 1 admin queue and 63 I/O queues (4 bytes per doorbell, 2 doorbells -per queue). - -Signed-off-by: Klaus Jensen -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Maxim Levitsky -Reviewed-by: Keith Busch -Message-Id: <20200609190333.59390-2-its@irrelevant.dk> -Signed-off-by: Kevin Wolf -Signed-off-by: BiaoXiang Ye ---- - hw/block/nvme.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/hw/block/nvme.c b/hw/block/nvme.c -index 417068d8..edac2f1d 100644 ---- a/hw/block/nvme.c -+++ b/hw/block/nvme.c -@@ -42,6 +42,9 @@ - #include "trace.h" - #include "nvme.h" - -+#define NVME_REG_SIZE 0x1000 -+#define NVME_DB_SIZE 4 -+ - #define NVME_GUEST_ERR(trace, fmt, ...) \ - do { \ - (trace_##trace)(__VA_ARGS__); \ -@@ -1348,7 +1351,9 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) - pcie_endpoint_cap_init(pci_dev, 0x80); - - n->num_namespaces = 1; -- n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); -+ -+ /* num_queues is really number of pairs, so each has two doorbells */ -+ n->reg_size = pow2ceil(NVME_REG_SIZE + 2 * n->num_queues * NVME_DB_SIZE); - n->ns_size = bs_size / (uint64_t)n->num_namespaces; - - n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); --- -2.27.0.dirty - diff --git a/hw-block-nvme-fix-pin-based-interrupt-behavior.patch b/hw-block-nvme-fix-pin-based-interrupt-behavior.patch deleted file mode 100644 index 1fe1213d998869c0f87eabd5d75fc62c3750f06b..0000000000000000000000000000000000000000 --- a/hw-block-nvme-fix-pin-based-interrupt-behavior.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 74ef18c90684f0ae18aef071b9e11a5e8796177b Mon Sep 17 00:00:00 2001 -From: alexchen -Date: Tue, 8 Sep 2020 11:17:20 +0000 -Subject: [PATCH] hw/block/nvme: fix pin-based interrupt behavior - -First, since the device only supports MSI-X or pin-based interrupt, if -MSI-X is not enabled, it should not accept interrupt vectors different -from 0 when creating completion queues. - -Secondly, the irq_status NvmeCtrl member is meant to be compared to the -INTMS register, so it should only be 32 bits wide. And it is really only -useful when used with multi-message MSI. - -Third, since we do not force a 1-to-1 correspondence between cqid and -interrupt vector, the irq_status register should not have bits set -according to cqid, but according to the associated interrupt vector. - -Fix these issues, but keep irq_status available so we can easily support -multi-message MSI down the line. - -Fixes: 5e9aa92eb1a5 ("hw/block: Fix pin-based interrupt behaviour of NVMe") -Cc: "Michael S. Tsirkin" -Cc: Marcel Apfelbaum -Signed-off-by: Klaus Jensen -Reviewed-by: Keith Busch -Message-Id: <20200609190333.59390-8-its@irrelevant.dk> -Signed-off-by: Kevin Wolf -Signed-off-by: BiaoXiang Ye -Signed-off-by: Zhenyu Ye ---- - hw/block/nvme.c | 12 ++++++++---- - hw/block/nvme.h | 2 +- - 2 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/hw/block/nvme.c b/hw/block/nvme.c -index 36d6a8bb..e35c2e10 100644 ---- a/hw/block/nvme.c -+++ b/hw/block/nvme.c -@@ -115,8 +115,8 @@ static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) - msix_notify(&(n->parent_obj), cq->vector); - } else { - trace_nvme_irq_pin(); -- assert(cq->cqid < 64); -- n->irq_status |= 1 << cq->cqid; -+ assert(cq->vector < 32); -+ n->irq_status |= 1 << cq->vector; - nvme_irq_check(n); - } - } else { -@@ -130,8 +130,8 @@ static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq) - if (msix_enabled(&(n->parent_obj))) { - return; - } else { -- assert(cq->cqid < 64); -- n->irq_status &= ~(1 << cq->cqid); -+ assert(cq->vector < 32); -+ n->irq_status &= ~(1 << cq->vector); - nvme_irq_check(n); - } - } -@@ -630,6 +630,10 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) - trace_nvme_err_invalid_create_cq_addr(prp1); - return NVME_INVALID_FIELD | NVME_DNR; - } -+ if (unlikely(!msix_enabled(&n->parent_obj) && vector)) { -+ trace_nvme_err_invalid_create_cq_vector(vector); -+ return NVME_INVALID_IRQ_VECTOR | NVME_DNR; -+ } - if (unlikely(vector > n->num_queues)) { - trace_nvme_err_invalid_create_cq_vector(vector); - return NVME_INVALID_IRQ_VECTOR | NVME_DNR; -diff --git a/hw/block/nvme.h b/hw/block/nvme.h -index 557194ee..f4c1ff91 100644 ---- a/hw/block/nvme.h -+++ b/hw/block/nvme.h -@@ -78,7 +78,7 @@ typedef struct NvmeCtrl { - uint32_t cmbsz; - uint32_t cmbloc; - uint8_t *cmbuf; -- uint64_t irq_status; -+ uint32_t irq_status; - uint64_t host_timestamp; /* Timestamp sent by the host */ - uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ - --- -2.23.0 - diff --git a/hw-char-fix-qcode-array-bounds-check-in-ESCC-impl.patch b/hw-char-fix-qcode-array-bounds-check-in-ESCC-impl.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a00eb1be6f93ff6a03e40d44b1226b69c53070b --- /dev/null +++ b/hw-char-fix-qcode-array-bounds-check-in-ESCC-impl.patch @@ -0,0 +1,40 @@ +From 308cd236694ac13e2c45293b670b536b63765e62 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 4 Sep 2023 07:27:24 +0000 +Subject: [PATCH] hw/char: fix qcode array bounds check in ESCC impl mainline + inclusion commit 9aaf11e7f2b5487b684e900cf164f0aef25f72ab category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +There was an off-by-1 in the qcode conversion array bounds +check. + +Fixes: e709a61a8fe1076a487376fd657544418a38ba06 +Reported-by: Peter Maydell +Reviewed-by: Peter Maydell +Signed-off-by: Daniel P. Berrangé + +Signed-off-by: tangbinzy +--- + hw/char/escc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/escc.c b/hw/char/escc.c +index 8755d8d34f..17a908c59b 100644 +--- a/hw/char/escc.c ++++ b/hw/char/escc.c +@@ -828,7 +828,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, + } + } + +- if (qcode > qemu_input_map_qcode_to_sun_len) { ++ if (qcode >= qemu_input_map_qcode_to_sun_len) { + return; + } + +-- +2.41.0.windows.1 + diff --git a/hw-char-pl011-fix-baud-rate-calculation.patch b/hw-char-pl011-fix-baud-rate-calculation.patch new file mode 100644 index 0000000000000000000000000000000000000000..1921910ab02423536971975c965b3aa3c89ec5f4 --- /dev/null +++ b/hw-char-pl011-fix-baud-rate-calculation.patch @@ -0,0 +1,39 @@ +From 07639839666f134834b060a63d6b172812092366 Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Mon, 28 Nov 2022 02:50:07 +0000 +Subject: [PATCH 28/29] hw/char/pl011: fix baud rate calculation mainline + inclusion from mainline-v7.2.0-rc2 commit + 31cb769c317e0623cbe2a3e8da437b6cd7ddef9b category: bugfix + +-------------------------------- + +The PL011 TRM says that "UARTIBRD = 0 is invalid and UARTFBRD is ignored +when this is the case". But the code looks at FBRD for the invalid case. +Fix this. + +Signed-off-by: Baruch Siach +Message-id: 1408f62a2e45665816527d4845ffde650957d5ab.1665051588.git.baruchs-c@neureality.ai +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell + +Signed-off-by: cmss_dx +--- + hw/char/pl011.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/pl011.c b/hw/char/pl011.c +index 8ca2a4ed68..b24ccfeac7 100644 +--- a/hw/char/pl011.c ++++ b/hw/char/pl011.c +@@ -176,7 +176,7 @@ static unsigned int pl011_get_baudrate(const PL011State *s) + { + uint64_t clk; + +- if (s->fbrd == 0) { ++ if (s->ibrd == 0) { + return 0; + } + +-- +2.27.0 + diff --git a/hw-core-Rename-smp_parse-machine_parse_smp_config.patch b/hw-core-Rename-smp_parse-machine_parse_smp_config.patch new file mode 100644 index 0000000000000000000000000000000000000000..8537cc6adec12daacbd87f61ab6e36656117c8b0 --- /dev/null +++ b/hw-core-Rename-smp_parse-machine_parse_smp_config.patch @@ -0,0 +1,114 @@ +From 2ce1daae407033e689a559b7346523b18651ee0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 10:21:23 +0100 +Subject: [PATCH 09/24] hw/core: Rename smp_parse() -> + machine_parse_smp_config() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +All methods related to MachineState are prefixed with "machine_". +smp_parse() does not need to be an exception. Rename it and +const'ify the SMPConfiguration argument, since it doesn't need +to be modified. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-9-philmd@redhat.com> +--- + hw/core/machine-smp.c | 6 ++++-- + hw/core/machine.c | 2 +- + include/hw/boards.h | 3 ++- + tests/unit/test-smp-parse.c | 8 ++++---- + 4 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 116a0cbbfa..2cbfd57429 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -44,7 +44,8 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + } + + /* +- * smp_parse - Generic function used to parse the given SMP configuration ++ * machine_parse_smp_config: Generic function used to parse the given ++ * SMP configuration + * + * Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be + * automatically computed based on the provided ones. +@@ -63,7 +64,8 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + * introduced topology members which are likely to be target specific should + * be directly set as 1 if they are omitted (e.g. dies for PC since 4.1). + */ +-void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) ++void machine_parse_smp_config(MachineState *ms, ++ const SMPConfiguration *config, Error **errp) + { + MachineClass *mc = MACHINE_GET_CLASS(ms); + unsigned cpus = config->has_cpus ? config->cpus : 0; +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 53a99abc56..3993c534b9 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -761,7 +761,7 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, + return; + } + +- smp_parse(ms, config, errp); ++ machine_parse_smp_config(ms, config, errp); + } + + static void machine_class_init(ObjectClass *oc, void *data) +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 9c1c190104..7597cec440 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -34,7 +34,8 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine); + void machine_set_cpu_numa_node(MachineState *machine, + const CpuInstanceProperties *props, + Error **errp); +-void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp); ++void machine_parse_smp_config(MachineState *ms, ++ const SMPConfiguration *config, Error **errp); + + /** + * machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 0f98c9509e..b6df8137fc 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -337,7 +337,7 @@ static const struct SMPTestData data_with_dies_invalid[] = { + }, + }; + +-static char *smp_config_to_string(SMPConfiguration *config) ++static char *smp_config_to_string(const SMPConfiguration *config) + { + return g_strdup_printf( + "(SMPConfiguration) {\n" +@@ -371,7 +371,7 @@ static char *cpu_topology_to_string(const CpuTopology *topo) + topo->cores, topo->threads, topo->max_cpus); + } + +-static void check_parse(MachineState *ms, SMPConfiguration *config, ++static void check_parse(MachineState *ms, const SMPConfiguration *config, + const CpuTopology *expect_topo, const char *expect_err, + bool is_valid) + { +@@ -380,8 +380,8 @@ static void check_parse(MachineState *ms, SMPConfiguration *config, + g_autofree char *output_topo_str = NULL; + Error *err = NULL; + +- /* call the generic parser smp_parse() */ +- smp_parse(ms, config, &err); ++ /* call the generic parser */ ++ machine_parse_smp_config(ms, config, &err); + + output_topo_str = cpu_topology_to_string(&ms->smp); + +-- +2.27.0 + diff --git a/hw-core-loader-Fix-possible-crash-in-rom_copy.patch b/hw-core-loader-Fix-possible-crash-in-rom_copy.patch deleted file mode 100644 index 770f12b1acf9dfc3c4289e9a9bea7d5936df1968..0000000000000000000000000000000000000000 --- a/hw-core-loader-Fix-possible-crash-in-rom_copy.patch +++ /dev/null @@ -1,45 +0,0 @@ -From aae0faa5d3bee91c66dc4c1543190f55a242771e Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Wed, 25 Sep 2019 14:16:43 +0200 -Subject: [PATCH] hw/core/loader: Fix possible crash in rom_copy() - -Both, "rom->addr" and "addr" are derived from the binary image -that can be loaded with the "-kernel" paramer. The code in -rom_copy() then calculates: - - d = dest + (rom->addr - addr); - -and uses "d" as destination in a memcpy() some lines later. Now with -bad kernel images, it is possible that rom->addr is smaller than addr, -thus "rom->addr - addr" gets negative and the memcpy() then tries to -copy contents from the image to a bad memory location. This could -maybe be used to inject code from a kernel image into the QEMU binary, -so we better fix it with an additional sanity check here. - -Cc: qemu-stable@nongnu.org -Reported-by: Guangming Liu -Buglink: https://bugs.launchpad.net/qemu/+bug/1844635 -Message-Id: <20190925130331.27825-1-thuth@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Thomas Huth -(cherry picked from commit e423455c4f23a1a828901c78fe6d03b7dde79319) -Signed-off-by: Michael Roth ---- - hw/core/loader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/core/loader.c b/hw/core/loader.c -index 425bf69a99..838a34174a 100644 ---- a/hw/core/loader.c -+++ b/hw/core/loader.c -@@ -1242,7 +1242,7 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) - if (rom->addr + rom->romsize < addr) { - continue; - } -- if (rom->addr > end) { -+ if (rom->addr > end || rom->addr < addr) { - break; - } - --- -2.23.0 diff --git a/hw-core-machine-Fix-the-missing-consideration-of-clu.patch b/hw-core-machine-Fix-the-missing-consideration-of-clu.patch new file mode 100644 index 0000000000000000000000000000000000000000..5adcd2b3bd0c91f274a000b76d15c76f45c51ae4 --- /dev/null +++ b/hw-core-machine-Fix-the-missing-consideration-of-clu.patch @@ -0,0 +1,85 @@ +From bbf1fc67fb642833a23793081e812c36691c4df6 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Mon, 6 Mar 2023 20:50:33 +0800 +Subject: [PATCH] hw/core/machine:Fix the missing consideration of cluster-id + +Commit 5454c00908236 introduced the cluster-id for CPU +topology parameter "cluster", but has not fully considered +all the areas where we need to check cluster-id, e.g, when +assigning CPUs to numa nodes. + +If we have multiple clusters and multiple numa nodes for +a guest like below: +-smp cpus=8,maxcpus=8,sockets=1,dies=1,clusters=2,cores=4,threads=1 +-numa node nodeid=0,cpus=0-3 +-numa node nodeid=1,cpus=4-7 +QEMU will wrongly assign all the CPUs to numa0, because there +is no check about cluster_id of each CPU in function +machine_set_cpu_numa_node. Fix it. + +Also, fix some other areas which missed to verified cluster-id. + +Fixes: 5454c00908236 ("arm/virt: Add CPU topology support") +Signed-off-by: Yanan Wang +--- + hw/core/machine-hmp-cmds.c | 3 +++ + hw/core/machine.c | 15 +++++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c +index 4e2f319aeb..c4f63b1d63 100644 +--- a/hw/core/machine-hmp-cmds.c ++++ b/hw/core/machine-hmp-cmds.c +@@ -77,6 +77,9 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) + if (c->has_die_id) { + monitor_printf(mon, " die-id: \"%" PRIu64 "\"\n", c->die_id); + } ++ if (c->has_cluster_id) { ++ monitor_printf(mon, " cluster-id: \"%" PRIu64 "\"\n", c->cluster_id); ++ } + if (c->has_core_id) { + monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id); + } +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 45fb0fd2eb..cb539104a1 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -686,6 +686,11 @@ void machine_set_cpu_numa_node(MachineState *machine, + return; + } + ++ if (props->has_cluster_id && !slot->props.has_cluster_id) { ++ error_setg(errp, "cluster-id is not supported"); ++ return; ++ } ++ + /* skip slots with explicit mismatch */ + if (props->has_thread_id && props->thread_id != slot->props.thread_id) { + continue; +@@ -695,6 +700,10 @@ void machine_set_cpu_numa_node(MachineState *machine, + continue; + } + ++ if (props->has_cluster_id && props->cluster_id != slot->props.cluster_id) { ++ continue; ++ } ++ + if (props->has_die_id && props->die_id != slot->props.die_id) { + continue; + } +@@ -989,6 +998,12 @@ static char *cpu_slot_to_string(const CPUArchId *cpu) + } + g_string_append_printf(s, "die-id: %"PRId64, cpu->props.die_id); + } ++ if (cpu->props.has_cluster_id) { ++ if (s->len) { ++ g_string_append_printf(s, ", "); ++ } ++ g_string_append_printf(s, "cluster-id: %"PRId64, cpu->props.cluster_id); ++ } + if (cpu->props.has_core_id) { + if (s->len) { + g_string_append_printf(s, ", "); +-- +2.27.0 + diff --git a/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch b/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch new file mode 100644 index 0000000000000000000000000000000000000000..39956fbd8ae741e31fdf2c4a2eca362a6ec9f891 --- /dev/null +++ b/hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch @@ -0,0 +1,283 @@ +From bf4a20a82bd4804842dd2960db30e0be7ecb2d32 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:09 +0800 +Subject: [PATCH 11/24] hw/core/machine: Introduce CPU cluster topology support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The new Cluster-Aware Scheduling support has landed in Linux 5.16, +which has been proved to benefit the scheduling performance (e.g. +load balance and wake_affine strategy) on both x86_64 and AArch64. + +So now in Linux 5.16 we have four-level arch-neutral CPU topology +definition like below and a new scheduler level for clusters. +struct cpu_topology { + int thread_id; + int core_id; + int cluster_id; + int package_id; + int llc_id; + cpumask_t thread_sibling; + cpumask_t core_sibling; + cpumask_t cluster_sibling; + cpumask_t llc_sibling; +} + +A cluster generally means a group of CPU cores which share L2 cache +or other mid-level resources, and it is the shared resources that +is used to improve scheduler's behavior. From the point of view of +the size range, it's between CPU die and CPU core. For example, on +some ARM64 Kunpeng servers, we have 6 clusters in each NUMA node, +and 4 CPU cores in each cluster. The 4 CPU cores share a separate +L2 cache and a L3 cache tag, which brings cache affinity advantage. + +In virtualization, on the Hosts which have pClusters (physical +clusters), if we can design a vCPU topology with cluster level for +guest kernel and have a dedicated vCPU pinning. A Cluster-Aware +Guest kernel can also make use of the cache affinity of CPU clusters +to gain similar scheduling performance. + +This patch adds infrastructure for CPU cluster level topology +configuration and parsing, so that the user can specify cluster +parameter if their machines support it. + +Signed-off-by: Yanan Wang +Message-Id: <20211228092221.21068-3-wangyanan55@huawei.com> +Reviewed-by: Philippe Mathieu-Daudé +[PMD: Added '(since 7.0)' to @clusters in qapi/machine.json] +Signed-off-by: Philippe Mathieu-Daudé +--- + hw/core/machine-smp.c | 26 +++++++++++++++++++------- + hw/core/machine.c | 3 +++ + include/hw/boards.h | 6 +++++- + qapi/machine.json | 5 ++++- + qemu-options.hx | 7 ++++--- + softmmu/vl.c | 3 +++ + 6 files changed, 38 insertions(+), 12 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 2cbfd57429..b39ed21e65 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -37,6 +37,10 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + g_string_append_printf(s, " * dies (%u)", ms->smp.dies); + } + ++ if (mc->smp_props.clusters_supported) { ++ g_string_append_printf(s, " * clusters (%u)", ms->smp.clusters); ++ } ++ + g_string_append_printf(s, " * cores (%u)", ms->smp.cores); + g_string_append_printf(s, " * threads (%u)", ms->smp.threads); + +@@ -71,6 +75,7 @@ void machine_parse_smp_config(MachineState *ms, + unsigned cpus = config->has_cpus ? config->cpus : 0; + unsigned sockets = config->has_sockets ? config->sockets : 0; + unsigned dies = config->has_dies ? config->dies : 0; ++ unsigned clusters = config->has_clusters ? config->clusters : 0; + unsigned cores = config->has_cores ? config->cores : 0; + unsigned threads = config->has_threads ? config->threads : 0; + unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; +@@ -82,6 +87,7 @@ void machine_parse_smp_config(MachineState *ms, + if ((config->has_cpus && config->cpus == 0) || + (config->has_sockets && config->sockets == 0) || + (config->has_dies && config->dies == 0) || ++ (config->has_clusters && config->clusters == 0) || + (config->has_cores && config->cores == 0) || + (config->has_threads && config->threads == 0) || + (config->has_maxcpus && config->maxcpus == 0)) { +@@ -97,8 +103,13 @@ void machine_parse_smp_config(MachineState *ms, + error_setg(errp, "dies not supported by this machine's CPU topology"); + return; + } ++ if (!mc->smp_props.clusters_supported && clusters > 1) { ++ error_setg(errp, "clusters not supported by this machine's CPU topology"); ++ return; ++ } + + dies = dies > 0 ? dies : 1; ++ clusters = clusters > 0 ? clusters : 1; + + /* compute missing values based on the provided ones */ + if (cpus == 0 && maxcpus == 0) { +@@ -113,41 +124,42 @@ void machine_parse_smp_config(MachineState *ms, + if (sockets == 0) { + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; +- sockets = maxcpus / (dies * cores * threads); ++ sockets = maxcpus / (dies * clusters * cores * threads); + } else if (cores == 0) { + threads = threads > 0 ? threads : 1; +- cores = maxcpus / (sockets * dies * threads); ++ cores = maxcpus / (sockets * dies * clusters * threads); + } + } else { + /* prefer cores over sockets since 6.2 */ + if (cores == 0) { + sockets = sockets > 0 ? sockets : 1; + threads = threads > 0 ? threads : 1; +- cores = maxcpus / (sockets * dies * threads); ++ cores = maxcpus / (sockets * dies * clusters * threads); + } else if (sockets == 0) { + threads = threads > 0 ? threads : 1; +- sockets = maxcpus / (dies * cores * threads); ++ sockets = maxcpus / (dies * clusters * cores * threads); + } + } + + /* try to calculate omitted threads at last */ + if (threads == 0) { +- threads = maxcpus / (sockets * dies * cores); ++ threads = maxcpus / (sockets * dies * clusters * cores); + } + } + +- maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * cores * threads; ++ maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads; + cpus = cpus > 0 ? cpus : maxcpus; + + ms->smp.cpus = cpus; + ms->smp.sockets = sockets; + ms->smp.dies = dies; ++ ms->smp.clusters = clusters; + ms->smp.cores = cores; + ms->smp.threads = threads; + ms->smp.max_cpus = maxcpus; + + /* sanity-check of the computed topology */ +- if (sockets * dies * cores * threads != maxcpus) { ++ if (sockets * dies * clusters * cores * threads != maxcpus) { + g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); + error_setg(errp, "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 3993c534b9..a4a2df405f 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -742,10 +742,12 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name, + .has_cpus = true, .cpus = ms->smp.cpus, + .has_sockets = true, .sockets = ms->smp.sockets, + .has_dies = true, .dies = ms->smp.dies, ++ .has_clusters = true, .clusters = ms->smp.clusters, + .has_cores = true, .cores = ms->smp.cores, + .has_threads = true, .threads = ms->smp.threads, + .has_maxcpus = true, .maxcpus = ms->smp.max_cpus, + }; ++ + if (!visit_type_SMPConfiguration(v, name, &config, &error_abort)) { + return; + } +@@ -932,6 +934,7 @@ static void machine_initfn(Object *obj) + ms->smp.max_cpus = mc->default_cpus; + ms->smp.sockets = 1; + ms->smp.dies = 1; ++ ms->smp.clusters = 1; + ms->smp.cores = 1; + ms->smp.threads = 1; + } +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 7597cec440..f49a2578ea 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -129,10 +129,12 @@ typedef struct { + * SMPCompatProps: + * @prefer_sockets - whether sockets are preferred over cores in smp parsing + * @dies_supported - whether dies are supported by the machine ++ * @clusters_supported - whether clusters are supported by the machine + */ + typedef struct { + bool prefer_sockets; + bool dies_supported; ++ bool clusters_supported; + } SMPCompatProps; + + /** +@@ -299,7 +301,8 @@ typedef struct DeviceMemoryState { + * @cpus: the number of present logical processors on the machine + * @sockets: the number of sockets on the machine + * @dies: the number of dies in one socket +- * @cores: the number of cores in one die ++ * @clusters: the number of clusters in one die ++ * @cores: the number of cores in one cluster + * @threads: the number of threads in one core + * @max_cpus: the maximum number of logical processors on the machine + */ +@@ -307,6 +310,7 @@ typedef struct CpuTopology { + unsigned int cpus; + unsigned int sockets; + unsigned int dies; ++ unsigned int clusters; + unsigned int cores; + unsigned int threads; + unsigned int max_cpus; +diff --git a/qapi/machine.json b/qapi/machine.json +index f1839acf20..8faa51074e 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -1396,7 +1396,9 @@ + # + # @dies: number of dies per socket in the CPU topology + # +-# @cores: number of cores per die in the CPU topology ++# @clusters: number of clusters per die in the CPU topology (since 7.0) ++# ++# @cores: number of cores per cluster in the CPU topology + # + # @threads: number of threads per core in the CPU topology + # +@@ -1408,6 +1410,7 @@ + '*cpus': 'int', + '*sockets': 'int', + '*dies': 'int', ++ '*clusters': 'int', + '*cores': 'int', + '*threads': 'int', + '*maxcpus': 'int' } } +diff --git a/qemu-options.hx b/qemu-options.hx +index 7a59db7764..0f26f7dad7 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -206,13 +206,14 @@ SRST + ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, +- "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" ++ "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n" + " set the number of initial CPUs to 'n' [default=1]\n" + " maxcpus= maximum number of total CPUs, including\n" + " offline CPUs for hotplug, etc\n" + " sockets= number of sockets on the machine board\n" + " dies= number of dies in one socket\n" +- " cores= number of cores in one die\n" ++ " clusters= number of clusters in one die\n" ++ " cores= number of cores in one cluster\n" + " threads= number of threads in one core\n" + "Note: Different machines may have different subsets of the CPU topology\n" + " parameters supported, so the actual meaning of the supported parameters\n" +@@ -228,7 +229,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, + " must be set as 1 in the purpose of correct parsing.\n", + QEMU_ARCH_ALL) + SRST +-``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` ++``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]`` + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on + the machine type board. On boards supporting CPU hotplug, the optional + '\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be +diff --git a/softmmu/vl.c b/softmmu/vl.c +index 620a1f1367..d9e4c619d3 100644 +--- a/softmmu/vl.c ++++ b/softmmu/vl.c +@@ -726,6 +726,9 @@ static QemuOptsList qemu_smp_opts = { + }, { + .name = "dies", + .type = QEMU_OPT_NUMBER, ++ }, { ++ .name = "clusters", ++ .type = QEMU_OPT_NUMBER, + }, { + .name = "cores", + .type = QEMU_OPT_NUMBER, +-- +2.27.0 + diff --git a/hw-core-resettable-fix-reset-level-counting.patch b/hw-core-resettable-fix-reset-level-counting.patch new file mode 100644 index 0000000000000000000000000000000000000000..9c17651df636f6a23b99f27ca937330c1b9a9751 --- /dev/null +++ b/hw-core-resettable-fix-reset-level-counting.patch @@ -0,0 +1,82 @@ +From a6943e9033df97862b3ec0438ec85ff0abfb59c0 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 09:44:11 +0800 +Subject: [PATCH 20/29] hw/core/resettable: fix reset level counting + +The code for handling the reset level count in the Resettable code +has two issues: +The reset count is only decremented for the 1->0 case. This means +that if there's ever a nested reset that takes the count to 2 then it +will never again be decremented. Eventually the count will exceed +the '50' limit in resettable_phase_enter() and QEMU will trip over +the assertion failure. The repro case in issue 1266 is an example of +this that happens now the SCSI subsystem uses three-phase reset. +Secondly, the count is decremented only after the exit phase handler +is called. Moving the reset count decrement from "just after" to +"just before" calling the exit phase handler allows +resettable_is_in_reset() to return false during the handler +execution. +This simplifies reset handling in resettable devices. Typically, a +function that updates the device state will just need to read the +current reset state and not anymore treat the "in a reset-exit +transition" as a special case. +Note that the semantics change to the *_is_in_reset() functions +will have no effect on the current codebase, because only two +devices (hw/char/cadence_uart.c and hw/misc/zynq_sclr.c) currently +call those functions, and in neither case do they do it from the +device's exit phase methed. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1266 +Signed-off-by: Damien Hedde +Buglink: https://bugs.launchpad.net/qemu/+bug/1905297 +Reported-by: Michael Peter +[PMM: adjust the docs paragraph changed to get the name of the + 'enter' phase right and to clarify exactly when the count is + adjusted; rewrite the commit message] +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + docs/devel/reset.rst | 8 +++++--- + hw/core/resettable.c | 3 +-- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst +index abea1102dc..7cc6a6b314 100644 +--- a/docs/devel/reset.rst ++++ b/docs/devel/reset.rst +@@ -210,9 +210,11 @@ Polling the reset state + Resettable interface provides the ``resettable_is_in_reset()`` function. + This function returns true if the object parameter is currently under reset. + +-An object is under reset from the beginning of the *init* phase to the end of +-the *exit* phase. During all three phases, the function will return that the +-object is in reset. ++An object is under reset from the beginning of the *enter* phase (before ++either its children or its own enter method is called) to the *exit* ++phase. During *enter* and *hold* phase only, the function will return that the ++object is in reset. The state is changed after the *exit* is propagated to ++its children and just before calling the object's own *exit* method. + + This function may be used if the object behavior has to be adapted + while in reset state. For example if a device has an irq input, +diff --git a/hw/core/resettable.c b/hw/core/resettable.c +index 96a99ce39e..c3df75c6ba 100644 +--- a/hw/core/resettable.c ++++ b/hw/core/resettable.c +@@ -201,12 +201,11 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type) + resettable_child_foreach(rc, obj, resettable_phase_exit, NULL, type); + + assert(s->count > 0); +- if (s->count == 1) { ++ if (--s->count == 0) { + trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit); + if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) { + rc->phases.exit(obj); + } +- s->count = 0; + } + s->exit_phase_in_progress = false; + trace_resettable_phase_exit_end(obj, obj_typename, s->count); +-- +2.27.0 + diff --git a/hw-display-ati_2d-Fix-buffer-overflow-in-ati_2d_blt-.patch b/hw-display-ati_2d-Fix-buffer-overflow-in-ati_2d_blt-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f865075327b7885677c8da4bfc7b57e9e2281f9 --- /dev/null +++ b/hw-display-ati_2d-Fix-buffer-overflow-in-ati_2d_blt-.patch @@ -0,0 +1,83 @@ +From d1d13b1f86a5ac0520dc7369873d6478b583af04 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 6 Sep 2021 17:31:03 +0200 +Subject: [PATCH 6/6] hw/display/ati_2d: Fix buffer overflow in ati_2d_blt + (CVE-2021-3638) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When building QEMU with DEBUG_ATI defined then running with +'-device ati-vga,romfile="" -d unimp,guest_errors -trace ati\*' +we get: + + ati_mm_write 4 0x16c0 DP_CNTL <- 0x1 + ati_mm_write 4 0x146c DP_GUI_MASTER_CNTL <- 0x2 + ati_mm_write 4 0x16c8 DP_MIX <- 0xff0000 + ati_mm_write 4 0x16c4 DP_DATATYPE <- 0x2 + ati_mm_write 4 0x224 CRTC_OFFSET <- 0x0 + ati_mm_write 4 0x142c DST_PITCH_OFFSET <- 0xfe00000 + ati_mm_write 4 0x1420 DST_Y <- 0x3fff + ati_mm_write 4 0x1410 DST_HEIGHT <- 0x3fff + ati_mm_write 4 0x1588 DST_WIDTH_X <- 0x3fff3fff + ati_2d_blt: vram:0x7fff5fa00000 addr:0 ds:0x7fff61273800 stride:2560 bpp:32 rop:0xff + ati_2d_blt: 0 0 0, 0 127 0, (0,0) -> (16383,16383) 16383x16383 > ^ + ati_2d_blt: pixman_fill(dst:0x7fff5fa00000, stride:254, bpp:8, x:16383, y:16383, w:16383, h:16383, xor:0xff000000) + Thread 3 "qemu-system-i38" received signal SIGSEGV, Segmentation fault. + (gdb) bt + #0 0x00007ffff7f62ce0 in sse2_fill.lto_priv () at /lib64/libpixman-1.so.0 + #1 0x00007ffff7f09278 in pixman_fill () at /lib64/libpixman-1.so.0 + #2 0x0000555557b5a9af in ati_2d_blt (s=0x631000028800) at hw/display/ati_2d.c:196 + #3 0x0000555557b4b5a2 in ati_mm_write (opaque=0x631000028800, addr=5512, data=1073692671, size=4) at hw/display/ati.c:843 + #4 0x0000555558b90ec4 in memory_region_write_accessor (mr=0x631000039cc0, addr=5512, ..., size=4, ...) at softmmu/memory.c:492 + +Commit 584acf34cb0 ("ati-vga: Fix reverse bit blts") introduced +the local dst_x and dst_y which adjust the (x, y) coordinates +depending on the direction in the SRCCOPY ROP3 operation, but +forgot to address the same issue for the PATCOPY, BLACKNESS and +WHITENESS operations, which also call pixman_fill(). + +Fix that now by using the adjusted coordinates in the pixman_fill +call, and update the related debug printf(). + +Reported-by: Qiang Liu +Fixes: 584acf34cb0 ("ati-vga: Fix reverse bit blts") +Signed-off-by: Philippe Mathieu-Daudé +Tested-by: Mauro Matteo Cascella +Message-Id: <20210906153103.1661195-1-philmd@redhat.com> +Signed-off-by: Gerd Hoffmann +Signed-off-by: wanbo +--- + hw/display/ati_2d.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c +index 4dc10ea795..692bec91de 100644 +--- a/hw/display/ati_2d.c ++++ b/hw/display/ati_2d.c +@@ -84,7 +84,7 @@ void ati_2d_blt(ATIVGAState *s) + DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n", + s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset, + s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch, +- s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y, ++ s->regs.src_x, s->regs.src_y, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'), + (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^')); +@@ -180,11 +180,11 @@ void ati_2d_blt(ATIVGAState *s) + dst_stride /= sizeof(uint32_t); + DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n", + dst_bits, dst_stride, bpp, +- s->regs.dst_x, s->regs.dst_y, ++ dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + filler); + pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, +- s->regs.dst_x, s->regs.dst_y, ++ dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + filler); + if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && +-- +2.27.0 + diff --git a/hw-display-exynos4210_fimd-Fix-potential-NULL-pointe.patch b/hw-display-exynos4210_fimd-Fix-potential-NULL-pointe.patch deleted file mode 100644 index 98e3c3bed9a221c978c8f733e5d587dc2803180b..0000000000000000000000000000000000000000 --- a/hw-display-exynos4210_fimd-Fix-potential-NULL-pointe.patch +++ /dev/null @@ -1,46 +0,0 @@ -From b47d7ad29bc7f30d4ea3fdb0ef86942468416b79 Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Mon, 2 Nov 2020 16:52:17 +0000 -Subject: [PATCH] hw/display/exynos4210_fimd: Fix potential NULL pointer - dereference -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In exynos4210_fimd_update(), the pointer s is dereferinced before -being check if it is valid, which may lead to NULL pointer dereference. -So move the assignment to global_width after checking that the s is valid. - -Reported-by: Euler Robot -Signed-off-by: Alex Chen -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 5F9F8D88.9030102@huawei.com -Signed-off-by: Peter Maydell -(cherry-picked from commit 18520fa465) ---- - hw/display/exynos4210_fimd.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c -index 61f7408b1c..85b0ebf23a 100644 ---- a/hw/display/exynos4210_fimd.c -+++ b/hw/display/exynos4210_fimd.c -@@ -1271,12 +1271,14 @@ static void exynos4210_fimd_update(void *opaque) - bool blend = false; - uint8_t *host_fb_addr; - bool is_dirty = false; -- const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1; -+ int global_width; - - if (!s || !s->console || !s->enabled || - surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) { - return; - } -+ -+ global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1; - exynos4210_update_resolution(s); - surface = qemu_console_surface(s->console); - --- -2.27.0 - diff --git a/hw-display-next-fb-Fix-comment-typo.patch b/hw-display-next-fb-Fix-comment-typo.patch new file mode 100644 index 0000000000000000000000000000000000000000..f23a0732040f7dab84df7f2daa7a24c8e84f8482 --- /dev/null +++ b/hw-display-next-fb-Fix-comment-typo.patch @@ -0,0 +1,36 @@ +From 7252e8e0f5a4c43854efa3e31071a678f4e61d37 Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 01:49:31 -0800 +Subject: [PATCH] hw/display/next-fb: Fix comment typo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit c1966f515d9bb6d8ed7076f4bebdc45407700100 + +Signed-off-by: Evgeny Ermakov +Message-Id: <20221125160849.23711-1-evgeny.v.ermakov@gmail.com> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Peter Maydell +Signed-off-by: Thomas Huth +Signed-off-by: Wanghe Xiao +--- + hw/display/next-fb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c +index dd6a1aa8ae..8446ff3c00 100644 +--- a/hw/display/next-fb.c ++++ b/hw/display/next-fb.c +@@ -126,7 +126,7 @@ static void nextfb_class_init(ObjectClass *oc, void *data) + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->realize = nextfb_realize; + +- /* Note: This device does not any state that we have to reset or migrate */ ++ /* Note: This device does not have any state that we have to reset or migrate */ + } + + static const TypeInfo nextfb_info = { +-- +2.27.0 + diff --git a/hw-display-omap_lcdc-Fix-potential-NULL-pointer-dere.patch b/hw-display-omap_lcdc-Fix-potential-NULL-pointer-dere.patch deleted file mode 100644 index 9f11b2d8bbc047a93dd11cf9c6a16eb757676f86..0000000000000000000000000000000000000000 --- a/hw-display-omap_lcdc-Fix-potential-NULL-pointer-dere.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 38697076a98034a078c2411234b8979cf3cec6da Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Mon, 2 Nov 2020 16:52:17 +0000 -Subject: [PATCH] hw/display/omap_lcdc: Fix potential NULL pointer dereference - -In omap_lcd_interrupts(), the pointer omap_lcd is dereferinced before -being check if it is valid, which may lead to NULL pointer dereference. -So move the assignment to surface after checking that the omap_lcd is valid -and move surface_bits_per_pixel(surface) to after the surface assignment. - -Reported-by: Euler Robot -Signed-off-by: AlexChen -Message-id: 5F9CDB8A.9000001@huawei.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -(cherry-picked from commit 0080edc45e) ---- - hw/display/omap_lcdc.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c -index 07a5effe04..13ab73ec61 100644 ---- a/hw/display/omap_lcdc.c -+++ b/hw/display/omap_lcdc.c -@@ -77,14 +77,18 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) - static void omap_update_display(void *opaque) - { - struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; -- DisplaySurface *surface = qemu_console_surface(omap_lcd->con); -+ DisplaySurface *surface; - draw_line_func draw_line; - int size, height, first, last; - int width, linesize, step, bpp, frame_offset; - hwaddr frame_base; - -- if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || -- !surface_bits_per_pixel(surface)) { -+ if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable) { -+ return; -+ } -+ -+ surface = qemu_console_surface(omap_lcd->con); -+ if (!surface_bits_per_pixel(surface)) { - return; - } - --- -2.27.0 - diff --git a/hw-display-qxl-Assert-memory-slot-fits-in-preallocat.patch b/hw-display-qxl-Assert-memory-slot-fits-in-preallocat.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac6fa16c5fddff9f37e3babd328d60d29229b9c5 --- /dev/null +++ b/hw-display-qxl-Assert-memory-slot-fits-in-preallocat.patch @@ -0,0 +1,33 @@ +From ff99b327473454e3be7a89554ccbae856bcb7e3b Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Mon, 5 Dec 2022 16:09:13 +0800 +Subject: [PATCH 17/17] hw/display/qxl: Assert memory slot fits in preallocated + MemoryRegion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Assert memory slot fits in preallocated MemoryRegion. + +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Signed-off-by: jianchunfu +--- + hw/display/qxl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 2a4b2d4158..bcd9e8716a 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1372,6 +1372,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region); + return 1; + } ++ assert(guest_end - pci_start <= memory_region_size(mr)); + + virt_start = (intptr_t)memory_region_get_ram_ptr(mr); + memslot.slot_id = slot_id; +-- +2.27.0 + diff --git a/hw-display-qxl-Avoid-buffer-overrun-in-qxl_phys2virt.patch b/hw-display-qxl-Avoid-buffer-overrun-in-qxl_phys2virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..befedd54b6ae7836a30e5df1f7950c697428fb86 --- /dev/null +++ b/hw-display-qxl-Avoid-buffer-overrun-in-qxl_phys2virt.patch @@ -0,0 +1,107 @@ +From 0c4e22da6bd0d2c15e53cb0b38f13ef11a3bd370 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Mon, 5 Dec 2022 16:24:43 +0800 +Subject: [PATCH 16/17] hw/display/qxl: Avoid buffer overrun in qxl_phys2virt + (CVE-2022-4144) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Have qxl_get_check_slot_offset() return false if the requested +buffer size does not fit within the slot memory region. +Similarly qxl_phys2virt() now returns NULL in such case, and +qxl_dirty_one_surface() aborts. +This avoids buffer overrun in the host pointer returned by +memory_region_get_ram_ptr(). + +Fixes: CVE-2022-4144 (out-of-bounds read) +Reported-by: Wenxu Yin (@awxylitol) +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1336 +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Signed-off-by: jianchunfu +--- + hw/display/qxl.c | 27 +++++++++++++++++++++++---- + hw/display/qxl.h | 2 +- + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index aa9065183e..2a4b2d4158 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1412,11 +1412,13 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + + /* can be also called from spice server thread context */ + static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, +- uint32_t *s, uint64_t *o) ++ uint32_t *s, uint64_t *o, ++ size_t size_requested) + { + uint64_t phys = le64_to_cpu(pqxl); + uint32_t slot = (phys >> (64 - 8)) & 0xff; + uint64_t offset = phys & 0xffffffffffff; ++ uint64_t size_available; + + if (slot >= NUM_MEMSLOTS) { + qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, +@@ -1440,6 +1442,23 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + slot, offset, qxl->guest_slots[slot].size); + return false; + } ++ size_available = memory_region_size(qxl->guest_slots[slot].mr); ++ if (qxl->guest_slots[slot].offset + offset >= size_available) { ++ qxl_set_guest_bug(qxl, ++ "slot %d offset %"PRIu64" > region size %"PRIu64"\n", ++ slot, qxl->guest_slots[slot].offset + offset, ++ size_available); ++ return false; ++ } ++ size_available -= qxl->guest_slots[slot].offset + offset; ++ if (size_requested > size_available) { ++ qxl_set_guest_bug(qxl, ++ "slot %d offset %"PRIu64" size %zu: " ++ "overrun by %"PRIu64" bytes\n", ++ slot, offset, size_requested, ++ size_requested - size_available); ++ return false; ++ } + + *s = slot; + *o = offset; +@@ -1459,7 +1478,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, + offset = le64_to_cpu(pqxl) & 0xffffffffffff; + return (void *)(intptr_t)offset; + case MEMSLOT_GROUP_GUEST: +- if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { ++ if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { + return NULL; + } + ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); +@@ -1925,9 +1944,9 @@ static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + uint32_t slot; + bool rc; + +- rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); +- assert(rc == true); + size = (uint64_t)height * abs(stride); ++ rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size); ++ assert(rc == true); + trace_qxl_surfaces_dirty(qxl->id, offset, size); + qxl_set_dirty(qxl->guest_slots[slot].mr, + qxl->guest_slots[slot].offset + offset, +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index c784315daa..89ca832cf9 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -157,7 +157,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) + * + * Returns a host pointer to a buffer placed at offset @phys within the + * active slot @group_id of the PCI VGA RAM memory region associated with +- * the @qxl device. If the slot is inactive, or the offset is out ++ * the @qxl device. If the slot is inactive, or the offset + size are out + * of the memory region, returns NULL. + * + * Use with care; by the time this function returns, the returned pointer is +-- +2.27.0 + diff --git a/hw-display-qxl-Document-qxl_phys2virt.patch b/hw-display-qxl-Document-qxl_phys2virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..de1640d5f2bb08a19e4869d58d6e16e1e784ac0b --- /dev/null +++ b/hw-display-qxl-Document-qxl_phys2virt.patch @@ -0,0 +1,49 @@ +From c1747d1812a725b424745c6d1b291c176ed67bd3 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Mon, 5 Dec 2022 15:16:31 +0800 +Subject: [PATCH 14/17] hw/display/qxl: Document qxl_phys2virt() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Marc-André Lureau +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Signed-off-by: jianchunfu +--- + hw/display/qxl.h | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index 30d21f4d0b..c938f88a2f 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -147,6 +147,25 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) + #define QXL_DEFAULT_REVISION (QXL_REVISION_STABLE_V12 + 1) + + /* qxl.c */ ++/** ++ * qxl_phys2virt: Get a pointer within a PCI VRAM memory region. ++ * ++ * @qxl: QXL device ++ * @phys: physical offset of buffer within the VRAM ++ * @group_id: memory slot group ++ * ++ * Returns a host pointer to a buffer placed at offset @phys within the ++ * active slot @group_id of the PCI VGA RAM memory region associated with ++ * the @qxl device. If the slot is inactive, or the offset is out ++ * of the memory region, returns NULL. ++ * ++ * Use with care; by the time this function returns, the returned pointer is ++ * not protected by RCU anymore. If the caller is not within an RCU critical ++ * section and does not hold the iothread lock, it must have other means of ++ * protecting the pointer, such as a reference to the region that includes ++ * the incoming ram_addr_t. ++ * ++ */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); + void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + GCC_FMT_ATTR(2, 3); +-- +2.27.0 + diff --git a/hw-display-qxl-Have-qxl_log_command-Return-early-if-.patch b/hw-display-qxl-Have-qxl_log_command-Return-early-if-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc141323dd8b8b8b7def7410ab2f9839694f0be4 --- /dev/null +++ b/hw-display-qxl-Have-qxl_log_command-Return-early-if-.patch @@ -0,0 +1,53 @@ +From 2f991f98ba28e71ffc2ffdf704ee6568293a8bf0 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Mon, 5 Dec 2022 15:21:45 +0800 +Subject: [PATCH 13/17] hw/display/qxl: Have qxl_log_command Return early if no + log_cmd handler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only 3 command types are logged: no need to call qxl_phys2virt() +for the other types. Using different cases will help to pass +different structure sizes to qxl_phys2virt() in a pair of commits. + +Reviewed-by: Marc-André Lureau +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Signed-off-by: jianchunfu +--- + hw/display/qxl-logger.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c +index 68bfa47568..1bcf803db6 100644 +--- a/hw/display/qxl-logger.c ++++ b/hw/display/qxl-logger.c +@@ -247,6 +247,16 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + qxl_name(qxl_type, ext->cmd.type), + compat ? "(compat)" : ""); + ++ switch (ext->cmd.type) { ++ case QXL_CMD_DRAW: ++ break; ++ case QXL_CMD_SURFACE: ++ break; ++ case QXL_CMD_CURSOR: ++ break; ++ default: ++ goto out; ++ } + data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + if (!data) { + return 1; +@@ -269,6 +279,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + qxl_log_cmd_cursor(qxl, data, ext->group_id); + break; + } ++out: + fprintf(stderr, "\n"); + return 0; + } +-- +2.27.0 + diff --git a/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch b/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch new file mode 100644 index 0000000000000000000000000000000000000000..a923444fcd7db2725da333dd13db0fc1f9b57c97 --- /dev/null +++ b/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch @@ -0,0 +1,212 @@ +From 21082249be3cb9f5dd000f9d5f84e01548f825c9 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Mon, 5 Dec 2022 16:05:23 +0800 +Subject: [PATCH 15/17] hw/display/qxl: Pass requested buffer size to + qxl_phys2virt() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently qxl_phys2virt() doesn't check for buffer overrun. +In order to do so in the next commit, pass the buffer size +as argument. +For QXLCursor in qxl_render_cursor() -> qxl_cursor() we +verify the size of the chunked data ahead, checking we can +access 'sizeof(QXLCursor) + chunk->data_size' bytes. +Since in the SPICE_CURSOR_TYPE_MONO case the cursor is +assumed to fit in one chunk, no change are required. +In SPICE_CURSOR_TYPE_ALPHA the ahead read is handled in +qxl_unpack_chunks(). + +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Gerd Hoffmann +Signed-off-by: Stefan Hajnoczi +Signed-off-by: jianchunfu +--- + hw/display/qxl-logger.c | 11 ++++++++--- + hw/display/qxl-render.c | 20 ++++++++++++++++---- + hw/display/qxl.c | 14 +++++++++----- + hw/display/qxl.h | 4 +++- + 4 files changed, 36 insertions(+), 13 deletions(-) + +diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c +index 1bcf803db6..35c38f6252 100644 +--- a/hw/display/qxl-logger.c ++++ b/hw/display/qxl-logger.c +@@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) + QXLImage *image; + QXLImageDescriptor *desc; + +- image = qxl_phys2virt(qxl, addr, group_id); ++ image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage)); + if (!image) { + return 1; + } +@@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) + cmd->u.set.position.y, + cmd->u.set.visible ? "yes" : "no", + cmd->u.set.shape); +- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id, ++ sizeof(QXLCursor)); + if (!cursor) { + return 1; + } +@@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + { + bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; + void *data; ++ size_t datasz; + int ret; + + if (!qxl->cmdlog) { +@@ -249,15 +251,18 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + + switch (ext->cmd.type) { + case QXL_CMD_DRAW: ++ datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable); + break; + case QXL_CMD_SURFACE: ++ datasz = sizeof(QXLSurfaceCmd); + break; + case QXL_CMD_CURSOR: ++ datasz = sizeof(QXLCursorCmd); + break; + default: + goto out; + } +- data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz); + if (!data) { + return 1; + } +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index ca217004bf..fcfd40c3ac 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.resized = 0; + qxl->guest_primary.data = qxl_phys2virt(qxl, + qxl->guest_primary.surface.mem, +- MEMSLOT_GROUP_GUEST); ++ MEMSLOT_GROUP_GUEST, ++ qxl->guest_primary.abs_stride ++ * height); + if (!qxl->guest_primary.data) { + goto end; + } +@@ -228,7 +230,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, + if (offset == size) { + return; + } +- chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id); ++ chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, ++ sizeof(QXLDataChunk) + chunk->data_size); + if (!chunk) { + return; + } +@@ -295,7 +298,8 @@ fail: + /* called from spice server thread context only */ + int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) + { +- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLCursorCmd)); + QXLCursor *cursor; + QEMUCursor *c; + +@@ -314,7 +318,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) + } + switch (cmd->type) { + case QXL_CURSOR_SET: +- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); ++ /* First read the QXLCursor to get QXLDataChunk::data_size ... */ ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, ++ sizeof(QXLCursor)); ++ if (!cursor) { ++ return 1; ++ } ++ /* Then read including the chunked data following QXLCursor. */ ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, ++ sizeof(QXLCursor) + cursor->chunk.data_size); + if (!cursor) { + return 1; + } +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 29c80b4289..aa9065183e 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -274,7 +274,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) + QXL_IO_MONITORS_CONFIG_ASYNC)); + } + +- cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST); ++ cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST, ++ sizeof(QXLMonitorsConfig)); + if (cfg != NULL && cfg->count == 1) { + qxl->guest_primary.resized = 1; + qxl->guest_head0_width = cfg->heads[0].width; +@@ -459,7 +460,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + switch (le32_to_cpu(ext->cmd.type)) { + case QXL_CMD_SURFACE: + { +- QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLSurfaceCmd)); + + if (!cmd) { + return 1; +@@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + } + case QXL_CMD_CURSOR: + { +- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLCursorCmd)); + + if (!cmd) { + return 1; +@@ -1444,7 +1447,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + } + + /* can be also called from spice server thread context */ +-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, ++ size_t size) + { + uint64_t offset; + uint32_t slot; +@@ -1952,7 +1956,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + } + + cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], +- MEMSLOT_GROUP_GUEST); ++ MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd)); + assert(cmd); + assert(cmd->type == QXL_SURFACE_CMD_CREATE); + qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index c938f88a2f..c784315daa 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -153,6 +153,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) + * @qxl: QXL device + * @phys: physical offset of buffer within the VRAM + * @group_id: memory slot group ++ * @size: size of the buffer + * + * Returns a host pointer to a buffer placed at offset @phys within the + * active slot @group_id of the PCI VGA RAM memory region associated with +@@ -166,7 +167,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) + * the incoming ram_addr_t. + * + */ +-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id, ++ size_t size); + void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + GCC_FMT_ATTR(2, 3); + +-- +2.27.0 + diff --git a/hw-ehci-check-return-value-of-usb_packet_map.patch b/hw-ehci-check-return-value-of-usb_packet_map.patch deleted file mode 100644 index 2c05a2e61f8deef9a36ca8500cfabcb9736d14bc..0000000000000000000000000000000000000000 --- a/hw-ehci-check-return-value-of-usb_packet_map.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 02d63f9fd9655f1899dabbccaf0568bfaa3e97df Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Wed, 12 Aug 2020 09:17:27 -0700 -Subject: [PATCH] hw: ehci: check return value of 'usb_packet_map' - -If 'usb_packet_map' fails, we should stop to process the usb -request. - -Signed-off-by: Li Qiang -Message-Id: <20200812161727.29412-1-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann -(cherry-picked from 2fdb42d8) -Fix CVE-2020-25723 -Signed-off-by: Alex Chen ---- - hw/usb/hcd-ehci.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 5f089f3005..433e6a4fc0 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -1370,7 +1370,10 @@ static int ehci_execute(EHCIPacket *p, const char *action) - spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); - usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd, - (p->qtd.token & QTD_TOKEN_IOC) != 0); -- usb_packet_map(&p->packet, &p->sgl); -+ if (usb_packet_map(&p->packet, &p->sgl)) { -+ qemu_sglist_destroy(&p->sgl); -+ return -1; -+ } - p->async = EHCI_ASYNC_INITIALIZED; - } - -@@ -1449,7 +1452,10 @@ static int ehci_process_itd(EHCIState *ehci, - if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) { - usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false, - (itd->transact[i] & ITD_XACT_IOC) != 0); -- usb_packet_map(&ehci->ipacket, &ehci->isgl); -+ if (usb_packet_map(&ehci->ipacket, &ehci->isgl)) { -+ qemu_sglist_destroy(&ehci->isgl); -+ return -1; -+ } - usb_handle_packet(dev, &ehci->ipacket); - usb_packet_unmap(&ehci->ipacket, &ehci->isgl); - } else { --- -2.27.0 - diff --git a/hw-elf_ops-clear-uninitialized-segment-space.patch b/hw-elf_ops-clear-uninitialized-segment-space.patch new file mode 100644 index 0000000000000000000000000000000000000000..f502e7dfc43fe6b5dd92139007e7df7c21ebc263 --- /dev/null +++ b/hw-elf_ops-clear-uninitialized-segment-space.patch @@ -0,0 +1,74 @@ +From 081ccc809448bec8e2bf144b2d49e64ed01b0e9f Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Sat, 15 Jan 2022 21:37:24 +0100 +Subject: [PATCH 2/5] hw/elf_ops: clear uninitialized segment space +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the mem_size of the segment is bigger than the file_size, +and if this space doesn't overlap another segment, it needs +to be cleared. + +This bug is very similar to the one we had for linux-user, +22d113b52f41 ("linux-user: Fix loading of BSS segments"), +where .bss section is encoded as an extension of the the data +one by setting the segment p_memsz > p_filesz. + +Signed-off-by: Laurent Vivier +[PMD: Use recently added address_space_set()] +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Stefano Garzarella +Reviewed-by: Richard Henderson +Message-Id: <20220115203725.3834712-3-laurent@vivier.eu> +Signed-off-by: zhangxinhao +--- + hw/core/loader.c | 4 ++++ + include/hw/elf_ops.h | 13 +++++++++++++ + 2 files changed, 17 insertions(+) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index 052a0fd719..19edb928e9 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -1164,9 +1164,13 @@ static void rom_reset(void *unused) + if (rom->mr) { + void *host = memory_region_get_ram_ptr(rom->mr); + memcpy(host, rom->data, rom->datasize); ++ memset(host + rom->datasize, 0, rom->romsize - rom->datasize); + } else { + address_space_write_rom(rom->as, rom->addr, MEMTXATTRS_UNSPECIFIED, + rom->data, rom->datasize); ++ address_space_set(rom->as, rom->addr + rom->datasize, 0, ++ rom->romsize - rom->datasize, ++ MEMTXATTRS_UNSPECIFIED); + } + if (rom->isrom) { + /* rom needs to be written only once */ +diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h +index 995de8495c..7c3b1d0f6c 100644 +--- a/include/hw/elf_ops.h ++++ b/include/hw/elf_ops.h +@@ -555,6 +555,19 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, + if (res != MEMTX_OK) { + goto fail; + } ++ /* ++ * We need to zero'ify the space that is not copied ++ * from file ++ */ ++ if (file_size < mem_size) { ++ res = address_space_set(as ? as : &address_space_memory, ++ addr + file_size, 0, ++ mem_size - file_size, ++ MEMTXATTRS_UNSPECIFIED); ++ if (res != MEMTX_OK) { ++ goto fail; ++ } ++ } + } + } + +-- +2.27.0 + diff --git a/hw-hyperv-hyperv.c-Use-device_cold_reset-instead-of-.patch b/hw-hyperv-hyperv.c-Use-device_cold_reset-instead-of-.patch new file mode 100644 index 0000000000000000000000000000000000000000..e7ccad56ee0c89e77a8dc14491355a2ec4b4e208 --- /dev/null +++ b/hw-hyperv-hyperv.c-Use-device_cold_reset-instead-of-.patch @@ -0,0 +1,36 @@ +From 9ba48faf402e5964e1ab74decd8eddbc496082c9 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 11:05:17 +0800 +Subject: [PATCH 25/29] hw/hyperv/hyperv.c: Use device_cold_reset() instead of + device_legacy_reset() + +The semantic difference between the deprecated device_legacy_reset() +function and the newer device_cold_reset() function is that the new +function resets both the device itself and any qbuses it owns, +whereas the legacy function resets just the device itself and nothing +else. In hyperv_synic_reset() we reset a SynICState, which has no +qbuses, so for this purpose the two functions behave identically and +we can stop using the deprecated one. + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + hw/hyperv/hyperv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c +index cb1074f234..220481a1ca 100644 +--- a/hw/hyperv/hyperv.c ++++ b/hw/hyperv/hyperv.c +@@ -150,7 +150,7 @@ void hyperv_synic_reset(CPUState *cs) + SynICState *synic = get_synic(cs); + + if (synic) { +- device_legacy_reset(DEVICE(synic)); ++ device_cold_reset(DEVICE(synic)); + } + } + +-- +2.27.0 + diff --git a/hw-i2c-pmbus_device-Fix-modifying-QOM-class-internal.patch b/hw-i2c-pmbus_device-Fix-modifying-QOM-class-internal.patch new file mode 100644 index 0000000000000000000000000000000000000000..9b528ba567fd101ba7e93f7ab049f52ef3e4e650 --- /dev/null +++ b/hw-i2c-pmbus_device-Fix-modifying-QOM-class-internal.patch @@ -0,0 +1,63 @@ +From b2314562968c124503dbd08529a2bef39701aaa7 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 6 Sep 2023 20:30:27 +0800 +Subject: [PATCH] hw/i2c/pmbus_device: Fix modifying QOM class internals from + instance +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from f0e4588fd4ae39d1ad46f19c76ed298f89e61d6a + +QOM object instance should not modify its class state (because +all other objects instanciated from this class get affected). + +Instead of modifying the PMBusDeviceClass 'device_num_pages' field +the first time a instance is initialized (in pmbus_pages_alloc), +introduce a new pmbus_pages_num() helper which returns the page +number from the class without modifying the class state. + +The code logic become slighly simplified. + +Inspired-by: Bernhard Beschow +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-Id: <20230523064408.57941-4-philmd@linaro.org> +Signed-off-by: qihao_yewu +--- + hw/i2c/pmbus_device.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c +index 24f8f522d9..f39cd532de 100644 +--- a/hw/i2c/pmbus_device.c ++++ b/hw/i2c/pmbus_device.c +@@ -166,15 +166,18 @@ static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read) + } + } + +-static void pmbus_pages_alloc(PMBusDevice *pmdev) ++static uint8_t pmbus_pages_num(PMBusDevice *pmdev) + { ++ const PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); ++ + /* some PMBus devices don't use the PAGE command, so they get 1 page */ +- PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); +- if (k->device_num_pages == 0) { +- k->device_num_pages = 1; +- } +- pmdev->num_pages = k->device_num_pages; +- pmdev->pages = g_new0(PMBusPage, k->device_num_pages); ++ return k->device_num_pages ? : 1; ++} ++ ++static void pmbus_pages_alloc(PMBusDevice *pmdev) ++{ ++ pmdev->num_pages = pmbus_pages_num(pmdev); ++ pmdev->pages = g_new0(PMBusPage, pmdev->num_pages); + } + + void pmbus_check_limits(PMBusDevice *pmdev) +-- +2.41.0.windows.1 + diff --git a/hw-i386-Fix-comment-style-in-topology.h.patch b/hw-i386-Fix-comment-style-in-topology.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..562fda121cac6ab6e57f6ed3c7d845a933a73a52 --- /dev/null +++ b/hw-i386-Fix-comment-style-in-topology.h.patch @@ -0,0 +1,145 @@ +From 92bf314bb73b4df9b94e68448c37a8bbeed7ae65 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Tue, 24 Oct 2023 17:03:04 +0800 +Subject: [PATCH] hw/i386: Fix comment style in topology.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit 5f0d69b5a69f56d63a1afd5f927919b1584e5e9b +category: bugfix + +--------------------------------------------------------------- + +For function comments in this file, keep the comment style consistent +with other files in the directory. + +Signed-off-by: Zhao Liu +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Reviewed-by: Xiaoyao Li +Reviewed-by: Babu Moger +Tested-by: Babu Moger +Tested-by: Yongwei Ma +Acked-by: Michael S. Tsirkin +Message-ID: <20231024090323.1859210-2-zhao1.liu@linux.intel.com> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: zhujun2 +--- + include/hw/i386/topology.h | 33 +++++++++++++++++---------------- + 1 file changed, 17 insertions(+), 16 deletions(-) + +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index 81573f6cfd..5a19679f61 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -24,7 +24,8 @@ + #ifndef HW_I386_TOPOLOGY_H + #define HW_I386_TOPOLOGY_H + +-/* This file implements the APIC-ID-based CPU topology enumeration logic, ++/* ++ * This file implements the APIC-ID-based CPU topology enumeration logic, + * documented at the following document: + * Intel® 64 Architecture Processor Topology Enumeration + * http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ +@@ -41,7 +42,8 @@ + + #include "qemu/bitops.h" + +-/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support ++/* ++ * APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support + */ + typedef uint32_t apic_id_t; + +@@ -58,8 +60,7 @@ typedef struct X86CPUTopoInfo { + unsigned threads_per_core; + } X86CPUTopoInfo; + +-/* Return the bit width needed for 'count' IDs +- */ ++/* Return the bit width needed for 'count' IDs */ + static unsigned apicid_bitwidth_for_count(unsigned count) + { + g_assert(count >= 1); +@@ -67,15 +68,13 @@ static unsigned apicid_bitwidth_for_count(unsigned count) + return count ? 32 - clz32(count) : 0; + } + +-/* Bit width of the SMT_ID (thread ID) field on the APIC ID +- */ ++/* Bit width of the SMT_ID (thread ID) field on the APIC ID */ + static inline unsigned apicid_smt_width(X86CPUTopoInfo *topo_info) + { + return apicid_bitwidth_for_count(topo_info->threads_per_core); + } + +-/* Bit width of the Core_ID field +- */ ++/* Bit width of the Core_ID field */ + static inline unsigned apicid_core_width(X86CPUTopoInfo *topo_info) + { + return apicid_bitwidth_for_count(topo_info->cores_per_die); +@@ -87,8 +86,7 @@ static inline unsigned apicid_die_width(X86CPUTopoInfo *topo_info) + return apicid_bitwidth_for_count(topo_info->dies_per_pkg); + } + +-/* Bit offset of the Core_ID field +- */ ++/* Bit offset of the Core_ID field */ + static inline unsigned apicid_core_offset(X86CPUTopoInfo *topo_info) + { + return apicid_smt_width(topo_info); +@@ -100,14 +98,14 @@ static inline unsigned apicid_die_offset(X86CPUTopoInfo *topo_info) + return apicid_core_offset(topo_info) + apicid_core_width(topo_info); + } + +-/* Bit offset of the Pkg_ID (socket ID) field +- */ ++/* Bit offset of the Pkg_ID (socket ID) field */ + static inline unsigned apicid_pkg_offset(X86CPUTopoInfo *topo_info) + { + return apicid_die_offset(topo_info) + apicid_die_width(topo_info); + } + +-/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID ++/* ++ * Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID + * + * The caller must make sure core_id < nr_cores and smt_id < nr_threads. + */ +@@ -120,7 +118,8 @@ static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info, + topo_ids->smt_id; + } + +-/* Calculate thread/core/package IDs for a specific topology, ++/* ++ * Calculate thread/core/package IDs for a specific topology, + * based on (contiguous) CPU index + */ + static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info, +@@ -137,7 +136,8 @@ static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info, + topo_ids->smt_id = cpu_index % nr_threads; + } + +-/* Calculate thread/core/package IDs for a specific topology, ++/* ++ * Calculate thread/core/package IDs for a specific topology, + * based on APIC ID + */ + static inline void x86_topo_ids_from_apicid(apic_id_t apicid, +@@ -155,7 +155,8 @@ static inline void x86_topo_ids_from_apicid(apic_id_t apicid, + topo_ids->pkg_id = apicid >> apicid_pkg_offset(topo_info); + } + +-/* Make APIC ID for the CPU 'cpu_index' ++/* ++ * Make APIC ID for the CPU 'cpu_index' + * + * 'cpu_index' is a sequential, contiguous ID for the CPU. + */ +-- +2.27.0 + diff --git a/hw-i386-Use-device_cold_reset-to-reset-the-APIC.patch b/hw-i386-Use-device_cold_reset-to-reset-the-APIC.patch new file mode 100644 index 0000000000000000000000000000000000000000..1777d54fa3f607606064137e870e118af4a60a85 --- /dev/null +++ b/hw-i386-Use-device_cold_reset-to-reset-the-APIC.patch @@ -0,0 +1,51 @@ +From b65da0b1f73a47754a5056b89948d06d9eeaf596 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 11:00:24 +0800 +Subject: [PATCH 24/29] hw/i386: Use device_cold_reset() to reset the APIC + +The semantic difference between the deprecated device_legacy_reset() +function and the newer device_cold_reset() function is that the new +function resets both the device itself and any qbuses it owns, +whereas the legacy function resets just the device itself and nothing +else. +The pc_machine_reset() and microvm_machine_reset() functions use +device_legacy_reset() to reset the APIC; this is an APICCommonState +and does not have any qbuses, so for this purpose the two functions +behave identically and we can stop using the deprecated one. + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + hw/i386/microvm.c | 2 +- + hw/i386/pc.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c +index 4b3b1dd262..3ee95f9b4d 100644 +--- a/hw/i386/microvm.c ++++ b/hw/i386/microvm.c +@@ -486,7 +486,7 @@ static void microvm_machine_reset(MachineState *machine) + cpu = X86_CPU(cs); + + if (cpu->apic_state) { +- device_legacy_reset(cpu->apic_state); ++ device_cold_reset(cpu->apic_state); + } + } + } +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index a2ef40ecbc..4870ce0f96 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1642,7 +1642,7 @@ static void pc_machine_reset(MachineState *machine) + cpu = X86_CPU(cs); + + if (cpu->apic_state) { +- device_legacy_reset(cpu->apic_state); ++ device_cold_reset(cpu->apic_state); + } + } + } +-- +2.27.0 + diff --git a/hw-i386-pc-Add-missing-property-descriptions.patch b/hw-i386-pc-Add-missing-property-descriptions.patch new file mode 100644 index 0000000000000000000000000000000000000000..d5e699cb077f40d2587ac888692b05053bfd6f7c --- /dev/null +++ b/hw-i386-pc-Add-missing-property-descriptions.patch @@ -0,0 +1,53 @@ +From 5ce3662809ab7a594fcbe024eb81416e8556f5ea Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 19:13:02 +0800 +Subject: [PATCH] hw/i386/pc: Add missing property descriptions + +cherry picked from 44bff3767ced18845adb2612a2cf9691d8769d41 + +When running "qemu-system-x86_64 -M pc,help" I noticed that some +properties were still missing their description. Add them now so +that users get at least a slightly better idea what they are all +about. + +Signed-off-by: Thomas Huth +Message-Id: <20211206134255.94784-1-thuth@redhat.com> +Reviewed-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: boringandboring +--- + hw/i386/pc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index c5f430f83d..7003ea1a05 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1726,15 +1726,23 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) + + object_class_property_add_bool(oc, PC_MACHINE_SMBUS, + pc_machine_get_smbus, pc_machine_set_smbus); ++ object_class_property_set_description(oc, PC_MACHINE_SMBUS, ++ "Enable/disable system management bus"); + + object_class_property_add_bool(oc, PC_MACHINE_SATA, + pc_machine_get_sata, pc_machine_set_sata); ++ object_class_property_set_description(oc, PC_MACHINE_SATA, ++ "Enable/disable Serial ATA bus"); + + object_class_property_add_bool(oc, PC_MACHINE_PIT, + pc_machine_get_pit, pc_machine_set_pit); ++ object_class_property_set_description(oc, PC_MACHINE_PIT, ++ "Enable/disable Intel 8254 programmable interval timer emulation"); + + object_class_property_add_bool(oc, "hpet", + pc_machine_get_hpet, pc_machine_set_hpet); ++ object_class_property_set_description(oc, "hpet", ++ "Enable/disable high precision event timer emulation"); + + object_class_property_add_bool(oc, "default-bus-bypass-iommu", + pc_machine_get_default_bus_bypass_iommu, +-- +2.27.0 + diff --git a/hw-ide-atapi.c-Correct-typos-CD-CDROM-CD-ROM.patch b/hw-ide-atapi.c-Correct-typos-CD-CDROM-CD-ROM.patch new file mode 100644 index 0000000000000000000000000000000000000000..672ab70952fb78c15854cc1d0a4ce7bff17c4ee3 --- /dev/null +++ b/hw-ide-atapi.c-Correct-typos-CD-CDROM-CD-ROM.patch @@ -0,0 +1,41 @@ +From c8c702a9970572800626be337e3b5c8b44e4bcca Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:43:50 -0800 +Subject: [PATCH] hw/ide/atapi.c: Correct typos (CD-CDROM -> CD-ROM) + +cherry picked from commit 99337bd1e3a323d07dc29da99cf3f48d3990ad81 + +Signed-off-by: Lev Kujawski +Reviewed-by: Laurent Vivier +Message-Id: <20220528204702.167912-1-lkujaw@member.fsf.org> +Signed-off-by: Laurent Vivier +Signed-off-by: Wanghe Xiao +--- + hw/ide/atapi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c +index b626199e3d..88b2890faf 100644 +--- a/hw/ide/atapi.c ++++ b/hw/ide/atapi.c +@@ -318,7 +318,7 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) + } + } + +-/* start a CD-CDROM read command */ ++/* start a CD-ROM read command */ + static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, + int sector_size) + { +@@ -417,7 +417,7 @@ eot: + ide_set_inactive(s, false); + } + +-/* start a CD-CDROM read command with DMA */ ++/* start a CD-ROM read command with DMA */ + /* XXX: test if DMA is available */ + static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, + int sector_size) +-- +2.27.0 + diff --git a/hw-ide-check-null-block-before-_cancel_dma_sync.patch b/hw-ide-check-null-block-before-_cancel_dma_sync.patch deleted file mode 100644 index 1ff20a9683ec88de3d3a67086ffc82eedff9697e..0000000000000000000000000000000000000000 --- a/hw-ide-check-null-block-before-_cancel_dma_sync.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 3b23698e240bd0efe987cf113e3bc8d233991d21 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Wed, 14 Oct 2020 15:57:18 +0800 -Subject: [PATCH] hw/ide: check null block before _cancel_dma_sync - -fix CVE-2020-25743 - -patch link: https://lists.nongnu.org/archive/html/qemu-devel/2020-09/msg05967.html - -When canceling an i/o operation via ide_cancel_dam_sync(), -a block pointer may be null. Add check to avoid null pointer -dereference. - - -> https://ruhr-uni-bochum.sciebo.de/s/NNWP2GfwzYKeKwE?path=%2Fide_nullptr1 - ==1803100==Hint: address points to the zero page. - #0 blk_bs ../block/block-backend.c:714 - #1 blk_drain ../block/block-backend.c:1715 - #2 ide_cancel_dma_sync ../hw/ide/core.c:723 - #3 bmdma_cmd_writeb ../hw/ide/core.c:723 - #4 bmdma_write ../hw/ide/pci.c:298 - #5 memory_region_write_accessor ../softmmu/memory.c:483 - #6 access_with_adjusted_size ../softmmu/memory.c:544 - #7 memory_region_dispatch_write ../softmmu/memory.c:1465 - #8 flatview_write_continue ../exe.c:3176 - ... - -Reported-by: Ruhr-University -Signed-off-by: Prasad J Pandit ---- - hw/ide/core.c | 1 + - hw/ide/pci.c | 5 ++++- - 2 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/hw/ide/core.c b/hw/ide/core.c -index f76f7e5234..8105187f49 100644 ---- a/hw/ide/core.c -+++ b/hw/ide/core.c -@@ -718,6 +718,7 @@ void ide_cancel_dma_sync(IDEState *s) - * whole DMA operation will be submitted to disk with a single - * aio operation with preadv/pwritev. - */ -+ assert(s->blk); - if (s->bus->dma->aiocb) { - trace_ide_cancel_dma_sync_remaining(); - blk_drain(s->blk); -diff --git a/hw/ide/pci.c b/hw/ide/pci.c -index b50091b615..b47e675456 100644 ---- a/hw/ide/pci.c -+++ b/hw/ide/pci.c -@@ -295,7 +295,10 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) - /* Ignore writes to SSBM if it keeps the old value */ - if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { - if (!(val & BM_CMD_START)) { -- ide_cancel_dma_sync(idebus_active_if(bm->bus)); -+ IDEState *s = idebus_active_if(bm->bus); -+ if (s->blk) { -+ ide_cancel_dma_sync(s); -+ } - bm->status &= ~BM_STATUS_DMAING; - } else { - bm->cur_addr = bm->addr; --- -2.23.0 - diff --git a/hw-ide-microdrive-Use-device_cold_reset-for-self-res.patch b/hw-ide-microdrive-Use-device_cold_reset-for-self-res.patch new file mode 100644 index 0000000000000000000000000000000000000000..f289626dd405e0635a20730412dd28da058f234b --- /dev/null +++ b/hw-ide-microdrive-Use-device_cold_reset-for-self-res.patch @@ -0,0 +1,77 @@ +From a9269ae78f478e70ba58df388b8110c7e9c81035 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 10:53:29 +0800 +Subject: [PATCH 23/29] hw/ide/microdrive: Use device_cold_reset() for + self-resets + +Currently the microdrive code uses device_legacy_reset() to reset +itself, and has its reset method call reset on the IDE bus as the +last thing it does. Switch to using device_cold_reset(). +The only concrete microdrive device is the TYPE_DSCM1XXXX; it is not +command-line pluggable, so it is used only by the old pxa2xx Arm +boards 'akita', 'borzoi', 'spitz', 'terrier' and 'tosa'. +You might think that this would result in the IDE bus being +reset automatically, but it does not, because the IDEBus type +does not set the BusClass::reset method. Instead the controller +must explicitly call ide_bus_reset(). We therefore leave that +call in md_reset(). +Note also that because the PCMCIA card device is a direct subclass of +TYPE_DEVICE and we don't model the PCMCIA controller-to-card +interface as a qbus, PCMCIA cards are not on any qbus and so they +don't get reset when the system is reset. The reset only happens via +the dscm1xxxx_attach() and dscm1xxxx_detach() functions during +machine creation. +Because our aim here is merely to try to get rid of calls to the +device_legacy_reset() function, we leave these other dubious +reset-related issues alone. (They all stem from this code being +absolutely ancient.) + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + hw/ide/microdrive.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c +index 6df9b4cbbe..56c5be3655 100644 +--- a/hw/ide/microdrive.c ++++ b/hw/ide/microdrive.c +@@ -175,7 +175,7 @@ static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value) + case 0x00: /* Configuration Option Register */ + s->opt = value & 0xcf; + if (value & OPT_SRESET) { +- device_legacy_reset(DEVICE(s)); ++ device_cold_reset(DEVICE(s)); + } + md_interrupt_update(s); + break; +@@ -318,7 +318,7 @@ static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value) + case 0xe: /* Device Control */ + s->ctrl = value; + if (value & CTRL_SRST) { +- device_legacy_reset(DEVICE(s)); ++ device_cold_reset(DEVICE(s)); + } + md_interrupt_update(s); + break; +@@ -543,7 +543,7 @@ static int dscm1xxxx_attach(PCMCIACardState *card) + md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8); + md->io_base = 0x0; + +- device_legacy_reset(DEVICE(md)); ++ device_cold_reset(DEVICE(md)); + md_interrupt_update(md); + + return 0; +@@ -553,7 +553,7 @@ static int dscm1xxxx_detach(PCMCIACardState *card) + { + MicroDriveState *md = MICRODRIVE(card); + +- device_legacy_reset(DEVICE(md)); ++ device_cold_reset(DEVICE(md)); + return 0; + } + +-- +2.27.0 + diff --git a/hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch b/hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch deleted file mode 100644 index de999b8c89a41d54879d2fd22cc3b852e6c16138..0000000000000000000000000000000000000000 --- a/hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 3e28567104500238b89ea6b4d684c5350194fea9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Mon, 21 Jun 2021 10:12:41 +0800 -Subject: [PATCH] hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-20221 - -Per the ARM Generic Interrupt Controller Architecture specification -(document "ARM IHI 0048B.b (ID072613)"), the SGIINTID field is 4 bit, -not 10: - - - 4.3 Distributor register descriptions - - 4.3.15 Software Generated Interrupt Register, GICD_SG - - - Table 4-21 GICD_SGIR bit assignments - - The Interrupt ID of the SGI to forward to the specified CPU - interfaces. The value of this field is the Interrupt ID, in - the range 0-15, for example a value of 0b0011 specifies - Interrupt ID 3. - -Correct the irq mask to fix an undefined behavior (which eventually -lead to a heap-buffer-overflow, see [Buglink]): - - $ echo 'writel 0x8000f00 0xff4affb0' | qemu-system-aarch64 -M virt,accel=qtest -qtest stdio - [I 1612088147.116987] OPENED - [R +0.278293] writel 0x8000f00 0xff4affb0 - ../hw/intc/arm_gic.c:1498:13: runtime error: index 944 out of bounds for type 'uint8_t [16][8]' - SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../hw/intc/arm_gic.c:1498:13 - -This fixes a security issue when running with KVM on Arm with -kernel-irqchip=off. (The default is kernel-irqchip=on, which is -unaffected, and which is also the correct choice for performance.) - -Cc: qemu-stable@nongnu.org -Fixes: CVE-2021-20221 -Fixes: 9ee6e8bb ("ARMv7 support.") -Buglink: https://bugs.launchpad.net/qemu/+bug/1913916 -Buglink: https://bugs.launchpad.net/qemu/+bug/1913917 - -Reported-by: Alexander Bulekov's avatarAlexander Bulekov -Signed-off-by: Philippe Mathieu-Daudé's avatarPhilippe Mathieu-Daudé -Message-id: 20210131103401.217160-1-f4bug@amsat.org -Reviewed-by: Peter Maydell's avatarPeter Maydell -Signed-off-by: Peter Maydell's avatarPeter Maydell - -Signed-off-by: Jiajie Li ---- - hw/intc/arm_gic.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c -index 77427a4188..492dabaa1c 100644 ---- a/hw/intc/arm_gic.c -+++ b/hw/intc/arm_gic.c -@@ -1454,7 +1454,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset, - int target_cpu; - - cpu = gic_get_current_cpu(s); -- irq = value & 0x3ff; -+ irq = value & 0xf; - switch ((value >> 24) & 3) { - case 0: - mask = (value >> 16) & ALL_CPU_MASK; --- -2.27.0 - diff --git a/hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch b/hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf1bd37de19b3a21dd1ffc7544efaafde72439a7 --- /dev/null +++ b/hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch @@ -0,0 +1,55 @@ +From 5c3db1128c90e0fa2bec139de6022aea0ae2ad12 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 19:24:19 +0100 +Subject: [PATCH 1/3] hw/intc/arm_gicv3: Check for !MEMTX_OK instead of + MEMTX_ERROR +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Quoting Peter Maydell: + + "These MEMTX_* aren't from the memory transaction + API functions; they're just being used by gicd_readl() and + friends as a way to indicate a success/failure so that the + actual MemoryRegionOps read/write fns like gicv3_dist_read() + can log a guest error." + +We are going to introduce more MemTxResult bits, so it is +safer to check for !MEMTX_OK rather than MEMTX_ERROR. + +Reviewed-by: Peter Xu +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Maydell +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Peter Maydell +--- + hw/intc/arm_gicv3_redist.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c +index c8ff3eca08..99b11ca5ee 100644 +--- a/hw/intc/arm_gicv3_redist.c ++++ b/hw/intc/arm_gicv3_redist.c +@@ -462,7 +462,7 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, + break; + } + +- if (r == MEMTX_ERROR) { ++ if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest read at offset " TARGET_FMT_plx + " size %u\n", __func__, offset, size); +@@ -521,7 +521,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, + break; + } + +- if (r == MEMTX_ERROR) { ++ if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest write at offset " TARGET_FMT_plx + " size %u\n", __func__, offset, size); +-- +2.27.0 + diff --git a/hw-intc-arm_gicv3-ICC_PMR_EL1-high-bits-should-be-RA.patch b/hw-intc-arm_gicv3-ICC_PMR_EL1-high-bits-should-be-RA.patch new file mode 100644 index 0000000000000000000000000000000000000000..92d2b86e043b65d42a950acb354bfba61ea39666 --- /dev/null +++ b/hw-intc-arm_gicv3-ICC_PMR_EL1-high-bits-should-be-RA.patch @@ -0,0 +1,54 @@ +From bd71d640e5d3731a91ccd6cc4ded251d401b4b2d Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Tue, 28 Nov 2023 09:38:09 +0800 +Subject: [PATCH] hw/intc/arm_gicv3: ICC_PMR_EL1 high bits should be RAZ + +cherry picked from 70726a15bc7e61d16f3efe5bfd9b061ca077f533 + +The ICC_PMR_ELx and ICV_PMR_ELx bit masks returned from +ic{c,v}_fullprio_mask should technically also remove any +bit above 7 as these are marked reserved (read 0) and should +therefore should not be written as anything other than 0. + +This was noted during a run of a proprietary test system and +discused on the mailing list [1] and initially thought not to +be an issue due to RES0 being technically allowed to be +written to and read back as long as the implementation does +not use the RES0 bits. It is very possible that the values +are used in comparison without masking, as pointed out by +Peter in [2], if (cs->hppi.prio >= cs->icc_pmr_el1) may well +do the wrong thing. + +Masking these values in ic{c,v}_fullprio_mask() should fix +this and prevent any future problems with playing with the +values. + +[1]: https://lists.nongnu.org/archive/html/qemu-arm/2023-11/msg00607.html +[2]: https://lists.nongnu.org/archive/html/qemu-arm/2023-11/msg00737.html + +Signed-off-by: Ben Dooks +Message-id: 20231116172818.792364-1-ben.dooks@codethink.co.uk +Suggested-by: Peter Maydell +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: boringandboring +--- + hw/intc/arm_gicv3_cpuif.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index 274a40a40c..eaa1381b3d 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -137,7 +137,7 @@ static uint32_t icv_fullprio_mask(GICv3CPUState *cs) + * with the group priority, whose mask depends on the value of VBPR + * for the interrupt group.) + */ +- return ~0U << (8 - cs->vpribits); ++ return (~0U << (8 - cs->vpribits)) & 0xff; + } + + static int ich_highest_active_virt_prio(GICv3CPUState *cs) +-- +2.27.0 + diff --git a/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch b/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch index 2b77e0b0ce8a678b0c13b7f9f852522617b90c71..926a619152e8af57e0c55b2664d4b2d0c4fc9445 100644 --- a/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch +++ b/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch @@ -1,4 +1,4 @@ -From 6bbfb186c8d66b745aeb08143d3198fcedc52d6c Mon Sep 17 00:00:00 2001 +From e94b8dc43d416b3ebf316faf14309fe4c4d0b4f0 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 6 Apr 2020 11:26:35 +0800 Subject: [PATCH] hw/intc/gicv3: Add CPU hotplug realize hook @@ -17,13 +17,13 @@ Signed-off-by: Salil Mehta 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c -index 2fe79f794d..cacef26546 100644 +index 40016cb84a..9591cfbcc0 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c -@@ -361,6 +361,19 @@ static const MemoryRegionOps gic_ops[] = { +@@ -376,6 +376,19 @@ static const MemoryRegionOps gic_ops[] = { } }; - + +static void gicv3_cpu_realize(GICv3State *s, int i) +{ + gicv3_init_one_cpuif(s, i); @@ -40,32 +40,32 @@ index 2fe79f794d..cacef26546 100644 static void arm_gic_realize(DeviceState *dev, Error **errp) { /* Device instance realize function for the GIC sysbus device */ -@@ -388,7 +401,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) - } - +@@ -393,7 +406,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops); + for (i = 0; i < s->num_cpu; i++) { - gicv3_init_one_cpuif(s, i); + gicv3_cpu_realize(s, i); } } - -@@ -398,6 +411,8 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) + +@@ -403,6 +416,8 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); - + + agc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize; + agcc->cpu_hotplug_realize = arm_gicv3_cpu_hotplug_realize; agcc->post_load = arm_gicv3_post_load; device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); } diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c -index 798f295d7c..8740a52c9f 100644 +index 1a11d1986d..f8ef6817a4 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c -@@ -313,6 +313,11 @@ static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) +@@ -311,6 +311,11 @@ static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) gicv3_set_gicv3state(cpu, &s->cpu[ncpu]); } - + +static void arm_gicv3_common_cpu_hotplug_realize(GICv3State *s, int ncpu) +{ + arm_gicv3_common_cpu_realize(s, ncpu); @@ -74,45 +74,45 @@ index 798f295d7c..8740a52c9f 100644 static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) { GICv3State *s = ARM_GICV3_COMMON(dev); -@@ -357,6 +362,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) - +@@ -371,6 +376,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + for (i = 0; i < s->num_cpu; i++) { CPUState *cpu = qemu_get_cpu(i); + uint64_t cpu_affid; - int last; - -@@ -508,12 +514,14 @@ static Property arm_gicv3_common_properties[] = { + + arm_gicv3_common_cpu_realize(s, i); +@@ -537,12 +543,14 @@ static Property arm_gicv3_common_properties[] = { static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); - + dc->reset = arm_gicv3_common_reset; dc->realize = arm_gicv3_common_realize; - dc->props = arm_gicv3_common_properties; + device_class_set_props(dc, arm_gicv3_common_properties); dc->vmsd = &vmstate_gicv3; + agcc->cpu_hotplug_realize = arm_gicv3_common_cpu_hotplug_realize; albifc->arm_linux_init = arm_gic_common_linux_init; } - + diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c -index b2936938cb..f8d7be5479 100644 +index 596b31998b..95271e754b 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c -@@ -78,6 +78,7 @@ typedef struct KVMARMGICv3Class { +@@ -76,6 +76,7 @@ struct KVMARMGICv3Class { ARMGICv3CommonClass parent_class; DeviceRealize parent_realize; void (*parent_reset)(DeviceState *dev); + CPUHotplugRealize parent_cpu_hotplug_realize; - } KVMARMGICv3Class; - + }; + static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) -@@ -768,6 +769,14 @@ static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu) +@@ -771,6 +772,14 @@ static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu) define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); } - + +static void kvm_arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu) +{ + KVMARMGICv3Class *kagcc = KVM_ARM_GICV3_GET_CLASS(s); @@ -124,47 +124,48 @@ index b2936938cb..f8d7be5479 100644 static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); -@@ -884,6 +893,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) +@@ -881,6 +890,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); - + + kgc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize; + agcc->cpu_hotplug_realize = kvm_arm_gicv3_cpu_hotplug_realize; agcc->pre_save = kvm_arm_gicv3_get; agcc->post_load = kvm_arm_gicv3_put; device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h -index 4a6fd85e22..98f2bdb7e9 100644 +index a81a6ae7ec..e360556bd5 100644 --- a/include/hw/intc/arm_gicv3.h +++ b/include/hw/intc/arm_gicv3.h -@@ -26,6 +26,8 @@ typedef struct ARMGICv3Class { +@@ -26,6 +26,8 @@ struct ARMGICv3Class { ARMGICv3CommonClass parent_class; /*< public >*/ - + + CPUHotplugRealize parent_cpu_hotplug_realize; + DeviceRealize parent_realize; - } ARMGICv3Class; - + }; + diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h -index 31ec9a1ae4..45cc50ed3b 100644 +index fc38e4b7dc..c208a191ff 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h -@@ -286,11 +286,15 @@ GICV3_BITMAP_ACCESSORS(edge_trigger) - #define ARM_GICV3_COMMON_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON) - +@@ -306,11 +306,15 @@ typedef struct ARMGICv3CommonClass ARMGICv3CommonClass; + DECLARE_OBJ_CHECKERS(GICv3State, ARMGICv3CommonClass, + ARM_GICV3_COMMON, TYPE_ARM_GICV3_COMMON) + +typedef void (*CPUHotplugRealize)(GICv3State *s, int ncpu); + - typedef struct ARMGICv3CommonClass { + struct ARMGICv3CommonClass { /*< private >*/ SysBusDeviceClass parent_class; /*< public >*/ - + + CPUHotplugRealize cpu_hotplug_realize; + void (*pre_save)(GICv3State *s); void (*post_load)(GICv3State *s); - } ARMGICv3CommonClass; --- -2.19.1 + }; +-- +2.27.0 + diff --git a/hw-mem-nvdimm-fix-error-message-for-unarmed-flag.patch b/hw-mem-nvdimm-fix-error-message-for-unarmed-flag.patch new file mode 100644 index 0000000000000000000000000000000000000000..88bb34e10ac60d7cf606f6c6062855441fea4b05 --- /dev/null +++ b/hw-mem-nvdimm-fix-error-message-for-unarmed-flag.patch @@ -0,0 +1,41 @@ +From b1201fb95d14f5564d4df28ab53d16676d335934 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Wed, 23 Nov 2022 10:57:07 +0800 +Subject: [PATCH 05/29] hw/mem/nvdimm: fix error message for 'unarmed' flag +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the ACPI specification [1], the 'unarmed' bit is set when a device +cannot accept a persistent write. This means that when a memdev is +read-only, the 'unarmed' flag must be turned on. The logic is correct, +just changing the error message. +[1] ACPI NFIT NVDIMM Region Mapping Structure "NVDIMM State Flags" Bit 3 + +Fixes: dbd730e859 ("nvdimm: check -object memory-backend-file, readonly=on option") +Signed-off-by: Julia Suvorova +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Pankaj Gupta +Reviewed-by: Philippe Mathieu-Daudé +Acked-by: David Hildenbrand +Signed-off-by: jianchunfu +--- + hw/mem/nvdimm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c +index 7397b67156..8df1d7e088 100644 +--- a/hw/mem/nvdimm.c ++++ b/hw/mem/nvdimm.c +@@ -149,7 +149,7 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp) + if (!nvdimm->unarmed && memory_region_is_rom(mr)) { + HostMemoryBackend *hostmem = dimm->hostmem; + +- error_setg(errp, "'unarmed' property must be off since memdev %s " ++ error_setg(errp, "'unarmed' property must be 'on' since memdev %s " + "is read-only", + object_get_canonical_path_component(OBJECT(hostmem))); + return; +-- +2.27.0 + diff --git a/hw-net-Fix-read-of-uninitialized-memory-in-ftgmac100.patch b/hw-net-Fix-read-of-uninitialized-memory-in-ftgmac100.patch new file mode 100644 index 0000000000000000000000000000000000000000..55ad629995ea8e03e4a2e985ae900959d2e1e0e9 --- /dev/null +++ b/hw-net-Fix-read-of-uninitialized-memory-in-ftgmac100.patch @@ -0,0 +1,49 @@ +From 967c8f6e799756baf95c025ba8107206c3afd398 Mon Sep 17 00:00:00 2001 +From: dinglimin_yewu +Date: Thu, 28 Sep 2023 16:25:23 +0800 +Subject: [PATCH] hw/net: Fix read of uninitialized memory in ftgmac100 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 036e98e5c2b4e25c8d6ccbddb85c7ab05a753f6a + +With the `size += 4` before the call to `crc32`, the CRC calculation +would overrun the buffer. Size is used in the while loop starting on +line 1009 to determine how much data to write back, with the last +four bytes coming from `crc_ptr`, so do need to increase it, but should +do this after the computation. + +I'm unsure why this use of uninitialized memory in the CRC doesn't +result in CRC errors, but it seems clear to me that it should not be +included in the calculation. + +Signed-off-by: Stephen Longfield +Reviewed-by: Hao Wu +Reviewed-by: Joel Stanley +Message-Id: <20221220221437.3303721-1-slongfield@google.com> +Signed-off-by: Cédric Le Goater +Signed-off-by: dinglimin_yewu +--- + hw/net/ftgmac100.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c +index 83ef0a783e..d3bf14be53 100644 +--- a/hw/net/ftgmac100.c ++++ b/hw/net/ftgmac100.c +@@ -980,9 +980,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, + return size; + } + +- /* 4 bytes for the CRC. */ +- size += 4; + crc = cpu_to_be32(crc32(~0, buf, size)); ++ /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */ ++ size += 4; + crc_ptr = (uint8_t *) &crc; + + /* Huge frames are truncated. */ +-- +2.41.0.windows.1 + diff --git a/hw-net-cadence_gem.c-spelling-fixes-Octects.patch b/hw-net-cadence_gem.c-spelling-fixes-Octects.patch new file mode 100644 index 0000000000000000000000000000000000000000..31ebc99f4cd161bfdaed64a15f4e8621061da394 --- /dev/null +++ b/hw-net-cadence_gem.c-spelling-fixes-Octects.patch @@ -0,0 +1,39 @@ +From 2e37d6ac7713c9962cb006900d18e83df54e8e0f Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Fri, 24 Nov 2023 00:21:31 -0800 +Subject: [PATCH] hw/net/cadence_gem.c: spelling fixes: Octects + +Signed-off-by: zhujun2 +--- + hw/net/cadence_gem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index 24b3a0ff66..21e1bd091f 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -81,8 +81,8 @@ + #define GEM_IPGSTRETCH (0x000000BC / 4) /* IPG Stretch reg */ + #define GEM_SVLAN (0x000000C0 / 4) /* Stacked VLAN reg */ + #define GEM_MODID (0x000000FC / 4) /* Module ID reg */ +-#define GEM_OCTTXLO (0x00000100 / 4) /* Octects transmitted Low reg */ +-#define GEM_OCTTXHI (0x00000104 / 4) /* Octects transmitted High reg */ ++#define GEM_OCTTXLO (0x00000100 / 4) /* Octets transmitted Low reg */ ++#define GEM_OCTTXHI (0x00000104 / 4) /* Octets transmitted High reg */ + #define GEM_TXCNT (0x00000108 / 4) /* Error-free Frames transmitted */ + #define GEM_TXBCNT (0x0000010C / 4) /* Error-free Broadcast Frames */ + #define GEM_TXMCNT (0x00000110 / 4) /* Error-free Multicast Frame */ +@@ -101,8 +101,8 @@ + #define GEM_LATECOLLCNT (0x00000144 / 4) /* Late Collision Frames */ + #define GEM_DEFERTXCNT (0x00000148 / 4) /* Deferred Transmission Frames */ + #define GEM_CSENSECNT (0x0000014C / 4) /* Carrier Sense Error Counter */ +-#define GEM_OCTRXLO (0x00000150 / 4) /* Octects Received register Low */ +-#define GEM_OCTRXHI (0x00000154 / 4) /* Octects Received register High */ ++#define GEM_OCTRXLO (0x00000150 / 4) /* Octets Received register Low */ ++#define GEM_OCTRXHI (0x00000154 / 4) /* Octets Received register High */ + #define GEM_RXCNT (0x00000158 / 4) /* Error-free Frames Received */ + #define GEM_RXBROADCNT (0x0000015C / 4) /* Error-free Broadcast Frames RX */ + #define GEM_RXMULTICNT (0x00000160 / 4) /* Error-free Multicast Frames RX */ +-- +2.27.0 + diff --git a/hw-net-can-fix-Xilinx-ZynqMP-CAN-RX-FIFO-logic.patch b/hw-net-can-fix-Xilinx-ZynqMP-CAN-RX-FIFO-logic.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b308514351cb76c7f798a6cbcfd393a27738103 --- /dev/null +++ b/hw-net-can-fix-Xilinx-ZynqMP-CAN-RX-FIFO-logic.patch @@ -0,0 +1,82 @@ +From 071249a10ebc2cd8af68ee72d409e23c6bc0ea7c Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Wed, 30 Nov 2022 01:52:08 -0500 +Subject: [PATCH 04/17] hw/net/can: fix Xilinx ZynqMP CAN RX FIFO logic + +mainline inclusion +from mainline-v7.2.0-rc2 +commit fb96d131eec66ecb2993c544058a8cb2c9c3521f +category: bugfix + +----------------------- + +For consistency, function "update_rx_fifo()" should use the RX FIFO +register field names, not the TX FIFO ones, even if they refer to the +same bit positions in the register. + +Signed-off-by: Anton Kochkov +Reviewed-by: Francisco Iglesias +Message-id: 20220817141754.2105981-1-anton.kochkov@proton.me +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1123 +[PMM: tweaked commit message] +Signed-off-by: Peter Maydell + +Signed-off-by: cmss_dx +--- + hw/net/can/xlnx-zynqmp-can.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c +index 22bb8910fa..78a76a8ce2 100644 +--- a/hw/net/can/xlnx-zynqmp-can.c ++++ b/hw/net/can/xlnx-zynqmp-can.c +@@ -696,30 +696,30 @@ static void update_rx_fifo(XlnxZynqMPCANState *s, const qemu_can_frame *frame) + timestamp)); + + /* First 32 bit of the data. */ +- fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA1_DB3_SHIFT, +- R_TXFIFO_DATA1_DB3_LENGTH, ++ fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA1_DB3_SHIFT, ++ R_RXFIFO_DATA1_DB3_LENGTH, + frame->data[0]) | +- deposit32(0, R_TXFIFO_DATA1_DB2_SHIFT, +- R_TXFIFO_DATA1_DB2_LENGTH, ++ deposit32(0, R_RXFIFO_DATA1_DB2_SHIFT, ++ R_RXFIFO_DATA1_DB2_LENGTH, + frame->data[1]) | +- deposit32(0, R_TXFIFO_DATA1_DB1_SHIFT, +- R_TXFIFO_DATA1_DB1_LENGTH, ++ deposit32(0, R_RXFIFO_DATA1_DB1_SHIFT, ++ R_RXFIFO_DATA1_DB1_LENGTH, + frame->data[2]) | +- deposit32(0, R_TXFIFO_DATA1_DB0_SHIFT, +- R_TXFIFO_DATA1_DB0_LENGTH, ++ deposit32(0, R_RXFIFO_DATA1_DB0_SHIFT, ++ R_RXFIFO_DATA1_DB0_LENGTH, + frame->data[3])); + /* Last 32 bit of the data. */ +- fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA2_DB7_SHIFT, +- R_TXFIFO_DATA2_DB7_LENGTH, ++ fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA2_DB7_SHIFT, ++ R_RXFIFO_DATA2_DB7_LENGTH, + frame->data[4]) | +- deposit32(0, R_TXFIFO_DATA2_DB6_SHIFT, +- R_TXFIFO_DATA2_DB6_LENGTH, ++ deposit32(0, R_RXFIFO_DATA2_DB6_SHIFT, ++ R_RXFIFO_DATA2_DB6_LENGTH, + frame->data[5]) | +- deposit32(0, R_TXFIFO_DATA2_DB5_SHIFT, +- R_TXFIFO_DATA2_DB5_LENGTH, ++ deposit32(0, R_RXFIFO_DATA2_DB5_SHIFT, ++ R_RXFIFO_DATA2_DB5_LENGTH, + frame->data[6]) | +- deposit32(0, R_TXFIFO_DATA2_DB4_SHIFT, +- R_TXFIFO_DATA2_DB4_LENGTH, ++ deposit32(0, R_RXFIFO_DATA2_DB4_SHIFT, ++ R_RXFIFO_DATA2_DB4_LENGTH, + frame->data[7])); + + ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1); +-- +2.27.0 + diff --git a/hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch b/hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch deleted file mode 100644 index 3bffc1cf188e0ca6167e1ffb3cd138f14073dc8b..0000000000000000000000000000000000000000 --- a/hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2b157688d19da5ce4fca6b5f3c78d2e309ecec9a Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Wed, 11 Nov 2020 18:36:36 +0530 -Subject: [PATCH] hw/net/e1000e: advance desc_offset in case of null descriptor - -While receiving packets via e1000e_write_packet_to_guest() routine, -'desc_offset' is advanced only when RX descriptor is processed. And -RX descriptor is not processed if it has NULL buffer address. -This may lead to an infinite loop condition. Increament 'desc_offset' -to process next descriptor in the ring to avoid infinite loop. - -Reported-by: Cheol-woo Myung <330cjfdn@gmail.com> -Signed-off-by: Prasad J Pandit -Signed-off-by: Jason Wang -(cherry-picked from c2cb5116) -Fix CVE-2020-28916 -Signed-off-by: Alex Chen ---- - hw/net/e1000e_core.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c -index 2a221c2ef9..e45d47f584 100644 ---- a/hw/net/e1000e_core.c -+++ b/hw/net/e1000e_core.c -@@ -1595,13 +1595,13 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, - (const char *) &fcs_pad, e1000x_fcs_len(core->mac)); - } - } -- desc_offset += desc_size; -- if (desc_offset >= total_size) { -- is_last = true; -- } - } else { /* as per intel docs; skip descriptors with null buf addr */ - trace_e1000e_rx_null_descriptor(); - } -+ desc_offset += desc_size; -+ if (desc_offset >= total_size) { -+ is_last = true; -+ } - - e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL, - rss_info, do_ps ? ps_hdr_len : 0, &bastate.written); --- -2.27.0 - diff --git a/hw-net-fix-vmxnet3-live-migration.patch b/hw-net-fix-vmxnet3-live-migration.patch deleted file mode 100644 index be97b3ac0dc76d839f646078151cddc0861ab094..0000000000000000000000000000000000000000 --- a/hw-net-fix-vmxnet3-live-migration.patch +++ /dev/null @@ -1,136 +0,0 @@ -From b8b9f58ee5d3cff0a1e7cca770fe632043efb728 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Fri, 5 Jul 2019 04:07:11 +0300 -Subject: [PATCH] hw/net: fix vmxnet3 live migration - -At some point vmxnet3 live migration stopped working and git-bisect -didn't help finding a working version. -The issue is the PCI configuration space is not being migrated -successfully and MSIX remains masked at destination. - -Remove the migration differentiation between PCI and PCIe since -the logic resides now inside VMSTATE_PCI_DEVICE. -Remove also the VMXNET3_COMPAT_FLAG_DISABLE_PCIE based differentiation -since at 'realize' time is decided if the device is PCI or PCIe, -then the above macro is enough. - -Use the opportunity to move to the standard VMSTATE_MSIX -instead of the deprecated SaveVMHandlers. - -Signed-off-by: Marcel Apfelbaum -Message-Id: <20190705010711.23277-1-marcel.apfelbaum@gmail.com> -Tested-by: Sukrit Bhatnagar -Reviewed-by: Dmitry Fleytman -Signed-off-by: Dr. David Alan Gilbert ---- - hw/net/vmxnet3.c | 52 ++---------------------------------------------- - 1 file changed, 2 insertions(+), 50 deletions(-) - -diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c -index ecc4f5bcf0..bf8e6ca4c9 100644 ---- a/hw/net/vmxnet3.c -+++ b/hw/net/vmxnet3.c -@@ -2153,21 +2153,6 @@ vmxnet3_cleanup_msi(VMXNET3State *s) - msi_uninit(d); - } - --static void --vmxnet3_msix_save(QEMUFile *f, void *opaque) --{ -- PCIDevice *d = PCI_DEVICE(opaque); -- msix_save(d, f); --} -- --static int --vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id) --{ -- PCIDevice *d = PCI_DEVICE(opaque); -- msix_load(d, f); -- return 0; --} -- - static const MemoryRegionOps b0_ops = { - .read = vmxnet3_io_bar0_read, - .write = vmxnet3_io_bar0_write, -@@ -2188,11 +2173,6 @@ static const MemoryRegionOps b1_ops = { - }, - }; - --static SaveVMHandlers savevm_vmxnet3_msix = { -- .save_state = vmxnet3_msix_save, -- .load_state = vmxnet3_msix_load, --}; -- - static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) - { - uint64_t dsn_payload; -@@ -2215,7 +2195,6 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) - - static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) - { -- DeviceState *dev = DEVICE(pci_dev); - VMXNET3State *s = VMXNET3(pci_dev); - int ret; - -@@ -2261,8 +2240,6 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) - pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET, - vmxnet3_device_serial_num(s)); - } -- -- register_savevm_live(dev, "vmxnet3-msix", -1, 1, &savevm_vmxnet3_msix, s); - } - - static void vmxnet3_instance_init(Object *obj) -@@ -2452,29 +2429,6 @@ static const VMStateDescription vmstate_vmxnet3_int_state = { - } - }; - --static bool vmxnet3_vmstate_need_pcie_device(void *opaque) --{ -- VMXNET3State *s = VMXNET3(opaque); -- -- return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE); --} -- --static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id) --{ -- return !vmxnet3_vmstate_need_pcie_device(opaque); --} -- --static const VMStateDescription vmstate_vmxnet3_pcie_device = { -- .name = "vmxnet3/pcie", -- .version_id = 1, -- .minimum_version_id = 1, -- .needed = vmxnet3_vmstate_need_pcie_device, -- .fields = (VMStateField[]) { -- VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), -- VMSTATE_END_OF_LIST() -- } --}; -- - static const VMStateDescription vmstate_vmxnet3 = { - .name = "vmxnet3", - .version_id = 1, -@@ -2482,9 +2436,8 @@ static const VMStateDescription vmstate_vmxnet3 = { - .pre_save = vmxnet3_pre_save, - .post_load = vmxnet3_post_load, - .fields = (VMStateField[]) { -- VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State, -- vmxnet3_vmstate_test_pci_device, 0, -- vmstate_pci_device, PCIDevice), -+ VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), -+ VMSTATE_MSIX(parent_obj, VMXNET3State), - VMSTATE_BOOL(rx_packets_compound, VMXNET3State), - VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State), - VMSTATE_BOOL(lro_supported, VMXNET3State), -@@ -2520,7 +2473,6 @@ static const VMStateDescription vmstate_vmxnet3 = { - }, - .subsections = (const VMStateDescription*[]) { - &vmxstate_vmxnet3_mcast_list, -- &vmstate_vmxnet3_pcie_device, - NULL - } - }; --- -2.27.0 - diff --git a/hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch b/hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch deleted file mode 100644 index a763f93bc4859f6f38fa8f6d83da6d84f1ab01f2..0000000000000000000000000000000000000000 --- a/hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 596e7e8908b742f727d02ec9ab747116573f67e0 Mon Sep 17 00:00:00 2001 -From: Mauro Matteo Cascella -Date: Sat, 1 Aug 2020 18:42:38 +0200 -Subject: [PATCH] hw/net/net_tx_pkt: fix assertion failure in - net_tx_pkt_add_raw_fragment() - -An assertion failure issue was found in the code that processes network packets -while adding data fragments into the packet context. It could be abused by a -malicious guest to abort the QEMU process on the host. This patch replaces the -affected assert() with a conditional statement, returning false if the current -data fragment exceeds max_raw_frags. - -Reported-by: Alexander Bulekov -Reported-by: Ziming Zhang -Reviewed-by: Dmitry Fleytman -Signed-off-by: Mauro Matteo Cascella -Signed-off-by: Jason Wang ---- - hw/net/net_tx_pkt.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c -index 162f802dd7..54d4c3bbd0 100644 ---- a/hw/net/net_tx_pkt.c -+++ b/hw/net/net_tx_pkt.c -@@ -379,7 +379,10 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, - hwaddr mapped_len = 0; - struct iovec *ventry; - assert(pkt); -- assert(pkt->max_raw_frags > pkt->raw_frags); -+ -+ if (pkt->raw_frags >= pkt->max_raw_frags) { -+ return false; -+ } - - if (!len) { - return true; --- -2.23.0 - diff --git a/hw-net-npcm7xx_emc-fix-missing-queue_flush.patch b/hw-net-npcm7xx_emc-fix-missing-queue_flush.patch new file mode 100644 index 0000000000000000000000000000000000000000..bce9a4f925f61e43711dae879a820c206619cf4a --- /dev/null +++ b/hw-net-npcm7xx_emc-fix-missing-queue_flush.patch @@ -0,0 +1,75 @@ +From cf11e02156e202db1be5e9c85b67d5dfaa56ce48 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 10:28:53 +0800 +Subject: [PATCH] hw/net: npcm7xx_emc fix missing queue_flush +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 530cd6c26df47c4f294c6335c9829e6c968fe7a8 + +The rx_active boolean change to true should always trigger a try_read +call that flushes the queue. + +Signed-off-by: Patrick Venture +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20211203221002.1719306-1-venture@google.com +Signed-off-by: Peter Maydell +Signed-off-by: Luo Yifan +--- + hw/net/npcm7xx_emc.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c +index df2efe1bf8..9a2328935c 100644 +--- a/hw/net/npcm7xx_emc.c ++++ b/hw/net/npcm7xx_emc.c +@@ -286,6 +286,12 @@ static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag) + emc_set_mista(emc, mista_flag); + } + ++static void emc_enable_rx_and_flush(NPCM7xxEMCState *emc) ++{ ++ emc->rx_active = true; ++ qemu_flush_queued_packets(qemu_get_queue(emc->nic)); ++} ++ + static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc, + const NPCM7xxEMCTxDesc *tx_desc, + uint32_t desc_addr) +@@ -585,13 +591,6 @@ static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1) + return len; + } + +-static void emc_try_receive_next_packet(NPCM7xxEMCState *emc) +-{ +- if (emc_can_receive(qemu_get_queue(emc->nic))) { +- qemu_flush_queued_packets(qemu_get_queue(emc->nic)); +- } +-} +- + static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size) + { + NPCM7xxEMCState *emc = opaque; +@@ -707,7 +706,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset, + emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA; + } + if (value & REG_MCMDR_RXON) { +- emc->rx_active = true; ++ emc_enable_rx_and_flush(emc); + } else { + emc_halt_rx(emc, 0); + } +@@ -743,8 +742,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset, + break; + case REG_RSDR: + if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) { +- emc->rx_active = true; +- emc_try_receive_next_packet(emc); ++ emc_enable_rx_and_flush(emc); + } + break; + case REG_MIIDA: +-- +2.27.0 + diff --git a/hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch b/hw-net-rocker-fix-security-vulnerability.patch similarity index 33% rename from hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch rename to hw-net-rocker-fix-security-vulnerability.patch index dd3a972936049057760b5819669beec96cbeb48c..c841e9709c0b60127be40a7f163f3f9fcd0124bc 100644 --- a/hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch +++ b/hw-net-rocker-fix-security-vulnerability.patch @@ -1,29 +1,18 @@ -From e921d308845a0249126c59655d985007acf58ed7 Mon Sep 17 00:00:00 2001 -From: Qiang Ning -Date: Mon, 12 Jul 2021 17:30:45 +0800 -Subject: [PATCH] hw/net/rocker_of_dpa: fix double free bug of rocker device +From 9a8de722b047ba66f70e87fb29b877935c187457 Mon Sep 17 00:00:00 2001 +From: Lichang Zhao +Date: Thu, 10 Feb 2022 16:54:06 +0800 +Subject: [PATCH] hw/net/rocker: fix security vulnerability -The of_dpa_cmd_add_l2_flood function of the rocker device -releases the memory of group->l2_flood.group_ids before -applying for new memory. If the l2_group configured by -the guest does not match the input group->l2_flood.group_ids, -the err_out branch is redirected to release the memory of the -group->l2_flood.group_ids branch. The pointer is not set to -NULL after the memory is freed. When the guest accesses the -of_dpa_cmd_add_l2_flood function again, the memory of -group->l2_flood.group_ids is released again. As a result, -the memory is double free. +fix security vulnerability -Fix that by setting group->l2_flood.group_ids to NULL after free. - -Signed-off-by: Jiajie Li -Signed-off-by: Qiang Ning +Signed-off-by: Lichang zhao +Signed-off-by: Jinhao Gao --- hw/net/rocker/rocker_of_dpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c -index 8e347d1ee4..0c9de5f014 100644 +index b3b8c5bb6d..8ac26e6beb 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -2070,6 +2070,7 @@ static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group, diff --git a/hw-net-virtio-net-make-some-VirtIONet-const.patch b/hw-net-virtio-net-make-some-VirtIONet-const.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2ff4b1bc903bd2a83f546bab732a25c6367dbb7 --- /dev/null +++ b/hw-net-virtio-net-make-some-VirtIONet-const.patch @@ -0,0 +1,44 @@ +From f6e12a7c892c5e823157f6b84955544ff659e980 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Fri, 30 Jun 2023 22:19:22 +0800 +Subject: [PATCH] hw/net/virtio-net: make some VirtIONet const +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The VirtIONet structure is not modified in +virtio_net_supported_guest_offloads(). +Therefore, make it const to allow this function to +accept const variables. + +cheery-pick from 705e89cfaafc54491482742a756cf661b48608d2 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Hawkins Jiawei +Reviewed-by: Eugenio Pérez +Message-Id: <489b09c3998ac09b9135e57a7dd8c56a4be8cdf9.1685704856.git.yin31149@gmail.com> +Tested-by: Lei Yang +Reviewed-by: Eugenio Pérez +Tested-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/net/virtio-net.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 4946b65e22..3bd786cc22 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -811,7 +811,7 @@ static uint64_t virtio_net_guest_offloads_by_features(uint32_t features) + return guest_offloads_mask & features; + } + +-static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) ++static inline uint64_t virtio_net_supported_guest_offloads(const VirtIONet *n) + { + VirtIODevice *vdev = VIRTIO_DEVICE(n); + return virtio_net_guest_offloads_by_features(vdev->guest_features); +-- +2.41.0.windows.1 + diff --git a/hw-net-vmxnet3-Log-guest-triggerable-errors-using-LO.patch b/hw-net-vmxnet3-Log-guest-triggerable-errors-using-LO.patch new file mode 100644 index 0000000000000000000000000000000000000000..90631fb16d28b26ee5e95b419eb8b4eca1294bb4 --- /dev/null +++ b/hw-net-vmxnet3-Log-guest-triggerable-errors-using-LO.patch @@ -0,0 +1,64 @@ +From ad2660c287ff03d0190eff5f841452e618d368ff Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 24 Mar 2023 07:16:21 +0000 +Subject: [PATCH] hw/net/vmxnet3: Log guest-triggerable errors using + LOG_GUEST_ERROR mainline inclusion commit + f3e5a17593b972a9a6079ccf7677b4389d74d5a1 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +The "Interrupt Cause" register (VMXNET3_REG_ICR) is read-only. +Write accesses are ignored. Log them with as LOG_GUEST_ERROR +instead of aborting: + + [R +0.239743] writeq 0xe0002031 0x46291a5a55460800 + ERROR:hw/net/vmxnet3.c:1819:vmxnet3_io_bar1_write: code should not be reached + Thread 1 "qemu-system-i38" received signal SIGABRT, Aborted. + (gdb) bt + #3 0x74c397d3 in __GI_abort () at abort.c:79 + #4 0x76d3cd4c in g_assertion_message (domain=, file=, line=, func=, message=) at ../glib/gtestutils.c:3223 + #5 0x76d9d45f in g_assertion_message_expr + (domain=0x0, file=0x59fc2e53 "hw/net/vmxnet3.c", line=1819, func=0x59fc11e0 <__func__.vmxnet3_io_bar1_write> "vmxnet3_io_bar1_write", expr=) + at ../glib/gtestutils.c:3249 + #6 0x57e80a3a in vmxnet3_io_bar1_write (opaque=0x62814100, addr=56, val=70, size=4) at hw/net/vmxnet3.c:1819 + #7 0x58c2d894 in memory_region_write_accessor (mr=0x62816b90, addr=56, value=0x7fff9450, size=4, shift=0, mask=4294967295, attrs=...) at softmmu/memory.c:492 + #8 0x58c2d1d2 in access_with_adjusted_size (addr=56, value=0x7fff9450, size=1, access_size_min=4, access_size_max=4, access_fn= + 0x58c2d290 , mr=0x62816b90, attrs=...) at softmmu/memory.c:554 + #9 0x58c2bae7 in memory_region_dispatch_write (mr=0x62816b90, addr=56, data=70, op=MO_8, attrs=...) at softmmu/memory.c:1504 + #10 0x58bfd034 in flatview_write_continue (fv=0x606000181700, addr=0xe0002038, attrs=..., ptr=0x7fffb9e0, len=1, addr1=56, l=1, mr=0x62816b90) + at softmmu/physmem.c:2782 + #11 0x58beba00 in flatview_write (fv=0x606000181700, addr=0xe0002031, attrs=..., buf=0x7fffb9e0, len=8) at softmmu/physmem.c:2822 + #12 0x58beb589 in address_space_write (as=0x608000015f20, addr=0xe0002031, attrs=..., buf=0x7fffb9e0, len=8) at softmmu/physmem.c:2914 + +Reported-by: Dike +Reported-by: Duhao <504224090@qq.com> +BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=2032932 +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + hw/net/vmxnet3.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c +index f65af4e9ef..0b7acf7f89 100644 +--- a/hw/net/vmxnet3.c ++++ b/hw/net/vmxnet3.c +@@ -1816,7 +1816,9 @@ vmxnet3_io_bar1_write(void *opaque, + case VMXNET3_REG_ICR: + VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d", + val, size); +- g_assert_not_reached(); ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: write to read-only register VMXNET3_REG_ICR\n", ++ TYPE_VMXNET3); + break; + + /* Event Cause Register */ +-- +2.27.0 + diff --git a/hw-net-vmxnet3-allow-VMXNET3_MAX_MTU-itself-as-a-val.patch b/hw-net-vmxnet3-allow-VMXNET3_MAX_MTU-itself-as-a-val.patch new file mode 100644 index 0000000000000000000000000000000000000000..8219c0f9d855aae5aeeeed4076fb8fe3e8ef6a84 --- /dev/null +++ b/hw-net-vmxnet3-allow-VMXNET3_MAX_MTU-itself-as-a-val.patch @@ -0,0 +1,47 @@ +From 2d7c5ea10b443c33ffe2c21de5a495bd6d2a67bd Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 28 Jun 2023 09:37:04 +0800 +Subject: [PATCH] hw/net/vmxnet3: allow VMXNET3_MAX_MTU itself as a value + +cheery-pick from b209cc4556d56938fa8a933670b8fb98c036af37 + +Currently, VMXNET3_MAX_MTU itself (being 9000) is not considered a +valid value for the MTU, but a guest running ESXi 7.0 might try to +set it and fail the assert [0]. + +In the Linux kernel, dev->max_mtu itself is a valid value for the MTU +and for the vmxnet3 driver it's 9000, so a guest running Linux will +also fail the assert when trying to set an MTU of 9000. + +VMXNET3_MAX_MTU and s->mtu don't seem to be used in relation to buffer +allocations/accesses, so allowing the upper limit itself as a value +should be fine. + +[0]: https://forum.proxmox.com/threads/114011/ + +Fixes: d05dcd94ae ("net: vmxnet3: validate configuration values during activate (CVE-2021-20203)") +Signed-off-by: Fiona Ebner +Signed-off-by: Jason Wang +(cherry picked from commit 099a63828130843741d317cb28e936f468b2b53b) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/net/vmxnet3.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c +index 0b7acf7f89..a2037583bf 100644 +--- a/hw/net/vmxnet3.c ++++ b/hw/net/vmxnet3.c +@@ -1441,7 +1441,7 @@ static void vmxnet3_activate_device(VMXNET3State *s) + vmxnet3_setup_rx_filtering(s); + /* Cache fields from shared memory */ + s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); +- assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU); ++ assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu <= VMXNET3_MAX_MTU); + VMW_CFPRN("MTU is %u", s->mtu); + + s->max_rx_frags = +-- +2.41.0.windows.1 + diff --git a/hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch b/hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch deleted file mode 100644 index 62be98b6f147c098f57efbad27cbc6a5831d5ea2..0000000000000000000000000000000000000000 --- a/hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 2d18434c1ca66d68f80954be6828a3770176dab4 Mon Sep 17 00:00:00 2001 -From: Mauro Matteo Cascella -Date: Fri, 10 Jul 2020 11:19:41 +0200 -Subject: [PATCH] hw/net/xgmac: Fix buffer overflow in xgmac_enet_send() - -A buffer overflow issue was reported by Mr. Ziming Zhang, CC'd here. It -occurs while sending an Ethernet frame due to missing break statements -and improper checking of the buffer size. - -Reported-by: Ziming Zhang -Signed-off-by: Mauro Matteo Cascella -Reviewed-by: Peter Maydell -Signed-off-by: Jason Wang ---- - hw/net/xgmac.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c -index f49df95b07..f496f7ed4c 100644 ---- a/hw/net/xgmac.c -+++ b/hw/net/xgmac.c -@@ -217,21 +217,31 @@ static void xgmac_enet_send(XgmacState *s) - } - len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff); - -+ /* -+ * FIXME: these cases of malformed tx descriptors (bad sizes) -+ * should probably be reported back to the guest somehow -+ * rather than simply silently stopping processing, but we -+ * don't know what the hardware does in this situation. -+ * This will only happen for buggy guests anyway. -+ */ - if ((bd.buffer1_size & 0xfff) > 2048) { - DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " - "xgmac buffer 1 len on send > 2048 (0x%x)\n", - __func__, bd.buffer1_size & 0xfff); -+ break; - } - if ((bd.buffer2_size & 0xfff) != 0) { - DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " - "xgmac buffer 2 len on send != 0 (0x%x)\n", - __func__, bd.buffer2_size & 0xfff); -+ break; - } -- if (len >= sizeof(frame)) { -+ if (frame_size + len >= sizeof(frame)) { - DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu " -- "buffer\n" , __func__, len, sizeof(frame)); -+ "buffer\n" , __func__, frame_size + len, sizeof(frame)); - DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n", - __func__, bd.buffer1_size, bd.buffer2_size); -+ break; - } - - cpu_physical_memory_read(bd.buffer1_addr, ptr, len); --- -2.23.0 - diff --git a/hw-nvme-Avoid-dynamic-stack-allocation.patch b/hw-nvme-Avoid-dynamic-stack-allocation.patch new file mode 100644 index 0000000000000000000000000000000000000000..aaa5f740eeb3a4a3c808b264c10fd5a4594eb1f4 --- /dev/null +++ b/hw-nvme-Avoid-dynamic-stack-allocation.patch @@ -0,0 +1,38 @@ +From aa1f9c961de247522e772275635b7f15bf5bb13f Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Sat, 16 Sep 2023 17:20:08 +0800 +Subject: [PATCH] hw/nvme: Avoid dynamic stack allocation + +cheery-pick from b3c8246750b7077add335559341268f2956f6470 + +Instead of using a variable-length array in nvme_map_prp(), +allocate on the stack with a g_autofree pointer. + +The codebase has very few VLAs, and if we can get rid of them all we +can make the compiler error on new additions. This is a defensive +measure against security bugs where an on-stack dynamic allocation +isn't correctly size-checked (e.g. CVE-2021-3527). + +Signed-off-by: Peter Maydell +Signed-off-by: Klaus Jensen +Signed-off-by: dinglimin_yewu +--- + hw/nvme/ctrl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index debd3916dd..d64dd9c361 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -702,7 +702,7 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, NvmeSg *sg, uint64_t prp1, + len -= trans_len; + if (len) { + if (len > n->page_size) { +- uint64_t prp_list[n->max_prp_ents]; ++ g_autofree uint64_t *prp_list = g_new(uint64_t, n->max_prp_ents); + uint32_t nents, prp_trans; + int i = 0; + +-- +2.41.0.windows.1 + diff --git a/hw-nvme-Change-alignment-in-dma-functions-for-nvme_b.patch b/hw-nvme-Change-alignment-in-dma-functions-for-nvme_b.patch new file mode 100644 index 0000000000000000000000000000000000000000..65165c0425637cc6e42e8636c63785d1128f69bf --- /dev/null +++ b/hw-nvme-Change-alignment-in-dma-functions-for-nvme_b.patch @@ -0,0 +1,91 @@ +From f0ac211aab73b5b78795cd7bc94e0159c8e3cc1a Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 26 May 2023 11:03:29 +0800 +Subject: [PATCH] hw/nvme: Change alignment in dma functions for nvme_blk_* + +Since the nvme_blk_read/write are used by both the data and metadata +portions of the IO, it can't have the 512B alignment requirement. +Without this change any metadata transfer, which length isn't a multiple +of 512B and which is bigger than 512B, will result in only a partial +transfer. + +origin commit: https://gitlab.com/qemu-project/qemu/-/commit/9b4f01812f69ad6066725338c89945bb61f41823 +Signed-off-by: Meiyang Wang +Signed-off-by: Mateusz Kozlowski +Reviewed-by: Klaus Jensen +Signed-off-by: Klaus Jensen +--- + hw/nvme/ctrl.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 40fbda3b03..282abdda91 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -1263,26 +1263,28 @@ uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + } + + static inline void nvme_blk_read(BlockBackend *blk, int64_t offset, +- BlockCompletionFunc *cb, NvmeRequest *req) ++ uint32_t align, BlockCompletionFunc *cb, ++ NvmeRequest *req) + { + assert(req->sg.flags & NVME_SG_ALLOC); + + if (req->sg.flags & NVME_SG_DMA) { +- req->aiocb = dma_blk_read(blk, &req->sg.qsg, offset, BDRV_SECTOR_SIZE, +- cb, req); ++ req->aiocb = dma_blk_read(blk, &req->sg.qsg, offset, align, cb, req); + } else { + req->aiocb = blk_aio_preadv(blk, offset, &req->sg.iov, 0, cb, req); + } + } + + static inline void nvme_blk_write(BlockBackend *blk, int64_t offset, +- BlockCompletionFunc *cb, NvmeRequest *req) ++ uint32_t align, BlockCompletionFunc *cb, ++ NvmeRequest *req) + { + assert(req->sg.flags & NVME_SG_ALLOC); + + if (req->sg.flags & NVME_SG_DMA) { + req->aiocb = dma_blk_write(blk, &req->sg.qsg, offset, BDRV_SECTOR_SIZE, + cb, req); ++ req->aiocb = dma_blk_write(blk, &req->sg.qsg, offset, align, cb, req); + } else { + req->aiocb = blk_aio_pwritev(blk, offset, &req->sg.iov, 0, cb, req); + } +@@ -1958,10 +1960,10 @@ static void nvme_rw_cb(void *opaque, int ret) + } + + if (req->cmd.opcode == NVME_CMD_READ) { +- return nvme_blk_read(blk, offset, nvme_rw_complete_cb, req); ++ return nvme_blk_read(blk, offset, 1, nvme_rw_complete_cb, req); + } + +- return nvme_blk_write(blk, offset, nvme_rw_complete_cb, req); ++ return nvme_blk_write(blk, offset, 1, nvme_rw_complete_cb, req); + } + } + +@@ -3145,7 +3147,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) + + block_acct_start(blk_get_stats(blk), &req->acct, data_size, + BLOCK_ACCT_READ); +- nvme_blk_read(blk, data_offset, nvme_rw_cb, req); ++ nvme_blk_read(blk, data_offset, BDRV_SECTOR_SIZE, nvme_rw_cb, req); + return NVME_NO_COMPLETE; + + invalid: +@@ -3272,7 +3274,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, + + block_acct_start(blk_get_stats(blk), &req->acct, data_size, + BLOCK_ACCT_WRITE); +- nvme_blk_write(blk, data_offset, nvme_rw_cb, req); ++ nvme_blk_write(blk, data_offset, BDRV_SECTOR_SIZE, nvme_rw_cb, req); + } else { + req->aiocb = blk_aio_pwrite_zeroes(blk, data_offset, data_size, + BDRV_REQ_MAY_UNMAP, nvme_rw_cb, +-- +2.41.0.windows.1 + diff --git a/hw-nvme-fix-CVE-2021-3929.patch b/hw-nvme-fix-CVE-2021-3929.patch new file mode 100644 index 0000000000000000000000000000000000000000..c00c465c8d531679bbfe78ad85e59297fc972980 --- /dev/null +++ b/hw-nvme-fix-CVE-2021-3929.patch @@ -0,0 +1,65 @@ +From 4f45d3a6a7c7803d31705e58f0e6356024998ef8 Mon Sep 17 00:00:00 2001 +From: Klaus Jensen +Date: Fri, 17 Dec 2021 10:44:01 +0100 +Subject: [PATCH] hw/nvme: fix CVE-2021-3929 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes CVE-2021-3929 "locally" by denying DMA to the iomem of the +device itself. This still allows DMA to MMIO regions of other devices +(e.g. doing P2P DMA to the controller memory buffer of another NVMe +device). + +Fixes: CVE-2021-3929 +Reported-by: Qiuhao Li +Reviewed-by: Keith Busch +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Klaus Jensen +--- + hw/nvme/ctrl.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 462f79a1f6..40fbda3b03 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -357,6 +357,24 @@ static inline void *nvme_addr_to_pmr(NvmeCtrl *n, hwaddr addr) + return memory_region_get_ram_ptr(&n->pmr.dev->mr) + (addr - n->pmr.cba); + } + ++static inline bool nvme_addr_is_iomem(NvmeCtrl *n, hwaddr addr) ++{ ++ hwaddr hi, lo; ++ ++ /* ++ * The purpose of this check is to guard against invalid "local" access to ++ * the iomem (i.e. controller registers). Thus, we check against the range ++ * covered by the 'bar0' MemoryRegion since that is currently composed of ++ * two subregions (the NVMe "MBAR" and the MSI-X table/pba). Note, however, ++ * that if the device model is ever changed to allow the CMB to be located ++ * in BAR0 as well, then this must be changed. ++ */ ++ lo = n->bar0.addr; ++ hi = lo + int128_get64(n->bar0.size); ++ ++ return addr >= lo && addr < hi; ++} ++ + static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) + { + hwaddr hi = addr + size - 1; +@@ -614,6 +632,10 @@ static uint16_t nvme_map_addr(NvmeCtrl *n, NvmeSg *sg, hwaddr addr, size_t len) + + trace_pci_nvme_map_addr(addr, len); + ++ if (nvme_addr_is_iomem(n, addr)) { ++ return NVME_DATA_TRAS_ERROR; ++ } ++ + if (nvme_addr_is_cmb(n, addr)) { + cmb = true; + } else if (nvme_addr_is_pmr(n, addr)) { +-- +2.27.0 + diff --git a/hw-nvme-fix-memory-leak-in-nvme_dsm.patch b/hw-nvme-fix-memory-leak-in-nvme_dsm.patch new file mode 100644 index 0000000000000000000000000000000000000000..501c8d629e522d782a9d4b7b8e01ec15ec4680c5 --- /dev/null +++ b/hw-nvme-fix-memory-leak-in-nvme_dsm.patch @@ -0,0 +1,40 @@ +From 2a3757a66aad487b64afb8935015c408fd9fdcbb Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 28 Apr 2023 12:01:45 +0800 +Subject: [PATCH] hw/nvme: fix memory leak in nvme_dsm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The iocb (and the allocated memory to hold LBA ranges) leaks if reading +the LBA ranges fails. + +Fix this by adding a free and an unref of the iocb. + +origin commit: https://gitlab.com/qemu-project/qemu/-/commit/4b32319cdacd99be983e1a74128289ef52c5964e +Signed-off-by: Meiyang Wang +Reported-by: Coverity (CID 1508281) +Fixes: d7d1474fd85d ("hw/nvme: reimplement dsm to allow cancellation") +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Klaus Jensen +--- + hw/nvme/ctrl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 40fbda3b03..5f1515828b 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -2381,6 +2381,9 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) + status = nvme_h2c(n, (uint8_t *)iocb->range, sizeof(NvmeDsmRange) * nr, + req); + if (status) { ++ g_free(iocb->range); ++ qemu_aio_unref(iocb); ++ + return status; + } + +-- +2.27.0 + diff --git a/hw-nvme-fix-missing-DNR-on-compare-failure.patch b/hw-nvme-fix-missing-DNR-on-compare-failure.patch new file mode 100644 index 0000000000000000000000000000000000000000..32fe676050ca40b1b0503c175f0bb88b2c49ec6b --- /dev/null +++ b/hw-nvme-fix-missing-DNR-on-compare-failure.patch @@ -0,0 +1,52 @@ +From 5d4fdfc6639103d0ea5754537886921e59abb2fc Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 26 May 2023 10:52:48 +0800 +Subject: [PATCH] hw/nvme: fix missing DNR on compare failure + +Even if the host is somehow using compare to do compare-and-write, the +host should be notified immediately about the compare failure and not +have to wait for the driver to potentially retry the command. + +origin commit: https://gitlab.com/qemu-project/qemu/-/commit/ca2a091802872b265bc6007a2d36276d51d8e4b3 +Signed-off-by: Meiyang Wang +Fixes: 0a384f923f51 ("hw/block/nvme: add compare command") +Reported-by: Jim Harris +Signed-off-by: Klaus Jensen +--- + hw/nvme/ctrl.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 40fbda3b03..0b4df77e3c 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -2123,7 +2123,7 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) + + for (bufp = buf; mbufp < end; bufp += ns->lbaf.ms, mbufp += ns->lbaf.ms) { + if (memcmp(bufp + pil, mbufp + pil, ns->lbaf.ms - pil)) { +- req->status = NVME_CMP_FAILURE; ++ req->status = NVME_CMP_FAILURE | NVME_DNR; + goto out; + } + } +@@ -2132,7 +2132,7 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) + } + + if (memcmp(buf, ctx->mdata.bounce, ctx->mdata.iov.size)) { +- req->status = NVME_CMP_FAILURE; ++ req->status = NVME_CMP_FAILURE | NVME_DNR; + goto out; + } + +@@ -2181,7 +2181,7 @@ static void nvme_compare_data_cb(void *opaque, int ret) + } + + if (memcmp(buf, ctx->data.bounce, ctx->data.iov.size)) { +- req->status = NVME_CMP_FAILURE; ++ req->status = NVME_CMP_FAILURE | NVME_DNR; + goto out; + } + +-- +2.41.0.windows.1 + diff --git a/hw-pci-Fix-a-typo.patch b/hw-pci-Fix-a-typo.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ecad41c6cb4f537b12bb6c7498794838bb41068 --- /dev/null +++ b/hw-pci-Fix-a-typo.patch @@ -0,0 +1,32 @@ +From c7fe3321e6abb3502a7d4366c9fdbe690bfa9ea9 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 17 Mar 2023 11:04:01 +0800 +Subject: [PATCH] hw/pci: Fix a typo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix 'interrutp' typo. + +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: jianchunfu +--- + hw/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 0743dc7c42..b89c36ab80 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -1579,7 +1579,7 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev, + * 9.1: Interrupt routing. Table 9-1 + * + * the PCI Express Base Specification, Revision 2.1 +- * 2.2.8.1: INTx interrutp signaling - Rules ++ * 2.2.8.1: INTx interrupt signaling - Rules + * the Implementation Note + * Table 2-20 + */ +-- +2.27.0 + diff --git a/hw-pci-Trace-IRQ-routing-on-PCI-topology.patch b/hw-pci-Trace-IRQ-routing-on-PCI-topology.patch new file mode 100644 index 0000000000000000000000000000000000000000..873bfcd92456d2a213e4cb7ca3b3efd3c72d80ce --- /dev/null +++ b/hw-pci-Trace-IRQ-routing-on-PCI-topology.patch @@ -0,0 +1,65 @@ +From b5e972454b1c4784c6b8e163016a237c084a1b46 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 17 Mar 2023 11:12:02 +0800 +Subject: [PATCH] hw/pci: Trace IRQ routing on PCI topology +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Trace how IRQ are rooted from EP to RC. + +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: jianchunfu +--- + hw/pci/pci.c | 8 ++++++++ + hw/pci/trace-events | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index b89c36ab80..96dcc738f2 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -269,11 +269,15 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) + { + PCIBus *bus; + for (;;) { ++ int dev_irq = irq_num; + bus = pci_get_bus(pci_dev); + if (!bus) { + return; + } + irq_num = bus->map_irq(pci_dev, irq_num); ++ trace_pci_route_irq(dev_irq, DEVICE(pci_dev)->canonical_path, irq_num, ++ pci_bus_is_root(bus) ? "root-complex" ++ : DEVICE(bus->parent_dev)->canonical_path); + if (bus->set_irq) + break; + pci_dev = bus->parent_dev; +@@ -1531,8 +1535,12 @@ PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) + PCIBus *bus; + + do { ++ int dev_irq = pin; + bus = pci_get_bus(dev); + pin = bus->map_irq(dev, pin); ++ trace_pci_route_irq(dev_irq, DEVICE(dev)->canonical_path, pin, ++ pci_bus_is_root(bus) ? "root-complex" ++ : DEVICE(bus->parent_dev)->canonical_path); + dev = bus->parent_dev; + } while (dev); + +diff --git a/hw/pci/trace-events b/hw/pci/trace-events +index fc777d0b5e..7e294b7e8a 100644 +--- a/hw/pci/trace-events ++++ b/hw/pci/trace-events +@@ -3,6 +3,7 @@ + # pci.c + pci_update_mappings_del(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 + pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 ++pci_route_irq(int dev_irq, const char *dev_path, int parent_irq, const char *parent_path) "IRQ %d @%s -> IRQ %d @%s" + + # pci_host.c + pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" +-- +2.27.0 + diff --git a/hw-pci-bridge-pxb-Fix-missing-swizzle.patch b/hw-pci-bridge-pxb-Fix-missing-swizzle.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d114f54d4291c662a5a8456f1032146e812d5a4 --- /dev/null +++ b/hw-pci-bridge-pxb-Fix-missing-swizzle.patch @@ -0,0 +1,52 @@ +From bf6161d03c1d6a8cb378a2f84743aa45b0ddf84b Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 26 Jul 2023 02:34:48 +0000 +Subject: [PATCH] hw/pci-bridge/pxb: Fix missing swizzle mainline inclusion + commit e609301b458bf6daba478299dc5aea5d1fbaea39 category: bugfix + +--------------------------------------------------------------- + +pxb_map_irq_fn() handled the necessary removal of the swizzle +applied to the PXB interrupts by the bus to which it was attached +but neglected to apply the normal swizzle for PCI root ports +on the expander bridge. + +Result of this was on ARM virt, the PME interrupts for a second +RP on a PXB instance were miss-routed to #45 rather than #46. + +Tested with a selection of different configurations with 1 to 5 +RP per PXB instance. Note on my x86 test setup the PME interrupts +are not triggered so I haven't been able to test this. + +Signed-off-by: Jonathan Cameron +Cc: Michael S. Tsirkin +Cc: Marcel Apfelbaum +Message-Id: <20220118174855.19325-1-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + hw/pci-bridge/pci_expander_bridge.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c +index 10e6e7c2ab..de932286b5 100644 +--- a/hw/pci-bridge/pci_expander_bridge.c ++++ b/hw/pci-bridge/pci_expander_bridge.c +@@ -192,6 +192,12 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) + { + PCIDevice *pxb = pci_get_bus(pci_dev)->parent_dev; + ++ /* ++ * First carry out normal swizzle to handle ++ * multple root ports on a pxb instance. ++ */ ++ pin = pci_swizzle_map_irq_fn(pci_dev, pin); ++ + /* + * The bios does not index the pxb slot number when + * it computes the IRQ because it resides on bus 0 +-- +2.41.0.windows.1 + diff --git a/hw-pci-host-add-pci-intack-write-method.patch b/hw-pci-host-add-pci-intack-write-method.patch deleted file mode 100644 index bb09d022bb7b23fae8cc34e7c7feae65c6e5bc3e..0000000000000000000000000000000000000000 --- a/hw-pci-host-add-pci-intack-write-method.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 80214941ed6ce24983d8f161a7c9532678acc6f1 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:03:57 +0800 -Subject: [PATCH] hw/pci-host: add pci-intack write method - -fix CVE-2020-15469 - -Add pci-intack mmio write method to avoid NULL pointer dereference -issue. - -Reported-by: Lei Sun -Reviewed-by: Li Qiang -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/pci-host/prep.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c -index c564f234af..f03c81f651 100644 ---- a/hw/pci-host/prep.c -+++ b/hw/pci-host/prep.c -@@ -26,6 +26,7 @@ - #include "qemu/osdep.h" - #include "qemu-common.h" - #include "qemu/units.h" -+#include "qemu/log.h" - #include "qapi/error.h" - #include "hw/hw.h" - #include "hw/pci/pci.h" -@@ -117,8 +118,15 @@ static uint64_t raven_intack_read(void *opaque, hwaddr addr, - return pic_read_irq(isa_pic); - } - -+static void raven_intack_write(void *opaque, hwaddr addr, -+ uint64_t data, unsigned size) -+{ -+ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); -+} -+ - static const MemoryRegionOps raven_intack_ops = { - .read = raven_intack_read, -+ .write = raven_intack_write, - .valid = { - .max_access_size = 1, - }, --- -2.27.0 - diff --git a/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch b/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch deleted file mode 100644 index 76497d9ef4f4e111baba53cdd84ac7b7dbecb112..0000000000000000000000000000000000000000 --- a/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 595a0d0a0f21cd73863ea3b78ecccb6e0ea8b7a8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Mon, 1 Jun 2020 16:29:25 +0200 -Subject: [PATCH 2/5] hw/pci/pci_bridge: Correct pci_bridge_io memory region - size -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -memory_region_set_size() handle the 16 Exabytes limit by -special-casing the UINT64_MAX value. This is not a problem -for the 32-bit maximum, 4 GiB. -By using the UINT32_MAX value, the pci_bridge_io MemoryRegion -ends up missing 1 byte: - - (qemu) info mtree - memory-region: pci_bridge_io - 0000000000000000-00000000fffffffe (prio 0, i/o): pci_bridge_io - 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data - 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd - 00000000000001ce-00000000000001d1 (prio 0, i/o): vbe - 0000000000000378-000000000000037f (prio 0, i/o): parallel - 00000000000003b4-00000000000003b5 (prio 0, i/o): vga - ... - -Fix by using the correct value. We now have: - - memory-region: pci_bridge_io - 0000000000000000-00000000ffffffff (prio 0, i/o): pci_bridge_io - 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data - 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd - ... - -Reviewed-by: Peter Maydell -Signed-off-by: Philippe Mathieu-Daudé -Message-Id: <20200601142930.29408-4-f4bug@amsat.org> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Richard Henderson ---- - hw/pci/pci_bridge.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c -index 715b9a4f..d67c691d 100644 ---- a/hw/pci/pci_bridge.c -+++ b/hw/pci/pci_bridge.c -@@ -30,6 +30,7 @@ - */ - - #include "qemu/osdep.h" -+#include "qemu/units.h" - #include "hw/pci/pci_bridge.h" - #include "hw/pci/pci_bus.h" - #include "qemu/module.h" -@@ -381,7 +382,7 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) - memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX); - sec_bus->address_space_io = &br->address_space_io; - memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", -- UINT32_MAX); -+ 4 * GiB); - br->windows = pci_bridge_region_init(br); - QLIST_INIT(&sec_bus->child); - QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); --- -2.23.0 - diff --git a/hw-pci-pcie-Move-hot-plug-capability-check-to-pre_pl.patch b/hw-pci-pcie-Move-hot-plug-capability-check-to-pre_pl.patch deleted file mode 100644 index e2f772c6ac1ac3c7b5cdcbf5e2ac033903a723e3..0000000000000000000000000000000000000000 --- a/hw-pci-pcie-Move-hot-plug-capability-check-to-pre_pl.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 86f70ed090478cc3b569b3606eb2723a0baadb52 Mon Sep 17 00:00:00 2001 -From: Julia Suvorova -Date: Tue, 16 Jun 2020 12:25:36 -0400 -Subject: [PATCH] hw/pci/pcie: Move hot plug capability check to pre_plug - callback - -RH-Author: Julia Suvorova -Message-id: <20200616122536.1027685-1-jusual@redhat.com> -Patchwork-id: 97548 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 1/1] hw/pci/pcie: Move hot plug capability check to pre_plug callback -Bugzilla: 1820531 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Auger Eric -RH-Acked-by: Sergio Lopez Pascual - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1820531 -BRANCH: rhel-av-8.2.1 -UPSTREAM: merged -BREW: 29422092 - -Check for hot plug capability earlier to avoid removing devices attached -during the initialization process. - -Run qemu with an unattached drive: - -drive file=$FILE,if=none,id=drive0 \ - -device pcie-root-port,id=rp0,slot=3,bus=pcie.0,hotplug=off -Hotplug a block device: - device_add virtio-blk-pci,id=blk0,drive=drive0,bus=rp0 -If hotplug fails on plug_cb, drive0 will be deleted. - -Fixes: 0501e1aa1d32a6 ("hw/pci/pcie: Forbid hot-plug if it's disabled on the slot") - -Acked-by: Igor Mammedov -Signed-off-by: Julia Suvorova -Message-Id: <20200604125947.881210-1-jusual@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 0dabc0f6544f2c0310546f6d6cf3b68979580a9c) -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/pci/pcie.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c -index 2b4eedd2bb..b5190a3a55 100644 ---- a/hw/pci/pcie.c -+++ b/hw/pci/pcie.c -@@ -419,6 +419,17 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, - void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) - { -+ PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); -+ uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; -+ uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); -+ -+ /* Check if hot-plug is disabled on the slot */ -+ if (dev->hotplugged && (sltcap & PCI_EXP_SLTCAP_HPC) == 0) { -+ error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'", -+ DEVICE(hotplug_pdev)->id); -+ return; -+ } -+ - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp); - } - --- -2.27.0 - diff --git a/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch deleted file mode 100644 index ad3fc3a8356d20d28805db548c12b2b3745e8054..0000000000000000000000000000000000000000 --- a/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 95cbe18c649a20f98562a993537a67e0ad78bf36 Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Tue, 21 Jan 2020 10:29:34 -0500 -Subject: [PATCH 08/19] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES - config -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Stefan Berger -Reviewed-by: Marc-André Lureau -Reviewed-by: David Gibson -Message-Id: <20200121152935.649898-6-stefanb@linux.ibm.com> -[dwg: Use default in Kconfig rather than select to avoid breaking - Windows host build] -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - hw/tpm/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig -index 4d4ab085..9e67d990 100644 ---- a/hw/tpm/Kconfig -+++ b/hw/tpm/Kconfig -@@ -25,6 +25,6 @@ config TPM_EMULATOR - - config TPM_SPAPR - bool -- default n -+ default y - depends on TPM && PSERIES - select TPMDEV --- -2.23.0 - diff --git a/hw-ppc-Kconfig-MAC_NEWWORLD-should-always-select-USB.patch b/hw-ppc-Kconfig-MAC_NEWWORLD-should-always-select-USB.patch new file mode 100644 index 0000000000000000000000000000000000000000..524446612bf5c87080b046f6fda81df1cd239e1b --- /dev/null +++ b/hw-ppc-Kconfig-MAC_NEWWORLD-should-always-select-USB.patch @@ -0,0 +1,43 @@ +From f2ee3b11fc10dd5353beb8efca7d919668dd332c Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 26 Jun 2023 11:04:33 +0800 +Subject: [PATCH] hw/ppc/Kconfig: MAC_NEWWORLD should always select + USB_OHCI_PCI +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick 9ec08f3569be3bc8bfd4d9b8b0445b9136910661 + +The PowerMacs have an OHCI controller soldered on the motherboard, +so this should always be enabled for the "mac99" machine. +This fixes the problem that QEMU aborts when the user tries to run +the "mac99" machine with a build that has been compiled with the +"--without-default-devices" configure switch. + +Signed-off-by: Thomas Huth +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Reviewed-by: Mark Cave-Ayland +Message-Id: <20230530102041.55527-1-thuth@redhat.com> +Signed-off-by: Daniel Henrique Barboza +Signed-off-by: qihao_yewu +--- + hw/ppc/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig +index 400511c6b7..9e0b7184e3 100644 +--- a/hw/ppc/Kconfig ++++ b/hw/ppc/Kconfig +@@ -119,6 +119,7 @@ config MAC_NEWWORLD + select MAC_PMU + select UNIN_PCI + select FW_CFG_PPC ++ select USB_OHCI_PCI + + config E500 + bool +-- +2.41.0.windows.1 + diff --git a/hw-ppc-spapr_pci.c-Use-device_cold_reset-rather-than.patch b/hw-ppc-spapr_pci.c-Use-device_cold_reset-rather-than.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9522e50023d1d9b8d2c205b06df67b9118b80a0 --- /dev/null +++ b/hw-ppc-spapr_pci.c-Use-device_cold_reset-rather-than.patch @@ -0,0 +1,34 @@ +From 77c0eacba702ad1799b71b00315313e1f9de2e1a Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 10:44:28 +0800 +Subject: [PATCH 22/29] hw/ppc/spapr_pci.c: Use device_cold_reset() rather than + device_legacy_reset() + +In spapr_phb_children_reset() we call device_legacy_reset() to reset any +QOM children of the SPAPR PCI host bridge device. This will not reset +any qbus such a child might own. Switch to device_cold_reset(), which will +reset both the device and its buses. (If the child has no qbuses then +there will be no change in behaviour.) + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + hw/ppc/spapr_pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c +index 5bfd4aa9e5..d3367e8578 100644 +--- a/hw/ppc/spapr_pci.c ++++ b/hw/ppc/spapr_pci.c +@@ -2044,7 +2044,7 @@ static int spapr_phb_children_reset(Object *child, void *opaque) + DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE); + + if (dev) { +- device_legacy_reset(dev); ++ device_cold_reset(dev); + } + + return 0; +-- +2.27.0 + diff --git a/hw-pvrdma-Protect-against-buggy-or-malicious-guest-d.patch b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..07ca361f450df2d31f5ec3ec736d7bcc1e4a43c7 --- /dev/null +++ b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-d.patch @@ -0,0 +1,42 @@ +From 38f8c09d9916e76d2907d68fbe69115aef3a5310 Mon Sep 17 00:00:00 2001 +From: Yuval Shaia +Date: Sun, 3 Apr 2022 12:52:34 +0300 +Subject: [PATCH] hw/pvrdma: Protect against buggy or malicious guest driver + +Guest driver might execute HW commands when shared buffers are not yet +allocated. +This could happen on purpose (malicious guest) or because of some other +guest/host address mapping error. +We need to protect againts such case. + +Fixes: CVE-2022-1050 + +Reported-by: Raven +Signed-off-by: Yuval Shaia +Message-Id: <20220403095234.2210-1-yuval.shaia.ml@gmail.com> +Signed-off-by: Laurent Vivier +Signed-off-by: liuxiangdong +--- + hw/rdma/vmw/pvrdma_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c +index da7ddfa548..89db963c46 100644 +--- a/hw/rdma/vmw/pvrdma_cmd.c ++++ b/hw/rdma/vmw/pvrdma_cmd.c +@@ -796,6 +796,12 @@ int pvrdma_exec_cmd(PVRDMADev *dev) + + dsr_info = &dev->dsr_info; + ++ if (!dsr_info->dsr) { ++ /* Buggy or malicious guest driver */ ++ rdma_error_report("Exec command without dsr, req or rsp buffers"); ++ goto out; ++ } ++ + if (dsr_info->req->hdr.cmd >= sizeof(cmd_handlers) / + sizeof(struct cmd_handler)) { + rdma_error_report("Unsupported command"); +-- +2.27.0 + diff --git a/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch new file mode 100644 index 0000000000000000000000000000000000000000..edc0d62fcecfeb7f5746ceaeb5ac7a98d34186ee --- /dev/null +++ b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch @@ -0,0 +1,65 @@ +From 6532f02449e7a001bc74ea43690d6e1a87a7e3fc Mon Sep 17 00:00:00 2001 +From: Yuval Shaia +Date: Wed, 1 Mar 2023 16:29:26 +0200 +Subject: [PATCH] hw/pvrdma: Protect against buggy or malicious guest driver + +Guest driver allocates and initialize page tables to be used as a ring +of descriptors for CQ and async events. +The page table that represents the ring, along with the number of pages +in the page table is passed to the device. +Currently our device supports only one page table for a ring. + +Let's make sure that the number of page table entries the driver +reports, do not exceeds the one page table size. + +Reported-by: Soul Chen +Signed-off-by: Yuval Shaia +Fixes: CVE-2023-1544 +Message-ID: <20230301142926.18686-1-yuval.shaia.ml@gmail.com> +Signed-off-by: Thomas Huth +--- + hw/rdma/vmw/pvrdma_main.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c +index 91206dbb8e..f99b12a592 100644 +--- a/hw/rdma/vmw/pvrdma_main.c ++++ b/hw/rdma/vmw/pvrdma_main.c +@@ -91,19 +91,33 @@ static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state, + dma_addr_t dir_addr, uint32_t num_pages) + { + uint64_t *dir, *tbl; +- int rc = 0; ++ int max_pages, rc = 0; + + if (!num_pages) { + rdma_error_report("Ring pages count must be strictly positive"); + return -EINVAL; + } + ++ /* ++ * Make sure we can satisfy the requested number of pages in a single ++ * TARGET_PAGE_SIZE sized page table (taking into account that first entry ++ * is reserved for ring-state) ++ */ ++ max_pages = TARGET_PAGE_SIZE / sizeof(dma_addr_t) - 1; ++ if (num_pages > max_pages) { ++ rdma_error_report("Maximum pages on a single directory must not exceed %d\n", ++ max_pages); ++ return -EINVAL; ++ } ++ + dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE); + if (!dir) { + rdma_error_report("Failed to map to page directory (ring %s)", name); + rc = -ENOMEM; + goto out; + } ++ ++ /* We support only one page table for a ring */ + tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE); + if (!tbl) { + rdma_error_report("Failed to map to page table (ring %s)", name); +-- +2.27.0 + diff --git a/hw-qdev-Cosmetic-around-documentation.patch b/hw-qdev-Cosmetic-around-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..cacee6c6a06e3ee2e6f1cb1686e3ec0c2b3d2768 --- /dev/null +++ b/hw-qdev-Cosmetic-around-documentation.patch @@ -0,0 +1,117 @@ +From 14c2249a3caa3afc6252ac61fb700378c4d32a40 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 11:13:33 +0800 +Subject: [PATCH] hw/qdev: Cosmetic around documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 694804ed7b26e66e114a2330887187d697a0d92b + +Add empty lines to have a clearer distinction between different +functions declarations. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Message-Id: <20211218130437.1516929-2-f4bug@amsat.org> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: boringandboring +--- + include/hw/qdev-core.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h +index 20d3066595..59a822ffce 100644 +--- a/include/hw/qdev-core.h ++++ b/include/hw/qdev-core.h +@@ -321,6 +321,7 @@ compat_props_add(GPtrArray *arr, + * The returned object has a reference count of 1. + */ + DeviceState *qdev_new(const char *name); ++ + /** + * qdev_try_new: Try to create a device on the heap + * @name: device type to create +@@ -329,6 +330,7 @@ DeviceState *qdev_new(const char *name); + * does not exist, rather than asserting. + */ + DeviceState *qdev_try_new(const char *name); ++ + /** + * qdev_realize: Realize @dev. + * @dev: device to realize +@@ -347,6 +349,7 @@ DeviceState *qdev_try_new(const char *name); + * qdev_realize_and_unref() instead. + */ + bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); ++ + /** + * qdev_realize_and_unref: Realize @dev and drop a reference + * @dev: device to realize +@@ -372,6 +375,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); + * would be incorrect. For that use case you want qdev_realize(). + */ + bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); ++ + /** + * qdev_unrealize: Unrealize a device + * @dev: device to unrealize +@@ -450,6 +454,7 @@ typedef enum { + * For named input GPIO lines, use qdev_get_gpio_in_named(). + */ + qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); ++ + /** + * qdev_get_gpio_in_named: Get one of a device's named input GPIO lines + * @dev: Device whose GPIO we want +@@ -497,6 +502,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n); + * For named output GPIO lines, use qdev_connect_gpio_out_named(). + */ + void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); ++ + /** + * qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines + * @dev: Device whose GPIO to connect +@@ -524,6 +530,7 @@ void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); + */ + void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, + qemu_irq pin); ++ + /** + * qdev_get_gpio_out_connector: Get the qemu_irq connected to an output GPIO + * @dev: Device whose output GPIO we are interested in +@@ -541,6 +548,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, + * by the platform-bus subsystem. + */ + qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n); ++ + /** + * qdev_intercept_gpio_out: Intercept an existing GPIO connection + * @dev: Device to intercept the outbound GPIO line from +@@ -582,6 +590,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name); + * hold of an input GPIO line to manipulate it. + */ + void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); ++ + /** + * qdev_init_gpio_out: create an array of anonymous output GPIO lines + * @dev: Device to create output GPIOs for +@@ -610,6 +619,7 @@ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); + * handler. + */ + void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); ++ + /** + * qdev_init_gpio_out: create an array of named output GPIO lines + * @dev: Device to create output GPIOs for +@@ -623,6 +633,7 @@ void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); + */ + void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, + const char *name, int n); ++ + /** + * qdev_init_gpio_in_named_with_opaque: create an array of input GPIO lines + * for the specified device +-- +2.27.0 + diff --git a/hw-riscv-boot-Reduce-FDT-address-alignment-constrain.patch b/hw-riscv-boot-Reduce-FDT-address-alignment-constrain.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca3125a43beed631db6e1fc0c283aa22914839d9 --- /dev/null +++ b/hw-riscv-boot-Reduce-FDT-address-alignment-constrain.patch @@ -0,0 +1,46 @@ +From 919af9a7472996b17c45fcd508ae29ec58117e8c Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:39:26 -0800 +Subject: [PATCH] hw/riscv: boot: Reduce FDT address alignment constraints + +cherry picked from commit ec2c62dacc186893a6ce63089f96b1906dd68804 + +We previously stored the device tree at a 16MB alignment from the end of +memory (or 3GB). This means we need at least 16MB of memory to be able +to do this. We don't actually need the FDT to be 16MB aligned, so let's +drop it down to 2MB so that we can support systems with less memory, +while also allowing FDT size expansion. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/992 +Signed-off-by: Alistair Francis +Reviewed-by: Atish Patra +Reviewed-by: Bin Meng +Tested-by: Bin Meng +Message-Id: <20220608062015.317894-1-alistair.francis@opensource.wdc.com> +Signed-off-by: Alistair Francis +Signed-off-by: Wanghe Xiao +--- + hw/riscv/boot.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c +index 519fa455a1..c035aa68f5 100644 +--- a/hw/riscv/boot.c ++++ b/hw/riscv/boot.c +@@ -217,11 +217,11 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) + /* + * We should put fdt as far as possible to avoid kernel/initrd overwriting + * its content. But it should be addressable by 32 bit system as well. +- * Thus, put it at an 16MB aligned address that less than fdt size from the ++ * Thus, put it at an 2MB aligned address that less than fdt size from the + * end of dram or 3GB whichever is lesser. + */ + temp = MIN(dram_end, 3072 * MiB); +- fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 16 * MiB); ++ fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); + + ret = fdt_pack(fdt); + /* Should only fail if we've built a corrupted tree */ +-- +2.27.0 + diff --git a/hw-riscv-virt-Simplify-virt_-get-set-_aclint.patch b/hw-riscv-virt-Simplify-virt_-get-set-_aclint.patch new file mode 100644 index 0000000000000000000000000000000000000000..caa2cc1911056b6715a49c3712a97527e7e86e10 --- /dev/null +++ b/hw-riscv-virt-Simplify-virt_-get-set-_aclint.patch @@ -0,0 +1,39 @@ +From 612fe39ec96f7171501dd3b86af7ca2d9a8efbfe Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 16 Mar 2023 16:27:05 +0800 +Subject: [PATCH] hw/riscv: virt: Simplify virt_{get,set}_aclint() + +There is no need to declare an intermediate "MachineState *ms". + +Signed-off-by: Bin Meng +Signed-off-by: jianchunfu +--- + hw/riscv/virt.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c +index 3af074148e..cd03ba1d76 100644 +--- a/hw/riscv/virt.c ++++ b/hw/riscv/virt.c +@@ -984,16 +984,14 @@ static void virt_machine_instance_init(Object *obj) + + static bool virt_get_aclint(Object *obj, Error **errp) + { +- MachineState *ms = MACHINE(obj); +- RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); + + return s->have_aclint; + } + + static void virt_set_aclint(Object *obj, bool value, Error **errp) + { +- MachineState *ms = MACHINE(obj); +- RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); + + s->have_aclint = value; + } +-- +2.27.0 + diff --git a/hw-rx-rx-gdbsim-DTB-load-address-aligned-of-16byte.patch b/hw-rx-rx-gdbsim-DTB-load-address-aligned-of-16byte.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1959c8c107b7a909844a7b96d590cd534e52a54 --- /dev/null +++ b/hw-rx-rx-gdbsim-DTB-load-address-aligned-of-16byte.patch @@ -0,0 +1,42 @@ +From 97928027aadb358cdee1a2d0c4152979d867b575 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 21 Aug 2023 06:33:49 +0000 +Subject: [PATCH] hw/rx: rx-gdbsim DTB load address aligned of 16byte. + mainline inclusion commit bcc6f33b671d223a1d7b81491d45c58b35ed6e3e category: + bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +Linux kernel required alined address of DTB. +But missing align in dtb load function. +Fixed to load to the correct address. + +Signed-off-by: Yoshinori Sato +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220207132758.84403-1-ysato@users.sourceforge.jp> +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + hw/rx/rx-gdbsim.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c +index 75d1fec6ca..887083737b 100644 +--- a/hw/rx/rx-gdbsim.c ++++ b/hw/rx/rx-gdbsim.c +@@ -142,7 +142,7 @@ static void rx_gdbsim_init(MachineState *machine) + exit(1); + } + /* DTB is located at the end of SDRAM space. */ +- dtb_offset = machine->ram_size - dtb_size; ++ dtb_offset = ROUND_DOWN(machine->ram_size - dtb_size, 16); + rom_add_blob_fixed("dtb", dtb, dtb_size, + SDRAM_BASE + dtb_offset); + /* Set dtb address to R1 */ +-- +2.41.0.windows.1 + diff --git a/hw-scsi-lsi53c895a-Do-not-abort-when-DMA-requested-a.patch b/hw-scsi-lsi53c895a-Do-not-abort-when-DMA-requested-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..36c85f00192d6db85b41ecda9fa5834071ecbbb1 --- /dev/null +++ b/hw-scsi-lsi53c895a-Do-not-abort-when-DMA-requested-a.patch @@ -0,0 +1,71 @@ +From eb84ec128104b04861283adbc8b0fe7d11f638c0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Tue, 23 Nov 2021 12:17:31 +0100 +Subject: [PATCH 1/4] hw/scsi/lsi53c895a: Do not abort when DMA requested and + no data queued +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If asked for DMA request and no data is available, simply wait +for data to be queued, do not abort. This fixes: + + $ cat << EOF | \ + qemu-system-i386 -nographic -M q35,accel=qtest -serial none \ + -monitor none -qtest stdio -trace lsi* \ + -drive if=none,id=drive0,file=null-co://,file.read-zeroes=on,format=raw \ + -device lsi53c895a,id=scsi0 -device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 + lsi_reset Reset + lsi_reg_write Write reg DSP2 0x2e = 0xff + lsi_reg_write Write reg DSP3 0x2f = 0xff + lsi_execute_script SCRIPTS dsp=0xffff0000 opcode 0x184a3900 arg 0x4a8b2d75 + qemu-system-i386: hw/scsi/lsi53c895a.c:624: lsi_do_dma: Assertion `s->current' failed. + + (gdb) bt + #5 0x00007ffff4e8a3a6 in __GI___assert_fail + (assertion=0x5555560accbc "s->current", file=0x5555560acc28 "hw/scsi/lsi53c895a.c", line=624, function=0x5555560adb18 "lsi_do_dma") at assert.c:101 + #6 0x0000555555aa33b9 in lsi_do_dma (s=0x555557805ac0, out=1) at hw/scsi/lsi53c895a.c:624 + #7 0x0000555555aa5042 in lsi_execute_script (s=0x555557805ac0) at hw/scsi/lsi53c895a.c:1250 + #8 0x0000555555aa757a in lsi_reg_writeb (s=0x555557805ac0, offset=47, val=255 '\377') at hw/scsi/lsi53c895a.c:1984 + #9 0x0000555555aa875b in lsi_mmio_write (opaque=0x555557805ac0, addr=47, val=255, size=1) at hw/scsi/lsi53c895a.c:2095 + +Cc: qemu-stable@nongnu.org +Cc: Gerd Hoffmann +Cc: Vadim Rozenfeld +Cc: Stefan Hajnoczi +Reported-by: Jérôme Poulin +Reported-by: Ruhr-University +Reported-by: Gaoning Pan +Reported-by: Cheolwoo Myung +Fixes: b96a0da06bd ("lsi: move dma_len+dma_buf into lsi_request") +BugLink: https://bugs.launchpad.net/qemu/+bug/697510 +BugLink: https://bugs.launchpad.net/qemu/+bug/1905521 +BugLink: https://bugs.launchpad.net/qemu/+bug/1908515 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/84 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/305 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/552 +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laurent Vivier +Message-Id: <20211123111732.83137-2-philmd@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/lsi53c895a.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 85e907a785..4c431adb77 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -621,8 +621,7 @@ static void lsi_do_dma(LSIState *s, int out) + dma_addr_t addr; + SCSIDevice *dev; + +- assert(s->current); +- if (!s->current->dma_len) { ++ if (!s->current || !s->current->dma_len) { + /* Wait until data is available. */ + trace_lsi_do_dma_unavailable(); + return; +-- +2.27.0 + diff --git a/hw-scsi-lsi53c895a-Fix-reentrancy-issues-in-the-LSI-.patch b/hw-scsi-lsi53c895a-Fix-reentrancy-issues-in-the-LSI-.patch new file mode 100644 index 0000000000000000000000000000000000000000..69170583c94f513dd5cedc0e95d51b414e094edc --- /dev/null +++ b/hw-scsi-lsi53c895a-Fix-reentrancy-issues-in-the-LSI-.patch @@ -0,0 +1,124 @@ +From ef9a2635bf418f2a625e2421d3bfe1fe58ac0bec Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 22 May 2023 11:10:11 +0200 +Subject: [PATCH] hw/scsi/lsi53c895a: Fix reentrancy issues in the LSI + controller (CVE-2023-0330) + +We cannot use the generic reentrancy guard in the LSI code, so +we have to manually prevent endless reentrancy here. The problematic +lsi_execute_script() function has already a way to detect whether +too many instructions have been executed - we just have to slightly +change the logic here that it also takes into account if the function +has been called too often in a reentrant way. + +The code in fuzz-lsi53c895a-test.c has been taken from an earlier +patch by Mauro Matteo Cascella. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1563 +Message-Id: <20230522091011.1082574-1-thuth@redhat.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alexander Bulekov +Signed-off-by: Thomas Huth +Signed-off-by: liuxiangdong +--- + hw/scsi/lsi53c895a.c | 23 +++++++++++++++------ + tests/qtest/fuzz-lsi53c895a-test.c | 32 ++++++++++++++++++++++++++++++ + 2 files changed, 49 insertions(+), 6 deletions(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index b9c9eb0dac..f7559051c5 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1134,15 +1134,24 @@ static void lsi_execute_script(LSIState *s) + uint32_t addr, addr_high; + int opcode; + int insn_processed = 0; ++ static int reentrancy_level; ++ ++ reentrancy_level++; + + s->istat1 |= LSI_ISTAT1_SRUN; + again: +- if (++insn_processed > LSI_MAX_INSN) { +- /* Some windows drivers make the device spin waiting for a memory +- location to change. If we have been executed a lot of code then +- assume this is the case and force an unexpected device disconnect. +- This is apparently sufficient to beat the drivers into submission. +- */ ++ /* ++ * Some windows drivers make the device spin waiting for a memory location ++ * to change. If we have executed more than LSI_MAX_INSN instructions then ++ * assume this is the case and force an unexpected device disconnect. This ++ * is apparently sufficient to beat the drivers into submission. ++ * ++ * Another issue (CVE-2023-0330) can occur if the script is programmed to ++ * trigger itself again and again. Avoid this problem by stopping after ++ * being called multiple times in a reentrant way (8 is an arbitrary value ++ * which should be enough for all valid use cases). ++ */ ++ if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) { + if (!(s->sien0 & LSI_SIST0_UDC)) { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: inf. loop with UDC masked"); +@@ -1596,6 +1605,8 @@ again: + } + } + trace_lsi_execute_script_stop(); ++ ++ reentrancy_level--; + } + + static uint8_t lsi_reg_readb(LSIState *s, int offset) +diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c +index 0f968024c8..9c50958796 100644 +--- a/tests/qtest/fuzz-lsi53c895a-test.c ++++ b/tests/qtest/fuzz-lsi53c895a-test.c +@@ -8,6 +8,36 @@ + #include "qemu/osdep.h" + #include "libqos/libqtest.h" + ++/* ++ * This used to trigger a DMA reentrancy issue ++ * leading to memory corruption bugs like stack ++ * overflow or use-after-free ++ * https://gitlab.com/qemu-project/qemu/-/issues/1563 ++ */ ++static void test_lsi_dma_reentrancy(void) ++{ ++ QTestState *s; ++ ++ s = qtest_init("-M q35 -m 512M -nodefaults " ++ "-blockdev driver=null-co,node-name=null0 " ++ "-device lsi53c810 -device scsi-cd,drive=null0"); ++ ++ qtest_outl(s, 0xcf8, 0x80000804); /* PCI Command Register */ ++ qtest_outw(s, 0xcfc, 0x7); /* Enables accesses */ ++ qtest_outl(s, 0xcf8, 0x80000814); /* Memory Bar 1 */ ++ qtest_outl(s, 0xcfc, 0xff100000); /* Set MMIO Address*/ ++ qtest_outl(s, 0xcf8, 0x80000818); /* Memory Bar 2 */ ++ qtest_outl(s, 0xcfc, 0xff000000); /* Set RAM Address*/ ++ qtest_writel(s, 0xff000000, 0xc0000024); ++ qtest_writel(s, 0xff000114, 0x00000080); ++ qtest_writel(s, 0xff00012c, 0xff000000); ++ qtest_writel(s, 0xff000004, 0xff000114); ++ qtest_writel(s, 0xff000008, 0xff100014); ++ qtest_writel(s, 0xff10002f, 0x000000ff); ++ ++ qtest_quit(s); ++} ++ + /* + * This used to trigger a UAF in lsi_do_msgout() + * https://gitlab.com/qemu-project/qemu/-/issues/972 +@@ -121,6 +151,8 @@ int main(int argc, char **argv) + test_lsi_do_dma_empty_queue); + qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req", + test_lsi_do_msgout_cancel_req); ++ qtest_add_func("fuzz/lsi53c895a/lsi_dma_reentrancy", ++ test_lsi_dma_reentrancy); + } + + return g_test_run(); +-- +2.27.0 + diff --git a/hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch b/hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d286a60ba2e25cc34cbf0fbe65ab532a369a7b0 --- /dev/null +++ b/hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch @@ -0,0 +1,39 @@ +From 19692eed451101e16399673cd5c3ee9c684cfde0 Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Sun, 28 Jan 2024 21:22:14 +0100 +Subject: [PATCH] hw/scsi/lsi53c895a: add missing decrement of reentrancy + counter + +When the maximum count of SCRIPTS instructions is reached, the code +stops execution and returns, but fails to decrement the reentrancy +counter. This effectively renders the SCSI controller unusable +because on next entry the reentrancy counter is still above the limit. + +This bug was seen on HP-UX 10.20 which seems to trigger SCRIPTS +loops. + +Fixes: b987718bbb ("hw/scsi/lsi53c895a: Fix reentrancy issues in the LSI controller (CVE-2023-0330)") +Signed-off-by: Sven Schnelle +Message-ID: <20240128202214.2644768-1-svens@stackframe.org> +Reviewed-by: Thomas Huth +Tested-by: Helge Deller +Signed-off-by: Thomas Huth +--- + hw/scsi/lsi53c895a.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index f7559051c5..71f1505227 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1159,6 +1159,7 @@ again: + lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); + lsi_disconnect(s); + trace_lsi_execute_script_stop(); ++ reentrancy_level--; + return; + } + insn = read_dword(s, s->dsp); +-- +2.27.0 + diff --git a/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch b/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch deleted file mode 100644 index 12c907453efdaa1141217b3adccf27d4099ee924..0000000000000000000000000000000000000000 --- a/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 5ec15fabe78e385a81e44c7944cd05309de7f36e Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 15 Jun 2020 09:26:29 +0200 -Subject: [PATCH 7/9] hw/scsi/megasas: Fix possible out-of-bounds array access - in tracepoints -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Some tracepoints in megasas.c use a guest-controlled value as an index -into the mfi_frame_desc[] array. Thus a malicious guest could cause an -out-of-bounds error here. Fortunately, the impact is very low since this -can only happen when the corresponding tracepoints have been enabled -before, but the problem should be fixed anyway with a proper check. - -Buglink: https://bugs.launchpad.net/qemu/+bug/1882065 -Signed-off-by: Thomas Huth -Message-Id: <20200615072629.32321-1-thuth@redhat.com> -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Paolo Bonzini ---- - hw/scsi/megasas.c | 36 +++++++++++++++++++++++------------- - 1 file changed, 23 insertions(+), 13 deletions(-) - -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 94469e8169..9421f4d14e 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -53,10 +53,6 @@ - #define MEGASAS_FLAG_USE_QUEUE64 1 - #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) - --static const char *mfi_frame_desc[] = { -- "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", -- "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"}; -- - typedef struct MegasasCmd { - uint32_t index; - uint16_t flags; -@@ -182,6 +178,20 @@ static void megasas_frame_set_scsi_status(MegasasState *s, - stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), v); - } - -+static inline const char *mfi_frame_desc(unsigned int cmd) -+{ -+ static const char *mfi_frame_descs[] = { -+ "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", -+ "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop" -+ }; -+ -+ if (cmd < ARRAY_SIZE(mfi_frame_descs)) { -+ return mfi_frame_descs[cmd]; -+ } -+ -+ return "Unknown"; -+} -+ - /* - * Context is considered opaque, but the HBA firmware is running - * in little endian mode. So convert it to little endian, too. -@@ -1669,25 +1679,25 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, - if (is_logical) { - if (target_id >= MFI_MAX_LD || lun_id != 0) { - trace_megasas_scsi_target_not_present( -- mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); -+ mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); - return MFI_STAT_DEVICE_NOT_FOUND; - } - } - sdev = scsi_device_find(&s->bus, 0, target_id, lun_id); - - cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len); -- trace_megasas_handle_scsi(mfi_frame_desc[frame_cmd], is_logical, -+ trace_megasas_handle_scsi(mfi_frame_desc(frame_cmd), is_logical, - target_id, lun_id, sdev, cmd->iov_size); - - if (!sdev || (megasas_is_jbod(s) && is_logical)) { - trace_megasas_scsi_target_not_present( -- mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); -+ mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); - return MFI_STAT_DEVICE_NOT_FOUND; - } - - if (cdb_len > 16) { - trace_megasas_scsi_invalid_cdb_len( -- mfi_frame_desc[frame_cmd], is_logical, -+ mfi_frame_desc(frame_cmd), is_logical, - target_id, lun_id, cdb_len); - megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); - cmd->frame->header.scsi_status = CHECK_CONDITION; -@@ -1705,7 +1715,7 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, - cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd); - if (!cmd->req) { - trace_megasas_scsi_req_alloc_failed( -- mfi_frame_desc[frame_cmd], target_id, lun_id); -+ mfi_frame_desc(frame_cmd), target_id, lun_id); - megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); - cmd->frame->header.scsi_status = BUSY; - s->event_count++; -@@ -1750,17 +1760,17 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) - } - - trace_megasas_handle_io(cmd->index, -- mfi_frame_desc[frame_cmd], target_id, lun_id, -+ mfi_frame_desc(frame_cmd), target_id, lun_id, - (unsigned long)lba_start, (unsigned long)lba_count); - if (!sdev) { - trace_megasas_io_target_not_present(cmd->index, -- mfi_frame_desc[frame_cmd], target_id, lun_id); -+ mfi_frame_desc(frame_cmd), target_id, lun_id); - return MFI_STAT_DEVICE_NOT_FOUND; - } - - if (cdb_len > 16) { - trace_megasas_scsi_invalid_cdb_len( -- mfi_frame_desc[frame_cmd], 1, target_id, lun_id, cdb_len); -+ mfi_frame_desc(frame_cmd), 1, target_id, lun_id, cdb_len); - megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); - cmd->frame->header.scsi_status = CHECK_CONDITION; - s->event_count++; -@@ -1780,7 +1790,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) - lun_id, cdb, cmd); - if (!cmd->req) { - trace_megasas_scsi_req_alloc_failed( -- mfi_frame_desc[frame_cmd], target_id, lun_id); -+ mfi_frame_desc(frame_cmd), target_id, lun_id); - megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); - cmd->frame->header.scsi_status = BUSY; - s->event_count++; --- -2.25.1 - diff --git a/hw-scsi-megasas-Use-uint32_t-for-reply-queue-head-ta.patch b/hw-scsi-megasas-Use-uint32_t-for-reply-queue-head-ta.patch new file mode 100644 index 0000000000000000000000000000000000000000..4577f84f01eebfb61f991aa4d951f487c4b5b588 --- /dev/null +++ b/hw-scsi-megasas-Use-uint32_t-for-reply-queue-head-ta.patch @@ -0,0 +1,79 @@ +From e430aa3df353a19370ebd91421f5a545fa4ce211 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 22:43:05 +0100 +Subject: [PATCH 01/25] hw/scsi/megasas: Use uint32_t for reply queue head/tail + values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While the reply queue values fit in 16-bit, they are accessed +as 32-bit: + + 661: s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa); + 662: s->reply_queue_head %= MEGASAS_MAX_FRAMES; + 663: s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa); + 664: s->reply_queue_tail %= MEGASAS_MAX_FRAMES; + +Having: + + 41:#define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ + +In order to update the ld/st*_pci_dma() API to pass the address +of the value to access, it is simpler to have the head/tail declared +as 32-bit values. Replace the uint16_t by uint32_t, wasting 4 bytes in +the MegasasState structure. + +Acked-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-20-philmd@redhat.com> +--- + hw/scsi/megasas.c | 4 ++-- + hw/scsi/trace-events | 8 ++++---- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 4ff51221d4..6d21bf9fdd 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -109,8 +109,8 @@ struct MegasasState { + uint64_t reply_queue_pa; + void *reply_queue; + uint16_t reply_queue_len; +- uint16_t reply_queue_head; +- uint16_t reply_queue_tail; ++ uint32_t reply_queue_head; ++ uint32_t reply_queue_tail; + uint64_t consumer_pa; + uint64_t producer_pa; + +diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events +index 92d5b40f89..ae8551f279 100644 +--- a/hw/scsi/trace-events ++++ b/hw/scsi/trace-events +@@ -42,18 +42,18 @@ mptsas_config_sas_phy(void *dev, int address, int port, int phy_handle, int dev_ + + # megasas.c + megasas_init_firmware(uint64_t pa) "pa 0x%" PRIx64 " " +-megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at 0x%" PRIx64 " len %d head 0x%" PRIx64 " tail 0x%" PRIx64 " flags 0x%x" ++megasas_init_queue(uint64_t queue_pa, int queue_len, uint32_t head, uint32_t tail, uint32_t flags) "queue at 0x%" PRIx64 " len %d head 0x%" PRIx32 " tail 0x%" PRIx32 " flags 0x%x" + megasas_initq_map_failed(int frame) "scmd %d: failed to map queue" + megasas_initq_mapped(uint64_t pa) "queue already mapped at 0x%" PRIx64 + megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d" + megasas_qf_mapped(unsigned int index) "skip mapped frame 0x%x" + megasas_qf_new(unsigned int index, uint64_t frame) "frame 0x%x addr 0x%" PRIx64 + megasas_qf_busy(unsigned long pa) "all frames busy for frame 0x%lx" +-megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int head, unsigned int tail, int busy) "frame 0x%x count %d context 0x%" PRIx64 " head 0x%x tail 0x%x busy %d" +-megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head 0x%x tail 0x%x busy %d" ++megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, uint32_t head, uint32_t tail, unsigned int busy) "frame 0x%x count %d context 0x%" PRIx64 " head 0x%" PRIx32 " tail 0x%" PRIx32 " busy %u" ++megasas_qf_update(uint32_t head, uint32_t tail, unsigned int busy) "head 0x%" PRIx32 " tail 0x%" PRIx32 " busy %u" + megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" + megasas_qf_complete_noirq(uint64_t context) "context 0x%" PRIx64 " " +-megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy) "context 0x%" PRIx64 " head 0x%x tail 0x%x busy %d" ++megasas_qf_complete(uint64_t context, uint32_t head, uint32_t tail, int busy) "context 0x%" PRIx64 " head 0x%" PRIx32 " tail 0x%" PRIx32 " busy %u" + megasas_frame_busy(uint64_t addr) "frame 0x%" PRIx64 " busy" + megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd 0x%x" + megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu" +-- +2.27.0 + diff --git a/hw-scsi-vhost-scsi-don-t-double-close-vhostfd-on-err.patch b/hw-scsi-vhost-scsi-don-t-double-close-vhostfd-on-err.patch new file mode 100644 index 0000000000000000000000000000000000000000..84db18055bf4c0b9627b072c8d2de7c669ce60d5 --- /dev/null +++ b/hw-scsi-vhost-scsi-don-t-double-close-vhostfd-on-err.patch @@ -0,0 +1,49 @@ +From 69f5f16cee63b0d07ee612b59a0d125780c13bdb Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Fri, 8 Dec 2023 09:13:42 +0800 +Subject: [PATCH] hw/scsi/vhost-scsi: don't double close vhostfd on error + +cherry picked from 539ba1acacb11a0f27a7e7ff7e2a7c1294e0a1ea + +vhost_dev_init calls vhost_dev_cleanup on error, which closes vhostfd, +don't double close it. + +Signed-off-by: Daniil Tatianin +Message-Id: <20211129132358.1110372-2-d-tatianin@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: boringandboring +--- + hw/scsi/vhost-scsi.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c +index b0a9c45e43..5536cc8a88 100644 +--- a/hw/scsi/vhost-scsi.c ++++ b/hw/scsi/vhost-scsi.c +@@ -220,6 +220,11 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) + ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd, + VHOST_BACKEND_TYPE_KERNEL, 0, errp); + if (ret < 0) { ++ /* ++ * vhost_dev_init calls vhost_dev_cleanup on error, which closes ++ * vhostfd, don't double close it. ++ */ ++ vhostfd = -1; + goto free_vqs; + } + +@@ -240,7 +245,9 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) + error_free(vsc->migration_blocker); + virtio_scsi_common_unrealize(dev); + close_fd: +- close(vhostfd); ++ if (vhostfd >= 0) { ++ close(vhostfd); ++ } + return; + } + +-- +2.27.0 + diff --git a/hw-scsi-vhost-scsi-don-t-leak-vqs-on-error.patch b/hw-scsi-vhost-scsi-don-t-leak-vqs-on-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d898ce546de60926c05cce0fede7bbf0102b9e6 --- /dev/null +++ b/hw-scsi-vhost-scsi-don-t-leak-vqs-on-error.patch @@ -0,0 +1,55 @@ +From ad55425ad09197b443c150828ac16dbf4242141f Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 19:45:33 +0800 +Subject: [PATCH] hw/scsi/vhost-scsi: don't leak vqs on error + +cherry picked from b259772afc29ef6af4e911d8e695dd7e2ed31066 + +vhost_dev_init calls vhost_dev_cleanup in case of an error during +initialization, which zeroes out the entire vsc->dev as well as the +vsc->dev.vqs pointer. This prevents us from properly freeing it in free_vqs. +Keep a local copy of the pointer so we can free it later. + +Signed-off-by: Daniil Tatianin +Message-Id: <20211129132358.1110372-1-d-tatianin@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: boringandboring +--- + hw/scsi/vhost-scsi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c +index b0a9c45e43..2fbc7f039d 100644 +--- a/hw/scsi/vhost-scsi.c ++++ b/hw/scsi/vhost-scsi.c +@@ -170,6 +170,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) + Error *err = NULL; + int vhostfd = -1; + int ret; ++ struct vhost_virtqueue *vqs = NULL; + + if (!vs->conf.wwpn) { + error_setg(errp, "vhost-scsi: missing wwpn"); +@@ -213,7 +214,8 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) + } + + vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; +- vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); ++ vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); ++ vsc->dev.vqs = vqs; + vsc->dev.vq_index = 0; + vsc->dev.backend_features = 0; + +@@ -232,7 +234,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) + return; + + free_vqs: +- g_free(vsc->dev.vqs); ++ g_free(vqs); + if (!vsc->migratable) { + migrate_del_blocker(vsc->migration_blocker); + } +-- +2.27.0 + diff --git a/hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch b/hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch deleted file mode 100644 index 42df9650a9e378fbb0d96afbd5b8a844c8ed64c7..0000000000000000000000000000000000000000 --- a/hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 8b8d3992db22a583b69b6e2ae1d9cd87e2179e21 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 18 Sep 2020 10:55:22 +0800 -Subject: [PATCH] hw/sd/sdhci: Fix DMA Transfer Block Size field The 'Transfer - Block Size' field is 12-bit wide. See section '2.2.2 Block Size Register - (Offset 004h)' in datasheet. - -Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 - -diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c -index 7b80b1d9..acf482b8 100644 ---- a/hw/sd/sdhci.c -+++ b/hw/sd/sdhci.c -@@ -1127,7 +1127,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) - break; - case SDHC_BLKSIZE: - if (!TRANSFERRING_DATA(s->prnsts)) { -- MASKED_WRITE(s->blksize, mask, value); -+ MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); - MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); - } - --- -2.23.0 - diff --git a/hw-ssi-Fix-Linux-driver-init-issue-with-xilinx_spi.patch b/hw-ssi-Fix-Linux-driver-init-issue-with-xilinx_spi.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b74eaa48d2e14530138f4a7915c729f4a03b777 --- /dev/null +++ b/hw-ssi-Fix-Linux-driver-init-issue-with-xilinx_spi.patch @@ -0,0 +1,39 @@ +From 58a192d877acfe06964d91ef831597f833ac4f0c Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Mon, 14 Aug 2023 18:57:59 -0700 +Subject: [PATCH] hw/ssi: Fix Linux driver init issue with xilinx_spi + +cherry picked from commit a0eaa126af3c5a43937a22c58cfb9bb36e4a5001 + +The problem is that the Linux driver expects the master transaction inhibit +bit(R_SPICR_MTI) to be set during driver initialization so that it can +detect the fifo size but QEMU defaults it to zero out of reset. The +datasheet indicates this bit is active on reset. + +See page 25, SPI Control Register section: +https://www.xilinx.com/content/dam/xilinx/support/documents/ip_documentation/axi_quad_spi/v3_2/pg153-axi-quad-spi.pdf + +Signed-off-by: Chris Rauer +Message-id: 20230323182811.2641044-1-crauer@google.com +Reviewed-by: Edgar E. Iglesias +Signed-off-by: Peter Maydell +Signed-off-by: Wanghe Xiao +--- + hw/ssi/xilinx_spi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c +index b2819a7ff0..92e7cabf42 100644 +--- a/hw/ssi/xilinx_spi.c ++++ b/hw/ssi/xilinx_spi.c +@@ -156,6 +156,7 @@ static void xlx_spi_do_reset(XilinxSPI *s) + txfifo_reset(s); + + s->regs[R_SPISSR] = ~0; ++ s->regs[R_SPICR] = R_SPICR_MTI; + xlx_spi_update_irq(s); + xlx_spi_update_cs(s); + } +-- +2.41.0.windows.1 + diff --git a/hw-timer-fix-systick-trace-message.patch b/hw-timer-fix-systick-trace-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..42e6a26a54b9e77389f3ab4d03d003fc4b70e345 --- /dev/null +++ b/hw-timer-fix-systick-trace-message.patch @@ -0,0 +1,37 @@ +From 81e188ec0547708416c0cfc426ba9ffcd56fcfc2 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 8 Feb 2024 11:31:02 +0800 +Subject: [PATCH] hw/timer: fix systick trace message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 7c8faaf2a4fa8ad2d291662ac7e7eeea1fe8d47c + +Signed-off-by: Samuel Tardieu +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Laurent Vivier +Message-id: 20240109184508.3189599-1-sam@rfc1149.net +Fixes: ff68dacbc786 ("armv7m: Split systick out from NVIC") +Signed-off-by: Peter Maydell +Signed-off-by: qihao_yewu +--- + hw/timer/trace-events | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/timer/trace-events b/hw/timer/trace-events +index 3eccef8385..8145e18e3d 100644 +--- a/hw/timer/trace-events ++++ b/hw/timer/trace-events +@@ -35,7 +35,7 @@ aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRI + + # armv7m_systick.c + systick_reload(void) "systick reload" +-systick_timer_tick(void) "systick reload" ++systick_timer_tick(void) "systick tick" + systick_read(uint64_t addr, uint32_t value, unsigned size) "systick read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" + systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" + +-- +2.27.0 + diff --git a/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch b/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..c554bb4c3e77d88c4224611962cacc7936e2b478 --- /dev/null +++ b/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch @@ -0,0 +1,38 @@ +From 7f5cf2958ee5d178d058470031b96a82d3002a5c Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 1 Nov 2023 19:00:34 +0800 +Subject: [PATCH] hw/timer/npcm7xx_timer: Prevent timer from counting down past + zero + +cheery-pick from 9ef2629712680e70cbf39d8b6cb1ec0e0e2e72fa + +The counter register is only 24-bits and counts down. If the timer is +running but the qtimer to reset it hasn't fired off yet, there is a chance +the regster read can return an invalid result. + +Signed-off-by: Chris Rauer +Message-id: 20230922181411.2697135-1-crauer@google.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: qihao_yewu +--- + hw/timer/npcm7xx_timer.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c +index 32f5e021f8..a8bd93aeb2 100644 +--- a/hw/timer/npcm7xx_timer.c ++++ b/hw/timer/npcm7xx_timer.c +@@ -138,6 +138,9 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) + /* Convert a time interval in nanoseconds to a timer cycle count. */ + static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) + { ++ if (ns < 0) { ++ return 0; ++ } + return clock_ns_to_ticks(t->ctrl->clock, ns) / + npcm7xx_tcsr_prescaler(t->tcsr); + } +-- +2.27.0 + diff --git a/hw-tpm-rename-Error-parameter-to-more-common-errp.patch b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch deleted file mode 100644 index a47a1ae68da792d7811b9d85cb5cbd5f5d5ac0cd..0000000000000000000000000000000000000000 --- a/hw-tpm-rename-Error-parameter-to-more-common-errp.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f2dceb3cde537210896a2cadb8958cfd310113a3 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Thu, 5 Dec 2019 20:46:30 +0300 -Subject: [PATCH 01/19] hw/tpm: rename Error ** parameter to more common errp -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Stefan Berger -Message-Id: <20191205174635.18758-17-vsementsov@virtuozzo.com> -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Markus Armbruster -Signed-off-by: jiangfangjie ---- - hw/tpm/tpm_emulator.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c -index fc0b512f..38bf5fd6 100644 ---- a/hw/tpm/tpm_emulator.c -+++ b/hw/tpm/tpm_emulator.c -@@ -155,7 +155,7 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, - const uint8_t *in, uint32_t in_len, - uint8_t *out, uint32_t out_len, - bool *selftest_done, -- Error **err) -+ Error **errp) - { - ssize_t ret; - bool is_selftest = false; -@@ -165,20 +165,20 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, - is_selftest = tpm_util_is_selftest(in, in_len); - } - -- ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err); -+ ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); - if (ret != 0) { - return -1; - } - - ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, -- sizeof(struct tpm_resp_hdr), err); -+ sizeof(struct tpm_resp_hdr), errp); - if (ret != 0) { - return -1; - } - - ret = qio_channel_read_all(tpm_emu->data_ioc, - (char *)out + sizeof(struct tpm_resp_hdr), -- tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); -+ tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); - if (ret != 0) { - return -1; - } --- -2.23.0 - diff --git a/hw-usb-core-fix-buffer-overflow.patch b/hw-usb-core-fix-buffer-overflow.patch deleted file mode 100644 index 494955788a2506fd2d28521ff234118025fbe674..0000000000000000000000000000000000000000 --- a/hw-usb-core-fix-buffer-overflow.patch +++ /dev/null @@ -1,46 +0,0 @@ -hw-usb-core-fix-buffer-overflow - -From 18ad0451f113ffc3a2ff59c059d189cca1e42842 Mon Sep 17 00:00:00 2001 -From: root -Date: Wed, 19 Aug 2020 17:04:04 +0800 -Subject: [PATCH] hw/usb/core.c fix buffer overflow - -Store calculated setup_len in a local variable, verify it, - and only write it to the struct (USBDevice->setup_len) in case it passed the - sanity checks. - -This prevents other code (do_token_{in,out} function specifically) -from working with invalid USBDevice->setup_len values and overruning -the USBDevice->setup_buf[] buffer. -Store -Fixes: CVE-2020-14364 -Signed-off-by: Gred Hoffman ---- - hw/usb/core.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/usb/core.c b/hw/usb/core.c -index 5abd128b..12342f13 100644 ---- a/hw/usb/core.c -+++ b/hw/usb/core.c -@@ -144,6 +144,8 @@ static void do_token_setup(USBDevice *s, USBPacket *p) - "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", - s->setup_len, sizeof(s->data_buf)); - p->status = USB_RET_STALL; -+ s->setup_len = 0; -+ s->setup_state = SETUP_STATE_ACK; - return; - } - -@@ -277,6 +279,8 @@ static void do_parameter(USBDevice *s, USBPacket *p) - "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", - s->setup_len, sizeof(s->data_buf)); - p->status = USB_RET_STALL; -+ s->setup_len = 0; -+ s->setup_state = SETUP_STATE_ACK; - return; - } - --- -2.23.0 - diff --git a/hw-usb-dev-mtp-Use-g_mkdir.patch b/hw-usb-dev-mtp-Use-g_mkdir.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e866717a8a86eae95e563f8cbc6ebbb3ddd14ba --- /dev/null +++ b/hw-usb-dev-mtp-Use-g_mkdir.patch @@ -0,0 +1,48 @@ +From af6c51e5ef35cdf966888fb6874944d9615384a8 Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:20:54 -0800 +Subject: [PATCH] hw/usb: dev-mtp: Use g_mkdir() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 34b55848a15bca120d9b9381881c40b045409ee9 + +Use g_mkdir() to create a directory on all platforms. + +Signed-off-by: Bin Meng +Acked-by: Gerd Hoffmann +Signed-off-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20221006151927.2079583-8-bmeng.cn@gmail.com> +Message-Id: <20221027183637.2772968-15-alex.bennee@linaro.org> +Signed-off-by: Wanghe Xiao +--- + hw/usb/dev-mtp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c +index c1d1694fd0..882f6bc72f 100644 +--- a/hw/usb/dev-mtp.c ++++ b/hw/usb/dev-mtp.c +@@ -15,7 +15,7 @@ + #include "qemu/error-report.h" + #include + #include +- ++#include + #include + + +@@ -1623,7 +1623,7 @@ static void usb_mtp_write_data(MTPState *s, uint32_t handle) + if (s->dataset.filename) { + path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename); + if (s->dataset.format == FMT_ASSOCIATION) { +- ret = mkdir(path, mask); ++ ret = g_mkdir(path, mask); + if (!ret) { + usb_mtp_queue_result(s, RES_OK, d->trans, 3, + QEMU_STORAGE_ID, +-- +2.27.0 + diff --git a/hw-usb-hcd-ehci-fix-writeback-order.patch b/hw-usb-hcd-ehci-fix-writeback-order.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d0d61187c5bacca8ad56d6815f153f2fcd73cc3 --- /dev/null +++ b/hw-usb-hcd-ehci-fix-writeback-order.patch @@ -0,0 +1,64 @@ +From fc52088f7aa8a1be3b3c7d135a2aebd28ba4c673 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:57:46 +0000 +Subject: [PATCH] hw/usb/hcd-ehci: fix writeback order mainline inclusion + commit f471e8b060798f26a7fc339c6152f82f22a7b33d category: bugfix + +--------------------------------------------------------------- + +The 'active' bit passes control over a qTD between the guest and the +controller: set to 1 by guest to enable execution by the controller, +and the controller sets it to '0' to hand back control to the guest. + +ehci_state_writeback write two dwords to main memory using DMA: +the third dword of the qTD (containing dt, total bytes to transfer, +cpage, cerr and status) and the fourth dword of the qTD (containing +the offset). + +This commit makes sure the fourth dword is written before the third, +avoiding a race condition where a new offset written into the qTD +by the guest after it observed the status going to go to '0' gets +overwritten by a 'late' DMA writeback of the previous offset. + +This race condition could lead to 'cpage out of range (5)' errors, +and reproduced by: + +./qemu-system-x86_64 -enable-kvm -bios $SEABIOS/bios.bin -m 4096 -device usb-ehci -blockdev driver=file,read-only=on,filename=/home/aengelen/Downloads/openSUSE-Tumbleweed-DVD-i586-Snapshot20220428-Media.iso,node-name=iso -device usb-storage,drive=iso,bootindex=0 -chardev pipe,id=shell,path=/tmp/pipe -device virtio-serial -device virtconsole,chardev=shell -device virtio-rng-pci -serial mon:stdio -nographic + +(press a key, select 'Installation' (2), and accept the default +values. On my machine the 'cpage out of range' is reproduced while +loading the Linux Kernel about once per 7 attempts. With the fix in +this commit it no longer fails) + +This problem was previously reported as a seabios problem in +https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/OUTHT5ISSQJGXPNTUPY3O5E5EPZJCHM3/ +and as a nixos CI build failure in +https://github.com/NixOS/nixpkgs/issues/170803 + +Signed-off-by: Arnout Engelen +Signed-off-by: Gerd Hoffmann + +Signed-off-by: tangbinzy +--- + hw/usb/hcd-ehci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 0289b3696d..f9aa567f5d 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2013,7 +2013,10 @@ static int ehci_state_writeback(EHCIQueue *q) + ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd); + qtd = (uint32_t *) &q->qh.next_qtd; + addr = NLPTR_GET(p->qtdaddr); +- put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2); ++ /* First write back the offset */ ++ put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qtd + 3, 1); ++ /* Then write back the token, clearing the 'active' bit */ ++ put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 1); + ehci_free_packet(p); + + /* +-- +2.27.0 + diff --git a/hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch b/hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch deleted file mode 100644 index 96a45b8100318237976abc51ac2b584b569e018a..0000000000000000000000000000000000000000 --- a/hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch +++ /dev/null @@ -1,40 +0,0 @@ -From b1398dc6f3eb16e006167bdd8666fb7c52918e13 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 15 Sep 2020 23:52:59 +0530 -Subject: [PATCH] hw: usb: hcd-ohci: check for processed TD before retire - -While servicing OHCI transfer descriptors(TD), ohci_service_iso_td -retires a TD if it has passed its time frame. It does not check if -the TD was already processed once and holds an error code in TD_CC. -It may happen if the TD list has a loop. Add check to avoid an -infinite loop condition. - -Signed-off-by: Prasad J Pandit -Reviewed-by: Li Qiang -Message-id: 20200915182259.68522-3-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry-picked from 1be90ebe) -Fix CVE-2020-25625 -Signed-off-by: Alex Chen ---- - hw/usb/hcd-ohci.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c -index 4f6fdbc0a7..ffe52a09d7 100644 ---- a/hw/usb/hcd-ohci.c -+++ b/hw/usb/hcd-ohci.c -@@ -689,6 +689,10 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - the next ISO TD of the same ED */ - trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, - frame_count); -+ if (OHCI_CC_DATAOVERRUN == OHCI_BM(iso_td.flags, TD_CC)) { -+ /* avoid infinite loop */ -+ return 1; -+ } - OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); - ed->head &= ~OHCI_DPTR_MASK; - ed->head |= (iso_td.next & OHCI_DPTR_MASK); --- -2.27.0 - diff --git a/hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch b/hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch deleted file mode 100644 index 0133d70db8abfb7338a57f5cf305c68ac8811e56..0000000000000000000000000000000000000000 --- a/hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 789723b95045b6e44d1d1aef56a8bcb255a10476 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 15 Sep 2020 23:52:58 +0530 -Subject: [PATCH] hw: usb: hcd-ohci: check len and frame_number variables - -While servicing the OHCI transfer descriptors(TD), OHCI host -controller derives variables 'start_addr', 'end_addr', 'len' -etc. from values supplied by the host controller driver. -Host controller driver may supply values such that using -above variables leads to out-of-bounds access issues. -Add checks to avoid them. - -AddressSanitizer: stack-buffer-overflow on address 0x7ffd53af76a0 - READ of size 2 at 0x7ffd53af76a0 thread T0 - #0 ohci_service_iso_td ../hw/usb/hcd-ohci.c:734 - #1 ohci_service_ed_list ../hw/usb/hcd-ohci.c:1180 - #2 ohci_process_lists ../hw/usb/hcd-ohci.c:1214 - #3 ohci_frame_boundary ../hw/usb/hcd-ohci.c:1257 - #4 timerlist_run_timers ../util/qemu-timer.c:572 - #5 qemu_clock_run_timers ../util/qemu-timer.c:586 - #6 qemu_clock_run_all_timers ../util/qemu-timer.c:672 - #7 main_loop_wait ../util/main-loop.c:527 - #8 qemu_main_loop ../softmmu/vl.c:1676 - #9 main ../softmmu/main.c:50 - -Reported-by: Gaoning Pan -Reported-by: Yongkang Jia -Reported-by: Yi Ren -Signed-off-by: Prasad J Pandit -Message-id: 20200915182259.68522-2-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry-picked from 1328fe0c) -Fix CVE-2020-25624 -Signed-off-by: Alex Chen ---- - hw/usb/hcd-ohci.c | 24 ++++++++++++++++++++++-- - 1 file changed, 22 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c -index ffe52a09d7..d2dd8efd58 100644 ---- a/hw/usb/hcd-ohci.c -+++ b/hw/usb/hcd-ohci.c -@@ -733,7 +733,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - } - - start_offset = iso_td.offset[relative_frame_number]; -- next_offset = iso_td.offset[relative_frame_number + 1]; -+ if (relative_frame_number < frame_count) { -+ next_offset = iso_td.offset[relative_frame_number + 1]; -+ } else { -+ next_offset = iso_td.be; -+ } - - if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || - ((relative_frame_number < frame_count) && -@@ -766,7 +770,12 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - } - } else { - /* Last packet in the ISO TD */ -- end_addr = iso_td.be; -+ end_addr = next_offset; -+ } -+ -+ if (start_addr > end_addr) { -+ trace_usb_ohci_iso_td_bad_cc_overrun(start_addr, end_addr); -+ return 1; - } - - if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { -@@ -775,6 +784,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - } else { - len = end_addr - start_addr + 1; - } -+ if (len > sizeof(ohci->usb_buf)) { -+ len = sizeof(ohci->usb_buf); -+ } - - if (len && dir != OHCI_TD_DIR_IN) { - if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, -@@ -977,8 +989,16 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) - if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { - len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); - } else { -+ if (td.cbp > td.be) { -+ trace_usb_ohci_iso_td_bad_cc_overrun(td.cbp, td.be); -+ ohci_die(ohci); -+ return 1; -+ } - len = (td.be - td.cbp) + 1; - } -+ if (len > sizeof(ohci->usb_buf)) { -+ len = sizeof(ohci->usb_buf); -+ } - - pktlen = len; - if (len && dir != OHCI_TD_DIR_IN) { --- -2.27.0 - diff --git a/hw-usb-hcd-xhci-Fix-unbounded-loop-in-xhci_ring_chai.patch b/hw-usb-hcd-xhci-Fix-unbounded-loop-in-xhci_ring_chai.patch new file mode 100644 index 0000000000000000000000000000000000000000..2caeb1c9b5b6a36043914a1eb3afce01b1f35521 --- /dev/null +++ b/hw-usb-hcd-xhci-Fix-unbounded-loop-in-xhci_ring_chai.patch @@ -0,0 +1,74 @@ +From 95970127dcd1d5d2f365f87fa888e5f0baa3cd10 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Thu, 4 Aug 2022 15:13:00 +0200 +Subject: [PATCH] hw/usb/hcd-xhci: Fix unbounded loop in + xhci_ring_chain_length() (CVE-2020-14394) + +The loop condition in xhci_ring_chain_length() is under control of +the guest, and additionally the code does not check for failed DMA +transfers (e.g. if reaching the end of the RAM), so the loop there +could run for a very long time or even forever. Fix it by checking +the return value of dma_memory_read() and by introducing a maximum +loop length. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/646 +Message-Id: <20220804131300.96368-1-thuth@redhat.com> +Reviewed-by: Mauro Matteo Cascella +Acked-by: Gerd Hoffmann +Signed-off-by: Thomas Huth +--- + hw/usb/hcd-xhci.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 47fb79aa4d..ac02548dcf 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -21,6 +21,7 @@ + + #include "qemu/osdep.h" + #include "qemu/timer.h" ++#include "qemu/log.h" + #include "qemu/module.h" + #include "qemu/queue.h" + #include "migration/vmstate.h" +@@ -726,10 +727,14 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) + bool control_td_set = 0; + uint32_t link_cnt = 0; + +- while (1) { ++ do { + TRBType type; +- dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE, +- MEMTXATTRS_UNSPECIFIED); ++ if (dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE, ++ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", ++ __func__); ++ return -1; ++ } + le64_to_cpus(&trb.parameter); + le32_to_cpus(&trb.status); + le32_to_cpus(&trb.control); +@@ -763,7 +768,17 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) + if (!control_td_set && !(trb.control & TRB_TR_CH)) { + return length; + } +- } ++ ++ /* ++ * According to the xHCI spec, Transfer Ring segments should have ++ * a maximum size of 64 kB (see chapter "6 Data Structures") ++ */ ++ } while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE); ++ ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring size!\n", ++ __func__); ++ ++ return -1; + } + + static void xhci_er_reset(XHCIState *xhci, int v) +-- +2.27.0 + diff --git a/hw-usb-hcd-xhci-Reset-the-XHCIState-with-device_cold.patch b/hw-usb-hcd-xhci-Reset-the-XHCIState-with-device_cold.patch new file mode 100644 index 0000000000000000000000000000000000000000..30610073dbe2e61c473b2aa451f318f57b953904 --- /dev/null +++ b/hw-usb-hcd-xhci-Reset-the-XHCIState-with-device_cold.patch @@ -0,0 +1,52 @@ +From 5f738b6b95efbdd8d9398b45e038287c5dd3c413 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Fri, 25 Nov 2022 10:00:58 +0800 +Subject: [PATCH 21/29] hw/usb/hcd-xhci: Reset the XHCIState with + device_cold_reset() + +Currently the hcd-xhci-pci and hcd-xhci-sysbus devices, which are +mostly wrappers around the TYPE_XHCI device, which is a direct +subclass of TYPE_DEVICE. Since TYPE_DEVICE devices are not on any +qbus and do not get automatically reset, the wrapper devices both +reset the TYPE_XHCI device in their own reset functions. However, +they do this using device_legacy_reset(), which will reset the device +itself but not any bus it has. +Switch to device_cold_reset(), which avoids using a deprecated +function and also propagates reset along any child buses. + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + hw/usb/hcd-xhci-pci.c | 2 +- + hw/usb/hcd-xhci-sysbus.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c +index e934b1a5b1..643d4643e4 100644 +--- a/hw/usb/hcd-xhci-pci.c ++++ b/hw/usb/hcd-xhci-pci.c +@@ -85,7 +85,7 @@ static void xhci_pci_reset(DeviceState *dev) + { + XHCIPciState *s = XHCI_PCI(dev); + +- device_legacy_reset(DEVICE(&s->xhci)); ++ device_cold_reset(DEVICE(&s->xhci)); + } + + static int xhci_pci_vmstate_post_load(void *opaque, int version_id) +diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c +index a14e438196..faf57b4797 100644 +--- a/hw/usb/hcd-xhci-sysbus.c ++++ b/hw/usb/hcd-xhci-sysbus.c +@@ -29,7 +29,7 @@ void xhci_sysbus_reset(DeviceState *dev) + { + XHCISysbusState *s = XHCI_SYSBUS(dev); + +- device_legacy_reset(DEVICE(&s->xhci)); ++ device_cold_reset(DEVICE(&s->xhci)); + } + + static void xhci_sysbus_realize(DeviceState *dev, Error **errp) +-- +2.27.0 + diff --git a/hw-usb-hcd-xhci.c-spelling-tranfer.patch b/hw-usb-hcd-xhci.c-spelling-tranfer.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5a5189d41f8cd1bc8b6ebf8bb68cf8720caadbd --- /dev/null +++ b/hw-usb-hcd-xhci.c-spelling-tranfer.patch @@ -0,0 +1,38 @@ +From 755899cd2cb3d808717da99fa1447c3c81cc0dce Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Thu, 7 Dec 2023 18:03:12 -0800 +Subject: [PATCH] hw/usb/hcd-xhci.c: spelling: tranfer + +mainline inclusion +commit d68640f515320bf38617b68c970b569997cf0444 +category: bugfix + +--------------------------------------------------------------- + +Fixes: effaf5a240e03020f4ae953e10b764622c3e87cc +Signed-off-by: Michael Tokarev +Reviewed-by: Thomas Huth +Reviewed-by: Stefan Weil +Message-Id: <20221105114851.306206-1-mjt@msgid.tls.msk.ru> +Signed-off-by: Gerd Hoffmann +Signed-off-by: zhujun2 +--- + hw/usb/hcd-xhci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index ac02548dcf..40300e1bcd 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -775,7 +775,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) + */ + } while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE); + +- qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring size!\n", ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum transfer ring size!\n", + __func__); + + return -1; +-- +2.27.0 + diff --git a/hw-usb-imx-Fix-out-of-bounds-access-in-imx_usbphy_re.patch b/hw-usb-imx-Fix-out-of-bounds-access-in-imx_usbphy_re.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2656f2fc11a0301191078d5291e63db49bd5522 --- /dev/null +++ b/hw-usb-imx-Fix-out-of-bounds-access-in-imx_usbphy_re.patch @@ -0,0 +1,72 @@ +From b8822efafc2012de3e92700afc7524df027c914b Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Thu, 16 Mar 2023 16:49:26 -0700 +Subject: [PATCH] hw/usb/imx: Fix out of bounds access in imx_usbphy_read() + +The i.MX USB Phy driver does not check register ranges, resulting in out of +bounds accesses if an attempt is made to access non-existing PHY registers. +Add range check and conditionally report bad accesses to fix the problem. + +While at it, also conditionally log attempted writes to non-existing or +read-only registers. + +Reported-by: Qiang Liu +Signed-off-by: Guenter Roeck +Tested-by: Qiang Liu +Message-id: 20230316234926.208874-1-linux@roeck-us.net +Link: https://gitlab.com/qemu-project/qemu/-/issues/1408 +Fixes: 0701a5efa015 ("hw/usb: Add basic i.MX USB Phy support") +Signed-off-by: Guenter Roeck +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +--- + hw/usb/imx-usb-phy.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/imx-usb-phy.c b/hw/usb/imx-usb-phy.c +index 5d7a549e34..1a97b36a11 100644 +--- a/hw/usb/imx-usb-phy.c ++++ b/hw/usb/imx-usb-phy.c +@@ -13,6 +13,7 @@ + #include "qemu/osdep.h" + #include "hw/usb/imx-usb-phy.h" + #include "migration/vmstate.h" ++#include "qemu/log.h" + #include "qemu/module.h" + + static const VMStateDescription vmstate_imx_usbphy = { +@@ -90,7 +91,15 @@ static uint64_t imx_usbphy_read(void *opaque, hwaddr offset, unsigned size) + value = s->usbphy[index - 3]; + break; + default: +- value = s->usbphy[index]; ++ if (index < USBPHY_MAX) { ++ value = s->usbphy[index]; ++ } else { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: Read from non-existing USB PHY register 0x%" ++ HWADDR_PRIx "\n", ++ __func__, offset); ++ value = 0; ++ } + break; + } + return (uint64_t)value; +@@ -168,7 +177,13 @@ static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value, + s->usbphy[index - 3] ^= value; + break; + default: +- /* Other registers are read-only */ ++ /* Other registers are read-only or do not exist */ ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: Write to %s USB PHY register 0x%" ++ HWADDR_PRIx "\n", ++ __func__, ++ index >= USBPHY_MAX ? "non-existing" : "read-only", ++ offset); + break; + } + } +-- +2.27.0 + diff --git a/hw-usb-reduce-the-vpcu-cost-of-UHCI-when-VNC-disconn.patch b/hw-usb-reduce-the-vpcu-cost-of-UHCI-when-VNC-disconn.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef734a61a77554550863159a804acf5019f40328 --- /dev/null +++ b/hw-usb-reduce-the-vpcu-cost-of-UHCI-when-VNC-disconn.patch @@ -0,0 +1,459 @@ +From 93f01916f0c1e11f38edb8ccc4118c940d9c089f Mon Sep 17 00:00:00 2001 +From: eillon +Date: Tue, 8 Feb 2022 22:43:59 -0500 +Subject: [PATCH] hw/usb: reduce the vpcu cost of UHCI when VNC disconnect + +Reduce the vpcu cost by set a lower FRAME_TIMER_FREQ of the UHCI +when VNC client disconnected. This can reduce about 3% cost of +vcpu thread. + +Signed-off-by: eillon +--- + hw/usb/core.c | 5 ++-- + hw/usb/desc.c | 7 +++-- + hw/usb/dev-hid.c | 2 +- + hw/usb/hcd-uhci.c | 63 ++++++++++++++++++++++++++++++++++------ + hw/usb/hcd-uhci.h | 1 + + hw/usb/host-libusb.c | 32 ++++++++++++++++++++ + include/hw/usb.h | 1 + + include/qemu/timer.h | 28 ++++++++++++++++++ + ui/vnc.c | 4 +++ + util/qemu-timer.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ + 10 files changed, 197 insertions(+), 15 deletions(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 975f76250a..51b36126ca 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -87,7 +87,7 @@ void usb_device_reset(USBDevice *dev) + return; + } + usb_device_handle_reset(dev); +- dev->remote_wakeup = 0; ++ dev->remote_wakeup &= ~USB_DEVICE_REMOTE_WAKEUP; + dev->addr = 0; + dev->state = USB_STATE_DEFAULT; + } +@@ -105,7 +105,8 @@ void usb_wakeup(USBEndpoint *ep, unsigned int stream) + */ + return; + } +- if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { ++ if ((dev->remote_wakeup & USB_DEVICE_REMOTE_WAKEUP) ++ && dev->port && dev->port->ops->wakeup) { + dev->port->ops->wakeup(dev->port); + } + if (bus->ops->wakeup_endpoint) { +diff --git a/hw/usb/desc.c b/hw/usb/desc.c +index 8b6eaea407..78bbe74c71 100644 +--- a/hw/usb/desc.c ++++ b/hw/usb/desc.c +@@ -751,7 +751,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, + if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) { + data[0] |= 1 << USB_DEVICE_SELF_POWERED; + } +- if (dev->remote_wakeup) { ++ if (dev->remote_wakeup & USB_DEVICE_REMOTE_WAKEUP) { + data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; + } + data[1] = 0x00; +@@ -761,14 +761,15 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, + } + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { +- dev->remote_wakeup = 0; ++ dev->remote_wakeup &= ~USB_DEVICE_REMOTE_WAKEUP; + ret = 0; + } + trace_usb_clear_device_feature(dev->addr, value, ret); + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: ++ dev->remote_wakeup |= USB_DEVICE_REMOTE_WAKEUP_IS_SUPPORTED; + if (value == USB_DEVICE_REMOTE_WAKEUP) { +- dev->remote_wakeup = 1; ++ dev->remote_wakeup |= USB_DEVICE_REMOTE_WAKEUP; + ret = 0; + } + trace_usb_set_device_feature(dev->addr, value, ret); +diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c +index 1c7ae97c30..9fb89f6955 100644 +--- a/hw/usb/dev-hid.c ++++ b/hw/usb/dev-hid.c +@@ -745,7 +745,7 @@ static int usb_ptr_post_load(void *opaque, int version_id) + { + USBHIDState *s = opaque; + +- if (s->dev.remote_wakeup) { ++ if (s->dev.remote_wakeup & USB_DEVICE_REMOTE_WAKEUP) { + hid_pointer_activate(&s->hid); + } + return 0; +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index d1b5657d72..693c68f445 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -44,6 +44,8 @@ + #include "hcd-uhci.h" + + #define FRAME_TIMER_FREQ 1000 ++#define FRAME_TIMER_FREQ_LAZY 10 ++#define USB_DEVICE_NEED_NORMAL_FREQ "QEMU USB Tablet" + + #define FRAME_MAX_LOOPS 256 + +@@ -111,6 +113,22 @@ static void uhci_async_cancel(UHCIAsync *async); + static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); + static void uhci_resume(void *opaque); + ++static int64_t uhci_frame_timer_freq = FRAME_TIMER_FREQ_LAZY; ++ ++static void uhci_set_frame_freq(int freq) ++{ ++ if (freq <= 0) { ++ return; ++ } ++ ++ uhci_frame_timer_freq = freq; ++} ++ ++static qemu_usb_controller qemu_uhci = { ++ .name = "uhci", ++ .qemu_set_freq = uhci_set_frame_freq, ++}; ++ + static inline int32_t uhci_queue_token(UHCI_TD *td) + { + if ((td->token & (0xf << 15)) == 0) { +@@ -353,7 +371,7 @@ static int uhci_post_load(void *opaque, int version_id) + + if (version_id < 2) { + s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + +- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ); ++ (NANOSECONDS_PER_SECOND / uhci_frame_timer_freq); + } + return 0; + } +@@ -394,8 +412,29 @@ static void uhci_port_write(void *opaque, hwaddr addr, + if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { + /* start frame processing */ + trace_usb_uhci_schedule_start(); +- s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + +- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ); ++ ++ /* ++ * If the frequency of frame_timer is too slow, Guest OS (Win2012) would become ++ * blue-screen after hotplugging some vcpus. ++ * If this USB device support the remote-wakeup, the UHCI controller ++ * will enter global suspend mode when there is no input for several seconds. ++ * In this case, Qemu will delete the frame_timer. Since the frame_timer has been deleted, ++ * there is no influence to the performance of Vms. So, we can change the frequency to 1000. ++ * After that the frequency will be safe when we trigger the frame_timer again. ++ * Excepting this, there are two ways to change the frequency: ++ * 1)VNC connect/disconnect;2)attach/detach USB device. ++ */ ++ if ((uhci_frame_timer_freq != FRAME_TIMER_FREQ) ++ && (s->ports[0].port.dev) ++ && (!memcmp(s->ports[0].port.dev->product_desc, ++ USB_DEVICE_NEED_NORMAL_FREQ, strlen(USB_DEVICE_NEED_NORMAL_FREQ))) ++ && (s->ports[0].port.dev->remote_wakeup & USB_DEVICE_REMOTE_WAKEUP_IS_SUPPORTED)) { ++ qemu_log("turn up the frequency of UHCI controller to %d\n", FRAME_TIMER_FREQ); ++ uhci_frame_timer_freq = FRAME_TIMER_FREQ; ++ } ++ ++ s->frame_time = NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ; ++ s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->frame_time; + timer_mod(s->frame_timer, s->expire_time); + s->status &= ~UHCI_STS_HCHALTED; + } else if (!(val & UHCI_CMD_RS)) { +@@ -1083,7 +1122,6 @@ static void uhci_frame_timer(void *opaque) + UHCIState *s = opaque; + uint64_t t_now, t_last_run; + int i, frames; +- const uint64_t frame_t = NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ; + + s->completions_only = false; + qemu_bh_cancel(s->bh); +@@ -1099,14 +1137,14 @@ static void uhci_frame_timer(void *opaque) + } + + /* We still store expire_time in our state, for migration */ +- t_last_run = s->expire_time - frame_t; ++ t_last_run = s->expire_time - s->frame_time; + t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + /* Process up to MAX_FRAMES_PER_TICK frames */ +- frames = (t_now - t_last_run) / frame_t; ++ frames = (t_now - t_last_run) / s->frame_time; + if (frames > s->maxframes) { + int skipped = frames - s->maxframes; +- s->expire_time += skipped * frame_t; ++ s->expire_time += skipped * s->frame_time; + s->frnum = (s->frnum + skipped) & 0x7ff; + frames -= skipped; + } +@@ -1123,7 +1161,7 @@ static void uhci_frame_timer(void *opaque) + /* The spec says frnum is the frame currently being processed, and + * the guest must look at frnum - 1 on interrupt, so inc frnum now */ + s->frnum = (s->frnum + 1) & 0x7ff; +- s->expire_time += frame_t; ++ s->expire_time += s->frame_time; + } + + /* Complete the previous frame(s) */ +@@ -1134,7 +1172,12 @@ static void uhci_frame_timer(void *opaque) + } + s->pending_int_mask = 0; + +- timer_mod(s->frame_timer, t_now + frame_t); ++ /* expire_time is calculated from last frame_time, we should calculate it ++ * according to new frame_time which equals to ++ * NANOSECONDS_PER_SECOND / uhci_frame_timer_freq */ ++ s->expire_time -= s->frame_time - NANOSECONDS_PER_SECOND / uhci_frame_timer_freq; ++ s->frame_time = NANOSECONDS_PER_SECOND / uhci_frame_timer_freq; ++ timer_mod(s->frame_timer, t_now + s->frame_time); + } + + static const MemoryRegionOps uhci_ioport_ops = { +@@ -1196,8 +1239,10 @@ void usb_uhci_common_realize(PCIDevice *dev, Error **errp) + s->bh = qemu_bh_new(uhci_bh, s); + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s); + s->num_ports_vmstate = NB_PORTS; ++ s->frame_time = NANOSECONDS_PER_SECOND / uhci_frame_timer_freq; + QTAILQ_INIT(&s->queues); + ++ qemu_register_usb_controller(&qemu_uhci, QEMU_USB_CONTROLLER_UHCI); + memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s, + "uhci", 0x20); + +diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h +index c85ab7868e..5194d22ab4 100644 +--- a/hw/usb/hcd-uhci.h ++++ b/hw/usb/hcd-uhci.h +@@ -50,6 +50,7 @@ typedef struct UHCIState { + uint16_t status; + uint16_t intr; /* interrupt enable register */ + uint16_t frnum; /* frame number */ ++ uint64_t frame_time; /* frame time in ns */ + uint32_t fl_base_addr; /* frame list base address */ + uint8_t sof_timing; + uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index d0d46dd0a4..8f521ad586 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -945,6 +945,30 @@ static void usb_host_ep_update(USBHostDevice *s) + libusb_free_config_descriptor(conf); + } + ++static unsigned int usb_get_controller_type(int speed) ++{ ++ unsigned int type = MAX_USB_CONTROLLER_TYPES; ++ ++ switch (speed) { ++ case USB_SPEED_SUPER: ++ type = QEMU_USB_CONTROLLER_XHCI; ++ break; ++ case USB_SPEED_HIGH: ++ type = QEMU_USB_CONTROLLER_EHCI; ++ break; ++ case USB_SPEED_FULL: ++ type = QEMU_USB_CONTROLLER_UHCI; ++ break; ++ case USB_SPEED_LOW: ++ type = QEMU_USB_CONTROLLER_OHCI; ++ break; ++ default: ++ break; ++ } ++ ++ return type; ++} ++ + static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) + { + USBDevice *udev = USB_DEVICE(s); +@@ -1054,6 +1078,12 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) + } + + trace_usb_host_open_success(bus_num, addr); ++ ++ /* change ehci frame time freq when USB passthrough */ ++ qemu_log("usb host speed is %d\n", udev->speed); ++ qemu_timer_set_mode(QEMU_TIMER_USB_NORMAL_MODE, ++ usb_get_controller_type(udev->speed)); ++ + return 0; + + fail: +@@ -1129,6 +1159,8 @@ static int usb_host_close(USBHostDevice *s) + } + + usb_host_auto_check(NULL); ++ qemu_timer_set_mode(QEMU_TIMER_USB_LAZY_MODE, ++ usb_get_controller_type(udev->speed)); + return 0; + } + +diff --git a/include/hw/usb.h b/include/hw/usb.h +index 33668dd0a9..fa3a176159 100644 +--- a/include/hw/usb.h ++++ b/include/hw/usb.h +@@ -142,6 +142,7 @@ + + #define USB_DEVICE_SELF_POWERED 0 + #define USB_DEVICE_REMOTE_WAKEUP 1 ++#define USB_DEVICE_REMOTE_WAKEUP_IS_SUPPORTED 2 + + #define USB_DT_DEVICE 0x01 + #define USB_DT_CONFIG 0x02 +diff --git a/include/qemu/timer.h b/include/qemu/timer.h +index 88ef114689..d263fad9a4 100644 +--- a/include/qemu/timer.h ++++ b/include/qemu/timer.h +@@ -91,6 +91,34 @@ struct QEMUTimer { + int scale; + }; + ++#define QEMU_USB_NORMAL_FREQ 1000 ++#define QEMU_USB_LAZY_FREQ 10 ++#define MAX_USB_CONTROLLER_TYPES 4 ++#define QEMU_USB_CONTROLLER_OHCI 0 ++#define QEMU_USB_CONTROLLER_UHCI 1 ++#define QEMU_USB_CONTROLLER_EHCI 2 ++#define QEMU_USB_CONTROLLER_XHCI 3 ++ ++typedef void (*QEMUSetFreqHandler) (int freq); ++ ++typedef struct qemu_usb_controller { ++ const char *name; ++ QEMUSetFreqHandler qemu_set_freq; ++} qemu_usb_controller; ++ ++typedef qemu_usb_controller* qemu_usb_controller_ptr; ++ ++enum qemu_timer_mode { ++ QEMU_TIMER_USB_NORMAL_MODE = 1 << 0, /* Set when VNC connect or ++ * with usb dev passthrough ++ */ ++ QEMU_TIMER_USB_LAZY_MODE = 1 << 1, /* Set when VNC disconnect */ ++}; ++ ++int qemu_register_usb_controller(qemu_usb_controller_ptr controller, ++ unsigned int type); ++int qemu_timer_set_mode(enum qemu_timer_mode mode, unsigned int type); ++ + extern QEMUTimerListGroup main_loop_tlg; + + /* +diff --git a/ui/vnc.c b/ui/vnc.c +index af02522e84..bc86c20370 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -1379,6 +1379,8 @@ void vnc_disconnect_finish(VncState *vs) + g_free(vs->zrle); + g_free(vs->tight); + g_free(vs); ++ ++ qemu_timer_set_mode(QEMU_TIMER_USB_LAZY_MODE, QEMU_USB_CONTROLLER_UHCI); + } + + size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err) +@@ -3333,6 +3335,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, + } + } + } ++ ++ qemu_timer_set_mode(QEMU_TIMER_USB_NORMAL_MODE, QEMU_USB_CONTROLLER_UHCI); + } + + void vnc_start_protocol(VncState *vs) +diff --git a/util/qemu-timer.c b/util/qemu-timer.c +index f36c75e594..40e8c83722 100644 +--- a/util/qemu-timer.c ++++ b/util/qemu-timer.c +@@ -23,6 +23,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/log.h" + #include "qemu/main-loop.h" + #include "qemu/timer.h" + #include "qemu/lockable.h" +@@ -75,6 +76,74 @@ struct QEMUTimerList { + QemuEvent timers_done_ev; + }; + ++typedef struct qemu_controller_timer_state { ++ qemu_usb_controller_ptr controller; ++ int refs; ++} controller_timer_state; ++ ++typedef controller_timer_state* controller_timer_state_ptr; ++ ++static controller_timer_state uhci_timer_state = { ++ .controller = NULL, ++ .refs = 0, ++}; ++ ++static controller_timer_state_ptr \ ++ qemu_usb_controller_tab[MAX_USB_CONTROLLER_TYPES] = {NULL, ++ &uhci_timer_state, ++ NULL, NULL}; ++ ++int qemu_register_usb_controller(qemu_usb_controller_ptr controller, ++ unsigned int type) ++{ ++ if (type != QEMU_USB_CONTROLLER_UHCI) { ++ return 0; ++ } ++ ++ /* for companion EHCI controller will create three UHCI controllers, ++ * we init it only once. ++ */ ++ if (!qemu_usb_controller_tab[type]->controller) { ++ qemu_log("the usb controller (%d) registed frame handler\n", type); ++ qemu_usb_controller_tab[type]->controller = controller; ++ } ++ ++ return 0; ++} ++ ++int qemu_timer_set_mode(enum qemu_timer_mode mode, unsigned int type) ++{ ++ if (type != QEMU_USB_CONTROLLER_UHCI) { ++ qemu_log("the usb controller (%d) no need change frame frep\n", type); ++ return 0; ++ } ++ ++ if (!qemu_usb_controller_tab[type]->controller) { ++ qemu_log("the usb controller (%d) not registed yet\n", type); ++ return 0; ++ } ++ ++ if (mode == QEMU_TIMER_USB_NORMAL_MODE) { ++ if (qemu_usb_controller_tab[type]->refs++ > 0) { ++ return 0; ++ } ++ qemu_usb_controller_tab[type]->controller-> ++ qemu_set_freq(QEMU_USB_NORMAL_FREQ); ++ qemu_log("Set the controller (%d) of freq %d HZ,\n", ++ type, QEMU_USB_NORMAL_FREQ); ++ } else { ++ if (--qemu_usb_controller_tab[type]->refs > 0) { ++ return 0; ++ } ++ qemu_usb_controller_tab[type]->controller-> ++ qemu_set_freq(QEMU_USB_LAZY_FREQ); ++ qemu_log("Set the controller(type:%d) of freq %d HZ,\n", ++ type, QEMU_USB_LAZY_FREQ); ++ } ++ ++ return 0; ++} ++ + /** + * qemu_clock_ptr: + * @type: type of clock +-- +2.27.0 + diff --git a/hw-vfio-common-trace-vfio_connect_container-operatio.patch b/hw-vfio-common-trace-vfio_connect_container-operatio.patch deleted file mode 100644 index bd952359250359770ea8d51711e88be943ee2c72..0000000000000000000000000000000000000000 --- a/hw-vfio-common-trace-vfio_connect_container-operatio.patch +++ /dev/null @@ -1,53 +0,0 @@ -From b107e6ec2a5a34e0ba95345a89dcf5f505ad9da4 Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Mon, 22 Feb 2021 10:13:55 -0500 -Subject: [PATCH] hw/vfio/common: trace vfio_connect_container operations - -We currently trace vfio_disconnect_container() but we do not trace -the container <-> group creation, which can be useful to understand -the VFIO topology. - -Signed-off-by: Eric Auger -Signed-off-by: Kunkun Jiang ---- - hw/vfio/common.c | 3 +++ - hw/vfio/trace-events | 2 ++ - 2 files changed, 5 insertions(+) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 206fb83e28..fefa2ccfdf 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -1848,6 +1848,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - QLIST_FOREACH(container, &space->containers, next) { - if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { - group->container = container; -+ trace_vfio_connect_existing_container(group->groupid, -+ container->fd); - QLIST_INSERT_HEAD(&container->group_list, group, container_next); - vfio_kvm_device_add_group(group); - return 0; -@@ -1881,6 +1883,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - if (ret) { - goto free_container_exit; - } -+ trace_vfio_connect_new_container(group->groupid, container->fd); - - switch (container->iommu_type) { - case VFIO_TYPE1v2_IOMMU: -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 575ebde6e0..561dc6e758 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -102,6 +102,8 @@ vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t si - vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 - vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 - vfio_disconnect_container(int fd) "close container->fd=%d" -+vfio_connect_existing_container(int groupid, int container_fd) "group=%d existing container fd=%d" -+vfio_connect_new_container(int groupid, int container_fd) "group=%d new container fd=%d" - vfio_put_group(int fd) "close group->fd=%d" - vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" - vfio_put_base_device(int fd) "close vdev->fd=%d" --- -2.27.0 - diff --git a/hw-vfio-pci-quirks-Sanitize-capability-pointer.patch b/hw-vfio-pci-quirks-Sanitize-capability-pointer.patch new file mode 100644 index 0000000000000000000000000000000000000000..c6c480839523301648eb24f82915a85df1d001e7 --- /dev/null +++ b/hw-vfio-pci-quirks-Sanitize-capability-pointer.patch @@ -0,0 +1,60 @@ +From 193240c79f5c95aaf86b2998975189f1873ebcec Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Fri, 18 Aug 2023 14:41:45 +0800 +Subject: [PATCH] hw/vfio/pci-quirks: Sanitize capability pointer Coverity + reports a tained scalar when traversing the capabilities chain (CID 1516589). + In practice I've never seen a device with a chain so broken as to cause an + issue, but it's also pretty easy to sanitize. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: f6b30c1 ("hw/vfio/pci-quirks: Support alternate offset for +GPUDirect Cliques") +Signed-off-by: Alex Williamson +Reviewed-by: Cédric Le Goater +Signed-off-by: Cédric Le Goater + +Signed-off-by: Zhongrui Tang +--- + hw/vfio/pci-quirks.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index 7a8e6efcdc..a911e04a79 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1717,6 +1717,12 @@ const PropertyInfo qdev_prop_nv_gpudirect_clique = { + .set = set_nv_gpudirect_clique_id, + }; + ++static bool is_valid_std_cap_offset(uint8_t pos) ++{ ++ return (pos >= PCI_STD_HEADER_SIZEOF && ++ pos <= (PCI_CFG_SPACE_SIZE - PCI_CAP_SIZEOF)); ++} ++ + static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) + { + PCIDevice *pdev = &vdev->pdev; +@@ -1750,7 +1756,7 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) + */ + ret = pread(vdev->vbasedev.fd, &tmp, 1, + vdev->config_offset + PCI_CAPABILITY_LIST); +- if (ret != 1 || !tmp) { ++ if (ret != 1 || !is_valid_std_cap_offset(tmp)) { + error_setg(errp, "NVIDIA GPUDirect Clique ID: error getting cap list"); + return -EINVAL; + } +@@ -1762,7 +1768,7 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) + d4_conflict = true; + } + tmp = pdev->config[tmp + PCI_CAP_LIST_NEXT]; +- } while (tmp); ++ } while (is_valid_std_cap_offset(tmp)); + + if (!c8_conflict) { + pos = 0xC8; +-- +2.41.0.windows.1 + diff --git a/hw-vfio-pci-quirks-Support-alternate-offset-for-GPUD.patch b/hw-vfio-pci-quirks-Support-alternate-offset-for-GPUD.patch new file mode 100644 index 0000000000000000000000000000000000000000..7232ad3a34f8df7436134aec2368f1cf6c6c695c --- /dev/null +++ b/hw-vfio-pci-quirks-Support-alternate-offset-for-GPUD.patch @@ -0,0 +1,95 @@ +From d672e2f137933b26bd9b3488a873830435eadba5 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 3 Aug 2023 15:10:16 +0800 +Subject: [PATCH] hw/vfio/pci-quirks: Support alternate offset for GPUDirect + Cliques +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +NVIDIA Turing and newer GPUs implement the MSI-X capability at the offset +previously reserved for use by hypervisors to implement the GPUDirect +Cliques capability. A revised specification provides an alternate +location. Add a config space walk to the quirk to check for conflicts, +allowing us to fall back to the new location or generate an error at the +quirk setup rather than when the real conflicting capability is added +should there be no available location. + +Signed-off-by: Alex Williamson +Reviewed-by: Cédric Le Goater +Signed-off-by: Cédric Le Goater + +Signed-off-by: Zhongrui Tang +--- + hw/vfio/pci-quirks.c | 41 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 40 insertions(+), 1 deletion(-) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index 1222ccff0b..7a8e6efcdc 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1677,6 +1677,9 @@ void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev) + * +---------------------------------+---------------------------------+ + * + * https://lists.gnu.org/archive/html/qemu-devel/2017-08/pdfUda5iEpgOS.pdf ++ * ++ * Specification for Turning and later GPU architectures: ++ * https://lists.gnu.org/archive/html/qemu-devel/2023-06/pdf142OR4O4c2.pdf + */ + static void get_nv_gpudirect_clique_id(Object *obj, Visitor *v, + const char *name, void *opaque, +@@ -1717,7 +1720,9 @@ const PropertyInfo qdev_prop_nv_gpudirect_clique = { + static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) + { + PCIDevice *pdev = &vdev->pdev; +- int ret, pos = 0xC8; ++ int ret, pos; ++ bool c8_conflict = false, d4_conflict = false; ++ uint8_t tmp; + + if (vdev->nv_gpudirect_clique == 0xFF) { + return 0; +@@ -1734,6 +1739,40 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) + return -EINVAL; + } + ++ /* ++ * Per the updated specification above, it's recommended to use offset ++ * D4h for Turing and later GPU architectures due to a conflict of the ++ * MSI-X capability at C8h. We don't know how to determine the GPU ++ * architecture, instead we walk the capability chain to mark conflicts ++ * and choose one or error based on the result. ++ * ++ * NB. Cap list head in pdev->config is already cleared, read from device. ++ */ ++ ret = pread(vdev->vbasedev.fd, &tmp, 1, ++ vdev->config_offset + PCI_CAPABILITY_LIST); ++ if (ret != 1 || !tmp) { ++ error_setg(errp, "NVIDIA GPUDirect Clique ID: error getting cap list"); ++ return -EINVAL; ++ } ++ ++ do { ++ if (tmp == 0xC8) { ++ c8_conflict = true; ++ } else if (tmp == 0xD4) { ++ d4_conflict = true; ++ } ++ tmp = pdev->config[tmp + PCI_CAP_LIST_NEXT]; ++ } while (tmp); ++ ++ if (!c8_conflict) { ++ pos = 0xC8; ++ } else if (!d4_conflict) { ++ pos = 0xD4; ++ } else { ++ error_setg(errp, "NVIDIA GPUDirect Clique ID: invalid config space"); ++ return -EINVAL; ++ } ++ + ret = pci_add_capability(pdev, PCI_CAP_ID_VNDR, pos, 8, errp); + if (ret < 0) { + error_prepend(errp, "Failed to add NVIDIA GPUDirect cap: "); +-- +2.41.0.windows.1 + diff --git a/hw-vhost-user-blk-turn-on-VIRTIO_BLK_F_SIZE_MAX-feat.patch b/hw-vhost-user-blk-turn-on-VIRTIO_BLK_F_SIZE_MAX-feat.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c874a42f4dfe5b583aa612a2b6f7ff612fe45a4 --- /dev/null +++ b/hw-vhost-user-blk-turn-on-VIRTIO_BLK_F_SIZE_MAX-feat.patch @@ -0,0 +1,34 @@ +From 4f66d261c0f20189e387de57baca17167cc542ab Mon Sep 17 00:00:00 2001 +From: Andy Pei +Date: Mon, 3 Jan 2022 17:28:12 +0800 +Subject: [PATCH] hw/vhost-user-blk: turn on VIRTIO_BLK_F_SIZE_MAX feature for + virtio blk device + +Turn on pre-defined feature VIRTIO_BLK_F_SIZE_MAX for virtio blk device to +avoid guest DMA request sizes which are too large for hardware spec. + +Signed-off-by: dinglimin +Signed-off-by: Andy Pei +Message-Id: <1641202092-149677-1-git-send-email-andy.pei@intel.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Raphael Norwitz +--- + hw/block/vhost-user-blk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index ba13cb87e5..eb1264afc7 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -252,6 +252,7 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, + VHostUserBlk *s = VHOST_USER_BLK(vdev); + + /* Turn on pre-defined features */ ++ virtio_add_feature(&features, VIRTIO_BLK_F_SIZE_MAX); + virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); + virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); + virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); +-- +2.27.0 + diff --git a/hw-virtio-add-some-vhost-user-trace-events.patch b/hw-virtio-add-some-vhost-user-trace-events.patch new file mode 100644 index 0000000000000000000000000000000000000000..5979d6250ac21e9b2d5adde6501a64bb86c7c894 --- /dev/null +++ b/hw-virtio-add-some-vhost-user-trace-events.patch @@ -0,0 +1,70 @@ +From f5b5cba0b86caacdea334725bedcdfb689504b3a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Tue, 2 Aug 2022 10:49:57 +0100 +Subject: [PATCH] hw/virtio: add some vhost-user trace events +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are useful for tracing the lifetime of vhost-user connections. + +Signed-off-by: Alex Bennée +Message-Id: <20220802095010.3330793-10-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 4 ++++ + hw/virtio/vhost.c | 6 ++++++ + 2 files changed, 10 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 63c7668e5b..b8a33b2a83 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -8,6 +8,10 @@ vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, + vhost_section(const char *name) "%s" + vhost_reject_section(const char *name, int d) "%s:%d" + vhost_iotlb_miss(void *dev, int step) "%p step %d" ++vhost_dev_cleanup(void *dev) "%p" ++vhost_dev_start(void *dev, const char *name) "%p:%s" ++vhost_dev_stop(void *dev, const char *name) "%p:%s" ++ + + # vhost-user.c + vhost_user_postcopy_end_entry(void) "" +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index c1f5cb5b91..86c727d2ab 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1460,6 +1460,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) + { + int i; + ++ trace_vhost_dev_cleanup(hdev); ++ + for (i = 0; i < hdev->nvqs; ++i) { + vhost_virtqueue_cleanup(hdev->vqs + i); + } +@@ -1766,6 +1768,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ trace_vhost_dev_start(hdev, vdev->name); ++ + vdev->vhost_started = true; + hdev->started = true; + hdev->vdev = vdev; +@@ -1852,6 +1856,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ trace_vhost_dev_stop(hdev, vdev->name); ++ + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } +-- +2.27.0 + diff --git a/hw-virtio-add-vhost_user_-read-write-trace-points.patch b/hw-virtio-add-vhost_user_-read-write-trace-points.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca9de06066b268c039c0c4a58a0a029cea815c5c --- /dev/null +++ b/hw-virtio-add-vhost_user_-read-write-trace-points.patch @@ -0,0 +1,62 @@ +From 57451ee8e278827ef0ab592d565c14076dd62fd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 21 Mar 2022 15:30:27 +0000 +Subject: [PATCH] hw/virtio: add vhost_user_[read|write] trace points +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are useful when trying to debug the initial vhost-user +negotiation, especially when it hard to get logging from the low level +library on the other side. + +Signed-off-by: Alex Bennée + +Message-Id: <20220321153037.3622127-4-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 2 ++ + hw/virtio/vhost-user.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 37c1555330..63c7668e5b 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -21,6 +21,8 @@ vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_siz + vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 + vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 + vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 ++vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" ++vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + + # vhost-vdpa.c + vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 358dc82010..ea6d40eb5f 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -491,6 +491,8 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, + return ret < 0 ? -saved_errno : -EIO; + } + ++ trace_vhost_user_write(msg->hdr.request, msg->hdr.flags); ++ + return 0; + } + +@@ -544,6 +546,8 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + } + } + ++ trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); ++ + return 0; + } + +-- +2.27.0 + diff --git a/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch b/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch new file mode 100644 index 0000000000000000000000000000000000000000..76a7d1c9bc309e0974acef7804821dc5d27645ed --- /dev/null +++ b/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch @@ -0,0 +1,135 @@ +From 6cbac9f34c67e2a2e28109152957f5eca35b6e73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 10 Jul 2023 16:35:05 +0100 +Subject: [PATCH] hw/virtio: fix typo in VIRTIO_CONFIG_IRQ_IDX comments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 544f0278af (virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX) +Signed-off-by: Alex Bennée +Message-Id: <20230710153522.3469097-4-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 4 ++-- + hw/net/virtio-net.c | 4 ++-- + hw/virtio/vhost-user-fs.c | 4 ++-- + hw/virtio/vhost-vsock-common.c | 4 ++-- + hw/virtio/virtio-crypto.c | 4 ++-- + 5 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 1c78272a83..4363e34db1 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -487,7 +487,7 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -504,7 +504,7 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index ae37b3461b..3e1fa6adf3 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3249,7 +3249,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + } + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return false + */ + +@@ -3281,7 +3281,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + } + /* + *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 0c6ecd3b4f..5ac5dcce49 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -163,7 +163,7 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -179,7 +179,7 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index e4a8d90f4c..b9cf5f3f29 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -127,7 +127,7 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -144,7 +144,7 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 9f7dcc88ba..61b421aab3 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -960,7 +960,7 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -979,7 +979,7 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +-- +2.27.0 + diff --git a/hw-virtio-fix-vhost_user_read-tracepoint.patch b/hw-virtio-fix-vhost_user_read-tracepoint.patch new file mode 100644 index 0000000000000000000000000000000000000000..6185ae48b4fcd425b364ebd27e5903c9266e5a49 --- /dev/null +++ b/hw-virtio-fix-vhost_user_read-tracepoint.patch @@ -0,0 +1,48 @@ +From 09081b494d4aad3137fd375f5f18edc63c7e5d10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Thu, 28 Jul 2022 14:55:03 +0100 +Subject: [PATCH] hw/virtio: fix vhost_user_read tracepoint +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As reads happen in the callback we were never seeing them. We only +really care about the header so move the tracepoint to when the header +is complete. + +Fixes: 6ca6d8ee9d (hw/virtio: add vhost_user_[read|write] trace points) +Signed-off-by: Alex Bennée +Acked-by: Jason Wang +Message-Id: <20220728135503.1060062-5-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index ea6d40eb5f..937b3021e9 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -297,6 +297,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + return -EPROTO; + } + ++ trace_vhost_user_read(msg->hdr.request, msg->hdr.flags); ++ + return 0; + } + +@@ -546,8 +548,6 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + } + } + +- trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); +- + return 0; + } + +-- +2.27.0 + diff --git a/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch b/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2dea4b59ec023616bfdb8936e09520368846251 --- /dev/null +++ b/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch @@ -0,0 +1,52 @@ +From edbbc82bdf7cdb21604bb1c8b4a222691b3c3665 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Thu, 28 Jul 2022 14:55:01 +0100 +Subject: [PATCH] hw/virtio: gracefully handle unset vhost_dev vdev +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I've noticed asserts firing because we query the status of vdev after +a vhost connection is closed down. Rather than faulting on the NULL +indirect just quietly reply false. + +Signed-off-by: Alex Bennée +Message-Id: <20220728135503.1060062-3-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2f0ddd35d6..8e8657fb0d 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -310,7 +310,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + dev->log_size = size; + } + +-static int vhost_dev_has_iommu(struct vhost_dev *dev) ++static bool vhost_dev_has_iommu(struct vhost_dev *dev) + { + VirtIODevice *vdev = dev->vdev; + +@@ -320,8 +320,12 @@ static int vhost_dev_has_iommu(struct vhost_dev *dev) + * does not have IOMMU, there's no need to enable this feature + * which may cause unnecessary IOTLB miss/update transactions. + */ +- return virtio_bus_device_iommu_enabled(vdev) && +- virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ if (vdev) { ++ return virtio_bus_device_iommu_enabled(vdev) && ++ virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ } else { ++ return false; ++ } + } + + static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, +-- +2.27.0 + diff --git a/hw-virtio-vdpa-Fix-leak-of-host-notifier-memory-regi.patch b/hw-virtio-vdpa-Fix-leak-of-host-notifier-memory-regi.patch new file mode 100644 index 0000000000000000000000000000000000000000..ada19f02f2e7c43c6b1392d4f86acdf5ba9c58d7 --- /dev/null +++ b/hw-virtio-vdpa-Fix-leak-of-host-notifier-memory-regi.patch @@ -0,0 +1,50 @@ +From 862a150140b95bbd23d174307aacd06f65d36f1c Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 21 Jul 2023 07:26:44 +0000 +Subject: [PATCH] hw/virtio: vdpa: Fix leak of host-notifier memory-region + mainline inclusion commit 98f7607ecda00dea3cbb2ed7b4427c96846efb83 category: + bugfix + +--------------------------------------------------------------- + +If call virtio_queue_set_host_notifier_mr fails, should free +host-notifier memory-region. + +This problem can trigger a coredump with some vDPA drivers (mlx5, +but not with the vdpasim), if we unplug the virtio-net card from +the guest after a stop/start. + +The same fix has been done for vhost-user: + 1f89d3b91e3e ("hw/virtio: Fix leak of host-notifier memory-region") + +Fixes: d0416d487bd5 ("vhost-vdpa: map virtqueue notification area if possible") +Cc: jasowang@redhat.com +Resolves: https://bugzilla.redhat.com/2027208 +Signed-off-by: Laurent Vivier +Message-Id: <20220211170259.1388734-1-lvivier@redhat.com> +Cc: qemu-stable@nongnu.org +Acked-by: Jason Wang +Reviewed-by: Stefano Garzarella +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + hw/virtio/vhost-vdpa.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f285edb786..225c9b1730 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -417,6 +417,7 @@ static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index) + g_free(name); + + if (virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, true)) { ++ object_unparent(OBJECT(&n->mr)); + munmap(addr, page_size); + goto err; + } +-- +2.41.0.windows.1 + diff --git a/hw-virtio-vhost-Fix-typo-in-comment.patch b/hw-virtio-vhost-Fix-typo-in-comment.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3da1d04e45f6b5925d50d875a21591ce0f7c69d --- /dev/null +++ b/hw-virtio-vhost-Fix-typo-in-comment.patch @@ -0,0 +1,34 @@ +From 7c0b752e2bfd9c6e12570d7a9229a6f733d9ca59 Mon Sep 17 00:00:00 2001 +From: Leonardo Garcia +Date: Tue, 23 Nov 2021 08:48:31 -0300 +Subject: [PATCH] hw/virtio/vhost: Fix typo in comment. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Leonardo Garcia +Reviewed-by: Laurent Vivier +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 22ec9e1ef7..2f0ddd35d6 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -318,7 +318,7 @@ static int vhost_dev_has_iommu(struct vhost_dev *dev) + * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support + * incremental memory mapping API via IOTLB API. For platform that + * does not have IOMMU, there's no need to enable this feature +- * which may cause unnecessary IOTLB miss/update trnasactions. ++ * which may cause unnecessary IOTLB miss/update transactions. + */ + return virtio_bus_device_iommu_enabled(vdev) && + virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); +-- +2.27.0 + diff --git a/hw-virtio-virtio-iommu-pci-Enforce-the-device-is-plu.patch b/hw-virtio-virtio-iommu-pci-Enforce-the-device-is-plu.patch new file mode 100644 index 0000000000000000000000000000000000000000..f442f06b339a0ced45647349d10ee50bdeb7fba0 --- /dev/null +++ b/hw-virtio-virtio-iommu-pci-Enforce-the-device-is-plu.patch @@ -0,0 +1,69 @@ +From a2323aa79da71c92e818306f1e18184619309a35 Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:03:07 -0800 +Subject: [PATCH] hw/virtio/virtio-iommu-pci: Enforce the device is plugged on + the root bus + +cherry picked from commit e72cfabf4ef2f0031e5d0b8129fb1533d383654d + +In theory the virtio-iommu-pci could be plugged anywhere in the PCIe +topology and as long as the dt/acpi info are properly built this should +work. However at the moment we fail to do that because the +virtio-iommu-pci BDF is not computed at plug time and in that case +vms->virtio_iommu_bdf gets an incorrect value. + +For instance if the virtio-iommu-pci is plugged onto a pcie root port +and the virtio-iommu protects a virtio-block-pci device the guest does +not boot. + +So let's do not pretend we do support this case and fail the initialize() +if we detect the virtio-iommu-pci is plugged anywhere else than on the +root bus. Anyway this ability is not needed. + +Signed-off-by: Eric Auger +Message-Id: <20221012163448.121368-1-eric.auger@redhat.com> +Reviewed-by: Jean-Philippe Brucker +Tested-by: Jean-Philippe Brucker +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Wanghe Xiao +--- + hw/virtio/virtio-iommu-pci.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c +index a160ae6b41..37eb2fb979 100644 +--- a/hw/virtio/virtio-iommu-pci.c ++++ b/hw/virtio/virtio-iommu-pci.c +@@ -44,6 +44,7 @@ static Property virtio_iommu_pci_properties[] = { + static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + { + VirtIOIOMMUPCI *dev = VIRTIO_IOMMU_PCI(vpci_dev); ++ PCIBus *pbus = pci_get_bus(&vpci_dev->pci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); + +@@ -65,11 +66,17 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) { + error_setg(errp, "reserved region %d has an invalid type", i); + error_append_hint(errp, "Valid values are 0 and 1\n"); +- } ++ return; ++ } + } ++ if (!pci_bus_is_root(pbus)) { ++ error_setg(errp, "virtio-iommu-pci must be plugged on the root bus"); ++ return; ++ } ++ + object_property_set_link(OBJECT(dev), "primary-bus", +- OBJECT(pci_get_bus(&vpci_dev->pci_dev)), +- &error_abort); ++ OBJECT(pbus), &error_abort); ++ + virtio_pci_force_virtio_1(vpci_dev); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); + } +-- +2.27.0 + diff --git a/hw-virtio-virtio-pmem-Replace-impossible-check-by-as.patch b/hw-virtio-virtio-pmem-Replace-impossible-check-by-as.patch new file mode 100644 index 0000000000000000000000000000000000000000..4721ee7b8a877cc7cfc440cf488c7aa63f4bb046 --- /dev/null +++ b/hw-virtio-virtio-pmem-Replace-impossible-check-by-as.patch @@ -0,0 +1,45 @@ +From 12eed71f72cbb5d81b14f66fde254058f121979a Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 25 Oct 2023 17:44:42 +0800 +Subject: [PATCH] hw/virtio/virtio-pmem: Replace impossible check by assertion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 184256d261cfc773360f14a80092ace5a716bb8f + +The get_memory_region() handler is used when (un)plugging the +device, which can only occur *after* it is realized. + +virtio_pmem_realize() ensure the instance can not be realized +without 'memdev'. Remove the superfluous check, replacing it +by an assertion. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Manos Pitsidianakis +Message-Id: <20231017140150.44995-2-philmd@linaro.org> +Signed-off-by: qihao_yewu +--- + hw/virtio/virtio-pmem.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c +index d1aeb90a31..39f3949a3b 100644 +--- a/hw/virtio/virtio-pmem.c ++++ b/hw/virtio/virtio-pmem.c +@@ -149,10 +149,7 @@ static void virtio_pmem_fill_device_info(const VirtIOPMEM *pmem, + static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem, + Error **errp) + { +- if (!pmem->memdev) { +- error_setg(errp, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP); +- return NULL; +- } ++ assert(pmem->memdev); + + return &pmem->memdev->mr; + } +-- +2.41.0.windows.1 + diff --git a/hw-xen-xen_pt-fix-uninitialized-variable.patch b/hw-xen-xen_pt-fix-uninitialized-variable.patch new file mode 100644 index 0000000000000000000000000000000000000000..f511ca006dd76be4dde41205ab74607d25a2ef5e --- /dev/null +++ b/hw-xen-xen_pt-fix-uninitialized-variable.patch @@ -0,0 +1,45 @@ +From 26bc780b9357bc50131242915175cf1db8c82b0e Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Tue, 1 Aug 2023 23:30:04 -0700 +Subject: [PATCH] hw/xen/xen_pt: fix uninitialized variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 3856734d80fbf46683e4080117ed961f5ab1300b + +xen_pt_config_reg_init() reads only that many bytes as the size of the +register that is being initialized. It uses +xen_host_pci_get_{byte,word,long} and casts its last argument to +expected pointer type. This means for smaller registers higher bits of +'val' are not initialized. Then, the function fails if any of those +higher bits are set. + +Fix this by initializing 'val' with zero. + +Signed-off-by: Marek Marczykowski-Górecki +Reviewed-by: Stefano Stabellini +Message-Id: <20230127050815.4155276-1-marmarek@invisiblethingslab.com> +Signed-off-by: Anthony PERARD + +Signed-off-by: Wanghe Xiao +--- + hw/xen/xen_pt_config_init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c +index c5c4e943a8..e7bcbe4c4f 100644 +--- a/hw/xen/xen_pt_config_init.c ++++ b/hw/xen/xen_pt_config_init.c +@@ -1924,7 +1924,7 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s, + if (reg->init) { + uint32_t host_mask, size_mask; + unsigned int offset; +- uint32_t val; ++ uint32_t val = 0; + + /* initialize emulate register */ + rc = reg->init(s, reg_entry->reg, +-- +2.41.0.windows.1 + diff --git a/hw-xhci-check-return-value-of-usb_packet_map.patch b/hw-xhci-check-return-value-of-usb_packet_map.patch deleted file mode 100644 index fd81478de3a588852232349f483bbf16dd403034..0000000000000000000000000000000000000000 --- a/hw-xhci-check-return-value-of-usb_packet_map.patch +++ /dev/null @@ -1,31 +0,0 @@ -From e43f0019b0aff881c562c8d2428bce6b3d55845c Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Fri, 18 Sep 2020 11:08:28 +0800 -Subject: [PATCH] hw: xhci: check return value of 'usb_packet_map' - -Currently we don't check the return value of 'usb_packet_map', -this will cause an NAF issue. This is LP#1891341. -Following is the reproducer provided in: --->https://bugs.launchpad.net/qemu/+bug/1891341 - -This patch fixes this. - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index a21485fe..3b25abca 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1614,7 +1614,10 @@ static int xhci_setup_packet(XHCITransfer *xfer) - xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ - usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid, - xfer->trbs[0].addr, false, xfer->int_req); -- usb_packet_map(&xfer->packet, &xfer->sgl); -+ if (usb_packet_map(&xfer->packet, &xfer->sgl)) { -+ qemu_sglist_destroy(&xfer->sgl); -+ return -1; -+ } - DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", - xfer->packet.pid, ep->dev->addr, ep->nr); - return 0; --- -2.23.0 - diff --git a/i386-Add-CPUID-bit-for-CLZERO-and-XSAVEERPTR.patch b/i386-Add-CPUID-bit-for-CLZERO-and-XSAVEERPTR.patch deleted file mode 100644 index dfa4a7064590348b9353dee3515e9682d926cd3d..0000000000000000000000000000000000000000 --- a/i386-Add-CPUID-bit-for-CLZERO-and-XSAVEERPTR.patch +++ /dev/null @@ -1,44 +0,0 @@ -From a6206163d42156cb9de290f914c6883c77b012b9 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Wed, 25 Sep 2019 23:49:48 +0200 -Subject: [PATCH] i386: Add CPUID bit for CLZERO and XSAVEERPTR - -The CPUID bits CLZERO and XSAVEERPTR are availble on AMD's ZEN platform -and could be passed to the guest. - -Signed-off-by: Sebastian Andrzej Siewior -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index f09612f9da..e65f372f25 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1134,7 +1134,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - [FEAT_8000_0008_EBX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -- NULL, NULL, NULL, NULL, -+ "clzero", NULL, "xsaveerptr", NULL, - NULL, NULL, NULL, NULL, - NULL, "wbnoinvd", NULL, NULL, - "ibpb", NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 7ff8ddd464..24d489db0f 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -696,6 +696,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - - #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) /* AVX512 BFloat16 Instruction */ - -+#define CPUID_8000_0008_EBX_CLZERO (1U << 0) /* CLZERO instruction */ -+#define CPUID_8000_0008_EBX_XSAVEERPTR (1U << 2) /* Always save/restore FP error pointers */ - #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and - do not invalidate cache */ - #define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ --- -2.27.0 - diff --git a/i386-Add-MSR-feature-bit-for-MDS-NO.patch b/i386-Add-MSR-feature-bit-for-MDS-NO.patch deleted file mode 100644 index 9a24836e3bf8e9084dea784deec9f75b50f96633..0000000000000000000000000000000000000000 --- a/i386-Add-MSR-feature-bit-for-MDS-NO.patch +++ /dev/null @@ -1,34 +0,0 @@ -From aaa6c86f46232c68f6846b2da859e4e0b8198664 Mon Sep 17 00:00:00 2001 -From: Cathy Zhang -Date: Tue, 22 Oct 2019 15:35:26 +0800 -Subject: [PATCH] i386: Add MSR feature bit for MDS-NO - -Define MSR_ARCH_CAP_MDS_NO in the IA32_ARCH_CAPABILITIES MSR to allow -CPU models to report the feature when host supports it. - -Signed-off-by: Cathy Zhang -Reviewed-by: Xiaoyao Li -Reviewed-by: Tao Xu -Message-Id: <1571729728-23284-2-git-send-email-cathy.zhang@intel.com> -Signed-off-by: Eduardo Habkost - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 488b4dc778..9ef868eb71 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -747,6 +747,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - #define MSR_ARCH_CAP_RSBA (1U << 2) - #define MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY (1U << 3) - #define MSR_ARCH_CAP_SSB_NO (1U << 4) -+#define MSR_ARCH_CAP_MDS_NO (1U << 5) - - #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) - --- -2.27.0 - diff --git a/i386-Add-macro-for-stibp.patch b/i386-Add-macro-for-stibp.patch deleted file mode 100644 index bf53f56757197ffdc94f388b01800a82d32aed4a..0000000000000000000000000000000000000000 --- a/i386-Add-macro-for-stibp.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 67f68f735af6b1ba829689af2e021bba97e7132a Mon Sep 17 00:00:00 2001 -From: Cathy Zhang -Date: Tue, 22 Oct 2019 15:35:27 +0800 -Subject: [PATCH] i386: Add macro for stibp - -stibp feature is already added through the following commit. -https://github.com/qemu/qemu/commit/0e8916582991b9fd0b94850a8444b8b80d0a0955 - -Add a macro for it to allow CPU models to report it when host supports. - -Signed-off-by: Cathy Zhang -Reviewed-by: Xiaoyao Li -Reviewed-by: Tao Xu -Message-Id: <1571729728-23284-3-git-send-email-cathy.zhang@intel.com> -Signed-off-by: Eduardo Habkost - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 9ef868eb71..58d8c48964 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -689,6 +689,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ - #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ - #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */ -+#define CPUID_7_0_EDX_STIBP (1U << 27) /* Single Thread Indirect Branch Predictors */ - #define CPUID_7_0_EDX_ARCH_CAPABILITIES (1U << 29) /*Arch Capabilities*/ - #define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30) /*Core Capability*/ - #define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */ --- -2.27.0 - diff --git a/i386-Add-new-CPU-model-Cooperlake.patch b/i386-Add-new-CPU-model-Cooperlake.patch deleted file mode 100644 index 60d249fdcd743a6c57c3d1c7051de82c0e1fefe4..0000000000000000000000000000000000000000 --- a/i386-Add-new-CPU-model-Cooperlake.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 8e9eb2f71396e3293d9ba9b1cfaf5f1487f1d475 Mon Sep 17 00:00:00 2001 -From: Cathy Zhang -Date: Tue, 22 Oct 2019 15:35:28 +0800 -Subject: [PATCH] i386: Add new CPU model Cooperlake - -Cooper Lake is intel's successor to Cascade Lake, the new -CPU model inherits features from Cascadelake-Server, while -add one platform associated new feature: AVX512_BF16. Meanwhile, -add STIBP for speculative execution. - -Signed-off-by: Cathy Zhang -Reviewed-by: Xiaoyao Li -Reviewed-by: Tao Xu -Message-Id: <1571729728-23284-4-git-send-email-cathy.zhang@intel.com> -Reviewed-by: Bruce Rogers -Signed-off-by: Eduardo Habkost - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 60 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 1ade90c28b..5329d73316 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2378,6 +2378,66 @@ static X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - } - }, -+ { -+ .name = "Cooperlake", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 85, -+ .stepping = 10, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP | -+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLWB | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD | -+ CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_PKU | -+ CPUID_7_0_ECX_AVX512VNNI, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_STIBP | -+ CPUID_7_0_EDX_SPEC_CTRL_SSBD | CPUID_7_0_EDX_ARCH_CAPABILITIES, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX512_BF16, -+ /* -+ * Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component, -+ * and the only one defined in Skylake (processor tracing) -+ * probably will block migration anyway. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (Cooperlake)", -+ }, - { - .name = "Icelake-Client", - .level = 0xd, --- -2.27.0 - diff --git a/i386-Add-new-CPU-model-SapphireRapids.patch b/i386-Add-new-CPU-model-SapphireRapids.patch new file mode 100644 index 0000000000000000000000000000000000000000..9286476608a2b0cf722b3ff473904dc67c99cfc4 --- /dev/null +++ b/i386-Add-new-CPU-model-SapphireRapids.patch @@ -0,0 +1,221 @@ +From f91b5ed322bbb6d793fca7005ac350d466fff232 Mon Sep 17 00:00:00 2001 +From: "Wang, Lei" +Date: Thu, 11 Aug 2022 22:57:51 -0700 +Subject: [PATCH] i386: Add new CPU model SapphireRapids + +The new CPU model mostly inherits features from Icelake-Server, while +adding new features: + - AMX (Advance Matrix eXtensions) + - Bus Lock Debug Exception +and new instructions: + - AVX VNNI (Vector Neural Network Instruction): + - VPDPBUS: Multiply and Add Unsigned and Signed Bytes + - VPDPBUSDS: Multiply and Add Unsigned and Signed Bytes with Saturation + - VPDPWSSD: Multiply and Add Signed Word Integers + - VPDPWSSDS: Multiply and Add Signed Integers with Saturation + - FP16: Replicates existing AVX512 computational SP (FP32) instructions + using FP16 instead of FP32 for ~2X performance gain + - SERIALIZE: Provide software with a simple way to force the processor to + complete all modifications, faster, allowed in all privilege levels and + not causing an unconditional VM exit + - TSX Suspend Load Address Tracking: Allows programmers to choose which + memory accesses do not need to be tracked in the TSX read set + - AVX512_BF16: Vector Neural Network Instructions supporting BFLOAT16 + inputs and conversion instructions from IEEE single precision + - fast zero-length MOVSB (KVM doesn't support yet) + - fast short STOSB (KVM doesn't support yet) + - fast short CMPSB, SCASB (KVM doesn't support yet) + +Features that may be added in future versions: + - CET (virtualization support hasn't been merged) + +Signed-off-by: Wang, Lei +Reviewed-by: Robert Hoo +Message-Id: <20220812055751.14553-1-lei4.wang@intel.com> +Reviewed-by: Xiaoyao Li +Signed-off-by: Paolo Bonzini +--- + target/i386/cpu.c | 133 +++++++++++++++++++++++++++++++++++++++++++++- + target/i386/cpu.h | 4 ++ + 2 files changed, 135 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 7122af303d..61cd7abcaa 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3529,6 +3529,135 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .name = "SapphireRapids", ++ .level = 0x20, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 143, ++ .stepping = 4, ++ /* ++ * please keep the ascending order so that we can have a clear view of ++ * bit position of each feature. ++ */ ++ .features[FEAT_1_EDX] = ++ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | ++ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | ++ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | ++ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | ++ CPUID_SSE | CPUID_SSE2, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | ++ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | ++ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | ++ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | ++ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_WBNOINVD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | ++ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | ++ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | ++ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | ++ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | ++ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | ++ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | ++ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | ++ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | ++ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | ++ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | ++ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | ++ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, ++ .features[FEAT_ARCH_CAPABILITIES] = ++ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | ++ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | ++ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | ++ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC, ++ .features[FEAT_VMX_BASIC] = ++ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, ++ .features[FEAT_VMX_ENTRY_CTLS] = ++ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | ++ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, ++ .features[FEAT_VMX_EPT_VPID_CAPS] = ++ MSR_VMX_EPT_EXECONLY | ++ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | ++ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | ++ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | ++ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | ++ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, ++ .features[FEAT_VMX_EXIT_CTLS] = ++ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | ++ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | ++ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | ++ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, ++ .features[FEAT_VMX_MISC] = ++ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | ++ MSR_VMX_MISC_VMWRITE_VMEXIT, ++ .features[FEAT_VMX_PINBASED_CTLS] = ++ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | ++ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | ++ VMX_PIN_BASED_POSTED_INTR, ++ .features[FEAT_VMX_PROCBASED_CTLS] = ++ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | ++ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | ++ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | ++ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | ++ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | ++ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | ++ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | ++ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | ++ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | ++ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | ++ VMX_CPU_BASED_PAUSE_EXITING | ++ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, ++ .features[FEAT_VMX_SECONDARY_CTLS] = ++ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | ++ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | ++ VMX_SECONDARY_EXEC_RDTSCP | ++ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | ++ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | ++ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | ++ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | ++ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | ++ VMX_SECONDARY_EXEC_RDRAND_EXITING | ++ VMX_SECONDARY_EXEC_ENABLE_INVPCID | ++ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | ++ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | ++ VMX_SECONDARY_EXEC_XSAVES, ++ .features[FEAT_VMX_VMFUNC] = ++ MSR_VMX_VMFUNC_EPT_SWITCHING, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (SapphireRapids)", ++ .versions = (X86CPUVersionDefinition[]) { ++ { .version = 1 }, ++ { /* end of list */ }, ++ }, ++ }, + { + .name = "Denverton", + .level = 21, +@@ -5619,7 +5748,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + case 0x1D: { +- /* AMX TILE */ ++ /* AMX TILE, for now hardcoded for Sapphire Rapids*/ + *eax = 0; + *ebx = 0; + *ecx = 0; +@@ -5640,7 +5769,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + case 0x1E: { +- /* AMX TMUL */ ++ /* AMX TMUL, for now hardcoded for Sapphire Rapids */ + *eax = 0; + *ebx = 0; + *ecx = 0; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 7a32dabf12..d0c7791a1e 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -857,10 +857,14 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_0_EDX_SERIALIZE (1U << 14) + /* TSX Suspend Load Address Tracking instruction */ + #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) ++/* AMX_BF16 instruction */ ++#define CPUID_7_0_EDX_AMX_BF16 (1U << 22) + /* AVX512_FP16 instruction */ + #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) + /* AMX tile (two-dimensional register) */ + #define CPUID_7_0_EDX_AMX_TILE (1U << 24) ++/* AMX_INT8 instruction */ ++#define CPUID_7_0_EDX_AMX_INT8 (1U << 25) + /* Speculation Control */ + #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) + /* Single Thread Indirect Branch Predictors */ +-- +2.27.0 + diff --git a/i386-Resolve-CPU-models-to-v1-by-default.patch b/i386-Resolve-CPU-models-to-v1-by-default.patch deleted file mode 100644 index f8c6315866df7028a1135869a7aa44234eb07b44..0000000000000000000000000000000000000000 --- a/i386-Resolve-CPU-models-to-v1-by-default.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 6a5e994c1dec959143f6d3f83169a7adcb173fc4 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 5 Dec 2019 19:33:39 -0300 -Subject: [PATCH] i386: Resolve CPU models to v1 by default - -When using `query-cpu-definitions` using `-machine none`, -QEMU is resolving all CPU models to their latest versions. The -actual CPU model version being used by another machine type (e.g. -`pc-q35-4.0`) might be different. - -In theory, this was OK because the correct CPU model -version is returned when using the correct `-machine` argument. - -Except that in practice, this breaks libvirt expectations: -libvirt always use `-machine none` when checking if a CPU model -is runnable, because runnability is not expected to be affected -when the machine type is changed. - -For example, when running on a Haswell host without TSX, -Haswell-v4 is runnable, but Haswell-v1 is not. On those hosts, -`query-cpu-definitions` says Haswell is runnable if using -`-machine none`, but Haswell is actually not runnable using any -of the `pc-*` machine types (because they resolve Haswell to -Haswell-v1). In other words, we're breaking the "runnability -guarantee" we promised to not break for a few releases (see -qemu-deprecated.texi). - -To address this issue, change the default CPU model version to v1 -on all machine types, so we make `query-cpu-definitions` output -when using `-machine none` match the results when using `pc-*`. -This will change in the future (the plan is to always return the -latest CPU model version if using `-machine none`), but only -after giving libvirt the opportunity to adapt. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1779078 -Signed-off-by: Eduardo Habkost -Message-Id: <20191205223339.764534-1-ehabkost@redhat.com> -Signed-off-by: Eduardo Habkost ---- - qemu-deprecated.texi | 8 ++++++++ - target/i386/cpu.c | 8 +++++++- - 2 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi -index fff07bb2a3..719ac23d72 100644 ---- a/qemu-deprecated.texi -+++ b/qemu-deprecated.texi -@@ -331,3 +331,11 @@ existing CPU models. Management software that needs runnability - guarantees must resolve the CPU model aliases using te - ``alias-of'' field returned by the ``query-cpu-definitions'' QMP - command. -+ -+While those guarantees are kept, the return value of -+``query-cpu-definitions'' will have existing CPU model aliases -+point to a version that doesn't break runnability guarantees -+(specifically, version 1 of those CPU models). In future QEMU -+versions, aliases will point to newer CPU model versions -+depending on the machine type, so management software must -+resolve CPU model aliases before starting a virtual machine. -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index e0f3a2dd99..22e0e89718 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3933,7 +3933,13 @@ static PropValue tcg_default_props[] = { - }; - - --X86CPUVersion default_cpu_version = CPU_VERSION_LATEST; -+/* -+ * We resolve CPU model aliases using -v1 when using "-machine -+ * none", but this is just for compatibility while libvirt isn't -+ * adapted to resolve CPU model versions before creating VMs. -+ * See "Runnability guarantee of CPU models" at * qemu-deprecated.texi. -+ */ -+X86CPUVersion default_cpu_version = 1; - - void x86_cpu_set_default_version(X86CPUVersion version) - { --- -2.27.0 - diff --git a/i386-add-notify-VM-exit-support.patch b/i386-add-notify-VM-exit-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..83f47d1faec6f878420069ab274d41e49ec594d6 --- /dev/null +++ b/i386-add-notify-VM-exit-support.patch @@ -0,0 +1,270 @@ +From 06d1ed3c9e3b736944e5267ffc8d341801fb758b Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Thu, 29 Sep 2022 15:20:14 +0800 +Subject: [PATCH] i386: add notify VM exit support + +from mainline-v7.2.0-rc0 +commit e2e69f6bb907a70ac518230c54e98e7abcb0c911 +category: feature +feature: Notify VM Exit +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6GWQE + +Intel-SIG: commit e2e69f6bb907 ("i386: add notify VM exit support") + +------------------------------------------------------------------ + +i386: add notify VM exit support + +There are cases that malicious virtual machine can cause CPU stuck (due +to event windows don't open up), e.g., infinite loop in microcode when +nested #AC (CVE-2015-5307). No event window means no event (NMI, SMI and +IRQ) can be delivered. It leads the CPU to be unavailable to host or +other VMs. Notify VM exit is introduced to mitigate such kind of +attacks, which will generate a VM exit if no event window occurs in VM +non-root mode for a specified amount of time (notify window). + +A new KVM capability KVM_CAP_X86_NOTIFY_VMEXIT is exposed to user space +so that the user can query the capability and set the expected notify +window when creating VMs. The format of the argument when enabling this +capability is as follows: + Bit 63:32 - notify window specified in qemu command + Bit 31:0 - some flags (e.g. KVM_X86_NOTIFY_VMEXIT_ENABLED is set to + enable the feature.) + +Users can configure the feature by a new (x86 only) accel property: + qemu -accel kvm,notify-vmexit=run|internal-error|disable,notify-window=n + +The default option of notify-vmexit is run, which will enable the +capability and do nothing if the exit happens. The internal-error option +raises a KVM internal error if it happens. The disable option does not +enable the capability. The default value of notify-window is 0. It is valid +only when notify-vmexit is not disabled. The valid range of notify-window +is non-negative. It is even safe to set it to zero since there's an +internal hardware threshold to be added to ensure no false positive. + +Because a notify VM exit may happen with VM_CONTEXT_INVALID set in exit +qualification (no cases are anticipated that would set this bit), which +means VM context is corrupted. It would be reflected in the flags of +KVM_EXIT_NOTIFY exit. If KVM_NOTIFY_CONTEXT_INVALID bit is set, raise a KVM +internal error unconditionally. + +Acked-by: Peter Xu +Signed-off-by: Chenyi Qiang +Message-Id: <20220929072014.20705-5-chenyi.qiang@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + accel/kvm/kvm-all.c | 2 + + qapi/run-state.json | 17 ++++++++ + qemu-options.hx | 11 +++++ + target/i386/kvm/kvm.c | 98 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 128 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 91d93facf2..799d993f6c 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -3602,6 +3602,8 @@ static void kvm_accel_instance_init(Object *obj) + s->kernel_irqchip_split = ON_OFF_AUTO_AUTO; + /* KVM dirty ring is by default off */ + s->kvm_dirty_ring_size = 0; ++ s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN; ++ s->notify_window = 0; + } + + static void kvm_accel_class_init(ObjectClass *oc, void *data) +diff --git a/qapi/run-state.json b/qapi/run-state.json +index 43d66d700f..08c38b2c67 100644 +--- a/qapi/run-state.json ++++ b/qapi/run-state.json +@@ -638,3 +638,20 @@ + { 'struct': 'MemoryFailureFlags', + 'data': { 'action-required': 'bool', + 'recursive': 'bool'} } ++ ++## ++# @NotifyVmexitOption: ++# ++# An enumeration of the options specified when enabling notify VM exit ++# ++# @run: enable the feature, do nothing and continue if the notify VM exit happens. ++# ++# @internal-error: enable the feature, raise a internal error if the notify ++# VM exit happens. ++# ++# @disable: disable the feature. ++# ++# Since: 7.2 ++## ++{ 'enum': 'NotifyVmexitOption', ++ 'data': [ 'run', 'internal-error', 'disable' ] } +\ No newline at end of file +diff --git a/qemu-options.hx b/qemu-options.hx +index 047d28a357..3c9b0f022c 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -152,6 +152,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, + " split-wx=on|off (enable TCG split w^x mapping)\n" + " tb-size=n (TCG translation block cache size)\n" + " dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n" ++ " notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n" + " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) + SRST + ``-accel name[,prop=value[,...]]`` +@@ -203,6 +204,16 @@ SRST + is disabled (dirty-ring-size=0). When enabled, KVM will instead + record dirty pages in a bitmap. + ++ ``notify-vmexit=run|internal-error|disable,notify-window=n`` ++ Enables or disables notify VM exit support on x86 host and specify ++ the corresponding notify window to trigger the VM exit if enabled. ++ ``run`` option enables the feature. It does nothing and continue ++ if the exit happens. ``internal-error`` option enables the feature. ++ It raises a internal error. ``disable`` option doesn't enable the feature. ++ This feature can mitigate the CPU stuck issue due to event windows don't ++ open up for a specified of time (i.e. notify-window). ++ Default: notify-vmexit=run,notify-window=0. ++ + ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index e2f28ce958..b8257e7e5f 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -15,6 +15,7 @@ + #include "qemu/osdep.h" + #include "qapi/qapi-events-run-state.h" + #include "qapi/error.h" ++#include "qapi/visitor.h" + #include + #include + #include +@@ -2496,6 +2497,21 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + } + } + ++ if (s->notify_vmexit != NOTIFY_VMEXIT_OPTION_DISABLE && ++ kvm_check_extension(s, KVM_CAP_X86_NOTIFY_VMEXIT)) { ++ uint64_t notify_window_flags = ++ ((uint64_t)s->notify_window << 32) | ++ KVM_X86_NOTIFY_VMEXIT_ENABLED | ++ KVM_X86_NOTIFY_VMEXIT_USER; ++ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_NOTIFY_VMEXIT, 0, ++ notify_window_flags); ++ if (ret < 0) { ++ error_report("kvm: Failed to enable notify vmexit cap: %s", ++ strerror(-ret)); ++ return ret; ++ } ++ } ++ + return 0; + } + +@@ -4839,6 +4855,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + X86CPU *cpu = X86_CPU(cs); + uint64_t code; + int ret; ++ bool ctx_invalid; ++ char str[256]; ++ KVMState *state; + + switch (run->exit_reason) { + case KVM_EXIT_HLT: +@@ -4894,6 +4913,21 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + /* already handled in kvm_arch_post_run */ + ret = 0; + break; ++ case KVM_EXIT_NOTIFY: ++ ctx_invalid = !!(run->notify.flags & KVM_NOTIFY_CONTEXT_INVALID); ++ state = KVM_STATE(current_accel()); ++ sprintf(str, "Encounter a notify exit with %svalid context in" ++ " guest. There can be possible misbehaves in guest." ++ " Please have a look.", ctx_invalid ? "in" : ""); ++ if (ctx_invalid || ++ state->notify_vmexit == NOTIFY_VMEXIT_OPTION_INTERNAL_ERROR) { ++ warn_report("KVM internal error: %s", str); ++ ret = -1; ++ } else { ++ warn_report_once("KVM: %s", str); ++ ret = 0; ++ } ++ break; + default: + fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); + ret = -1; +@@ -5169,6 +5203,70 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask) + } + } + ++static int kvm_arch_get_notify_vmexit(Object *obj, Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ return s->notify_vmexit; ++} ++ ++static void kvm_arch_set_notify_vmexit(Object *obj, int value, Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ ++ if (s->fd != -1) { ++ error_setg(errp, "Cannot set properties after the accelerator has been initialized"); ++ return; ++ } ++ ++ s->notify_vmexit = value; ++} ++ ++static void kvm_arch_get_notify_window(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ uint32_t value = s->notify_window; ++ ++ visit_type_uint32(v, name, &value, errp); ++} ++ ++static void kvm_arch_set_notify_window(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ Error *error = NULL; ++ uint32_t value; ++ ++ if (s->fd != -1) { ++ error_setg(errp, "Cannot set properties after the accelerator has been initialized"); ++ return; ++ } ++ ++ visit_type_uint32(v, name, &value, &error); ++ if (error) { ++ error_propagate(errp, error); ++ return; ++ } ++ ++ s->notify_window = value; ++} ++ + void kvm_arch_accel_class_init(ObjectClass *oc) + { ++ object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption", ++ &NotifyVmexitOption_lookup, ++ kvm_arch_get_notify_vmexit, ++ kvm_arch_set_notify_vmexit); ++ object_class_property_set_description(oc, "notify-vmexit", ++ "Enable notify VM exit"); ++ ++ object_class_property_add(oc, "notify-window", "uint32", ++ kvm_arch_get_notify_window, ++ kvm_arch_set_notify_window, ++ NULL, NULL); ++ object_class_property_set_description(oc, "notify-window", ++ "Clock cycles without an event window " ++ "after which a notification VM exit occurs"); + } +-- +2.27.0 + diff --git a/i386-cache-passthrough-Update-AMD-8000_001D.EAX-25-1.patch b/i386-cache-passthrough-Update-AMD-8000_001D.EAX-25-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ffe327361a0156af4134d1fa57e987b5ada1b1a --- /dev/null +++ b/i386-cache-passthrough-Update-AMD-8000_001D.EAX-25-1.patch @@ -0,0 +1,64 @@ +From 475988057789a1f4dcd7354c8a07fd37dcbac79f Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Thu, 10 Feb 2022 20:06:01 +0800 +Subject: [PATCH] i386: cache passthrough: Update AMD 8000_001D.EAX[25:14] + based on vCPU topo + +On AMD target, when host cache passthrough is disabled we will +emulate the guest caches with default values and initialize the +shared cpu list of the caches based on vCPU topology. However +when host cache passthrough is enabled, the shared cpu list is +consistent with host regardless what the vCPU topology is. + +For example, when cache passthrough is enabled, running a guest +with vThreads=1 on a host with pThreads=2, we will get that there +are every *two* logical vCPUs sharing a L1/L2 cache, which is not +consistent with the vCPU topology (vThreads=1). + +So let's reinitialize BITs[25:14] of AMD CPUID 8000_001D.EAX +based on the actual vCPU topology instead of host pCPU topology. + +Signed-off-by: Yanan Wang +--- + target/i386/cpu.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index c1fe2895fd..002e32650d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5724,9 +5724,31 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + case 0x8000001D: ++ /* Populate AMD Processor Cache Information */ + *eax = 0; + if (cpu->cache_info_passthrough) { + host_cpuid(index, count, eax, ebx, ecx, edx); ++ ++ /* ++ * Clear BITs[25:14] and then update them based on the guest ++ * vCPU topology, like what we do in encode_cache_cpuid8000001d ++ * when cache_info_passthrough is not enabled. ++ */ ++ *eax &= ~0x03FFC000; ++ switch (count) { ++ case 0: /* L1 dcache info */ ++ case 1: /* L1 icache info */ ++ case 2: /* L2 cache info */ ++ *eax |= ((topo_info.threads_per_core - 1) << 14); ++ break; ++ case 3: /* L3 cache info */ ++ *eax |= ((topo_info.cores_per_die * ++ topo_info.threads_per_core - 1) << 14); ++ break; ++ default: /* end of info */ ++ *eax = *ebx = *ecx = *edx = 0; ++ break; ++ } + break; + } + switch (count) { +-- +2.27.0 + diff --git a/i386-cache-passthrough-Update-Intel-CPUID4.EAX-25-14.patch b/i386-cache-passthrough-Update-Intel-CPUID4.EAX-25-14.patch new file mode 100644 index 0000000000000000000000000000000000000000..a0fc157bf3e84734665871a86ca53bb25e5bbec5 --- /dev/null +++ b/i386-cache-passthrough-Update-Intel-CPUID4.EAX-25-14.patch @@ -0,0 +1,88 @@ +From 3eaa433ca1cbee753698893b7732819ba2e31302 Mon Sep 17 00:00:00 2001 +From: Jian Wang +Date: Thu, 10 Feb 2022 19:43:55 +0800 +Subject: [PATCH] i386: cache passthrough: Update Intel CPUID4.EAX[25:14] based + on vCPU topo + +On Intel target, when host cache passthrough is disabled we will +emulate the guest caches with default values and initialize the +shared cpu list of the caches based on vCPU topology. However when +host cache passthrough is enabled, the shared cpu list is consistent +with host regardless what the vCPU topology is. + +For example, when cache passthrough is enabled, running a guest +with vThreads=1 on a host with pThreads=2, we will get that there +are every *two* logical vCPUs sharing a L1/L2 cache, which is not +consistent with the vCPU topology (vThreads=1). + +So let's reinitialize BITs[25:14] of Intel CPUID 4 based on the +actual vCPU topology instead of host pCPU topology. + +Signed-off-by: Jian Wang +Signed-off-by: Yanan Wang +--- + target/i386/cpu.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 868cf3e7e8..c1fe2895fd 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5196,7 +5196,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + { + X86CPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); +- uint32_t die_offset; ++ uint32_t die_offset, smt_width; + uint32_t limit; + uint32_t signature[3]; + X86CPUTopoInfo topo_info; +@@ -5205,6 +5205,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + topo_info.cores_per_die = cs->nr_cores; + topo_info.threads_per_core = cs->nr_threads; + ++ die_offset = apicid_die_offset(&topo_info); ++ smt_width = apicid_smt_width(&topo_info); ++ + /* Calculate & apply limits for different index ranges */ + if (index >= 0xC0000000) { + limit = env->cpuid_xlevel2; +@@ -5272,8 +5275,25 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { + host_cpuid(index, count, eax, ebx, ecx, edx); +- /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ +- *eax &= ~0xFC000000; ++ /* ++ * QEMU gives out its own APIC IDs, never pass down bits 31..26. ++ * Update the cache topo bits 25..14, according to the guest ++ * vCPU topology instead of the host pCPU topology. ++ */ ++ *eax &= ~0xFFFFC000; ++ switch (count) { ++ case 0: /* L1 dcache info */ ++ case 1: /* L1 icache info */ ++ case 2: /* L2 cache info */ ++ *eax |= ((1 << smt_width) - 1) << 14; ++ break; ++ case 3: /* L3 cache info */ ++ *eax |= ((1 << die_offset) - 1) << 14; ++ break; ++ default: /* end of info */ ++ *eax = *ebx = *ecx = *edx = 0; ++ break; ++ } + if ((*eax & 31) && cs->nr_cores > 1) { + *eax |= (cs->nr_cores - 1) << 26; + } +@@ -5298,7 +5318,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ +- die_offset = apicid_die_offset(&topo_info); + if (cpu->enable_l3_cache) { + encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, + (1 << die_offset), cs->nr_cores, +-- +2.27.0 + diff --git a/i386-cpu-Don-t-add-unavailable_features-to-env-user_.patch b/i386-cpu-Don-t-add-unavailable_features-to-env-user_.patch deleted file mode 100644 index 3e42e71e5d9e2d038d4540fa0b57b87adcbf92d7..0000000000000000000000000000000000000000 --- a/i386-cpu-Don-t-add-unavailable_features-to-env-user_.patch +++ /dev/null @@ -1,33 +0,0 @@ -From e6f3e08acd55d13cbb154ff8abb1b3c2ed658285 Mon Sep 17 00:00:00 2001 -From: Xiaoyao Li -Date: Tue, 14 Jul 2020 01:44:36 +0800 -Subject: [PATCH] i386/cpu: Don't add unavailable_features to - env->user_features - -Features unavailable due to absent of their dependent features should -not be added to env->user_features. env->user_features only contains the -feature explicity specified with -feature/+feature by user. - -Fixes: 99e24dbdaa68 ("target/i386: introduce generic feature dependency mechanism") -Signed-off-by: Xiaoyao Li -Message-Id: <20200713174436.41070-3-xiaoyao.li@intel.com> -Signed-off-by: Eduardo Habkost ---- - target/i386/cpu.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 6f27a5170a..e0f3a2dd99 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6173,7 +6173,6 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - unavailable_features & env->user_features[d->to.index], - "This feature depends on other features that were not requested"); - -- env->user_features[d->to.index] |= unavailable_features; - env->features[d->to.index] &= ~unavailable_features; - } - } --- -2.27.0 - diff --git a/i386-cpu-fix-compile-error-in-all-target-configure.patch b/i386-cpu-fix-compile-error-in-all-target-configure.patch new file mode 100644 index 0000000000000000000000000000000000000000..0cadfa1a02feaf82b60c2582d8de35c8d040dafd --- /dev/null +++ b/i386-cpu-fix-compile-error-in-all-target-configure.patch @@ -0,0 +1,69 @@ +From 11498c2d92e703923d373b64ad3f33aec5f383f2 Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Thu, 17 Feb 2022 09:51:13 +0800 +Subject: [PATCH] i386/cpu: fix compile error in all target configure + +When compile with `./configure && make -j`, there will be +error: "unknown type name `ram_addr_t`", fix the error by +adding compilation macro to control it. + +Signed-off-by: Jiajie Li +--- + target/i386/cpu.c | 16 ++++++++-------- + target/i386/cpu.h | 2 ++ + 2 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a4732a7372..d9dca1dafb 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6711,14 +6711,6 @@ static bool x86_cpu_get_paging_enabled(const CPUState *cs) + + return cpu->env.cr[0] & CR0_PG_MASK; + } +-#endif /* !CONFIG_USER_ONLY */ +- +-static void x86_cpu_set_pc(CPUState *cs, vaddr value) +-{ +- X86CPU *cpu = X86_CPU(cs); +- +- cpu->env.eip = value; +-} + + /* At present, we check the vm is *LARGE* or not, i.e. whether + * the memory size is more than 4T or not. +@@ -6736,6 +6728,14 @@ void x86_cpu_adjuest_by_ram_size(ram_addr_t ram_size, X86CPU *cpu) + cpu->fill_mtrr_mask = true; + } + } ++#endif /* !CONFIG_USER_ONLY */ ++ ++static void x86_cpu_set_pc(CPUState *cs, vaddr value) ++{ ++ X86CPU *cpu = X86_CPU(cs); ++ ++ cpu->env.eip = value; ++} + + int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request) + { +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 6f777fd6ca..d9296a9abc 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1842,10 +1842,12 @@ struct X86CPU { + extern const VMStateDescription vmstate_x86_cpu; + #endif + ++#ifndef CONFIG_USER_ONLY + #define DEFAULT_VM_CPU_PHYS_BITS 42 + #define LARGE_VM_CPU_PHYS_BITS 46 + + void x86_cpu_adjuest_by_ram_size(ram_addr_t ram_size, X86CPU *cpu); ++#endif + + int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request); + +-- +2.27.0 + diff --git a/i386-kvm-extend-kvm_-get-put-_vcpu_events-to-support.patch b/i386-kvm-extend-kvm_-get-put-_vcpu_events-to-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..e4bc275fcfd83192deeaa07eb72f6f308c456cf1 --- /dev/null +++ b/i386-kvm-extend-kvm_-get-put-_vcpu_events-to-support.patch @@ -0,0 +1,156 @@ +From 752fe0479931f6ef512b6a048fb50364505ff713 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Thu, 29 Sep 2022 15:20:11 +0800 +Subject: [PATCH] i386: kvm: extend kvm_{get, put}_vcpu_events to support + pending triple fault + +from mainline-v7.2.0-rc0 +commit 12f89a39cf3c5760cba82ce68929d748961f62df +category: feature +feature: Notify VM Exit +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6GWQE + +Intel-SIG: commit 12f89a39cf3c ("i386: kvm: extend kvm_{get, put}_vcpu_events to support pending triple fault") + +------------------------------------------------------------------ + +i386: kvm: extend kvm_{get, put}_vcpu_events to support pending triple fault + +For the direct triple faults, i.e. hardware detected and KVM morphed +to VM-Exit, KVM will never lose them. But for triple faults sythesized +by KVM, e.g. the RSM path, if KVM exits to userspace before the request +is serviced, userspace could migrate the VM and lose the triple fault. + +A new flag KVM_VCPUEVENT_VALID_TRIPLE_FAULT is defined to signal that +the event.triple_fault_pending field contains a valid state if the +KVM_CAP_X86_TRIPLE_FAULT_EVENT capability is enabled. + +Acked-by: Peter Xu +Signed-off-by: Chenyi Qiang +Message-Id: <20220929072014.20705-2-chenyi.qiang@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 1 + + target/i386/cpu.h | 1 + + target/i386/kvm/kvm.c | 20 ++++++++++++++++++++ + target/i386/machine.c | 20 ++++++++++++++++++++ + 4 files changed, 42 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 551b47ab1e..e3cea8397c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6018,6 +6018,7 @@ static void x86_cpu_reset(DeviceState *dev) + env->exception_has_payload = false; + env->exception_payload = 0; + env->nmi_injected = false; ++ env->triple_fault_pending = false; + #if !defined(CONFIG_USER_ONLY) + /* We hard-wire the BSP to the first CPU. */ + apic_designate_bsp(cpu->apic_state, s->cpu_index == 0); +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 290f1beaea..4f7fa87b95 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1698,6 +1698,7 @@ typedef struct CPUX86State { + uint8_t has_error_code; + uint8_t exception_has_payload; + uint64_t exception_payload; ++ uint8_t triple_fault_pending; + uint32_t ins_len; + uint32_t sipi_vector; + bool tsc_valid; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 5b15e0430b..e97d967c73 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -127,6 +127,7 @@ static int has_xsave2; + static int has_xcrs; + static int has_pit_state2; + static int has_exception_payload; ++static int has_triple_fault_event; + + static bool has_msr_mcg_ext_ctl; + +@@ -2380,6 +2381,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + } + } + ++ has_triple_fault_event = kvm_check_extension(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT); ++ if (has_triple_fault_event) { ++ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 0, true); ++ if (ret < 0) { ++ error_report("kvm: Failed to enable triple fault event cap: %s", ++ strerror(-ret)); ++ return ret; ++ } ++ } ++ + ret = kvm_get_supported_msrs(s); + if (ret < 0) { + return ret; +@@ -4004,6 +4015,11 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) + } + } + ++ if (has_triple_fault_event) { ++ events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; ++ events.triple_fault.pending = env->triple_fault_pending; ++ } ++ + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events); + } + +@@ -4073,6 +4089,10 @@ static int kvm_get_vcpu_events(X86CPU *cpu) + } + } + ++ if (events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT) { ++ env->triple_fault_pending = events.triple_fault.pending; ++ } ++ + env->sipi_vector = events.sipi_vector; + + return 0; +diff --git a/target/i386/machine.c b/target/i386/machine.c +index 3977e9d8f8..41cf5c0053 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -1497,6 +1497,25 @@ static const VMStateDescription vmstate_amx_xtile = { + }; + #endif + ++static bool triple_fault_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return env->triple_fault_pending; ++} ++ ++static const VMStateDescription vmstate_triple_fault = { ++ .name = "cpu/triple_fault", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = triple_fault_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT8(env.triple_fault_pending, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + const VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -1639,6 +1658,7 @@ const VMStateDescription vmstate_x86_cpu = { + #ifdef TARGET_X86_64 + &vmstate_amx_xtile, + #endif ++ &vmstate_triple_fault, + NULL + } + }; +-- +2.27.0 + diff --git a/i386-sev-Avoid-SEV-ES-crash-due-to-missing-MSR_EFER_.patch b/i386-sev-Avoid-SEV-ES-crash-due-to-missing-MSR_EFER_.patch new file mode 100644 index 0000000000000000000000000000000000000000..50fd9c46e8e9da698371afa990cd4eb2a4e6659d --- /dev/null +++ b/i386-sev-Avoid-SEV-ES-crash-due-to-missing-MSR_EFER_.patch @@ -0,0 +1,73 @@ +From 92b95a2982e192b90b45a988afe81e253862690f Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 7 Dec 2023 20:06:08 +0800 +Subject: [PATCH] i386/sev: Avoid SEV-ES crash due to missing MSR_EFER_LMA + bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Commit 7191f24c7fcf ("accel/kvm/kvm-all: Handle register access errors") + added error checking for KVM_SET_SREGS/KVM_SET_SREGS2. In doing so, it + exposed a long-running bug in current KVM support for SEV-ES where the + kernel assumes that MSR_EFER_LMA will be set explicitly by the guest + kernel, in which case EFER write traps would result in KVM eventually + seeing MSR_EFER_LMA get set and recording it in such a way that it would + be subsequently visible when accessing it via KVM_GET_SREGS/etc. + + However, guest kernels currently rely on MSR_EFER_LMA getting set + automatically when MSR_EFER_LME is set and paging is enabled via + CR0_PG_MASK. As a result, the EFER write traps don't actually expose the + MSR_EFER_LMA bit, even though it is set internally, and when QEMU + subsequently tries to pass this EFER value back to KVM via + KVM_SET_SREGS* it will fail various sanity checks and return -EINVAL, + which is now considered fatal due to the aforementioned QEMU commit. + + This can be addressed by inferring the MSR_EFER_LMA bit being set when + paging is enabled and MSR_EFER_LME is set, and synthesizing it to ensure + the expected bits are all present in subsequent handling on the host + side. + + Ultimately, this handling will be implemented in the host kernel, but to + avoid breaking QEMU's SEV-ES support when using older host kernels, the + same handling can be done in QEMU just after fetching the register + values via KVM_GET_SREGS*. Implement that here. + + Cc: Paolo Bonzini + Cc: Marcelo Tosatti + Cc: Tom Lendacky + Cc: Akihiko Odaki + Cc: Philippe Mathieu-Daudé + Cc: Lara Lazier + Cc: Vitaly Kuznetsov + Cc: Maxim Levitsky + Cc: + Fixes: 7191f24c7fcf ("accel/kvm/kvm-all: Handle register access errors") + Signed-off-by: Michael Roth + Acked-by: Paolo Bonzini + Signed-off-by: Stefan Hajnoczi + Message-ID: <20231206155821.1194551-1-michael.roth@amd.com> + + Signed-off-by: Zhongrui Tang +--- + target/i386/kvm/kvm.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 55ee75e844..54e48530ad 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -3420,6 +3420,10 @@ static int kvm_get_sregs(X86CPU *cpu) + env->cr[4] = sregs.cr4; + + env->efer = sregs.efer; ++ if (sev_es_enabled() && env->efer & MSR_EFER_LME && ++ env->cr[0] & CR0_PG_MASK) { ++ env->efer |= MSR_EFER_LMA; ++ } + + /* changes to apic base and cr8/tpr are read back via kvm_arch_post_run */ + x86_update_hflags(env); +-- +2.27.0 + diff --git a/i6300esb-watchdog-bugfix-Add-a-runstate-transition.patch b/i6300esb-watchdog-bugfix-Add-a-runstate-transition.patch new file mode 100644 index 0000000000000000000000000000000000000000..f207f407048f49c972b8bf75548b081b567395a2 --- /dev/null +++ b/i6300esb-watchdog-bugfix-Add-a-runstate-transition.patch @@ -0,0 +1,42 @@ +From 3c283ea7ca1902b9d221897fd65c5edb1d16e004 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 20:33:47 +0800 +Subject: [PATCH] i6300esb watchdog: bugfix: Add a runstate transition + +QEMU will abort() for the reasons now: + + invalid runstate transition: 'prelaunch' -> 'postmigrate' + Aborted + +This happens when: + |<- watchdog timeout happened, then sets reset_requested to + | SHUTDOWN_CAUSE_GUEST_RESET; + |<- hot-migration thread sets vm state to RUN_STATE_FINISH_MIGRATE + | before the last time of migration; + |<- main thread gets the change of reset_requested and triggers + | reset, then sets vm state to RUN_STATE_PRELAUNCH; + |<- hot-migration thread sets vm state to RUN_STATE_POSTMIGRATE. + +Then 'prelaunch' -> 'postmigrate' runstate transition will happen. +It is legal so add this transition to runstate_transitions_def. + +Signed-off-by: Jinhua Cao +--- + softmmu/runstate.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/softmmu/runstate.c b/softmmu/runstate.c +index 5736d908db..680994cdf8 100644 +--- a/softmmu/runstate.c ++++ b/softmmu/runstate.c +@@ -115,6 +115,7 @@ static const RunStateTransition runstate_transitions_def[] = { + { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, + { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, ++ { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE }, + + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PAUSED }, +-- +2.27.0 + diff --git a/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch b/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch deleted file mode 100644 index 9570b46b755e06705212253195a6605d738db350..0000000000000000000000000000000000000000 --- a/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch +++ /dev/null @@ -1,89 +0,0 @@ -From ed78352a59ea7acf7520d4d47a96b9911bae7fc3 Mon Sep 17 00:00:00 2001 -From: Alexander Popov -Date: Mon, 23 Dec 2019 20:51:16 +0300 -Subject: [PATCH] ide: Fix incorrect handling of some PRDTs in ide_dma_cb() - -The commit a718978ed58a from July 2015 introduced the assertion which -implies that the size of successful DMA transfers handled in ide_dma_cb() -should be multiple of 512 (the size of a sector). But guest systems can -initiate DMA transfers that don't fit this requirement. - -For fixing that let's check the number of bytes prepared for the transfer -by the prepare_buf() handler. The code in ide_dma_cb() must behave -according to the Programming Interface for Bus Master IDE Controller -(Revision 1.0 5/16/94): -1. If PRDs specified a smaller size than the IDE transfer - size, then the Interrupt and Active bits in the Controller - status register are not set (Error Condition). -2. If the size of the physical memory regions was equal to - the IDE device transfer size, the Interrupt bit in the - Controller status register is set to 1, Active bit is set to 0. -3. If PRDs specified a larger size than the IDE transfer size, - the Interrupt and Active bits in the Controller status register - are both set to 1. - -Signed-off-by: Alexander Popov -Reviewed-by: Kevin Wolf -Message-id: 20191223175117.508990-2-alex.popov@linux.com -Signed-off-by: John Snow - -diff --git a/hw/ide/core.c b/hw/ide/core.c -index 754ff4dc34..80000eb766 100644 ---- a/hw/ide/core.c -+++ b/hw/ide/core.c -@@ -849,6 +849,7 @@ static void ide_dma_cb(void *opaque, int ret) - int64_t sector_num; - uint64_t offset; - bool stay_active = false; -+ int32_t prep_size = 0; - - if (ret == -EINVAL) { - ide_dma_error(s); -@@ -863,13 +864,15 @@ static void ide_dma_cb(void *opaque, int ret) - } - } - -- n = s->io_buffer_size >> 9; -- if (n > s->nsector) { -- /* The PRDs were longer than needed for this request. Shorten them so -- * we don't get a negative remainder. The Active bit must remain set -- * after the request completes. */ -+ if (s->io_buffer_size > s->nsector * 512) { -+ /* -+ * The PRDs were longer than needed for this request. -+ * The Active bit must remain set after the request completes. -+ */ - n = s->nsector; - stay_active = true; -+ } else { -+ n = s->io_buffer_size >> 9; - } - - sector_num = ide_get_sector(s); -@@ -892,9 +895,20 @@ static void ide_dma_cb(void *opaque, int ret) - n = s->nsector; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; -- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size) < 512) { -- /* The PRDs were too short. Reset the Active bit, but don't raise an -- * interrupt. */ -+ prep_size = s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size); -+ /* prepare_buf() must succeed and respect the limit */ -+ assert(prep_size >= 0 && prep_size <= n * 512); -+ -+ /* -+ * Now prep_size stores the number of bytes in the sglist, and -+ * s->io_buffer_size stores the number of bytes described by the PRDs. -+ */ -+ -+ if (prep_size < n * 512) { -+ /* -+ * The PRDs are too short for this request. Error condition! -+ * Reset the Active bit and don't raise the interrupt. -+ */ - s->status = READY_STAT | SEEK_STAT; - dma_buf_commit(s, 0); - goto eot; --- -2.23.0 - diff --git a/ide-Increment-BB-in-flight-counter-for-TRIM-BH.patch b/ide-Increment-BB-in-flight-counter-for-TRIM-BH.patch new file mode 100644 index 0000000000000000000000000000000000000000..9b551dc45668660ba0aed49220acca7f415901f0 --- /dev/null +++ b/ide-Increment-BB-in-flight-counter-for-TRIM-BH.patch @@ -0,0 +1,87 @@ +From 31ae365f6c13d1bdad9d4eefe6e9f00928e5dd64 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 26 Jul 2023 02:50:59 +0000 +Subject: [PATCH] ide: Increment BB in-flight counter for TRIM BH mainline + inclusion commit 7e5cdb345f77d76cb4877fe6230c4e17a7d0d0ca category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +When we still have an AIOCB registered for DMA operations, we try to +settle the respective operation by draining the BlockBackend associated +with the IDE device. + +However, this assumes that every DMA operation is associated with an +increment of the BlockBackend’s in-flight counter (e.g. through some +ongoing I/O operation), so that draining the BB until its in-flight +counter reaches 0 will settle all DMA operations. That is not the case: +For TRIM, the guest can issue a zero-length operation that will not +result in any I/O operation forwarded to the BlockBackend, and also not +increment the in-flight counter in any other way. In such a case, +blk_drain() will be a no-op if no other operations are in flight. + +It is clear that if blk_drain() is a no-op, the value of +s->bus->dma->aiocb will not change between checking it in the `if` +condition and asserting that it is NULL after blk_drain(). + +The particular problem is that ide_issue_trim() creates a BH +(ide_trim_bh_cb()) to settle the TRIM request: iocb->common.cb() is +ide_dma_cb(), which will either create a new request, or find the +transfer to be done and call ide_set_inactive(), which clears +s->bus->dma->aiocb. Therefore, the blk_drain() must wait for +ide_trim_bh_cb() to run, which currently it will not always do. + +To fix this issue, we increment the BlockBackend's in-flight counter +when the TRIM operation begins (in ide_issue_trim(), when the +ide_trim_bh_cb() BH is created) and decrement it when ide_trim_bh_cb() +is done. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2029980 +Suggested-by: Paolo Bonzini +Signed-off-by: Hanna Reitz +Message-Id: <20220120142259.120189-1-hreitz@redhat.com> +Reviewed-by: Paolo Bonzini +Reviewed-by: John Snow +Tested-by: John Snow + +Signed-off-by: tangbinzy +--- + hw/ide/core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index e28f8aad61..15138225be 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -433,12 +433,16 @@ static const AIOCBInfo trim_aiocb_info = { + static void ide_trim_bh_cb(void *opaque) + { + TrimAIOCB *iocb = opaque; ++ BlockBackend *blk = iocb->s->blk; + + iocb->common.cb(iocb->common.opaque, iocb->ret); + + qemu_bh_delete(iocb->bh); + iocb->bh = NULL; + qemu_aio_unref(iocb); ++ ++ /* Paired with an increment in ide_issue_trim() */ ++ blk_dec_in_flight(blk); + } + + static void ide_issue_trim_cb(void *opaque, int ret) +@@ -508,6 +512,9 @@ BlockAIOCB *ide_issue_trim( + IDEState *s = opaque; + TrimAIOCB *iocb; + ++ /* Paired with a decrement in ide_trim_bh_cb() */ ++ blk_inc_in_flight(s->blk); ++ + iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque); + iocb->s = s; + iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); +-- +2.41.0.windows.1 + diff --git a/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch b/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch index 97824d4d27236961e5a9c3e3f4242e73d1334d44..7cd2ccff36dc717b01363728e5d48f6be9661e0e 100644 --- a/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch +++ b/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch @@ -1,4 +1,4 @@ -From c7fd5f3841f14c24e442fb6968c9f2d9e016f28a Mon Sep 17 00:00:00 2001 +From 9169beed83ea77059a7240aae5621dcfb3178cba Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Mon, 21 Jun 2021 09:22:35 +0800 Subject: [PATCH] ide: ahci: add check to avoid null dereference @@ -14,15 +14,16 @@ Reported-by: Bugs SysSec Signed-off-by: Prasad J Pandit Signed-off-by: Jiajie Li +Signed-off-by: Yan Wang --- hw/ide/ahci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c -index 6aaf66534a..a7be0ae4fe 100644 +index a94c6e26fb..256b58026a 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c -@@ -1455,8 +1455,10 @@ static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes) +@@ -1459,8 +1459,10 @@ static void ahci_commit_buf(const IDEDMA *dma, uint32_t tx_bytes) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); @@ -34,7 +35,7 @@ index 6aaf66534a..a7be0ae4fe 100644 + } } - static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) + static int ahci_dma_rw_buf(const IDEDMA *dma, bool is_write) -- 2.27.0 diff --git a/ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch b/ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch deleted file mode 100644 index da58bb9cc28d6e193d7b55ba530768d69a04324a..0000000000000000000000000000000000000000 --- a/ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 5209fbd340efe3fa7f8ea82f671db2fa04dda19b Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 23 Feb 2021 15:20:03 +0800 -Subject: [PATCH] ide:atapi: check io_buffer_index in ide_atapi_cmd_reply_end - -Fix CVE-2020-29443 - -During data transfer via packet command in 'ide_atapi_cmd_reply_end' -'s->io_buffer_index' could exceed the 's->io_buffer' length, leading -to OOB access issue. Add check to avoid it. - ... - #9 ahci_pio_transfer ../hw/ide/ahci.c:1383 - #10 ide_transfer_start_norecurse ../hw/ide/core.c:553 - #11 ide_atapi_cmd_reply_end ../hw/ide/atapi.c:284 - #12 ide_atapi_cmd_read_pio ../hw/ide/atapi.c:329 - #13 ide_atapi_cmd_read ../hw/ide/atapi.c:442 - #14 cmd_read ../hw/ide/atapi.c:988 - #15 ide_atapi_cmd ../hw/ide/atapi.c:1352 - #16 ide_transfer_start ../hw/ide/core.c:561 - #17 cmd_packet ../hw/ide/core.c:1729 - #18 ide_exec_cmd ../hw/ide/core.c:2107 - #19 handle_reg_h2d_fis ../hw/ide/ahci.c:1267 - #20 handle_cmd ../hw/ide/ahci.c:1318 - #21 check_cmd ../hw/ide/ahci.c:592 - #22 ahci_port_write ../hw/ide/ahci.c:373 - #23 ahci_mem_write ../hw/ide/ahci.c:513 - -Reported-by: Wenxiang Qian -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/ide/atapi.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c -index 1b0f66cc08..fc9dc87f03 100644 ---- a/hw/ide/atapi.c -+++ b/hw/ide/atapi.c -@@ -300,6 +300,9 @@ void ide_atapi_cmd_reply_end(IDEState *s) - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; -+ if (s->io_buffer_index > s->io_buffer_total_len) { -+ return; -+ } - - /* Some adapters process PIO data right away. In that case, we need - * to avoid mutual recursion between ide_transfer_start --- -2.27.0 - diff --git a/ide-fix-leak-from-qemu_allocate_irqs.patch b/ide-fix-leak-from-qemu_allocate_irqs.patch deleted file mode 100644 index dce6e906ce92e7e303d2198d7a612905ca0632c1..0000000000000000000000000000000000000000 --- a/ide-fix-leak-from-qemu_allocate_irqs.patch +++ /dev/null @@ -1,28 +0,0 @@ -From df35f8fe2687df32cb65f6a03b8dd80314cc4c53 Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 15:00:08 +0800 -Subject: [PATCH] ide: fix leak from qemu_allocate_irqs - -The array returned by qemu_allocate_irqs is malloced, free it. - -Signed-off-by: Paolo Bonzini -Reviewed-by: Thomas Huth ---- - hw/ide/cmd646.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c -index ed23aabf..a149cd6c 100644 ---- a/hw/ide/cmd646.c -+++ b/hw/ide/cmd646.c -@@ -299,6 +299,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp) - d->bmdma[i].bus = &d->bus[i]; - ide_register_restart_cb(&d->bus[i]); - } -+ g_free(irq); - - vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); - qemu_register_reset(cmd646_reset, d); --- -2.19.1 - diff --git a/imx7-ccm-add-digprog-mmio-write-method.patch b/imx7-ccm-add-digprog-mmio-write-method.patch deleted file mode 100644 index b68bf028b9b3e9bc2fe2d1838f6d3cf64dce7866..0000000000000000000000000000000000000000 --- a/imx7-ccm-add-digprog-mmio-write-method.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 5979338f8fb4562f7af32c58b7e7542d7396954e Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:29:28 +0800 -Subject: [PATCH] imx7-ccm: add digprog mmio write method - -fix CVE-2020-15469 - -Add digprog mmio write method to avoid assert failure during -initialisation. - -Reviewed-by: Li Qiang -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/misc/imx7_ccm.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c -index d9bdcf1027..831311a7c8 100644 ---- a/hw/misc/imx7_ccm.c -+++ b/hw/misc/imx7_ccm.c -@@ -130,8 +130,15 @@ static const struct MemoryRegionOps imx7_set_clr_tog_ops = { - }, - }; - -+static void imx7_digprog_write(void *opaque, hwaddr addr, -+ uint64_t data, unsigned size) -+{ -+ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); -+} -+ - static const struct MemoryRegionOps imx7_digprog_ops = { - .read = imx7_set_clr_tog_read, -+ .write = imx7_digprog_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl = { - .min_access_size = 4, --- -2.27.0 - diff --git a/include-Make-headers-more-self-contained.patch b/include-Make-headers-more-self-contained.patch deleted file mode 100644 index 565471c8ce67ec70b0bb5691f66cba384b8a1202..0000000000000000000000000000000000000000 --- a/include-Make-headers-more-self-contained.patch +++ /dev/null @@ -1,1551 +0,0 @@ -From 1b6a1ef572411efee7cbf1b65aeb15c704b997cc Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Mon, 12 Aug 2019 07:23:31 +0200 -Subject: [PATCH] include: Make headers more self-contained -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Back in 2016, we discussed[1] rules for headers, and these were -generally liked: - -1. Have a carefully curated header that's included everywhere first. We - got that already thanks to Peter: osdep.h. - -2. Headers should normally include everything they need beyond osdep.h. - If exceptions are needed for some reason, they must be documented in - the header. If all that's needed from a header is typedefs, put - those into qemu/typedefs.h instead of including the header. - -3. Cyclic inclusion is forbidden. - -This patch gets include/ closer to obeying 2. - -It's actually extracted from my "[RFC] Baby steps towards saner -headers" series[2], which demonstrates a possible path towards -checking 2 automatically. It passes the RFC test there. - -[1] Message-ID: <87h9g8j57d.fsf@blackfin.pond.sub.org> - https://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg03345.html -[2] Message-Id: <20190711122827.18970-1-armbru@redhat.com> - https://lists.nongnu.org/archive/html/qemu-devel/2019-07/msg02715.html - -Signed-off-by: Markus Armbruster -Reviewed-by: Alistair Francis -Message-Id: <20190812052359.30071-2-armbru@redhat.com> -Tested-by: Philippe Mathieu-Daudé ---- - include/block/raw-aio.h | 2 ++ - include/block/write-threshold.h | 2 ++ - include/disas/disas.h | 1 + - include/exec/cputlb.h | 3 +++ - include/exec/exec-all.h | 1 + - include/exec/ioport.h | 2 ++ - include/exec/memory-internal.h | 2 ++ - include/exec/ram_addr.h | 1 + - include/exec/softmmu-semi.h | 2 ++ - include/exec/tb-hash.h | 2 ++ - include/exec/user/thunk.h | 2 ++ - include/fpu/softfloat-macros.h | 2 ++ - include/hw/acpi/pci.h | 3 +++ - include/hw/acpi/tco.h | 3 +++ - include/hw/adc/stm32f2xx_adc.h | 2 ++ - include/hw/arm/allwinner-a10.h | 1 + - include/hw/arm/aspeed_soc.h | 1 + - include/hw/arm/bcm2836.h | 1 + - include/hw/arm/exynos4210.h | 3 +-- - include/hw/arm/fsl-imx25.h | 1 + - include/hw/arm/fsl-imx31.h | 1 + - include/hw/arm/sharpsl.h | 3 +++ - include/hw/arm/xlnx-zynqmp.h | 1 + - include/hw/block/fdc.h | 2 ++ - include/hw/block/flash.h | 1 + - include/hw/char/escc.h | 1 + - include/hw/char/xilinx_uartlite.h | 2 ++ - include/hw/core/generic-loader.h | 1 + - include/hw/cris/etraxfs.h | 1 + - include/hw/cris/etraxfs_dma.h | 3 +++ - include/hw/display/i2c-ddc.h | 1 + - include/hw/empty_slot.h | 2 ++ - include/hw/gpio/bcm2835_gpio.h | 1 + - include/hw/i2c/aspeed_i2c.h | 2 ++ - include/hw/i386/apic_internal.h | 1 + - include/hw/i386/ioapic_internal.h | 1 + - include/hw/intc/allwinner-a10-pic.h | 2 ++ - include/hw/intc/heathrow_pic.h | 2 ++ - include/hw/intc/mips_gic.h | 1 + - include/hw/isa/vt82c686.h | 2 ++ - include/hw/mips/cps.h | 1 + - include/hw/misc/macio/cuda.h | 2 ++ - include/hw/misc/macio/gpio.h | 3 +++ - include/hw/misc/macio/macio.h | 2 ++ - include/hw/misc/macio/pmu.h | 3 +++ - include/hw/misc/mips_cmgcr.h | 2 ++ - include/hw/misc/mips_cpc.h | 2 ++ - include/hw/misc/pvpanic.h | 3 +++ - include/hw/net/allwinner_emac.h | 1 + - include/hw/net/lance.h | 1 + - include/hw/nvram/chrp_nvram.h | 2 ++ - include/hw/pci-host/sabre.h | 2 ++ - include/hw/pci-host/uninorth.h | 2 +- - include/hw/pci/pcie_aer.h | 1 + - include/hw/ppc/pnv_core.h | 1 + - include/hw/ppc/ppc4xx.h | 4 ++++ - include/hw/ppc/spapr_irq.h | 3 +++ - include/hw/ppc/spapr_vio.h | 1 + - include/hw/ppc/spapr_xive.h | 2 ++ - include/hw/ppc/xive_regs.h | 3 +++ - include/hw/riscv/boot.h | 2 ++ - include/hw/riscv/riscv_hart.h | 3 +++ - include/hw/riscv/sifive_clint.h | 2 ++ - include/hw/riscv/sifive_e.h | 1 + - include/hw/riscv/sifive_plic.h | 2 +- - include/hw/riscv/sifive_prci.h | 2 ++ - include/hw/riscv/sifive_test.h | 2 ++ - include/hw/riscv/sifive_u.h | 1 + - include/hw/riscv/sifive_uart.h | 3 +++ - include/hw/riscv/spike.h | 3 +++ - include/hw/riscv/virt.h | 3 +++ - include/hw/s390x/ap-device.h | 3 +++ - include/hw/s390x/css-bridge.h | 3 ++- - include/hw/s390x/css.h | 1 + - include/hw/s390x/tod.h | 2 +- - include/hw/semihosting/console.h | 2 ++ - include/hw/sh4/sh_intc.h | 1 + - include/hw/sparc/sparc64.h | 2 ++ - include/hw/ssi/aspeed_smc.h | 1 + - include/hw/ssi/xilinx_spips.h | 1 + - include/hw/timer/allwinner-a10-pit.h | 1 + - include/hw/timer/i8254_internal.h | 1 + - include/hw/timer/m48t59.h | 2 ++ - include/hw/timer/mc146818rtc_regs.h | 2 ++ - include/hw/timer/xlnx-zynqmp-rtc.h | 1 + - include/hw/virtio/virtio-access.h | 1 + - include/hw/virtio/virtio-gpu-bswap.h | 1 + - include/hw/virtio/virtio-rng.h | 1 + - include/hw/watchdog/wdt_aspeed.h | 1 + - include/libdecnumber/decNumberLocal.h | 1 + - include/migration/cpu.h | 3 +++ - include/monitor/hmp-target.h | 2 ++ - include/qemu/atomic128.h | 2 ++ - include/qemu/ratelimit.h | 2 ++ - include/qemu/thread-win32.h | 2 +- - include/sysemu/balloon.h | 1 + - include/sysemu/cryptodev-vhost-user.h | 3 +++ - include/sysemu/hvf.h | 1 + - include/sysemu/iothread.h | 1 + - include/sysemu/kvm_int.h | 2 ++ - include/sysemu/memory_mapping.h | 2 ++ - include/sysemu/xen-mapcache.h | 2 ++ - include/ui/egl-helpers.h | 3 +++ - include/ui/input.h | 1 + - include/ui/spice-display.h | 1 + - target/hppa/cpu.h | 2 +- - 106 files changed, 183 insertions(+), 8 deletions(-) - -diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h -index 0cb7cc74a2..4629f24d08 100644 ---- a/include/block/raw-aio.h -+++ b/include/block/raw-aio.h -@@ -12,9 +12,11 @@ - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -+ - #ifndef QEMU_RAW_AIO_H - #define QEMU_RAW_AIO_H - -+#include "block/aio.h" - #include "qemu/coroutine.h" - #include "qemu/iov.h" - -diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h -index 80d8aab5d0..c646f267a4 100644 ---- a/include/block/write-threshold.h -+++ b/include/block/write-threshold.h -@@ -9,9 +9,11 @@ - * This work is licensed under the terms of the GNU LGPL, version 2 or later. - * See the COPYING.LIB file in the top-level directory. - */ -+ - #ifndef BLOCK_WRITE_THRESHOLD_H - #define BLOCK_WRITE_THRESHOLD_H - -+#include "block/block_int.h" - - /* - * bdrv_write_threshold_set: -diff --git a/include/disas/disas.h b/include/disas/disas.h -index 15da511f49..ba47e9197c 100644 ---- a/include/disas/disas.h -+++ b/include/disas/disas.h -@@ -1,6 +1,7 @@ - #ifndef QEMU_DISAS_H - #define QEMU_DISAS_H - -+#include "exec/hwaddr.h" - - #ifdef NEED_CPU_H - #include "cpu.h" -diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h -index 5373188be3..a62cfb28d5 100644 ---- a/include/exec/cputlb.h -+++ b/include/exec/cputlb.h -@@ -16,9 +16,12 @@ - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -+ - #ifndef CPUTLB_H - #define CPUTLB_H - -+#include "exec/cpu-common.h" -+ - #if !defined(CONFIG_USER_ONLY) - /* cputlb.c */ - void tlb_protect_code(ram_addr_t ram_addr); -diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h -index 16034ee651..135aeaab0d 100644 ---- a/include/exec/exec-all.h -+++ b/include/exec/exec-all.h -@@ -20,6 +20,7 @@ - #ifndef EXEC_ALL_H - #define EXEC_ALL_H - -+#include "cpu.h" - #include "exec/tb-context.h" - #include "sysemu/cpus.h" - -diff --git a/include/exec/ioport.h b/include/exec/ioport.h -index a298b89ce1..97feb296d2 100644 ---- a/include/exec/ioport.h -+++ b/include/exec/ioport.h -@@ -24,6 +24,8 @@ - #ifndef IOPORT_H - #define IOPORT_H - -+#include "exec/memory.h" -+ - #define MAX_IOPORTS (64 * 1024) - #define IOPORTS_MASK (MAX_IOPORTS - 1) - -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index d1a9dd1ec8..ef4fb92371 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -20,6 +20,8 @@ - #ifndef MEMORY_INTERNAL_H - #define MEMORY_INTERNAL_H - -+#include "cpu.h" -+ - #ifndef CONFIG_USER_ONLY - static inline AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) - { -diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h -index 523440662b..27a164b669 100644 ---- a/include/exec/ram_addr.h -+++ b/include/exec/ram_addr.h -@@ -20,6 +20,7 @@ - #define RAM_ADDR_H - - #ifndef CONFIG_USER_ONLY -+#include "cpu.h" - #include "hw/xen/xen.h" - #include "sysemu/tcg.h" - #include "exec/ramlist.h" -diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h -index 970837992e..fbcae88f4b 100644 ---- a/include/exec/softmmu-semi.h -+++ b/include/exec/softmmu-semi.h -@@ -10,6 +10,8 @@ - #ifndef SOFTMMU_SEMI_H - #define SOFTMMU_SEMI_H - -+#include "cpu.h" -+ - static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr) - { - uint64_t val; -diff --git a/include/exec/tb-hash.h b/include/exec/tb-hash.h -index 4f3a37d927..805235d321 100644 ---- a/include/exec/tb-hash.h -+++ b/include/exec/tb-hash.h -@@ -20,6 +20,8 @@ - #ifndef EXEC_TB_HASH_H - #define EXEC_TB_HASH_H - -+#include "exec/cpu-defs.h" -+#include "exec/exec-all.h" - #include "qemu/xxhash.h" - - #ifdef CONFIG_SOFTMMU -diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h -index 8d3af5a3be..eae2c27f99 100644 ---- a/include/exec/user/thunk.h -+++ b/include/exec/user/thunk.h -@@ -16,10 +16,12 @@ - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -+ - #ifndef THUNK_H - #define THUNK_H - - #include "cpu.h" -+#include "exec/user/abitypes.h" - - /* types enums definitions */ - -diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h -index c55aa6d174..be83a833ec 100644 ---- a/include/fpu/softfloat-macros.h -+++ b/include/fpu/softfloat-macros.h -@@ -82,6 +82,8 @@ this code that are retained. - #ifndef FPU_SOFTFLOAT_MACROS_H - #define FPU_SOFTFLOAT_MACROS_H - -+#include "fpu/softfloat.h" -+ - /*---------------------------------------------------------------------------- - | Shifts `a' right by the number of bits given in `count'. If any nonzero - | bits are shifted off, they are ``jammed'' into the least significant bit of -diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h -index 8bbd32cf45..bf2a3ed0ba 100644 ---- a/include/hw/acpi/pci.h -+++ b/include/hw/acpi/pci.h -@@ -22,9 +22,12 @@ - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -+ - #ifndef HW_ACPI_PCI_H - #define HW_ACPI_PCI_H - -+#include "hw/acpi/bios-linker-loader.h" -+ - typedef struct AcpiMcfgInfo { - uint64_t base; - uint32_t size; -diff --git a/include/hw/acpi/tco.h b/include/hw/acpi/tco.h -index d19dd59353..726f840cce 100644 ---- a/include/hw/acpi/tco.h -+++ b/include/hw/acpi/tco.h -@@ -6,9 +6,12 @@ - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -+ - #ifndef HW_ACPI_TCO_H - #define HW_ACPI_TCO_H - -+#include "exec/memory.h" -+#include "migration/vmstate.h" - - /* As per ICH9 spec, the internal timer has an error of ~0.6s on every tick */ - #define TCO_TICK_NSEC 600000000LL -diff --git a/include/hw/adc/stm32f2xx_adc.h b/include/hw/adc/stm32f2xx_adc.h -index a72f734eb1..663b79f4f3 100644 ---- a/include/hw/adc/stm32f2xx_adc.h -+++ b/include/hw/adc/stm32f2xx_adc.h -@@ -25,6 +25,8 @@ - #ifndef HW_STM32F2XX_ADC_H - #define HW_STM32F2XX_ADC_H - -+#include "hw/sysbus.h" -+ - #define ADC_SR 0x00 - #define ADC_CR1 0x04 - #define ADC_CR2 0x08 -diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h -index e99fe2ea2e..7182ce5c4b 100644 ---- a/include/hw/arm/allwinner-a10.h -+++ b/include/hw/arm/allwinner-a10.h -@@ -11,6 +11,7 @@ - #include "hw/ide/ahci.h" - - #include "sysemu/sysemu.h" -+#include "target/arm/cpu.h" - - - #define AW_A10_PIC_REG_BASE 0x01c20400 -diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h -index cef605ad6b..976fd6be93 100644 ---- a/include/hw/arm/aspeed_soc.h -+++ b/include/hw/arm/aspeed_soc.h -@@ -22,6 +22,7 @@ - #include "hw/ssi/aspeed_smc.h" - #include "hw/watchdog/wdt_aspeed.h" - #include "hw/net/ftgmac100.h" -+#include "target/arm/cpu.h" - - #define ASPEED_SPIS_NUM 2 - #define ASPEED_WDTS_NUM 3 -diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h -index a2cb8454de..97187f72be 100644 ---- a/include/hw/arm/bcm2836.h -+++ b/include/hw/arm/bcm2836.h -@@ -13,6 +13,7 @@ - - #include "hw/arm/bcm2835_peripherals.h" - #include "hw/intc/bcm2836_control.h" -+#include "target/arm/cpu.h" - - #define TYPE_BCM283X "bcm283x" - #define BCM283X(obj) OBJECT_CHECK(BCM283XState, (obj), TYPE_BCM283X) -diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h -index aa137271c0..f0f23b0e9b 100644 ---- a/include/hw/arm/exynos4210.h -+++ b/include/hw/arm/exynos4210.h -@@ -19,13 +19,12 @@ - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . -- * - */ - - #ifndef EXYNOS4210_H - #define EXYNOS4210_H - --#include "exec/memory.h" -+#include "hw/sysbus.h" - #include "target/arm/cpu-qom.h" - - #define EXYNOS4210_NCPUS 2 -diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h -index 3280ab1fb0..241efb52ae 100644 ---- a/include/hw/arm/fsl-imx25.h -+++ b/include/hw/arm/fsl-imx25.h -@@ -27,6 +27,7 @@ - #include "hw/i2c/imx_i2c.h" - #include "hw/gpio/imx_gpio.h" - #include "exec/memory.h" -+#include "target/arm/cpu.h" - - #define TYPE_FSL_IMX25 "fsl,imx25" - #define FSL_IMX25(obj) OBJECT_CHECK(FslIMX25State, (obj), TYPE_FSL_IMX25) -diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h -index e68a81efd7..ac5ca9826a 100644 ---- a/include/hw/arm/fsl-imx31.h -+++ b/include/hw/arm/fsl-imx31.h -@@ -26,6 +26,7 @@ - #include "hw/i2c/imx_i2c.h" - #include "hw/gpio/imx_gpio.h" - #include "exec/memory.h" -+#include "target/arm/cpu.h" - - #define TYPE_FSL_IMX31 "fsl,imx31" - #define FSL_IMX31(obj) OBJECT_CHECK(FslIMX31State, (obj), TYPE_FSL_IMX31) -diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h -index 5bf6db1fa2..89e168fbff 100644 ---- a/include/hw/arm/sharpsl.h -+++ b/include/hw/arm/sharpsl.h -@@ -3,9 +3,12 @@ - * - * This file is licensed under the GNU GPL. - */ -+ - #ifndef QEMU_SHARPSL_H - #define QEMU_SHARPSL_H - -+#include "exec/hwaddr.h" -+ - #define zaurus_printf(format, ...) \ - fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__) - -diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h -index 35804ea80a..6cb65e7537 100644 ---- a/include/hw/arm/xlnx-zynqmp.h -+++ b/include/hw/arm/xlnx-zynqmp.h -@@ -32,6 +32,7 @@ - #include "hw/intc/xlnx-zynqmp-ipi.h" - #include "hw/timer/xlnx-zynqmp-rtc.h" - #include "hw/cpu/cluster.h" -+#include "target/arm/cpu.h" - - #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" - #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ -diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h -index 8cece84326..f4fe2f471b 100644 ---- a/include/hw/block/fdc.h -+++ b/include/hw/block/fdc.h -@@ -1,6 +1,8 @@ - #ifndef HW_FDC_H - #define HW_FDC_H - -+#include "exec/hwaddr.h" -+#include "hw/irq.h" - #include "qapi/qapi-types-block.h" - - /* fdc.c */ -diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h -index 1acaf7de80..83a75f3170 100644 ---- a/include/hw/block/flash.h -+++ b/include/hw/block/flash.h -@@ -4,6 +4,7 @@ - /* NOR flash devices */ - - #include "exec/memory.h" -+#include "migration/vmstate.h" - - /* pflash_cfi01.c */ - -diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h -index 42aca83611..d5196c53e6 100644 ---- a/include/hw/char/escc.h -+++ b/include/hw/char/escc.h -@@ -3,6 +3,7 @@ - - #include "chardev/char-fe.h" - #include "chardev/char-serial.h" -+#include "hw/sysbus.h" - #include "ui/input.h" - - /* escc.c */ -diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h -index 634086b657..99d8bbf405 100644 ---- a/include/hw/char/xilinx_uartlite.h -+++ b/include/hw/char/xilinx_uartlite.h -@@ -15,6 +15,8 @@ - #ifndef XILINX_UARTLITE_H - #define XILINX_UARTLITE_H - -+#include "hw/sysbus.h" -+ - static inline DeviceState *xilinx_uartlite_create(hwaddr addr, - qemu_irq irq, - Chardev *chr) -diff --git a/include/hw/core/generic-loader.h b/include/hw/core/generic-loader.h -index dd27c42ab0..9ffce1c5a3 100644 ---- a/include/hw/core/generic-loader.h -+++ b/include/hw/core/generic-loader.h -@@ -19,6 +19,7 @@ - #define GENERIC_LOADER_H - - #include "elf.h" -+#include "hw/qdev-core.h" - - typedef struct GenericLoaderState { - /* */ -diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h -index 8da965addb..494222d315 100644 ---- a/include/hw/cris/etraxfs.h -+++ b/include/hw/cris/etraxfs.h -@@ -27,6 +27,7 @@ - - #include "net/net.h" - #include "hw/cris/etraxfs_dma.h" -+#include "hw/sysbus.h" - - /* Instantiate an ETRAXFS Ethernet MAC. */ - static inline DeviceState * -diff --git a/include/hw/cris/etraxfs_dma.h b/include/hw/cris/etraxfs_dma.h -index f6f33e0980..31ae360611 100644 ---- a/include/hw/cris/etraxfs_dma.h -+++ b/include/hw/cris/etraxfs_dma.h -@@ -1,6 +1,9 @@ - #ifndef HW_ETRAXFS_DMA_H - #define HW_ETRAXFS_DMA_H - -+#include "exec/hwaddr.h" -+#include "hw/irq.h" -+ - struct dma_context_metadata { - /* data descriptor md */ - uint16_t metadata; -diff --git a/include/hw/display/i2c-ddc.h b/include/hw/display/i2c-ddc.h -index c29443c5af..1cf53a0c8d 100644 ---- a/include/hw/display/i2c-ddc.h -+++ b/include/hw/display/i2c-ddc.h -@@ -20,6 +20,7 @@ - #define I2C_DDC_H - - #include "hw/display/edid.h" -+#include "hw/i2c/i2c.h" - - /* A simple I2C slave which just returns the contents of its EDID blob. */ - struct I2CDDCState { -diff --git a/include/hw/empty_slot.h b/include/hw/empty_slot.h -index 123a9f8989..cb9a221aa6 100644 ---- a/include/hw/empty_slot.h -+++ b/include/hw/empty_slot.h -@@ -1,6 +1,8 @@ - #ifndef HW_EMPTY_SLOT_H - #define HW_EMPTY_SLOT_H - -+#include "exec/hwaddr.h" -+ - /* empty_slot.c */ - void empty_slot_init(hwaddr addr, uint64_t slot_size); - -diff --git a/include/hw/gpio/bcm2835_gpio.h b/include/hw/gpio/bcm2835_gpio.h -index 9f8e0c720c..b0de0a3c74 100644 ---- a/include/hw/gpio/bcm2835_gpio.h -+++ b/include/hw/gpio/bcm2835_gpio.h -@@ -15,6 +15,7 @@ - #define BCM2835_GPIO_H - - #include "hw/sd/sd.h" -+#include "hw/sysbus.h" - - typedef struct BCM2835GpioState { - SysBusDevice parent_obj; -diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h -index f9020acdef..a2753f0bbb 100644 ---- a/include/hw/i2c/aspeed_i2c.h -+++ b/include/hw/i2c/aspeed_i2c.h -@@ -17,10 +17,12 @@ - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -+ - #ifndef ASPEED_I2C_H - #define ASPEED_I2C_H - - #include "hw/i2c/i2c.h" -+#include "hw/sysbus.h" - - #define TYPE_ASPEED_I2C "aspeed.i2c" - #define ASPEED_I2C(obj) \ -diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h -index 1209eb483a..b04bdd947f 100644 ---- a/include/hw/i386/apic_internal.h -+++ b/include/hw/i386/apic_internal.h -@@ -24,6 +24,7 @@ - #include "cpu.h" - #include "exec/memory.h" - #include "qemu/timer.h" -+#include "target/i386/cpu-qom.h" - - /* APIC Local Vector Table */ - #define APIC_LVT_TIMER 0 -diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h -index 07002f9662..3d2eec2aa7 100644 ---- a/include/hw/i386/ioapic_internal.h -+++ b/include/hw/i386/ioapic_internal.h -@@ -24,6 +24,7 @@ - - #include "hw/hw.h" - #include "exec/memory.h" -+#include "hw/i386/ioapic.h" - #include "hw/sysbus.h" - #include "qemu/notify.h" - -diff --git a/include/hw/intc/allwinner-a10-pic.h b/include/hw/intc/allwinner-a10-pic.h -index 1d314a70d9..a5895401d1 100644 ---- a/include/hw/intc/allwinner-a10-pic.h -+++ b/include/hw/intc/allwinner-a10-pic.h -@@ -1,6 +1,8 @@ - #ifndef ALLWINNER_A10_PIC_H - #define ALLWINNER_A10_PIC_H - -+#include "hw/sysbus.h" -+ - #define TYPE_AW_A10_PIC "allwinner-a10-pic" - #define AW_A10_PIC(obj) OBJECT_CHECK(AwA10PICState, (obj), TYPE_AW_A10_PIC) - -diff --git a/include/hw/intc/heathrow_pic.h b/include/hw/intc/heathrow_pic.h -index 6c91ec91bb..b163e27ab9 100644 ---- a/include/hw/intc/heathrow_pic.h -+++ b/include/hw/intc/heathrow_pic.h -@@ -26,6 +26,8 @@ - #ifndef HW_INTC_HEATHROW_PIC_H - #define HW_INTC_HEATHROW_PIC_H - -+#include "hw/sysbus.h" -+ - #define TYPE_HEATHROW "heathrow" - #define HEATHROW(obj) OBJECT_CHECK(HeathrowState, (obj), TYPE_HEATHROW) - -diff --git a/include/hw/intc/mips_gic.h b/include/hw/intc/mips_gic.h -index 902a12b178..8428287bf9 100644 ---- a/include/hw/intc/mips_gic.h -+++ b/include/hw/intc/mips_gic.h -@@ -13,6 +13,7 @@ - - #include "qemu/units.h" - #include "hw/timer/mips_gictimer.h" -+#include "hw/sysbus.h" - #include "cpu.h" - /* - * GIC Specific definitions -diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h -index c3c2b6e786..a54c3fe60a 100644 ---- a/include/hw/isa/vt82c686.h -+++ b/include/hw/isa/vt82c686.h -@@ -1,6 +1,8 @@ - #ifndef HW_VT82C686_H - #define HW_VT82C686_H - -+#include "hw/irq.h" -+ - #define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" - - /* vt82c686.c */ -diff --git a/include/hw/mips/cps.h b/include/hw/mips/cps.h -index aab1af926d..a941c55f27 100644 ---- a/include/hw/mips/cps.h -+++ b/include/hw/mips/cps.h -@@ -25,6 +25,7 @@ - #include "hw/intc/mips_gic.h" - #include "hw/misc/mips_cpc.h" - #include "hw/misc/mips_itu.h" -+#include "target/mips/cpu.h" - - #define TYPE_MIPS_CPS "mips-cps" - #define MIPS_CPS(obj) OBJECT_CHECK(MIPSCPSState, (obj), TYPE_MIPS_CPS) -diff --git a/include/hw/misc/macio/cuda.h b/include/hw/misc/macio/cuda.h -index 7dad469142..5768075ac5 100644 ---- a/include/hw/misc/macio/cuda.h -+++ b/include/hw/misc/macio/cuda.h -@@ -26,6 +26,8 @@ - #ifndef CUDA_H - #define CUDA_H - -+#include "hw/misc/mos6522.h" -+ - /* CUDA commands (2nd byte) */ - #define CUDA_WARM_START 0x0 - #define CUDA_AUTOPOLL 0x1 -diff --git a/include/hw/misc/macio/gpio.h b/include/hw/misc/macio/gpio.h -index 2838ae5fde..24a4364b39 100644 ---- a/include/hw/misc/macio/gpio.h -+++ b/include/hw/misc/macio/gpio.h -@@ -26,6 +26,9 @@ - #ifndef MACIO_GPIO_H - #define MACIO_GPIO_H - -+#include "hw/ppc/openpic.h" -+#include "hw/sysbus.h" -+ - #define TYPE_MACIO_GPIO "macio-gpio" - #define MACIO_GPIO(obj) OBJECT_CHECK(MacIOGPIOState, (obj), TYPE_MACIO_GPIO) - -diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h -index 970058b6ed..070a694eb5 100644 ---- a/include/hw/misc/macio/macio.h -+++ b/include/hw/misc/macio/macio.h -@@ -27,10 +27,12 @@ - #define MACIO_H - - #include "hw/char/escc.h" -+#include "hw/ide/internal.h" - #include "hw/intc/heathrow_pic.h" - #include "hw/misc/macio/cuda.h" - #include "hw/misc/macio/gpio.h" - #include "hw/misc/macio/pmu.h" -+#include "hw/ppc/mac.h" - #include "hw/ppc/mac_dbdma.h" - #include "hw/ppc/openpic.h" - -diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h -index d10895ba5f..7ef83dee4c 100644 ---- a/include/hw/misc/macio/pmu.h -+++ b/include/hw/misc/macio/pmu.h -@@ -10,6 +10,9 @@ - #ifndef PMU_H - #define PMU_H - -+#include "hw/misc/mos6522.h" -+#include "hw/misc/macio/gpio.h" -+ - /* - * PMU commands - */ -diff --git a/include/hw/misc/mips_cmgcr.h b/include/hw/misc/mips_cmgcr.h -index c9dfcb4b84..3e6e223273 100644 ---- a/include/hw/misc/mips_cmgcr.h -+++ b/include/hw/misc/mips_cmgcr.h -@@ -10,6 +10,8 @@ - #ifndef MIPS_CMGCR_H - #define MIPS_CMGCR_H - -+#include "hw/sysbus.h" -+ - #define TYPE_MIPS_GCR "mips-gcr" - #define MIPS_GCR(obj) OBJECT_CHECK(MIPSGCRState, (obj), TYPE_MIPS_GCR) - -diff --git a/include/hw/misc/mips_cpc.h b/include/hw/misc/mips_cpc.h -index 72c834e039..3f670578b0 100644 ---- a/include/hw/misc/mips_cpc.h -+++ b/include/hw/misc/mips_cpc.h -@@ -20,6 +20,8 @@ - #ifndef MIPS_CPC_H - #define MIPS_CPC_H - -+#include "hw/sysbus.h" -+ - #define CPC_ADDRSPACE_SZ 0x6000 - - /* CPC blocks offsets relative to base address */ -diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h -index 1ee071a703..ae0c8188ce 100644 ---- a/include/hw/misc/pvpanic.h -+++ b/include/hw/misc/pvpanic.h -@@ -11,9 +11,12 @@ - * See the COPYING file in the top-level directory. - * - */ -+ - #ifndef HW_MISC_PVPANIC_H - #define HW_MISC_PVPANIC_H - -+#include "qom/object.h" -+ - #define TYPE_PVPANIC "pvpanic" - - #define PVPANIC_IOPORT_PROP "ioport" -diff --git a/include/hw/net/allwinner_emac.h b/include/hw/net/allwinner_emac.h -index 905a43deb4..5013207d15 100644 ---- a/include/hw/net/allwinner_emac.h -+++ b/include/hw/net/allwinner_emac.h -@@ -27,6 +27,7 @@ - #include "net/net.h" - #include "qemu/fifo8.h" - #include "hw/net/mii.h" -+#include "hw/sysbus.h" - - #define TYPE_AW_EMAC "allwinner-emac" - #define AW_EMAC(obj) OBJECT_CHECK(AwEmacState, (obj), TYPE_AW_EMAC) -diff --git a/include/hw/net/lance.h b/include/hw/net/lance.h -index ffdd35c4d7..0357f5f65c 100644 ---- a/include/hw/net/lance.h -+++ b/include/hw/net/lance.h -@@ -31,6 +31,7 @@ - - #include "net/net.h" - #include "hw/net/pcnet.h" -+#include "hw/sysbus.h" - - #define TYPE_LANCE "lance" - #define SYSBUS_PCNET(obj) \ -diff --git a/include/hw/nvram/chrp_nvram.h b/include/hw/nvram/chrp_nvram.h -index b4f5b2b104..09941a9be4 100644 ---- a/include/hw/nvram/chrp_nvram.h -+++ b/include/hw/nvram/chrp_nvram.h -@@ -18,6 +18,8 @@ - #ifndef CHRP_NVRAM_H - #define CHRP_NVRAM_H - -+#include "qemu/bswap.h" -+ - /* OpenBIOS NVRAM partition */ - typedef struct { - uint8_t signature; -diff --git a/include/hw/pci-host/sabre.h b/include/hw/pci-host/sabre.h -index 9afa4938fd..99b5aefbec 100644 ---- a/include/hw/pci-host/sabre.h -+++ b/include/hw/pci-host/sabre.h -@@ -1,6 +1,8 @@ - #ifndef HW_PCI_HOST_SABRE_H - #define HW_PCI_HOST_SABRE_H - -+#include "hw/pci/pci.h" -+#include "hw/pci/pci_host.h" - #include "hw/sparc/sun4u_iommu.h" - - #define MAX_IVEC 0x40 -diff --git a/include/hw/pci-host/uninorth.h b/include/hw/pci-host/uninorth.h -index 060324536a..9a5cabd4c5 100644 ---- a/include/hw/pci-host/uninorth.h -+++ b/include/hw/pci-host/uninorth.h -@@ -26,7 +26,7 @@ - #define UNINORTH_H - - #include "hw/hw.h" -- -+#include "hw/pci/pci_host.h" - #include "hw/ppc/openpic.h" - - /* UniNorth version */ -diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h -index 729a9439c8..502dcd7eba 100644 ---- a/include/hw/pci/pcie_aer.h -+++ b/include/hw/pci/pcie_aer.h -@@ -22,6 +22,7 @@ - #define QEMU_PCIE_AER_H - - #include "hw/hw.h" -+#include "hw/pci/pci_regs.h" - - /* definitions which PCIExpressDevice uses */ - -diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h -index d0926454a9..bfbd2ec42a 100644 ---- a/include/hw/ppc/pnv_core.h -+++ b/include/hw/ppc/pnv_core.h -@@ -21,6 +21,7 @@ - #define PPC_PNV_CORE_H - - #include "hw/cpu/core.h" -+#include "target/ppc/cpu.h" - - #define TYPE_PNV_CORE "powernv-cpu-core" - #define PNV_CORE(obj) \ -diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h -index 39a7ba1ce6..90f8866138 100644 ---- a/include/hw/ppc/ppc4xx.h -+++ b/include/hw/ppc/ppc4xx.h -@@ -25,6 +25,10 @@ - #ifndef PPC4XX_H - #define PPC4XX_H - -+#include "hw/ppc/ppc.h" -+#include "exec/cpu-common.h" -+#include "exec/memory.h" -+ - /* PowerPC 4xx core initialization */ - PowerPCCPU *ppc4xx_init(const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, -diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h -index f965a58f89..cd6e18b05e 100644 ---- a/include/hw/ppc/spapr_irq.h -+++ b/include/hw/ppc/spapr_irq.h -@@ -10,6 +10,9 @@ - #ifndef HW_SPAPR_IRQ_H - #define HW_SPAPR_IRQ_H - -+#include "hw/irq.h" -+#include "target/ppc/cpu-qom.h" -+ - /* - * IRQ range offsets per device type - */ -diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h -index 97951fc6b4..92bfa72caf 100644 ---- a/include/hw/ppc/spapr_vio.h -+++ b/include/hw/ppc/spapr_vio.h -@@ -22,6 +22,7 @@ - * License along with this library; if not, see . - */ - -+#include "hw/ppc/spapr.h" - #include "sysemu/dma.h" - - #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" -diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h -index 7197144265..a39e672f27 100644 ---- a/include/hw/ppc/spapr_xive.h -+++ b/include/hw/ppc/spapr_xive.h -@@ -10,7 +10,9 @@ - #ifndef PPC_SPAPR_XIVE_H - #define PPC_SPAPR_XIVE_H - -+#include "hw/ppc/spapr_irq.h" - #include "hw/ppc/xive.h" -+#include "sysemu/sysemu.h" - - #define TYPE_SPAPR_XIVE "spapr-xive" - #define SPAPR_XIVE(obj) OBJECT_CHECK(SpaprXive, (obj), TYPE_SPAPR_XIVE) -diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h -index 1a8c5b5e64..b0c68ab5f7 100644 ---- a/include/hw/ppc/xive_regs.h -+++ b/include/hw/ppc/xive_regs.h -@@ -16,6 +16,9 @@ - #ifndef PPC_XIVE_REGS_H - #define PPC_XIVE_REGS_H - -+#include "qemu/bswap.h" -+#include "qemu/host-utils.h" -+ - /* - * Interrupt source number encoding on PowerBUS - */ -diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h -index d56f2ae3eb..1f21c2bef1 100644 ---- a/include/hw/riscv/boot.h -+++ b/include/hw/riscv/boot.h -@@ -20,6 +20,8 @@ - #ifndef RISCV_BOOT_H - #define RISCV_BOOT_H - -+#include "exec/cpu-defs.h" -+ - void riscv_find_and_load_firmware(MachineState *machine, - const char *default_machine_firmware, - hwaddr firmware_load_addr); -diff --git a/include/hw/riscv/riscv_hart.h b/include/hw/riscv/riscv_hart.h -index 0671d88a44..3b52b50571 100644 ---- a/include/hw/riscv/riscv_hart.h -+++ b/include/hw/riscv/riscv_hart.h -@@ -21,6 +21,9 @@ - #ifndef HW_RISCV_HART_H - #define HW_RISCV_HART_H - -+#include "hw/sysbus.h" -+#include "target/riscv/cpu.h" -+ - #define TYPE_RISCV_HART_ARRAY "riscv.hart_array" - - #define RISCV_HART_ARRAY(obj) \ -diff --git a/include/hw/riscv/sifive_clint.h b/include/hw/riscv/sifive_clint.h -index e2865be1d1..ae8286c884 100644 ---- a/include/hw/riscv/sifive_clint.h -+++ b/include/hw/riscv/sifive_clint.h -@@ -20,6 +20,8 @@ - #ifndef HW_SIFIVE_CLINT_H - #define HW_SIFIVE_CLINT_H - -+#include "hw/sysbus.h" -+ - #define TYPE_SIFIVE_CLINT "riscv.sifive.clint" - - #define SIFIVE_CLINT(obj) \ -diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h -index d175b24cb2..9c868dd7f9 100644 ---- a/include/hw/riscv/sifive_e.h -+++ b/include/hw/riscv/sifive_e.h -@@ -19,6 +19,7 @@ - #ifndef HW_SIFIVE_E_H - #define HW_SIFIVE_E_H - -+#include "hw/riscv/riscv_hart.h" - #include "hw/riscv/sifive_gpio.h" - - #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" -diff --git a/include/hw/riscv/sifive_plic.h b/include/hw/riscv/sifive_plic.h -index ce8907f6aa..b0edba2884 100644 ---- a/include/hw/riscv/sifive_plic.h -+++ b/include/hw/riscv/sifive_plic.h -@@ -21,7 +21,7 @@ - #ifndef HW_SIFIVE_PLIC_H - #define HW_SIFIVE_PLIC_H - --#include "hw/irq.h" -+#include "hw/sysbus.h" - - #define TYPE_SIFIVE_PLIC "riscv.sifive.plic" - -diff --git a/include/hw/riscv/sifive_prci.h b/include/hw/riscv/sifive_prci.h -index bd51c4af3c..8b7de134f8 100644 ---- a/include/hw/riscv/sifive_prci.h -+++ b/include/hw/riscv/sifive_prci.h -@@ -19,6 +19,8 @@ - #ifndef HW_SIFIVE_PRCI_H - #define HW_SIFIVE_PRCI_H - -+#include "hw/sysbus.h" -+ - enum { - SIFIVE_PRCI_HFROSCCFG = 0x0, - SIFIVE_PRCI_HFXOSCCFG = 0x4, -diff --git a/include/hw/riscv/sifive_test.h b/include/hw/riscv/sifive_test.h -index 71d4c9fad7..3a603a6ead 100644 ---- a/include/hw/riscv/sifive_test.h -+++ b/include/hw/riscv/sifive_test.h -@@ -19,6 +19,8 @@ - #ifndef HW_SIFIVE_TEST_H - #define HW_SIFIVE_TEST_H - -+#include "hw/sysbus.h" -+ - #define TYPE_SIFIVE_TEST "riscv.sifive.test" - - #define SIFIVE_TEST(obj) \ -diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h -index 892f0eee21..be021ce256 100644 ---- a/include/hw/riscv/sifive_u.h -+++ b/include/hw/riscv/sifive_u.h -@@ -20,6 +20,7 @@ - #define HW_SIFIVE_U_H - - #include "hw/net/cadence_gem.h" -+#include "hw/riscv/riscv_hart.h" - - #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" - #define RISCV_U_SOC(obj) \ -diff --git a/include/hw/riscv/sifive_uart.h b/include/hw/riscv/sifive_uart.h -index c8dc1c57fd..65668825a3 100644 ---- a/include/hw/riscv/sifive_uart.h -+++ b/include/hw/riscv/sifive_uart.h -@@ -20,6 +20,9 @@ - #ifndef HW_SIFIVE_UART_H - #define HW_SIFIVE_UART_H - -+#include "chardev/char-fe.h" -+#include "hw/sysbus.h" -+ - enum { - SIFIVE_UART_TXFIFO = 0, - SIFIVE_UART_RXFIFO = 4, -diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h -index 641b70da67..03d870363c 100644 ---- a/include/hw/riscv/spike.h -+++ b/include/hw/riscv/spike.h -@@ -19,6 +19,9 @@ - #ifndef HW_RISCV_SPIKE_H - #define HW_RISCV_SPIKE_H - -+#include "hw/riscv/riscv_hart.h" -+#include "hw/sysbus.h" -+ - typedef struct { - /*< private >*/ - SysBusDevice parent_obj; -diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h -index d01a1a85c4..6e5fbe5d3b 100644 ---- a/include/hw/riscv/virt.h -+++ b/include/hw/riscv/virt.h -@@ -19,6 +19,9 @@ - #ifndef HW_RISCV_VIRT_H - #define HW_RISCV_VIRT_H - -+#include "hw/riscv/riscv_hart.h" -+#include "hw/sysbus.h" -+ - typedef struct { - /*< private >*/ - SysBusDevice parent_obj; -diff --git a/include/hw/s390x/ap-device.h b/include/hw/s390x/ap-device.h -index 765e9082a3..8df9cd2954 100644 ---- a/include/hw/s390x/ap-device.h -+++ b/include/hw/s390x/ap-device.h -@@ -7,9 +7,12 @@ - * your option) any later version. See the COPYING file in the top-level - * directory. - */ -+ - #ifndef HW_S390X_AP_DEVICE_H - #define HW_S390X_AP_DEVICE_H - -+#include "hw/qdev-core.h" -+ - #define AP_DEVICE_TYPE "ap-device" - - typedef struct APDevice { -diff --git a/include/hw/s390x/css-bridge.h b/include/hw/s390x/css-bridge.h -index 5a0203be5f..f7ed2d9a03 100644 ---- a/include/hw/s390x/css-bridge.h -+++ b/include/hw/s390x/css-bridge.h -@@ -12,8 +12,9 @@ - - #ifndef HW_S390X_CSS_BRIDGE_H - #define HW_S390X_CSS_BRIDGE_H -+ - #include "qom/object.h" --#include "hw/qdev-core.h" -+#include "hw/sysbus.h" - - /* virtual css bridge */ - typedef struct VirtualCssBridge { -diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h -index d033387fba..f46bcafb16 100644 ---- a/include/hw/s390x/css.h -+++ b/include/hw/s390x/css.h -@@ -17,6 +17,7 @@ - #include "hw/s390x/s390_flic.h" - #include "hw/s390x/ioinst.h" - #include "sysemu/kvm.h" -+#include "target/s390x/cpu-qom.h" - - /* Channel subsystem constants. */ - #define MAX_DEVNO 65535 -diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h -index 9c4a6000c3..d71f4ea8a7 100644 ---- a/include/hw/s390x/tod.h -+++ b/include/hw/s390x/tod.h -@@ -12,7 +12,7 @@ - #define HW_S390_TOD_H - - #include "hw/qdev.h" --#include "s390-tod.h" -+#include "target/s390x/s390-tod.h" - - typedef struct S390TOD { - uint8_t high; -diff --git a/include/hw/semihosting/console.h b/include/hw/semihosting/console.h -index cfab572c0c..9be9754bcd 100644 ---- a/include/hw/semihosting/console.h -+++ b/include/hw/semihosting/console.h -@@ -9,6 +9,8 @@ - #ifndef SEMIHOST_CONSOLE_H - #define SEMIHOST_CONSOLE_H - -+#include "cpu.h" -+ - /** - * qemu_semihosting_console_outs: - * @env: CPUArchState -diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h -index b7c2404334..3d3efde059 100644 ---- a/include/hw/sh4/sh_intc.h -+++ b/include/hw/sh4/sh_intc.h -@@ -1,6 +1,7 @@ - #ifndef SH_INTC_H - #define SH_INTC_H - -+#include "exec/memory.h" - #include "hw/irq.h" - - typedef unsigned char intc_enum; -diff --git a/include/hw/sparc/sparc64.h b/include/hw/sparc/sparc64.h -index 21ab79e343..4ced36fb5a 100644 ---- a/include/hw/sparc/sparc64.h -+++ b/include/hw/sparc/sparc64.h -@@ -1,6 +1,8 @@ - #ifndef HW_SPARC_SPARC64_H - #define HW_SPARC_SPARC64_H - -+#include "target/sparc/cpu-qom.h" -+ - #define IVEC_MAX 0x40 - - SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr); -diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h -index 591279ba1f..aa07dac4fe 100644 ---- a/include/hw/ssi/aspeed_smc.h -+++ b/include/hw/ssi/aspeed_smc.h -@@ -26,6 +26,7 @@ - #define ASPEED_SMC_H - - #include "hw/ssi/ssi.h" -+#include "hw/sysbus.h" - - typedef struct AspeedSegments { - hwaddr addr; -diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h -index a0a0ae7584..6a39b55a7b 100644 ---- a/include/hw/ssi/xilinx_spips.h -+++ b/include/hw/ssi/xilinx_spips.h -@@ -28,6 +28,7 @@ - #include "hw/ssi/ssi.h" - #include "qemu/fifo32.h" - #include "hw/stream.h" -+#include "hw/sysbus.h" - - typedef struct XilinxSPIPS XilinxSPIPS; - -diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h -index c0cc3e2169..871c95b512 100644 ---- a/include/hw/timer/allwinner-a10-pit.h -+++ b/include/hw/timer/allwinner-a10-pit.h -@@ -2,6 +2,7 @@ - #define ALLWINNER_A10_PIT_H - - #include "hw/ptimer.h" -+#include "hw/sysbus.h" - - #define TYPE_AW_A10_PIT "allwinner-A10-timer" - #define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT) -diff --git a/include/hw/timer/i8254_internal.h b/include/hw/timer/i8254_internal.h -index c37a438f82..e611c6f227 100644 ---- a/include/hw/timer/i8254_internal.h -+++ b/include/hw/timer/i8254_internal.h -@@ -27,6 +27,7 @@ - - #include "hw/hw.h" - #include "hw/isa/isa.h" -+#include "hw/timer/i8254.h" - #include "qemu/timer.h" - - typedef struct PITChannelState { -diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h -index 43efc91f56..d3fb50e08c 100644 ---- a/include/hw/timer/m48t59.h -+++ b/include/hw/timer/m48t59.h -@@ -1,6 +1,8 @@ - #ifndef HW_M48T59_H - #define HW_M48T59_H - -+#include "exec/hwaddr.h" -+#include "hw/irq.h" - #include "qom/object.h" - - #define TYPE_NVRAM "nvram" -diff --git a/include/hw/timer/mc146818rtc_regs.h b/include/hw/timer/mc146818rtc_regs.h -index c62f17bf2d..bfbb57e570 100644 ---- a/include/hw/timer/mc146818rtc_regs.h -+++ b/include/hw/timer/mc146818rtc_regs.h -@@ -25,6 +25,8 @@ - #ifndef MC146818RTC_REGS_H - #define MC146818RTC_REGS_H - -+#include "qemu/timer.h" -+ - #define RTC_ISA_IRQ 8 - - #define RTC_SECONDS 0 -diff --git a/include/hw/timer/xlnx-zynqmp-rtc.h b/include/hw/timer/xlnx-zynqmp-rtc.h -index 6e9134edf6..97e32322ed 100644 ---- a/include/hw/timer/xlnx-zynqmp-rtc.h -+++ b/include/hw/timer/xlnx-zynqmp-rtc.h -@@ -28,6 +28,7 @@ - #define HW_TIMER_XLNX_ZYNQMP_RTC_H - - #include "hw/register.h" -+#include "hw/sysbus.h" - - #define TYPE_XLNX_ZYNQMP_RTC "xlnx-zynmp.rtc" - -diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h -index bdf58f3119..6818a23a2d 100644 ---- a/include/hw/virtio/virtio-access.h -+++ b/include/hw/virtio/virtio-access.h -@@ -16,6 +16,7 @@ - #ifndef QEMU_VIRTIO_ACCESS_H - #define QEMU_VIRTIO_ACCESS_H - -+#include "exec/hwaddr.h" - #include "hw/virtio/virtio.h" - #include "hw/virtio/virtio-bus.h" - -diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h -index 38d12160f6..203f9e1718 100644 ---- a/include/hw/virtio/virtio-gpu-bswap.h -+++ b/include/hw/virtio/virtio-gpu-bswap.h -@@ -15,6 +15,7 @@ - #define HW_VIRTIO_GPU_BSWAP_H - - #include "qemu/bswap.h" -+#include "standard-headers/linux/virtio_gpu.h" - - static inline void - virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) -diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h -index 922dce7cac..ff699335e3 100644 ---- a/include/hw/virtio/virtio-rng.h -+++ b/include/hw/virtio/virtio-rng.h -@@ -12,6 +12,7 @@ - #ifndef QEMU_VIRTIO_RNG_H - #define QEMU_VIRTIO_RNG_H - -+#include "hw/virtio/virtio.h" - #include "sysemu/rng.h" - #include "sysemu/rng-random.h" - #include "standard-headers/linux/virtio_rng.h" -diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h -index daef0c0e23..8c5691ce20 100644 ---- a/include/hw/watchdog/wdt_aspeed.h -+++ b/include/hw/watchdog/wdt_aspeed.h -@@ -10,6 +10,7 @@ - #ifndef WDT_ASPEED_H - #define WDT_ASPEED_H - -+#include "hw/misc/aspeed_scu.h" - #include "hw/sysbus.h" - - #define TYPE_ASPEED_WDT "aspeed.wdt" -diff --git a/include/libdecnumber/decNumberLocal.h b/include/libdecnumber/decNumberLocal.h -index 12cf1d8b6f..4d53c077f2 100644 ---- a/include/libdecnumber/decNumberLocal.h -+++ b/include/libdecnumber/decNumberLocal.h -@@ -44,6 +44,7 @@ - #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ - - #include "libdecnumber/dconfig.h" -+ #include "libdecnumber/decContext.h" - - /* Conditional code flag -- set this to match hardware platform */ - /* 1=little-endian, 0=big-endian */ -diff --git a/include/migration/cpu.h b/include/migration/cpu.h -index a40bd3549f..da1618d620 100644 ---- a/include/migration/cpu.h -+++ b/include/migration/cpu.h -@@ -1,7 +1,10 @@ - /* Declarations for use for CPU state serialization. */ -+ - #ifndef MIGRATION_CPU_H - #define MIGRATION_CPU_H - -+#include "exec/cpu-defs.h" -+ - #if TARGET_LONG_BITS == 64 - #define qemu_put_betl qemu_put_be64 - #define qemu_get_betl qemu_get_be64 -diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h -index 454e8ed155..8b7820a3ad 100644 ---- a/include/monitor/hmp-target.h -+++ b/include/monitor/hmp-target.h -@@ -25,6 +25,8 @@ - #ifndef MONITOR_HMP_TARGET_H - #define MONITOR_HMP_TARGET_H - -+#include "cpu.h" -+ - #define MD_TLONG 0 - #define MD_I32 1 - -diff --git a/include/qemu/atomic128.h b/include/qemu/atomic128.h -index ddd0d55d31..6b34484e15 100644 ---- a/include/qemu/atomic128.h -+++ b/include/qemu/atomic128.h -@@ -13,6 +13,8 @@ - #ifndef QEMU_ATOMIC128_H - #define QEMU_ATOMIC128_H - -+#include "qemu/int128.h" -+ - /* - * GCC is a house divided about supporting large atomic operations. - * -diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h -index 1b38291823..01da8d63f1 100644 ---- a/include/qemu/ratelimit.h -+++ b/include/qemu/ratelimit.h -@@ -14,6 +14,8 @@ - #ifndef QEMU_RATELIMIT_H - #define QEMU_RATELIMIT_H - -+#include "qemu/timer.h" -+ - typedef struct { - int64_t slice_start_time; - int64_t slice_end_time; -diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h -index 50af5dd7ab..d0a1a9597e 100644 ---- a/include/qemu/thread-win32.h -+++ b/include/qemu/thread-win32.h -@@ -47,6 +47,6 @@ struct QemuThread { - }; - - /* Only valid for joinable threads. */ --HANDLE qemu_thread_get_handle(QemuThread *thread); -+HANDLE qemu_thread_get_handle(struct QemuThread *thread); - - #endif -diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h -index c8f6145257..aea0c44985 100644 ---- a/include/sysemu/balloon.h -+++ b/include/sysemu/balloon.h -@@ -14,6 +14,7 @@ - #ifndef QEMU_BALLOON_H - #define QEMU_BALLOON_H - -+#include "exec/cpu-common.h" - #include "qapi/qapi-types-misc.h" - - typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target); -diff --git a/include/sysemu/cryptodev-vhost-user.h b/include/sysemu/cryptodev-vhost-user.h -index 6debf53fc5..0d3421e7e8 100644 ---- a/include/sysemu/cryptodev-vhost-user.h -+++ b/include/sysemu/cryptodev-vhost-user.h -@@ -20,9 +20,12 @@ - * License along with this library; if not, see . - * - */ -+ - #ifndef CRYPTODEV_VHOST_USER_H - #define CRYPTODEV_VHOST_USER_H - -+#include "sysemu/cryptodev-vhost.h" -+ - #define VHOST_USER_MAX_AUTH_KEY_LEN 512 - #define VHOST_USER_MAX_CIPHER_KEY_LEN 64 - -diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h -index d275b5a843..dd1722f2df 100644 ---- a/include/sysemu/hvf.h -+++ b/include/sysemu/hvf.h -@@ -13,6 +13,7 @@ - #ifndef HVF_H - #define HVF_H - -+#include "cpu.h" - #include "qemu/bitops.h" - #include "exec/memory.h" - #include "sysemu/accel.h" -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index 5f6240d5cb..6181486401 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -16,6 +16,7 @@ - - #include "block/aio.h" - #include "qemu/thread.h" -+#include "qom/object.h" - - #define TYPE_IOTHREAD "iothread" - -diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h -index 31df465fdc..787dbc7770 100644 ---- a/include/sysemu/kvm_int.h -+++ b/include/sysemu/kvm_int.h -@@ -9,6 +9,8 @@ - #ifndef QEMU_KVM_INT_H - #define QEMU_KVM_INT_H - -+#include "exec/cpu-common.h" -+#include "exec/memory.h" - #include "sysemu/sysemu.h" - #include "sysemu/accel.h" - #include "sysemu/kvm.h" -diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h -index 58452457ce..1b440df486 100644 ---- a/include/sysemu/memory_mapping.h -+++ b/include/sysemu/memory_mapping.h -@@ -15,6 +15,8 @@ - #define MEMORY_MAPPING_H - - #include "qemu/queue.h" -+#include "exec/cpu-common.h" -+#include "exec/cpu-defs.h" - #include "exec/memory.h" - - typedef struct GuestPhysBlock { -diff --git a/include/sysemu/xen-mapcache.h b/include/sysemu/xen-mapcache.h -index a03e2f1878..c8e7c2f6cf 100644 ---- a/include/sysemu/xen-mapcache.h -+++ b/include/sysemu/xen-mapcache.h -@@ -9,6 +9,8 @@ - #ifndef XEN_MAPCACHE_H - #define XEN_MAPCACHE_H - -+#include "exec/cpu-common.h" -+ - typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset, - ram_addr_t size); - #ifdef CONFIG_XEN -diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h -index d714127799..58bd3a1ec4 100644 ---- a/include/ui/egl-helpers.h -+++ b/include/ui/egl-helpers.h -@@ -4,6 +4,9 @@ - #include - #include - #include -+#include "qapi/qapi-types-ui.h" -+#include "ui/console.h" -+#include "ui/shader.h" - - extern EGLDisplay *qemu_egl_display; - extern EGLConfig qemu_egl_config; -diff --git a/include/ui/input.h b/include/ui/input.h -index 8c8ccb999f..c86219a1c1 100644 ---- a/include/ui/input.h -+++ b/include/ui/input.h -@@ -2,6 +2,7 @@ - #define INPUT_H - - #include "qapi/qapi-types-ui.h" -+#include "qemu/notify.h" - - #define INPUT_EVENT_MASK_KEY (1< - #include - #include - #include -diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h -index aab251bc4b..e9fba96be9 100644 ---- a/target/hppa/cpu.h -+++ b/target/hppa/cpu.h -@@ -22,7 +22,7 @@ - - #include "cpu-qom.h" - #include "exec/cpu-defs.h" -- -+#include "exec/memory.h" - - /* PA-RISC 1.x processors have a strong memory model. */ - /* ??? While we do not yet implement PA-RISC 2.0, those processors have --- -2.27.0 - diff --git a/include-hw-start-documenting-the-vhost-API.patch b/include-hw-start-documenting-the-vhost-API.patch new file mode 100644 index 0000000000000000000000000000000000000000..f53f07c16a49f4984360332dd0d01249ebc02fb3 --- /dev/null +++ b/include-hw-start-documenting-the-vhost-API.patch @@ -0,0 +1,192 @@ +From 6e43246f43753030a247c23cd6082792a588817b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 21 Mar 2022 15:30:34 +0000 +Subject: [PATCH] include/hw: start documenting the vhost API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While trying to get my head around the nest of interactions for vhost +devices I though I could start by documenting the key API functions. +This patch documents the main API hooks for creating and starting a +vhost device as well as how the configuration changes are handled. + +Signed-off-by: Alex Bennée +Cc: Michael S. Tsirkin +Cc: Stefan Hajnoczi +Cc: Marc-André Lureau +Message-Id: <20220321153037.3622127-11-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + include/hw/virtio/vhost.h | 132 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 122 insertions(+), 10 deletions(-) + +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 86f36f0106..d7ab2579ff 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -61,6 +61,12 @@ typedef struct VhostDevConfigOps { + } VhostDevConfigOps; + + struct vhost_memory; ++ ++/** ++ * struct vhost_dev - common vhost_dev structure ++ * @vhost_ops: backend specific ops ++ * @config_ops: ops for config changes (see @vhost_dev_set_config_notifier) ++ */ + struct vhost_dev { + VirtIODevice *vdev; + MemoryListener memory_listener; +@@ -108,15 +114,129 @@ struct vhost_net { + NetClientState *nc; + }; + ++/** ++ * vhost_dev_init() - initialise the vhost interface ++ * @hdev: the common vhost_dev structure ++ * @opaque: opaque ptr passed to backend (vhost/vhost-user/vdpa) ++ * @backend_type: type of backend ++ * @busyloop_timeout: timeout for polling virtqueue ++ * @errp: error handle ++ * ++ * The initialisation of the vhost device will trigger the ++ * initialisation of the backend and potentially capability ++ * negotiation of backend interface. Configuration of the VirtIO ++ * itself won't happen until the interface is started. ++ * ++ * Return: 0 on success, non-zero on error while setting errp. ++ */ + int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + VhostBackendType backend_type, + uint32_t busyloop_timeout, Error **errp); ++ ++/** ++ * vhost_dev_cleanup() - tear down and cleanup vhost interface ++ * @hdev: the common vhost_dev structure ++ */ + void vhost_dev_cleanup(struct vhost_dev *hdev); +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_enable_notifiers() - enable event notifiers ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Enable notifications directly to the vhost device rather than being ++ * triggered by QEMU itself. Notifications should be enabled before ++ * the vhost device is started via @vhost_dev_start. ++ * ++ * Return: 0 on success, < 0 on error. ++ */ + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_disable_notifiers - disable event notifications ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Disable direct notifications to vhost device. ++ */ + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + ++/** ++ * vhost_dev_start() - start the vhost device ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Starts the vhost device. From this point VirtIO feature negotiation ++ * can start and the device can start processing VirtIO transactions. ++ * ++ * Return: 0 on success, < 0 on error. ++ */ ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_stop() - stop the vhost device ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Stop the vhost device. After the device is stopped the notifiers ++ * can be disabled (@vhost_dev_disable_notifiers) and the device can ++ * be torn down (@vhost_dev_cleanup). ++ */ ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * DOC: vhost device configuration handling ++ * ++ * The VirtIO device configuration space is used for rarely changing ++ * or initialisation time parameters. The configuration can be updated ++ * by either the guest driver or the device itself. If the device can ++ * change the configuration over time the vhost handler should ++ * register a @VhostDevConfigOps structure with ++ * @vhost_dev_set_config_notifier so the guest can be notified. Some ++ * devices register a handler anyway and will signal an error if an ++ * unexpected config change happens. ++ */ ++ ++/** ++ * vhost_dev_get_config() - fetch device configuration ++ * @hdev: common vhost_dev_structure ++ * @config: pointer to device appropriate config structure ++ * @config_len: size of device appropriate config structure ++ * ++ * Return: 0 on success, < 0 on error while setting errp ++ */ ++int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, ++ uint32_t config_len, Error **errp); ++ ++/** ++ * vhost_dev_set_config() - set device configuration ++ * @hdev: common vhost_dev_structure ++ * @data: pointer to data to set ++ * @offset: offset into configuration space ++ * @size: length of set ++ * @flags: @VhostSetConfigType flags ++ * ++ * By use of @offset/@size a subset of the configuration space can be ++ * written to. The @flags are used to indicate if it is a normal ++ * transaction or related to migration. ++ * ++ * Return: 0 on success, non-zero on error ++ */ ++int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, ++ uint32_t offset, uint32_t size, uint32_t flags); ++ ++/** ++ * vhost_dev_set_config_notifier() - register VhostDevConfigOps ++ * @hdev: common vhost_dev_structure ++ * @ops: notifier ops ++ * ++ * If the device is expected to change configuration a notifier can be ++ * setup to handle the case. ++ */ ++void vhost_dev_set_config_notifier(struct vhost_dev *dev, ++ const VhostDevConfigOps *ops); ++ ++ + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. + */ +@@ -136,14 +256,6 @@ int vhost_net_set_backend(struct vhost_dev *hdev, + struct vhost_vring_file *file); + + int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write); +-int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, +- uint32_t config_len, Error **errp); +-int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, +- uint32_t offset, uint32_t size, uint32_t flags); +-/* notifier callback in case vhost device config space changed +- */ +-void vhost_dev_set_config_notifier(struct vhost_dev *dev, +- const VhostDevConfigOps *ops); + + void vhost_dev_reset_inflight(struct vhost_inflight *inflight); + void vhost_dev_free_inflight(struct vhost_inflight *inflight); +-- +2.27.0 + diff --git a/intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch b/intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch deleted file mode 100644 index d69dcc71825a8ed70e133ffb7d28af03a08485a1..0000000000000000000000000000000000000000 --- a/intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 15849387df5c25e8ebaef19e2a16e8d428675f5d Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Thu, 3 Oct 2019 17:46:39 +0200 -Subject: [PATCH 2/3] intc/arm_gic: Support IRQ injection for more than 256 - vpus - -Host kernels that expose the KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 capability -allow injection of interrupts along with vcpu ids larger than 255. -Let's encode the vpcu id on 12 bits according to the upgraded KVM_IRQ_LINE -ABI when needed. - -Given that we have two callsites that need to assemble -the value for kvm_set_irq(), a new helper routine, kvm_arm_set_irq -is introduced. - -Without that patch qemu exits with "kvm_set_irq: Invalid argument" -message. - -Signed-off-by: Eric Auger -Reported-by: Zenghui Yu -Reviewed-by: Richard Henderson -Reviewed-by: Andrew Jones -Acked-by: Marc Zyngier -Message-id: 20191003154640.22451-3-eric.auger@redhat.com -Signed-off-by: Peter Maydell -(cherry-picked from commit f6530926e2310147a7844a3e663230d47b3d7333) -Signed-off-by: Zenghui Yu ---- - hw/intc/arm_gic_kvm.c | 7 ++----- - target/arm/cpu.c | 10 ++++------ - target/arm/kvm.c | 12 ++++++++++++ - target/arm/kvm_arm.h | 1 + - 4 files changed, 19 insertions(+), 11 deletions(-) - -diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c -index a611e8ee..7d600a61 100644 ---- a/hw/intc/arm_gic_kvm.c -+++ b/hw/intc/arm_gic_kvm.c -@@ -55,7 +55,7 @@ void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) - * has separate fields in the irq number for type, - * CPU number and interrupt number. - */ -- int kvm_irq, irqtype, cpu; -+ int irqtype, cpu; - - if (irq < (num_irq - GIC_INTERNAL)) { - /* External interrupt. The kernel numbers these like the GIC -@@ -72,10 +72,7 @@ void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) - cpu = irq / GIC_INTERNAL; - irq %= GIC_INTERNAL; - } -- kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) -- | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq; -- -- kvm_set_irq(kvm_state, kvm_irq, !!level); -+ kvm_arm_set_irq(cpu, irqtype, irq, !!level); - } - - static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level) -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 41557821..0b4c8e27 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -561,16 +561,16 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) - ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; - CPUState *cs = CPU(cpu); -- int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT; - uint32_t linestate_bit; -+ int irq_id; - - switch (irq) { - case ARM_CPU_IRQ: -- kvm_irq |= KVM_ARM_IRQ_CPU_IRQ; -+ irq_id = KVM_ARM_IRQ_CPU_IRQ; - linestate_bit = CPU_INTERRUPT_HARD; - break; - case ARM_CPU_FIQ: -- kvm_irq |= KVM_ARM_IRQ_CPU_FIQ; -+ irq_id = KVM_ARM_IRQ_CPU_FIQ; - linestate_bit = CPU_INTERRUPT_FIQ; - break; - default: -@@ -582,9 +582,7 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) - } else { - env->irq_line_state &= ~linestate_bit; - } -- -- kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT; -- kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0); -+ kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level); - #endif - } - -diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index 79a79f01..f60185ad 100644 ---- a/target/arm/kvm.c -+++ b/target/arm/kvm.c -@@ -728,6 +728,18 @@ int kvm_arm_vgic_probe(void) - } - } - -+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level) -+{ -+ int kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) | irq; -+ int cpu_idx1 = cpu % 256; -+ int cpu_idx2 = cpu / 256; -+ -+ kvm_irq |= (cpu_idx1 << KVM_ARM_IRQ_VCPU_SHIFT) | -+ (cpu_idx2 << KVM_ARM_IRQ_VCPU2_SHIFT); -+ -+ return kvm_set_irq(kvm_state, kvm_irq, !!level); -+} -+ - int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data, PCIDevice *dev) - { -diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 2a07333c..a9f3ccab 100644 ---- a/target/arm/kvm_arm.h -+++ b/target/arm/kvm_arm.h -@@ -235,6 +235,7 @@ int kvm_arm_vgic_probe(void); - - void kvm_arm_pmu_set_irq(CPUState *cs, int irq); - void kvm_arm_pmu_init(CPUState *cs); -+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); - - #else - --- -2.19.1 - diff --git a/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch index 30175fb5126a8a9b7138c206365b61c96bcddaf0..a68cdcbeecbc625c0313bc0bcf2b206eea5c8c17 100644 --- a/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch +++ b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch @@ -1,4 +1,4 @@ -From 0a75312c069d89be94bcaa688429d8f60a0c528b Mon Sep 17 00:00:00 2001 +From 3ed7dcc4a8ccf443d125e7908d8293b562c68d4b Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 13:15:35 +0800 Subject: [PATCH] intc/gicv3: Add pre-sizing capability to GICv3 @@ -20,17 +20,17 @@ Signed-off-by: Salil Mehta --- hw/arm/virt.c | 17 +++++++++++---- hw/intc/arm_gicv3.c | 43 +++++++++++++++++++++++++------------- - hw/intc/arm_gicv3_common.c | 23 ++++++++++++++++++-- + hw/intc/arm_gicv3_common.c | 22 +++++++++++++++++-- hw/intc/arm_gicv3_cpuif.c | 4 ++++ hw/intc/arm_gicv3_kvm.c | 28 ++++++++++++++++++++++++- include/hw/arm/virt.h | 3 ++- - 6 files changed, 96 insertions(+), 22 deletions(-) + 6 files changed, 95 insertions(+), 22 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 55d403bad6..dda22194b5 100644 +index 0af0a996a1..b1224fb1e4 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -761,14 +761,19 @@ static void create_gic(VirtMachineState *vms) +@@ -827,14 +827,19 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) SysBusDevice *gicbusdev; const char *gictype; int type = vms->gic_version, i; @@ -39,38 +39,38 @@ index 55d403bad6..dda22194b5 100644 + /* The number of CPUs present before boot */ unsigned int smp_cpus = ms->smp.cpus; uint32_t nb_redist_regions = 0; - + + assert(num_cpus >= smp_cpus); + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); - - vms->gic = qdev_create(NULL, gictype); + + vms->gic = qdev_new(gictype); qdev_prop_set_uint32(vms->gic, "revision", type); - qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); + qdev_prop_set_uint32(vms->gic, "num-cpu", num_cpus); /* Note that the num-irq property counts both internal and external * interrupts; there are always 32 of the former (mandated by GIC spec). */ -@@ -780,7 +785,7 @@ static void create_gic(VirtMachineState *vms) +@@ -846,7 +851,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) if (type == 3) { uint32_t redist0_capacity = vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; - uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); + uint32_t redist0_count = MIN(num_cpus, redist0_capacity); - + nb_redist_regions = virt_gicv3_redist_region_count(vms); - -@@ -793,7 +798,7 @@ static void create_gic(VirtMachineState *vms) + +@@ -867,7 +872,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; - + qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", - MIN(smp_cpus - redist0_count, redist1_capacity)); + MIN(num_cpus - redist0_count, redist1_capacity)); } } else { if (!kvm_irqchip_in_kernel()) { -@@ -820,7 +825,11 @@ static void create_gic(VirtMachineState *vms) - +@@ -894,7 +899,11 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) + /* Wire the outputs from each CPU's generic timer and the GICv3 * maintenance interrupt signal to the appropriate GIC PPI inputs, - * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. @@ -83,43 +83,43 @@ index 55d403bad6..dda22194b5 100644 for (i = 0; i < smp_cpus; i++) { connect_gic_cpu_irqs(vms, i); diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c -index cacef26546..a60185113f 100644 +index 9591cfbcc0..864d4e4034 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c -@@ -20,6 +20,7 @@ +@@ -19,6 +19,7 @@ + #include "qapi/error.h" #include "qemu/module.h" - #include "hw/sysbus.h" #include "hw/intc/arm_gicv3.h" -+#include "qom/cpu.h" ++#include "hw/core/cpu.h" #include "gicv3_internal.h" - + static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) -@@ -206,7 +207,9 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) +@@ -217,7 +218,9 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) assert(len > 0); - + for (i = 0; i < s->num_cpu; i++) { - s->cpu[i].seenbetter = false; + if (qemu_get_cpu(i)) { + s->cpu[i].seenbetter = false; + } } - + /* Find the highest priority pending interrupt in this range. */ -@@ -248,16 +251,18 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) +@@ -259,16 +262,18 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) * now be the new best one). */ for (i = 0; i < s->num_cpu; i++) { - GICv3CPUState *cs = &s->cpu[i]; + if (qemu_get_cpu(i)) { + GICv3CPUState *cs = &s->cpu[i]; - + - if (cs->seenbetter) { - cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); - } + if (cs->seenbetter) { + cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); + } - + - if (!cs->seenbetter && cs->hppi.prio != 0xff && - cs->hppi.irq >= start && cs->hppi.irq < start + len) { - gicv3_full_update_noirqset(s); @@ -132,8 +132,8 @@ index cacef26546..a60185113f 100644 } } } -@@ -268,7 +273,9 @@ void gicv3_update(GICv3State *s, int start, int len) - +@@ -279,7 +284,9 @@ void gicv3_update(GICv3State *s, int start, int len) + gicv3_update_noirqset(s, start, len); for (i = 0; i < s->num_cpu; i++) { - gicv3_cpuif_update(&s->cpu[i]); @@ -142,21 +142,21 @@ index cacef26546..a60185113f 100644 + } } } - -@@ -280,7 +287,9 @@ void gicv3_full_update_noirqset(GICv3State *s) + +@@ -291,7 +298,9 @@ void gicv3_full_update_noirqset(GICv3State *s) int i; - + for (i = 0; i < s->num_cpu; i++) { - s->cpu[i].hppi.prio = 0xff; + if (qemu_get_cpu(i)) { + s->cpu[i].hppi.prio = 0xff; + } } - + /* Note that we can guarantee that these functions will not -@@ -291,7 +300,9 @@ void gicv3_full_update_noirqset(GICv3State *s) +@@ -302,7 +311,9 @@ void gicv3_full_update_noirqset(GICv3State *s) gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL); - + for (i = 0; i < s->num_cpu; i++) { - gicv3_redist_update_noirqset(&s->cpu[i]); + if (qemu_get_cpu(i)) { @@ -164,9 +164,9 @@ index cacef26546..a60185113f 100644 + } } } - -@@ -304,7 +315,9 @@ void gicv3_full_update(GICv3State *s) - + +@@ -315,7 +326,9 @@ void gicv3_full_update(GICv3State *s) + gicv3_full_update_noirqset(s); for (i = 0; i < s->num_cpu; i++) { - gicv3_cpuif_update(&s->cpu[i]); @@ -175,10 +175,10 @@ index cacef26546..a60185113f 100644 + } } } - -@@ -401,7 +414,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) - } - + +@@ -406,7 +419,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops); + for (i = 0; i < s->num_cpu; i++) { - gicv3_cpu_realize(s, i); + if (qemu_get_cpu(i)) { @@ -186,42 +186,43 @@ index cacef26546..a60185113f 100644 + } } } - + diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c -index 8740a52c9f..913bf068be 100644 +index f8ef6817a4..a4976b2ba0 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c -@@ -24,10 +24,12 @@ +@@ -24,12 +24,14 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/error-report.h" - #include "qom/cpu.h" + #include "hw/core/cpu.h" #include "hw/intc/arm_gicv3_common.h" + #include "hw/qdev-properties.h" + #include "migration/vmstate.h" #include "gicv3_internal.h" #include "hw/arm/linux-boot-if.h" +#include "hw/boards.h" #include "sysemu/kvm.h" - - -@@ -363,10 +365,15 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + + +@@ -377,9 +379,14 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { CPUState *cpu = qemu_get_cpu(i); - + + MachineState *ms = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus = NULL; uint64_t cpu_affid; - int last; - + - arm_gicv3_common_cpu_realize(s, i); + if (cpu) { + arm_gicv3_common_cpu_realize(s, i); + } - + /* Pre-construct the GICR_TYPER: * For our implementation: -@@ -380,7 +387,19 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) +@@ -393,7 +400,18 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) * VLPIS == 0 (virtual LPIs not supported) * PLPIS == 0 (physical LPIs not supported) */ @@ -238,33 +239,32 @@ index 8740a52c9f..913bf068be 100644 + possible_cpus = mc->possible_cpu_arch_ids(ms); + cpu_affid = possible_cpus->cpus[i].arch_id; + } -+ - last = (i == s->num_cpu - 1); - + /* The CPU mp-affinity property is in MPIDR register format; squash + * the affinity bytes into 32 bits as the GICR_TYPER has them. diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c -index 56aa5efede..a20aa693ea 100644 +index 70809bcddd..274a40a40c 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c -@@ -1648,6 +1648,10 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs, +@@ -1676,6 +1676,10 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs, aff, targetlist); - + for (i = 0; i < s->num_cpu; i++) { + if (!qemu_get_cpu(i)) { + continue; + } + GICv3CPUState *ocs = &s->cpu[i]; - + if (irm) { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c -index f8d7be5479..8eea7c9dd9 100644 +index 95271e754b..2e2b08e31f 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c -@@ -341,6 +341,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) +@@ -342,6 +342,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { GICv3CPUState *c = &s->cpu[ncpu]; - + + if (!qemu_get_cpu(ncpu)) { + continue; + } @@ -272,21 +272,21 @@ index f8d7be5479..8eea7c9dd9 100644 reg64 = c->gicr_propbaser; regl = (uint32_t)reg64; kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, true); -@@ -366,6 +370,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) +@@ -361,6 +365,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { GICv3CPUState *c = &s->cpu[ncpu]; - + + if (!qemu_get_cpu(ncpu)) { + continue; + } + reg = c->gicr_ctlr; kvm_gicr_access(s, GICR_CTLR, ncpu, ®, true); - -@@ -462,6 +470,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) + +@@ -457,6 +465,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) GICv3CPUState *c = &s->cpu[ncpu]; int num_pri_bits; - + + if (!qemu_get_cpu(ncpu)) { + continue; + } @@ -294,19 +294,19 @@ index f8d7be5479..8eea7c9dd9 100644 kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true); kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, &c->icc_ctlr_el1[GICV3_NS], true); -@@ -525,6 +537,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) +@@ -524,6 +536,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) /* Redistributor state (one per CPU) */ - + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + if (!qemu_get_cpu(ncpu)) { + continue; + } + GICv3CPUState *c = &s->cpu[ncpu]; - + kvm_gicr_access(s, GICR_CTLR, ncpu, ®, false); -@@ -560,6 +576,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) - +@@ -559,6 +575,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) + if (redist_typer & GICR_TYPER_PLPIS) { for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + if (!qemu_get_cpu(ncpu)) { @@ -314,11 +314,11 @@ index f8d7be5479..8eea7c9dd9 100644 + } + GICv3CPUState *c = &s->cpu[ncpu]; - + kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, false); -@@ -613,6 +633,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) +@@ -612,6 +632,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) */ - + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + if (!qemu_get_cpu(ncpu)) { + continue; @@ -326,32 +326,33 @@ index f8d7be5479..8eea7c9dd9 100644 + GICv3CPUState *c = &s->cpu[ncpu]; int num_pri_bits; - -@@ -806,7 +830,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) - } - + +@@ -805,7 +829,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); + for (i = 0; i < s->num_cpu; i++) { - kvm_arm_gicv3_cpu_realize(s, i); + if (qemu_get_cpu(i)) { + kvm_arm_gicv3_cpu_realize(s, i); + } } - + /* Try to create the device via the device control API */ diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 6880ebe07c..beef4c8002 100644 +index 2a838620d8..947d41f767 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -168,8 +168,9 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) +@@ -196,8 +196,9 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; - - assert(vms->gic_version == 3); + + assert(vms->gic_version == VIRT_GIC_VERSION_3); + GICv3State *s = ARM_GICV3_COMMON(vms->gic); - -- return vms->smp_cpus > redist0_capacity ? 2 : 1; + +- return MACHINE(vms)->smp.cpus > redist0_capacity ? 2 : 1; + return s->num_cpu > redist0_capacity ? 2 : 1; } - + #endif /* QEMU_ARM_VIRT_H */ --- -2.19.1 +-- +2.27.0 + diff --git a/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch b/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch index 5232d3f2aeda4d3a8a83a725173eaff72d2af8d5..043573e8e69b51928402404d6bbc5fd8dd577e7d 100644 --- a/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch +++ b/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch @@ -1,4 +1,4 @@ -From a7391f391336024986a5997e3beae8882c983ed0 Mon Sep 17 00:00:00 2001 +From 06cb0756a01796352861b4d47d59db1bde84ec6f Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 12:55:17 +0800 Subject: [PATCH] intc/gicv3_common: Factor out arm_gicv3_common_cpu_realize @@ -14,13 +14,13 @@ Signed-off-by: Salil Mehta 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c -index 5edabb928f..798f295d7c 100644 +index 9884d2e39b..1a11d1986d 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c -@@ -303,6 +303,16 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, +@@ -301,6 +301,16 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, } } - + +static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) +{ + CPUState *cpu = qemu_get_cpu(ncpu); @@ -34,17 +34,18 @@ index 5edabb928f..798f295d7c 100644 static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) { GICv3State *s = ARM_GICV3_COMMON(dev); -@@ -350,10 +360,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) +@@ -363,10 +373,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + CPUState *cpu = qemu_get_cpu(i); uint64_t cpu_affid; - int last; - + - s->cpu[i].cpu = cpu; - s->cpu[i].gic = s; - /* Store GICv3CPUState in CPUARMState gicv3state pointer */ - gicv3_set_gicv3state(cpu, &s->cpu[i]); + arm_gicv3_common_cpu_realize(s, i); - + /* Pre-construct the GICR_TYPER: * For our implementation: --- -2.19.1 +-- +2.27.0 + diff --git a/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch index 95c60b02c66e48b2fbe6d64c5e139aa3ecdcfae9..87c93443458f9c763eae9dfc0b0406f27a9b205e 100644 --- a/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch +++ b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch @@ -1,4 +1,4 @@ -From de97ff4a01008ad98f7d69adc4b84843fff3ce19 Mon Sep 17 00:00:00 2001 +From 62b5c897e367c3db477a680b7557662347677433 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 10:59:55 +0800 Subject: [PATCH] intc/gicv3_cpuif: Factor out gicv3_init_one_cpuif @@ -16,36 +16,36 @@ Signed-off-by: Salil Mehta 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c -index 66eaa97198..2fe79f794d 100644 +index 9f5f815db9..40016cb84a 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c -@@ -367,6 +367,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) +@@ -382,6 +382,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) GICv3State *s = ARM_GICV3(dev); ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); Error *local_err = NULL; + int i; - + agc->parent_realize(dev, &local_err); if (local_err) { -@@ -386,7 +387,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) - return; - } - +@@ -391,7 +392,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + + gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops); + - gicv3_init_cpuif(s); + for (i = 0; i < s->num_cpu; i++) { + gicv3_init_one_cpuif(s, i); + } } - + static void arm_gicv3_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c -index 3b212d91c8..56aa5efede 100644 +index 85fc369e55..70809bcddd 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c -@@ -2597,78 +2597,74 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) +@@ -2625,76 +2625,72 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) gicv3_cpuif_update(cs); } - + -void gicv3_init_cpuif(GICv3State *s) +void gicv3_init_one_cpuif(GICv3State *s, int ncpu) { @@ -64,11 +64,6 @@ index 3b212d91c8..56aa5efede 100644 - * which case we'd get the wrong value. - * So instead we define the regs with no ri->opaque info, and - * get back to the GICv3CPUState from the CPUARMState. -- */ -- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); -- if (arm_feature(&cpu->env, ARM_FEATURE_EL2) -- && cpu->gic_num_lrs) { -- int j; + ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu)); + GICv3CPUState *cs = &s->cpu[ncpu]; + @@ -83,17 +78,24 @@ index 3b212d91c8..56aa5efede 100644 + if (arm_feature(&cpu->env, ARM_FEATURE_EL2) + && cpu->gic_num_lrs) { + int j; - -- cs->maintenance_irq = cpu->gicv3_maintenance_interrupt; -+ cs->maintenance_irq = cpu->gicv3_maintenance_interrupt; - -- cs->num_list_regs = cpu->gic_num_lrs; -- cs->vpribits = cpu->gic_vpribits; -- cs->vprebits = cpu->gic_vprebits; ++ + cs->num_list_regs = cpu->gic_num_lrs; + cs->vpribits = cpu->gic_vpribits; + cs->vprebits = cpu->gic_vprebits; - ++ ++ /* Check against architectural constraints: getting these ++ * wrong would be a bug in the CPU code defining these, ++ * and the implementation relies on them holding. + */ +- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); +- if (arm_feature(&cpu->env, ARM_FEATURE_EL2) +- && cpu->gic_num_lrs) { +- int j; +- +- cs->num_list_regs = cpu->gic_num_lrs; +- cs->vpribits = cpu->gic_vpribits; +- cs->vprebits = cpu->gic_vprebits; +- - /* Check against architectural constraints: getting these - * wrong would be a bug in the CPU code defining these, - * and the implementation relies on them holding. @@ -101,17 +103,13 @@ index 3b212d91c8..56aa5efede 100644 - g_assert(cs->vprebits <= cs->vpribits); - g_assert(cs->vprebits >= 5 && cs->vprebits <= 7); - g_assert(cs->vpribits >= 5 && cs->vpribits <= 8); -+ /* Check against architectural constraints: getting these -+ * wrong would be a bug in the CPU code defining these, -+ * and the implementation relies on them holding. -+ */ + g_assert(cs->vprebits <= cs->vpribits); + g_assert(cs->vprebits >= 5 && cs->vprebits <= 7); + g_assert(cs->vpribits >= 5 && cs->vpribits <= 8); - + - define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); + define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); - + - for (j = 0; j < cs->num_list_regs; j++) { - /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs - * are split into two cp15 regs, LR (the low part, with the @@ -181,17 +179,18 @@ index 3b212d91c8..56aa5efede 100644 + arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); } diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h -index 05303a55c8..cfbfe8a549 100644 +index b9c37453b0..65db012600 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h -@@ -297,7 +297,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, - void gicv3_dist_set_irq(GICv3State *s, int irq, int level); - void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); +@@ -495,7 +495,7 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs); + */ + void gicv3_redist_update_lpi_only(GICv3CPUState *cs); void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); -void gicv3_init_cpuif(GICv3State *s); +void gicv3_init_one_cpuif(GICv3State *s, int ncpu); - + /** * gicv3_cpuif_update: --- -2.19.1 +-- +2.27.0 + diff --git a/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch b/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch index 6af9a8f4f55fa4ce936c9d5898cd5c232abcaa9a..f9f4b940cc5efc5bb52f9be0f4b4e72c57e31769 100644 --- a/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch +++ b/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch @@ -1,4 +1,4 @@ -From f45964c7e0df4ef17457a9ea92bfd255064139e1 Mon Sep 17 00:00:00 2001 +From dd03bc60712bd41a9606742ea4b769aa8e360655 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 10 Apr 2020 12:49:12 +0800 Subject: [PATCH] intc/kvm_gicv3: Factor out kvm_arm_gicv3_cpu_realize @@ -14,32 +14,33 @@ Signed-off-by: Salil Mehta 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c -index b1e74147ba..b2936938cb 100644 +index 5ec5ff9ef6..596b31998b 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c -@@ -761,6 +761,12 @@ static void vm_change_state_handler(void *opaque, int running, +@@ -764,6 +764,12 @@ static void vm_change_state_handler(void *opaque, bool running, } } - + +static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu) +{ + ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu)); + + define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); +} - + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { -@@ -791,9 +797,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) - } - +@@ -790,9 +796,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); + for (i = 0; i < s->num_cpu; i++) { - ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); - - define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); + kvm_arm_gicv3_cpu_realize(s, i); } - + /* Try to create the device via the device control API */ --- -2.19.1 +-- +2.27.0 + diff --git a/io-Don-t-use-flag-of-printf-format.patch b/io-Don-t-use-flag-of-printf-format.patch deleted file mode 100644 index 61f3b71dda336dbc2c833b323880f7dd3be09dec..0000000000000000000000000000000000000000 --- a/io-Don-t-use-flag-of-printf-format.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0aa003cd0e117cb160da7d4b6e50630bf2fedfd6 Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Mon, 19 Oct 2020 20:12:02 +0800 -Subject: [PATCH] io: Don't use '#' flag of printf format -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: AlexChen -Signed-off-by: Daniel P. Berrangé -(cherry-picked from commit 77b7829e75) ---- - io/channel-websock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index fc36d44eba..d48a929e49 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -734,7 +734,7 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - opcode != QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE && - opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PING && - opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { -- error_setg(errp, "unsupported opcode: %#04x; only binary, close, " -+ error_setg(errp, "unsupported opcode: 0x%04x; only binary, close, " - "ping, and pong websocket frames are supported", opcode); - qio_channel_websock_write_close( - ioc, QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA , --- -2.27.0 - diff --git a/io-remove-io-watch-if-TLS-channel-is-closed-during-h.patch b/io-remove-io-watch-if-TLS-channel-is-closed-during-h.patch new file mode 100644 index 0000000000000000000000000000000000000000..73205745000ac9d3aa889999a2dc90fe6e64bc77 --- /dev/null +++ b/io-remove-io-watch-if-TLS-channel-is-closed-during-h.patch @@ -0,0 +1,83 @@ +From 979bb24c769a703c96067c9557d433492916aa67 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Tue, 20 Jun 2023 09:45:34 +0100 +Subject: [PATCH] io: remove io watch if TLS channel is closed during handshake +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The TLS handshake make take some time to complete, during which time an +I/O watch might be registered with the main loop. If the owner of the +I/O channel invokes qio_channel_close() while the handshake is waiting +to continue the I/O watch must be removed. Failing to remove it will +later trigger the completion callback which the owner is not expecting +to receive. In the case of the VNC server, this results in a SEGV as +vnc_disconnect_start() tries to shutdown a client connection that is +already gone / NULL. + +CVE-2023-3354 +Reported-by: jiangyegen +Signed-off-by: Daniel P. Berrangé +--- + include/io/channel-tls.h | 1 + + io/channel-tls.c | 18 ++++++++++++------ + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h +index 5672479e9e..26c67f17e2 100644 +--- a/include/io/channel-tls.h ++++ b/include/io/channel-tls.h +@@ -48,6 +48,7 @@ struct QIOChannelTLS { + QIOChannel *master; + QCryptoTLSSession *session; + QIOChannelShutdown shutdown; ++ guint hs_ioc_tag; + }; + + /** +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 2ae1b92fc0..34476e6b7b 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -195,12 +195,13 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, + } + + trace_qio_channel_tls_handshake_pending(ioc, status); +- qio_channel_add_watch_full(ioc->master, +- condition, +- qio_channel_tls_handshake_io, +- data, +- NULL, +- context); ++ ioc->hs_ioc_tag = ++ qio_channel_add_watch_full(ioc->master, ++ condition, ++ qio_channel_tls_handshake_io, ++ data, ++ NULL, ++ context); + } + } + +@@ -215,6 +216,7 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, + QIOChannelTLS *tioc = QIO_CHANNEL_TLS( + qio_task_get_source(task)); + ++ tioc->hs_ioc_tag = 0; + g_free(data); + qio_channel_tls_handshake_task(tioc, task, context); + +@@ -373,6 +375,10 @@ static int qio_channel_tls_close(QIOChannel *ioc, + { + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + ++ if (tioc->hs_ioc_tag) { ++ g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove); ++ } ++ + return qio_channel_close(tioc->master, errp); + } + +-- +2.41.0.windows.1 + diff --git a/io_uring-fix-short-read-slow-path.patch b/io_uring-fix-short-read-slow-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a0722beb2f4a32655549749a363682f286c6126 --- /dev/null +++ b/io_uring-fix-short-read-slow-path.patch @@ -0,0 +1,55 @@ +From 78cb2c9c218155d048e566c5ac6d59961703b5d3 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:14:40 +0000 +Subject: [PATCH] io_uring: fix short read slow path mainline inclusion commit + c06fc7ce147e57ab493bad9263f1601b8298484b category: bugfix + +--------------------------------------------------------------- + +sqeq.off here is the offset to read within the disk image, so obviously +not 'nread' (the amount we just read), but as the author meant to write +its current value incremented by the amount we just read. + +Normally recent versions of linux will not issue short reads, +but it can happen so we should fix this. + +This lead to weird image corruptions when short read happened + +Fixes: 6663a0a33764 ("block/io_uring: implements interfaces for io_uring") +Link: https://lkml.kernel.org/r/YrrFGO4A1jS0GI0G@atmark-techno.com +Signed-off-by: Dominique Martinet +Message-Id: <20220630010137.2518851-1-dominique.martinet@atmark-techno.com> +Reviewed-by: Hanna Reitz +Reviewed-by: Stefano Garzarella +Signed-off-by: Stefan Hajnoczi + +Signed-off-by: tangbinzy +--- + block/io_uring.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/io_uring.c b/block/io_uring.c +index dfa475cc87..e88d75d462 100644 +--- a/block/io_uring.c ++++ b/block/io_uring.c +@@ -89,7 +89,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, + trace_luring_resubmit_short_read(s, luringcb, nread); + + /* Update read position */ +- luringcb->total_read = nread; ++ luringcb->total_read += nread; + remaining = luringcb->qiov->size - luringcb->total_read; + + /* Shorten qiov */ +@@ -103,7 +103,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, + remaining); + + /* Update sqe */ +- luringcb->sqeq.off = nread; ++ luringcb->sqeq.off += nread; + luringcb->sqeq.addr = (__u64)(uintptr_t)luringcb->resubmit_qiov.iov; + luringcb->sqeq.len = luringcb->resubmit_qiov.niov; + +-- +2.27.0 + diff --git a/iommu-Introduce-generic-header.patch b/iommu-Introduce-generic-header.patch index 76e0c0c80ff83bfd8a5f0130ca73c0623e0efc35..84f3d77c057bee4e80d68e8dbf92c473089109f0 100644 --- a/iommu-Introduce-generic-header.patch +++ b/iommu-Introduce-generic-header.patch @@ -1,4 +1,4 @@ -From e8055075dbbc932afccc1f18f4acc093fe9e4dc3 Mon Sep 17 00:00:00 2001 +From 5e312f7b41ec48dc7dc9805af9f52aa8ed393bf9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jul 2019 12:20:12 +0200 Subject: [PATCH] iommu: Introduce generic header diff --git a/iotests-143-Create-socket-in-SOCK_DIR.patch b/iotests-143-Create-socket-in-SOCK_DIR.patch deleted file mode 100644 index 31d6a8421e46d181deb1e7c6792f78546a3d873e..0000000000000000000000000000000000000000 --- a/iotests-143-Create-socket-in-SOCK_DIR.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 2e8fecd9e963c740cfe73d0de4491541423e185f Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Thu, 17 Oct 2019 15:31:40 +0200 -Subject: [PATCH] iotests/143: Create socket in $SOCK_DIR - -Signed-off-by: Max Reitz -Reviewed-by: Eric Blake -Reviewed-by: Thomas Huth -Message-id: 20191017133155.5327-9-mreitz@redhat.com -Signed-off-by: Max Reitz ---- - tests/qemu-iotests/143 | 6 +++--- - tests/qemu-iotests/143.out | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 -index 92249ac8da..f649b36195 100755 ---- a/tests/qemu-iotests/143 -+++ b/tests/qemu-iotests/143 -@@ -29,7 +29,7 @@ status=1 # failure is the default! - _cleanup() - { - _cleanup_qemu -- rm -f "$TEST_DIR/nbd" -+ rm -f "$SOCK_DIR/nbd" - } - trap "_cleanup; exit \$status" 0 1 2 3 15 - -@@ -51,12 +51,12 @@ _send_qemu_cmd $QEMU_HANDLE \ - _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'nbd-server-start', - 'arguments': { 'addr': { 'type': 'unix', -- 'data': { 'path': '$TEST_DIR/nbd' }}}}" \ -+ 'data': { 'path': '$SOCK_DIR/nbd' }}}}" \ - 'return' - - # This should just result in a client error, not in the server crashing - $QEMU_IO_PROG -f raw -c quit \ -- "nbd+unix:///no_such_export?socket=$TEST_DIR/nbd" 2>&1 \ -+ "nbd+unix:///no_such_export?socket=$SOCK_DIR/nbd" 2>&1 \ - | _filter_qemu_io | _filter_nbd - - _send_qemu_cmd $QEMU_HANDLE \ -diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out -index ee71b5aa42..037d34a409 100644 ---- a/tests/qemu-iotests/143.out -+++ b/tests/qemu-iotests/143.out -@@ -1,7 +1,7 @@ - QA output created by 143 - {"return": {}} - {"return": {}} --qemu-io: can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: Requested export not available -+qemu-io: can't open device nbd+unix:///no_such_export?socket=SOCK_DIR/nbd: Requested export not available - server reported: export 'no_such_export' not present - {"return": {}} - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} --- -2.27.0 - diff --git a/iotests-fix-194-filter-out-racy-postcopy-active-even.patch b/iotests-fix-194-filter-out-racy-postcopy-active-even.patch new file mode 100644 index 0000000000000000000000000000000000000000..9acecfc9dd9e6c5d78092bcc49279eefa7a2f1fb --- /dev/null +++ b/iotests-fix-194-filter-out-racy-postcopy-active-even.patch @@ -0,0 +1,55 @@ +From fe75f8834809b41779366a852190715b33b2af5d Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 11:56:32 +0000 +Subject: [PATCH] iotests: fix 194: filter out racy postcopy-active event + +The event is racy: it will not appear in the output if bitmap is +migrated during downtime period of migration and postcopy phase is not +started. + +cheery-pick from dcc28ab603f30df5cc8be1f759b423e94ae7d10f + +Fixes: ae00aa239847 "iotests: 194: test also migration of dirty bitmap" +Reported-by: Richard Henderson + +Signed-off-by: jipengfei_yewu +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20230607143606.1557395-1-vsementsov@yandex-team.ru> +Reviewed-by: Richard Henderson +Signed-off-by: Richard Henderson +--- + tests/qemu-iotests/194 | 5 +++++ + tests/qemu-iotests/194.out | 1 - + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 +index e44b8df728..4c8a952cd8 100755 +--- a/tests/qemu-iotests/194 ++++ b/tests/qemu-iotests/194 +@@ -74,6 +74,11 @@ with iotests.FilePath('source.img') as source_img_path, \ + + while True: + event1 = source_vm.event_wait('MIGRATION') ++ if event1['data']['status'] == 'postcopy-active': ++ # This event is racy, it depends do we really do postcopy or bitmap ++ # was migrated during downtime (and no data to migrate in postcopy ++ # phase). So, don't log it. ++ continue + iotests.log(event1, filters=[iotests.filter_qmp_event]) + if event1['data']['status'] in ('completed', 'failed'): + iotests.log('Gracefully ending the `drive-mirror` job on source...') +diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out +index 4e6df1565a..376ed1d2e6 100644 +--- a/tests/qemu-iotests/194.out ++++ b/tests/qemu-iotests/194.out +@@ -14,7 +14,6 @@ Starting migration... + {"return": {}} + {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +-{"data": {"status": "postcopy-active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Gracefully ending the `drive-mirror` job on source... + {"return": {}} +-- +2.27.0 + diff --git a/iotests-fix-default-machine-type-detection.patch b/iotests-fix-default-machine-type-detection.patch new file mode 100644 index 0000000000000000000000000000000000000000..47910b76f6d8f200ae244a760e08d405feb28bdb --- /dev/null +++ b/iotests-fix-default-machine-type-detection.patch @@ -0,0 +1,40 @@ +From 1c60628eef43847595723a65ff9fd57f38cc70de Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 09:57:38 +0000 +Subject: [PATCH] iotests: fix default machine type detection + +The machine type is being detected based on "-M help" output, and we're +searching for the line ending with " (default)". However, in downstream +one of the machine types s marked as deprecated might become the +default, in which case this logic breaks as the line would now end with +" (default) (deprecated)". To fix potential issues here, let's relax +that requirement and detect the mere presence of " (default)" line +instead. + +cheery-pick from 3b7094fe8329c5c7bb0d685e1876aa30f59bece6 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Andrey Drobyshev +Message-ID: <20231122121538.32903-1-andrey.drobyshev@virtuozzo.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +--- + tests/qemu-iotests/testenv.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py +index 26ae6945cc..993e9c56be 100644 +--- a/tests/qemu-iotests/testenv.py ++++ b/tests/qemu-iotests/testenv.py +@@ -40,7 +40,7 @@ def get_default_machine(qemu_prog: str) -> str: + + machines = outp.split('\n') + try: +- default_machine = next(m for m in machines if m.endswith(' (default)')) ++ default_machine = next(m for m in machines if ' (default)' in m) + except StopIteration: + return '' + default_machine = default_machine.split(' ', 1)[0] +-- +2.27.0 + diff --git a/ip_reass-Fix-use-after-free.patch b/ip_reass-Fix-use-after-free.patch deleted file mode 100644 index b26e8afb629d7d768608fdc471a9cf754be36f7e..0000000000000000000000000000000000000000 --- a/ip_reass-Fix-use-after-free.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 63b07dfe20a0d4971b0929d27359f478ba2d816b Mon Sep 17 00:00:00 2001 -From: Samuel Thibault -Date: Fri, 22 May 2020 10:52:55 +0800 -Subject: [PATCH] ip_reass: Fix use after free - -Using ip_deq after m_free might read pointers from an allocation reuse. - -This would be difficult to exploit, but that is still related with -CVE-2019-14378 which generates fragmented IP packets that would trigger this -issue and at least produce a DoS. -Signed-off-by: Samuel Thibault's avatarSamuel Thibault - -diff --git a/slirp/src/ip_input.c b/slirp/src/ip_input.c -index 8c75d91..c07d7d4 100644 ---- a/slirp/src/ip_input.c -+++ b/slirp/src/ip_input.c -@@ -292,6 +292,7 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) - */ - while (q != (struct ipasfrag *)&fp->frag_link && - ip->ip_off + ip->ip_len > q->ipf_off) { -+ struct ipasfrag *prev; - i = (ip->ip_off + ip->ip_len) - q->ipf_off; - if (i < q->ipf_len) { - q->ipf_len -= i; -@@ -299,9 +300,10 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) - m_adj(dtom(slirp, q), i); - break; - } -+ prev = q; - q = q->ipf_next; -- m_free(dtom(slirp, q->ipf_prev)); -- ip_deq(q->ipf_prev); -+ ip_deq(prev); -+ m_free(dtom(slirp, prev)); - } - - insert: --- -1.8.3.1 - diff --git a/iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch b/iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch deleted file mode 100644 index e6abdf7a51d13c4a94ee722164df1fbc54ed48bb..0000000000000000000000000000000000000000 --- a/iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 693fd2acdf14dd86c0bf852610f1c2cca80a74dc Mon Sep 17 00:00:00 2001 -From: Felipe Franciosi -Date: Thu, 23 Jan 2020 12:44:59 +0000 -Subject: [PATCH] iscsi: Cap block count from GET LBA STATUS (CVE-2020-1711) - -When querying an iSCSI server for the provisioning status of blocks (via -GET LBA STATUS), Qemu only validates that the response descriptor zero's -LBA matches the one requested. Given the SCSI spec allows servers to -respond with the status of blocks beyond the end of the LUN, Qemu may -have its heap corrupted by clearing/setting too many bits at the end of -its allocmap for the LUN. - -A malicious guest in control of the iSCSI server could carefully program -Qemu's heap (by selectively setting the bitmap) and then smash it. - -This limits the number of bits that iscsi_co_block_status() will try to -update in the allocmap so it can't overflow the bitmap. - -Fixes: CVE-2020-1711 -Cc: qemu-stable@nongnu.org -Signed-off-by: Felipe Franciosi -Signed-off-by: Peter Turschmid -Signed-off-by: Raphael Norwitz -Signed-off-by: Kevin Wolf - -diff --git a/block/iscsi.c b/block/iscsi.c -index 2aea7e3f13..cbd57294ab 100644 ---- a/block/iscsi.c -+++ b/block/iscsi.c -@@ -701,7 +701,7 @@ static int coroutine_fn iscsi_co_block_status(BlockDriverState *bs, - struct scsi_get_lba_status *lbas = NULL; - struct scsi_lba_status_descriptor *lbasd = NULL; - struct IscsiTask iTask; -- uint64_t lba; -+ uint64_t lba, max_bytes; - int ret; - - iscsi_co_init_iscsitask(iscsilun, &iTask); -@@ -721,6 +721,7 @@ static int coroutine_fn iscsi_co_block_status(BlockDriverState *bs, - } - - lba = offset / iscsilun->block_size; -+ max_bytes = (iscsilun->num_blocks - lba) * iscsilun->block_size; - - qemu_mutex_lock(&iscsilun->mutex); - retry: -@@ -764,7 +765,7 @@ retry: - goto out_unlock; - } - -- *pnum = (int64_t) lbasd->num_blocks * iscsilun->block_size; -+ *pnum = MIN((int64_t) lbasd->num_blocks * iscsilun->block_size, max_bytes); - - if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED || - lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) { --- -2.21.1 (Apple Git-122.3) - diff --git a/job.c-add-missing-notifier-initialization.patch b/job.c-add-missing-notifier-initialization.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca795efe445ec045eba1e8ae718668442131deca --- /dev/null +++ b/job.c-add-missing-notifier-initialization.patch @@ -0,0 +1,37 @@ +From d8962af271345ae4d7880219a62abed76a0268e0 Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Wed, 3 Nov 2021 12:21:55 -0400 +Subject: [PATCH 1/6] job.c: add missing notifier initialization +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It seems that on_idle list is not properly initialized like +the other notifiers. + +Fixes: 34dc97b9a0e ("blockjob: Wake up BDS when job becomes idle") +Signed-off-by: Emanuele Giuseppe Esposito +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: wanbo +--- + job.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/job.c b/job.c +index dbfa67bb0a..54db80df66 100644 +--- a/job.c ++++ b/job.c +@@ -352,6 +352,7 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, + notifier_list_init(&job->on_finalize_completed); + notifier_list_init(&job->on_pending); + notifier_list_init(&job->on_ready); ++ notifier_list_init(&job->on_idle); + + job_state_transition(job, JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, +-- +2.27.0 + diff --git a/json-Fix-a-memleak-in-parse_pair.patch b/json-Fix-a-memleak-in-parse_pair.patch deleted file mode 100644 index c39776e6160b48f0f5bd1834899a0d186b03eeb7..0000000000000000000000000000000000000000 --- a/json-Fix-a-memleak-in-parse_pair.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 503d231e06c159c1530a76b1740b3ec7e47619e5 Mon Sep 17 00:00:00 2001 -From: Alex Chen -Date: Fri, 13 Nov 2020 14:55:25 +0000 -Subject: [PATCH] json: Fix a memleak in parse_pair() - -In qobject_type(), NULL is returned when the 'QObject' returned from parse_value() is not of QString type, -and this 'QObject' memory will leaked. -So we need to first cache the 'QObject' returned from parse_value(), and finally -free 'QObject' memory at the end of the function. -Also, we add a testcast about invalid dict key. - -The memleak stack is as follows: -Direct leak of 32 byte(s) in 1 object(s) allocated from: - #0 0xfffe4b3c34fb in __interceptor_malloc (/lib64/libasan.so.4+0xd34fb) - #1 0xfffe4ae48aa3 in g_malloc (/lib64/libglib-2.0.so.0+0x58aa3) - #2 0xaaab3557d9f7 in qnum_from_int qemu/qobject/qnum.c:25 - #3 0xaaab35584d23 in parse_literal qemu/qobject/json-parser.c:511 - #4 0xaaab35584d23 in parse_value qemu/qobject/json-parser.c:554 - #5 0xaaab35583d77 in parse_pair qemu/qobject/json-parser.c:270 - #6 0xaaab355845db in parse_object qemu/qobject/json-parser.c:327 - #7 0xaaab355845db in parse_value qemu/qobject/json-parser.c:546 - #8 0xaaab35585b1b in json_parser_parse qemu/qobject/json-parser.c:580 - #9 0xaaab35583703 in json_message_process_token qemu/qobject/json-streamer.c:92 - #10 0xaaab355ddccf in json_lexer_feed_char qemu/qobject/json-lexer.c:313 - #11 0xaaab355de0eb in json_lexer_feed qemu/qobject/json-lexer.c:350 - #12 0xaaab354aff67 in tcp_chr_read qemu/chardev/char-socket.c:525 - #13 0xfffe4ae429db in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x529db) - #14 0xfffe4ae42d8f (/lib64/libglib-2.0.so.0+0x52d8f) - #15 0xfffe4ae430df in g_main_loop_run (/lib64/libglib-2.0.so.0+0x530df) - #16 0xaaab34d70bff in iothread_run qemu/iothread.c:82 - #17 0xaaab3559d71b in qemu_thread_start qemu/util/qemu-thread-posix.c:519 - -Fixes: 532fb5328473 ("qapi: Make more of qobject_to()") -Reported-by: Euler Robot -Signed-off-by: Alex Chen -Signed-off-by: Chen Qun -Signed-off-by: Markus Armbruster -Message-Id: <20201113145525.85151-1-alex.chen@huawei.com> -[Commit message tweaked] -(cherry-picked form commit 922d42bb) ---- - qobject/json-parser.c | 12 ++++++------ - tests/check-qjson.c | 9 +++++++++ - 2 files changed, 15 insertions(+), 6 deletions(-) - -diff --git a/qobject/json-parser.c b/qobject/json-parser.c -index 7d23e12e33..840909ea6a 100644 ---- a/qobject/json-parser.c -+++ b/qobject/json-parser.c -@@ -257,8 +257,9 @@ static JSONToken *parser_context_peek_token(JSONParserContext *ctxt) - */ - static int parse_pair(JSONParserContext *ctxt, QDict *dict) - { -+ QObject *key_obj = NULL; -+ QString *key; - QObject *value; -- QString *key = NULL; - JSONToken *peek, *token; - - peek = parser_context_peek_token(ctxt); -@@ -267,7 +268,8 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict) - goto out; - } - -- key = qobject_to(QString, parse_value(ctxt)); -+ key_obj = parse_value(ctxt); -+ key = qobject_to(QString, key_obj); - if (!key) { - parse_error(ctxt, peek, "key is not a string in object"); - goto out; -@@ -297,13 +299,11 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict) - - qdict_put_obj(dict, qstring_get_str(key), value); - -- qobject_unref(key); -- -+ qobject_unref(key_obj); - return 0; - - out: -- qobject_unref(key); -- -+ qobject_unref(key_obj); - return -1; - } - -diff --git a/tests/check-qjson.c b/tests/check-qjson.c -index fa2afccb0a..5e3e08fe79 100644 ---- a/tests/check-qjson.c -+++ b/tests/check-qjson.c -@@ -1415,6 +1415,14 @@ static void invalid_dict_comma(void) - g_assert(obj == NULL); - } - -+static void invalid_dict_key(void) -+{ -+ Error *err = NULL; -+ QObject *obj = qobject_from_json("{32:'abc'}", &err); -+ error_free_or_abort(&err); -+ g_assert(obj == NULL); -+} -+ - static void unterminated_literal(void) - { - Error *err = NULL; -@@ -1500,6 +1508,7 @@ int main(int argc, char **argv) - g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma); - g_test_add_func("/errors/invalid_array_comma", invalid_array_comma); - g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma); -+ g_test_add_func("/errors/invalid_dict_key", invalid_dict_key); - g_test_add_func("/errors/unterminated/literal", unterminated_literal); - g_test_add_func("/errors/limits/nesting", limits_nesting); - g_test_add_func("/errors/multiple_values", multiple_values); --- -2.27.0 - diff --git a/kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch b/kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch deleted file mode 100644 index dfa8bf6a01201096881ec49e34ddf0ed18eec84f..0000000000000000000000000000000000000000 --- a/kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch +++ /dev/null @@ -1,99 +0,0 @@ -From ccfc5c99103e2f633084c906197075392f625a80 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 21 Nov 2019 16:56:45 +0000 -Subject: [PATCH] kvm: Reallocate dirty_bmap when we change a slot - -kvm_set_phys_mem can be called to reallocate a slot by something the -guest does (e.g. writing to PAM and other chipset registers). -This can happen in the middle of a migration, and if we're unlucky -it can now happen between the split 'sync' and 'clear'; the clear -asserts if there's no bmap to clear. Recreate the bmap whenever -we change the slot, keeping the clear path happy. - -Typically this is triggered by the guest rebooting during a migrate. - -Corresponds to: -https://bugzilla.redhat.com/show_bug.cgi?id=1772774 -https://bugzilla.redhat.com/show_bug.cgi?id=1771032 - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Signed-off-by: Kunkun Jiang ---- - accel/kvm/kvm-all.c | 44 +++++++++++++++++++++++++++++--------------- - 1 file changed, 29 insertions(+), 15 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 6828f6a1f9..5a6b89cc2a 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -536,6 +536,27 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section, - - #define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1)) - -+/* Allocate the dirty bitmap for a slot */ -+static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem) -+{ -+ /* -+ * XXX bad kernel interface alert -+ * For dirty bitmap, kernel allocates array of size aligned to -+ * bits-per-long. But for case when the kernel is 64bits and -+ * the userspace is 32bits, userspace can't align to the same -+ * bits-per-long, since sizeof(long) is different between kernel -+ * and user space. This way, userspace will provide buffer which -+ * may be 4 bytes less than the kernel will use, resulting in -+ * userspace memory corruption (which is not detectable by valgrind -+ * too, in most cases). -+ * So for now, let's align to 64 instead of HOST_LONG_BITS here, in -+ * a hope that sizeof(long) won't become >8 any time soon. -+ */ -+ hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), -+ /*HOST_LONG_BITS*/ 64) / 8; -+ mem->dirty_bmap = g_malloc0(bitmap_size); -+} -+ - /** - * kvm_physical_sync_dirty_bitmap - Sync dirty bitmap from kernel space - * -@@ -568,23 +589,9 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, - goto out; - } - -- /* XXX bad kernel interface alert -- * For dirty bitmap, kernel allocates array of size aligned to -- * bits-per-long. But for case when the kernel is 64bits and -- * the userspace is 32bits, userspace can't align to the same -- * bits-per-long, since sizeof(long) is different between kernel -- * and user space. This way, userspace will provide buffer which -- * may be 4 bytes less than the kernel will use, resulting in -- * userspace memory corruption (which is not detectable by valgrind -- * too, in most cases). -- * So for now, let's align to 64 instead of HOST_LONG_BITS here, in -- * a hope that sizeof(long) won't become >8 any time soon. -- */ - if (!mem->dirty_bmap) { -- hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), -- /*HOST_LONG_BITS*/ 64) / 8; - /* Allocate on the first log_sync, once and for all */ -- mem->dirty_bmap = g_malloc0(bitmap_size); -+ kvm_memslot_init_dirty_bitmap(mem); - } - - d.dirty_bitmap = mem->dirty_bmap; -@@ -1066,6 +1073,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, - mem->ram = ram; - mem->flags = kvm_mem_flags(mr); - -+ if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { -+ /* -+ * Reallocate the bmap; it means it doesn't disappear in -+ * middle of a migrate. -+ */ -+ kvm_memslot_init_dirty_bitmap(mem); -+ } - err = kvm_set_user_memory_region(kml, mem, true); - if (err) { - fprintf(stderr, "%s: error registering slot: %s\n", __func__, --- -2.27.0 - diff --git a/kvm-allow-target-specific-accelerator-properties.patch b/kvm-allow-target-specific-accelerator-properties.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c8c536c33753f55cf70a3b9be18ed6d382a45b6 --- /dev/null +++ b/kvm-allow-target-specific-accelerator-properties.patch @@ -0,0 +1,129 @@ +From f90dc9f811195fabd68faf2ca98b2fe5b4fbe3d0 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 29 Sep 2022 15:20:12 +0800 +Subject: [PATCH] kvm: allow target-specific accelerator properties + +from mainline-v7.2.0-rc0 +commit 3dba0a335cf5c53146b606be6ddfab4df81c464e +category: feature +feature: Notify VM Exit +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6GWQE + +Intel-SIG: commit 3dba0a335cf5 ("kvm: allow target-specific accelerator properties") + +------------------------------------------------------------------ + +kvm: allow target-specific accelerator properties + +Several hypervisor capabilities in KVM are target-specific. When exposed +to QEMU users as accelerator properties (i.e. -accel kvm,prop=value), they +should not be available for all targets. + +Add a hook for targets to add their own properties to -accel kvm, for +now no such property is defined. + +Signed-off-by: Paolo Bonzini +Message-Id: <20220929072014.20705-3-chenyi.qiang@intel.com> +Signed-off-by: Paolo Bonzini +[ remove changes in target/riscv/kvm.c since riscv kvm is not + supported in qemu-6.2.0 and linux 5.10 ] +Signed-off-by: Jason Zeng +--- + accel/kvm/kvm-all.c | 2 ++ + include/sysemu/kvm.h | 2 ++ + target/arm/kvm.c | 4 ++++ + target/i386/kvm/kvm.c | 4 ++++ + target/mips/kvm.c | 4 ++++ + target/ppc/kvm.c | 4 ++++ + target/s390x/kvm/kvm.c | 4 ++++ + 7 files changed, 24 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 946ccb260b..e5681a6cd0 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -3703,6 +3703,8 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) + NULL, NULL); + object_class_property_set_description(oc, "dirty-ring-size", + "Size of KVM dirty page ring buffer (default: 0, i.e. use bitmap)"); ++ ++ kvm_arch_accel_class_init(oc); + } + + static const TypeInfo kvm_accel_type = { +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 19c5c8402a..1ec9432493 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -334,6 +334,8 @@ bool kvm_device_supported(int vmfd, uint64_t type); + + extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; + ++void kvm_arch_accel_class_init(ObjectClass *oc); ++ + void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run); + MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run); + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 29ac3f40e0..22ac5bcb97 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -1095,3 +1095,7 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index e97d967c73..e2f28ce958 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5168,3 +5168,7 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask) + mask &= ~BIT_ULL(bit); + } + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +diff --git a/target/mips/kvm.c b/target/mips/kvm.c +index 086debd9f0..f80ac72dd1 100644 +--- a/target/mips/kvm.c ++++ b/target/mips/kvm.c +@@ -1295,3 +1295,7 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index d73563045b..9693aab3c7 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -2975,3 +2975,7 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c +index 5b1fdb55c4..671d0f179c 100644 +--- a/target/s390x/kvm/kvm.c ++++ b/target/s390x/kvm/kvm.c +@@ -2562,3 +2562,7 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +-- +2.27.0 + diff --git a/kvm-expose-struct-KVMState.patch b/kvm-expose-struct-KVMState.patch new file mode 100644 index 0000000000000000000000000000000000000000..8514cd8828f28213822a69be8d5419e2b9ac8d08 --- /dev/null +++ b/kvm-expose-struct-KVMState.patch @@ -0,0 +1,218 @@ +From 9f7f9fdf2246c653673d07fccc07cdc6b03f8722 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Thu, 29 Sep 2022 15:20:13 +0800 +Subject: [PATCH] kvm: expose struct KVMState + +from mainline-v7.2.0-rc0 +commit 5f8a6bce1f1080058ed29d716cae81ea805142ae +category: feature +feature: Notify VM Exit +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6GWQE + +Intel-SIG: commit 5f8a6bce1f10 ("kvm: expose struct KVMState") + +------------------------------------------------------------------ + +kvm: expose struct KVMState + +Expose struct KVMState out of kvm-all.c so that the field of struct +KVMState can be accessed when defining target-specific accelerator +properties. + +Signed-off-by: Chenyi Qiang +Message-Id: <20220929072014.20705-4-chenyi.qiang@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + accel/kvm/kvm-all.c | 74 -------------------------------------- + include/sysemu/kvm_int.h | 76 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 76 insertions(+), 74 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index e5681a6cd0..91d93facf2 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -72,86 +72,12 @@ + do { } while (0) + #endif + +-#define KVM_MSI_HASHTAB_SIZE 256 +- + struct KVMParkedVcpu { + unsigned long vcpu_id; + int kvm_fd; + QLIST_ENTRY(KVMParkedVcpu) node; + }; + +-enum KVMDirtyRingReaperState { +- KVM_DIRTY_RING_REAPER_NONE = 0, +- /* The reaper is sleeping */ +- KVM_DIRTY_RING_REAPER_WAIT, +- /* The reaper is reaping for dirty pages */ +- KVM_DIRTY_RING_REAPER_REAPING, +-}; +- +-/* +- * KVM reaper instance, responsible for collecting the KVM dirty bits +- * via the dirty ring. +- */ +-struct KVMDirtyRingReaper { +- /* The reaper thread */ +- QemuThread reaper_thr; +- volatile uint64_t reaper_iteration; /* iteration number of reaper thr */ +- volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */ +-}; +- +-struct KVMState +-{ +- AccelState parent_obj; +- +- int nr_slots; +- int fd; +- int vmfd; +- int coalesced_mmio; +- int coalesced_pio; +- struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; +- bool coalesced_flush_in_progress; +- int vcpu_events; +- int robust_singlestep; +- int debugregs; +-#ifdef KVM_CAP_SET_GUEST_DEBUG +- QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; +-#endif +- int max_nested_state_len; +- int many_ioeventfds; +- int intx_set_mask; +- int kvm_shadow_mem; +- bool kernel_irqchip_allowed; +- bool kernel_irqchip_required; +- OnOffAuto kernel_irqchip_split; +- bool sync_mmu; +- uint64_t manual_dirty_log_protect; +- /* The man page (and posix) say ioctl numbers are signed int, but +- * they're not. Linux, glibc and *BSD all treat ioctl numbers as +- * unsigned, and treating them as signed here can break things */ +- unsigned irq_set_ioctl; +- unsigned int sigmask_len; +- GHashTable *gsimap; +-#ifdef KVM_CAP_IRQ_ROUTING +- struct kvm_irq_routing *irq_routes; +- int nr_allocated_irq_routes; +- unsigned long *used_gsi_bitmap; +- unsigned int gsi_count; +- QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; +-#endif +- KVMMemoryListener memory_listener; +- QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; +- +- /* For "info mtree -f" to tell if an MR is registered in KVM */ +- int nr_as; +- struct KVMAs { +- KVMMemoryListener *ml; +- AddressSpace *as; +- } *as; +- uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */ +- uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ +- struct KVMDirtyRingReaper reaper; +-}; +- + KVMState *kvm_state; + bool kvm_kernel_irqchip; + bool kvm_split_irqchip; +diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h +index 1f5487d9b7..3b4adcdc10 100644 +--- a/include/sysemu/kvm_int.h ++++ b/include/sysemu/kvm_int.h +@@ -10,6 +10,7 @@ + #define QEMU_KVM_INT_H + + #include "exec/memory.h" ++#include "qapi/qapi-types-common.h" + #include "qemu/accel.h" + #include "sysemu/kvm.h" + +@@ -36,6 +37,81 @@ typedef struct KVMMemoryListener { + int as_id; + } KVMMemoryListener; + ++#define KVM_MSI_HASHTAB_SIZE 256 ++ ++enum KVMDirtyRingReaperState { ++ KVM_DIRTY_RING_REAPER_NONE = 0, ++ /* The reaper is sleeping */ ++ KVM_DIRTY_RING_REAPER_WAIT, ++ /* The reaper is reaping for dirty pages */ ++ KVM_DIRTY_RING_REAPER_REAPING, ++}; ++ ++/* ++ * KVM reaper instance, responsible for collecting the KVM dirty bits ++ * via the dirty ring. ++ */ ++struct KVMDirtyRingReaper { ++ /* The reaper thread */ ++ QemuThread reaper_thr; ++ volatile uint64_t reaper_iteration; /* iteration number of reaper thr */ ++ volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */ ++}; ++struct KVMState ++{ ++ AccelState parent_obj; ++ ++ int nr_slots; ++ int fd; ++ int vmfd; ++ int coalesced_mmio; ++ int coalesced_pio; ++ struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; ++ bool coalesced_flush_in_progress; ++ int vcpu_events; ++ int robust_singlestep; ++ int debugregs; ++#ifdef KVM_CAP_SET_GUEST_DEBUG ++ QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; ++#endif ++ int max_nested_state_len; ++ int many_ioeventfds; ++ int intx_set_mask; ++ int kvm_shadow_mem; ++ bool kernel_irqchip_allowed; ++ bool kernel_irqchip_required; ++ OnOffAuto kernel_irqchip_split; ++ bool sync_mmu; ++ uint64_t manual_dirty_log_protect; ++ /* The man page (and posix) say ioctl numbers are signed int, but ++ * they're not. Linux, glibc and *BSD all treat ioctl numbers as ++ * unsigned, and treating them as signed here can break things */ ++ unsigned irq_set_ioctl; ++ unsigned int sigmask_len; ++ GHashTable *gsimap; ++#ifdef KVM_CAP_IRQ_ROUTING ++ struct kvm_irq_routing *irq_routes; ++ int nr_allocated_irq_routes; ++ unsigned long *used_gsi_bitmap; ++ unsigned int gsi_count; ++ QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; ++#endif ++ KVMMemoryListener memory_listener; ++ QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; ++ ++ /* For "info mtree -f" to tell if an MR is registered in KVM */ ++ int nr_as; ++ struct KVMAs { ++ KVMMemoryListener *ml; ++ AddressSpace *as; ++ } *as; ++ uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */ ++ uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ ++ struct KVMDirtyRingReaper reaper; ++ NotifyVmexitOption notify_vmexit; ++ uint32_t notify_window; ++}; ++ + void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, + AddressSpace *as, int as_id, const char *name); + +-- +2.27.0 + diff --git a/kvm-split-too-big-memory-section-on-several-memslots.patch b/kvm-split-too-big-memory-section-on-several-memslots.patch deleted file mode 100644 index 9a94e21a773498e07764996501664313b9c98522..0000000000000000000000000000000000000000 --- a/kvm-split-too-big-memory-section-on-several-memslots.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 33f5a810b0edc1ac67163f396bd345e04b5c11e8 Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Tue, 24 Sep 2019 10:47:50 -0400 -Subject: [PATCH] kvm: split too big memory section on several memslots - -Max memslot size supported by kvm on s390 is 8Tb, -move logic of splitting RAM in chunks upto 8T to KVM code. - -This way it will hide KVM specific restrictions in KVM code -and won't affect board level design decisions. Which would allow -us to avoid misusing memory_region_allocate_system_memory() API -and eventually use a single hostmem backend for guest RAM. - -Signed-off-by: Igor Mammedov -Message-Id: <20190924144751.24149-4-imammedo@redhat.com> -Reviewed-by: Peter Xu -Acked-by: Paolo Bonzini -Signed-off-by: Christian Borntraeger -Signed-off-by: Kunkun Jiang ---- - accel/kvm/kvm-all.c | 124 +++++++++++++++++++++++++-------------- - include/sysemu/kvm_int.h | 1 + - 2 files changed, 81 insertions(+), 44 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 84edbe8bb1..6828f6a1f9 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -138,6 +138,7 @@ bool kvm_direct_msi_allowed; - bool kvm_ioeventfd_any_length_allowed; - bool kvm_msi_use_devid; - static bool kvm_immediate_exit; -+static hwaddr kvm_max_slot_size = ~0; - - static const KVMCapabilityInfo kvm_required_capabilites[] = { - KVM_CAP_INFO(USER_MEMORY), -@@ -458,7 +459,7 @@ static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem, - static int kvm_section_update_flags(KVMMemoryListener *kml, - MemoryRegionSection *section) - { -- hwaddr start_addr, size; -+ hwaddr start_addr, size, slot_size; - KVMSlot *mem; - int ret = 0; - -@@ -469,13 +470,18 @@ static int kvm_section_update_flags(KVMMemoryListener *kml, - - kvm_slots_lock(kml); - -- mem = kvm_lookup_matching_slot(kml, start_addr, size); -- if (!mem) { -- /* We don't have a slot if we want to trap every access. */ -- goto out; -- } -+ while (size && !ret) { -+ slot_size = MIN(kvm_max_slot_size, size); -+ mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); -+ if (!mem) { -+ /* We don't have a slot if we want to trap every access. */ -+ goto out; -+ } - -- ret = kvm_slot_update_flags(kml, mem, section->mr); -+ ret = kvm_slot_update_flags(kml, mem, section->mr); -+ start_addr += slot_size; -+ size -= slot_size; -+ } - - out: - kvm_slots_unlock(kml); -@@ -548,11 +554,15 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, - struct kvm_dirty_log d = {}; - KVMSlot *mem; - hwaddr start_addr, size; -+ hwaddr slot_size, slot_offset = 0; - int ret = 0; - - size = kvm_align_section(section, &start_addr); -- if (size) { -- mem = kvm_lookup_matching_slot(kml, start_addr, size); -+ while (size) { -+ MemoryRegionSection subsection = *section; -+ -+ slot_size = MIN(kvm_max_slot_size, size); -+ mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); - if (!mem) { - /* We don't have a slot if we want to trap every access. */ - goto out; -@@ -570,11 +580,11 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, - * So for now, let's align to 64 instead of HOST_LONG_BITS here, in - * a hope that sizeof(long) won't become >8 any time soon. - */ -- size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), -- /*HOST_LONG_BITS*/ 64) / 8; - if (!mem->dirty_bmap) { -+ hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), -+ /*HOST_LONG_BITS*/ 64) / 8; - /* Allocate on the first log_sync, once and for all */ -- mem->dirty_bmap = g_malloc0(size); -+ mem->dirty_bmap = g_malloc0(bitmap_size); - } - - d.dirty_bitmap = mem->dirty_bmap; -@@ -585,7 +595,13 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, - goto out; - } - -- kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); -+ subsection.offset_within_region += slot_offset; -+ subsection.size = int128_make64(slot_size); -+ kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap); -+ -+ slot_offset += slot_size; -+ start_addr += slot_size; -+ size -= slot_size; - } - out: - return ret; -@@ -974,6 +990,14 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) - return NULL; - } - -+void kvm_set_max_memslot_size(hwaddr max_slot_size) -+{ -+ g_assert( -+ ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size -+ ); -+ kvm_max_slot_size = max_slot_size; -+} -+ - static void kvm_set_phys_mem(KVMMemoryListener *kml, - MemoryRegionSection *section, bool add) - { -@@ -981,7 +1005,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, - int err; - MemoryRegion *mr = section->mr; - bool writeable = !mr->readonly && !mr->rom_device; -- hwaddr start_addr, size; -+ hwaddr start_addr, size, slot_size; - void *ram; - - if (!memory_region_is_ram(mr)) { -@@ -1006,41 +1030,52 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, - kvm_slots_lock(kml); - - if (!add) { -- mem = kvm_lookup_matching_slot(kml, start_addr, size); -- if (!mem) { -- goto out; -- } -- if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { -- kvm_physical_sync_dirty_bitmap(kml, section); -- } -+ do { -+ slot_size = MIN(kvm_max_slot_size, size); -+ mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); -+ if (!mem) { -+ goto out; -+ } -+ if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { -+ kvm_physical_sync_dirty_bitmap(kml, section); -+ } - -- /* unregister the slot */ -- g_free(mem->dirty_bmap); -- mem->dirty_bmap = NULL; -- mem->memory_size = 0; -- mem->flags = 0; -- err = kvm_set_user_memory_region(kml, mem, false); -- if (err) { -- fprintf(stderr, "%s: error unregistering slot: %s\n", -- __func__, strerror(-err)); -- abort(); -- } -+ /* unregister the slot */ -+ g_free(mem->dirty_bmap); -+ mem->dirty_bmap = NULL; -+ mem->memory_size = 0; -+ mem->flags = 0; -+ err = kvm_set_user_memory_region(kml, mem, false); -+ if (err) { -+ fprintf(stderr, "%s: error unregistering slot: %s\n", -+ __func__, strerror(-err)); -+ abort(); -+ } -+ start_addr += slot_size; -+ size -= slot_size; -+ } while (size); - goto out; - } - - /* register the new slot */ -- mem = kvm_alloc_slot(kml); -- mem->memory_size = size; -- mem->start_addr = start_addr; -- mem->ram = ram; -- mem->flags = kvm_mem_flags(mr); -- -- err = kvm_set_user_memory_region(kml, mem, true); -- if (err) { -- fprintf(stderr, "%s: error registering slot: %s\n", __func__, -- strerror(-err)); -- abort(); -- } -+ do { -+ slot_size = MIN(kvm_max_slot_size, size); -+ mem = kvm_alloc_slot(kml); -+ mem->memory_size = slot_size; -+ mem->start_addr = start_addr; -+ mem->ram = ram; -+ mem->flags = kvm_mem_flags(mr); -+ -+ err = kvm_set_user_memory_region(kml, mem, true); -+ if (err) { -+ fprintf(stderr, "%s: error registering slot: %s\n", __func__, -+ strerror(-err)); -+ abort(); -+ } -+ start_addr += slot_size; -+ ram += slot_size; -+ size -= slot_size; -+ } while (size); - - out: - kvm_slots_unlock(kml); -@@ -2880,6 +2915,7 @@ static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as, - - for (i = 0; i < kvm->nr_as; ++i) { - if (kvm->as[i].as == as && kvm->as[i].ml) { -+ size = MIN(kvm_max_slot_size, size); - return NULL != kvm_lookup_matching_slot(kvm->as[i].ml, - start_addr, size); - } -diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h -index 787dbc7770..f8e884f146 100644 ---- a/include/sysemu/kvm_int.h -+++ b/include/sysemu/kvm_int.h -@@ -43,4 +43,5 @@ typedef struct KVMMemoryListener { - void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, - AddressSpace *as, int as_id); - -+void kvm_set_max_memslot_size(hwaddr max_slot_size); - #endif --- -2.27.0 - diff --git a/libdecnumber-dpd-decimal64-Fix-compiler-warning-from.patch b/libdecnumber-dpd-decimal64-Fix-compiler-warning-from.patch new file mode 100644 index 0000000000000000000000000000000000000000..095e731beea27e321d7924e1ce63a71652eb4e79 --- /dev/null +++ b/libdecnumber-dpd-decimal64-Fix-compiler-warning-from.patch @@ -0,0 +1,51 @@ +From ddc9e2437ee5e9cd7fb0c0ad153c23feb9d9722b Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 1 Dec 2022 20:41:44 +0800 +Subject: [PATCH 05/17] libdecnumber/dpd/decimal64: Fix compiler warning from + Clang 15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Clang 15 from Fedora 37 complains: + + ../libdecnumber/dpd/decimal64.c:620:8: error: variable 'n' set but + not used [-Werror,-Wunused-but-set-variable] + Int n; /* output bunch counter */ + ^ + 1 error generated. + +Remove the unused variable to silence the compiler warning. + +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Cédric Le Goater +Signed-off-by: Thomas Huth +Signed-off-by: tangzhongrui tangzhongrui@cmss.chinamobile.com +--- + libdecnumber/dpd/decimal64.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/libdecnumber/dpd/decimal64.c b/libdecnumber/dpd/decimal64.c +index 4816176410..f6fb2963d9 100644 +--- a/libdecnumber/dpd/decimal64.c ++++ b/libdecnumber/dpd/decimal64.c +@@ -617,7 +617,6 @@ static const uInt multies[]={131073, 26215, 5243, 1049, 210}; + #endif + void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { + Int cut; /* work */ +- Int n; /* output bunch counter */ + Int digits=dn->digits; /* digit countdown */ + uInt dpd; /* densely packed decimal value */ + uInt bin; /* binary value 0-999 */ +@@ -676,7 +675,7 @@ void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { + bin=0; /* [keep compiler quiet] */ + #endif + +- for(n=0; digits>0; n++) { /* each output bunch */ ++ while (digits > 0) { /* each output bunch */ + #if DECDPUN==3 /* fast path, 3-at-a-time */ + bin=*inu; /* 3 digits ready for convert */ + digits-=3; /* [may go negative] */ +-- +2.27.0 + diff --git a/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch b/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch new file mode 100644 index 0000000000000000000000000000000000000000..23cde54cf1dcfe1b0c45e11bacd681d928d20a27 --- /dev/null +++ b/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch @@ -0,0 +1,48 @@ +From c2353941d94a5aeb8364dc5204c29a4fbb09437f Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:47:43 +0000 +Subject: [PATCH] libvhost-user: Fix VHOST_USER_ADD_MEM_REG reply mainline + inclusion commit 7f27d20ded2f480f3e66d03f90ea71507b834276 category: bugfix + +--------------------------------------------------------------- + +With REPLY_NEEDED, libvhost-user sends both the acutal result and an +additional ACK reply for VHOST_USER_ADD_MEM_REG. This is incorrect, the +spec mandates that it behave the same with and without REPLY_NEEDED +because it always sends a reply. + +Fixes: ec94c8e621de96c50c2d381c8c9ec94f5beec7c1 +Signed-off-by: Kevin Wolf +Message-Id: <20220627134500.94842-4-kwolf@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + subprojects/libvhost-user/libvhost-user.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c +index 787f4d2d4f..8ab20138f4 100644 +--- a/subprojects/libvhost-user/libvhost-user.c ++++ b/subprojects/libvhost-user/libvhost-user.c +@@ -756,15 +756,9 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { + + /* Send the message back to qemu with the addresses filled in. */ + vmsg->fd_num = 0; +- if (!vu_send_reply(dev, dev->sock, vmsg)) { +- vu_panic(dev, "failed to respond to add-mem-region for postcopy"); +- return false; +- } +- + DPRINT("Successfully added new region in postcopy\n"); + dev->nregions++; +- return false; +- ++ return true; + } else { + for (i = 0; i < dev->max_queues; i++) { + if (dev->vq[i].vring.desc) { +-- +2.27.0 + diff --git a/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch b/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch new file mode 100644 index 0000000000000000000000000000000000000000..fac419155b747664531c0cdbd0487dc560248256 --- /dev/null +++ b/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch @@ -0,0 +1,53 @@ +From 3e2df0133efdf3e3aea63f413b42e37bc6c87112 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:36:05 +0000 +Subject: [PATCH] libvhost-user: Fix VHOST_USER_GET_MAX_MEM_SLOTS reply + mainline inclusion commit 69a5daec06f423843ce1bb9be5fb049314996f78 category: + bugfix + +--------------------------------------------------------------- + +With REPLY_NEEDED, libvhost-user sends both the acutal result and an +additional ACK reply for VHOST_USER_GET_MAX_MEM_SLOTS. This is +incorrect, the spec mandates that it behave the same with and without +REPLY_NEEDED because it always sends a reply. + +Fixes: 6fb2e173d20c9bbb5466183d33a3ad7dcd0375fa +Signed-off-by: Kevin Wolf +Message-Id: <20220627134500.94842-3-kwolf@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + subprojects/libvhost-user/libvhost-user.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c +index 787f4d2d4f..27e7799262 100644 +--- a/subprojects/libvhost-user/libvhost-user.c ++++ b/subprojects/libvhost-user/libvhost-user.c +@@ -1788,18 +1788,11 @@ vu_handle_vring_kick(VuDev *dev, VhostUserMsg *vmsg) + + static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg) + { +- vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION; +- vmsg->size = sizeof(vmsg->payload.u64); +- vmsg->payload.u64 = VHOST_USER_MAX_RAM_SLOTS; +- vmsg->fd_num = 0; +- +- if (!vu_message_write(dev, dev->sock, vmsg)) { +- vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno)); +- } ++ vmsg_set_reply_u64(vmsg, VHOST_USER_MAX_RAM_SLOTS); + + DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_USER_MAX_RAM_SLOTS); + +- return false; ++ return true; + } + + static bool +-- +2.27.0 + diff --git a/libvhost-user-Fix-some-memtable-remap-cases.patch b/libvhost-user-Fix-some-memtable-remap-cases.patch deleted file mode 100644 index 4f4d0c9f7d4d55064785426f3014ee6efbac1d63..0000000000000000000000000000000000000000 --- a/libvhost-user-Fix-some-memtable-remap-cases.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 8fa62daca5978e77ed690797a882c3d0aad8d0d4 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Mon, 12 Aug 2019 17:35:19 +0100 -Subject: [PATCH] libvhost-user: Fix some memtable remap cases - -If a new setmemtable command comes in once the vhost threads are -running, it will remap the guests address space and the threads -will now be looking in the wrong place. - -Fortunately we're running this command under lock, so we can -update the queue mappings so that threads will look in the new-right -place. - -Note: This doesn't fix things that the threads might be doing -without a lock (e.g. a readv/writev!) That's for another time. - -Signed-off-by: Dr. David Alan Gilbert ---- - contrib/libvhost-user/libvhost-user.c | 33 ++++++++++++++++++++------- - contrib/libvhost-user/libvhost-user.h | 3 +++ - 2 files changed, 28 insertions(+), 8 deletions(-) - -diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c -index fb75837032..164e6d1df8 100644 ---- a/contrib/libvhost-user/libvhost-user.c -+++ b/contrib/libvhost-user/libvhost-user.c -@@ -559,6 +559,21 @@ vu_reset_device_exec(VuDev *dev, VhostUserMsg *vmsg) - return false; - } - -+static bool -+map_ring(VuDev *dev, VuVirtq *vq) -+{ -+ vq->vring.desc = qva_to_va(dev, vq->vra.desc_user_addr); -+ vq->vring.used = qva_to_va(dev, vq->vra.used_user_addr); -+ vq->vring.avail = qva_to_va(dev, vq->vra.avail_user_addr); -+ -+ DPRINT("Setting virtq addresses:\n"); -+ DPRINT(" vring_desc at %p\n", vq->vring.desc); -+ DPRINT(" vring_used at %p\n", vq->vring.used); -+ DPRINT(" vring_avail at %p\n", vq->vring.avail); -+ -+ return !(vq->vring.desc && vq->vring.used && vq->vring.avail); -+} -+ - static bool - vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) - { -@@ -762,6 +777,14 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) - close(vmsg->fds[i]); - } - -+ for (i = 0; i < dev->max_queues; i++) { -+ if (dev->vq[i].vring.desc) { -+ if (map_ring(dev, &dev->vq[i])) { -+ vu_panic(dev, "remaping queue %d during setmemtable", i); -+ } -+ } -+ } -+ - return false; - } - -@@ -848,18 +871,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) - DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", vra->avail_user_addr); - DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", vra->log_guest_addr); - -+ vq->vra = *vra; - vq->vring.flags = vra->flags; -- vq->vring.desc = qva_to_va(dev, vra->desc_user_addr); -- vq->vring.used = qva_to_va(dev, vra->used_user_addr); -- vq->vring.avail = qva_to_va(dev, vra->avail_user_addr); - vq->vring.log_guest_addr = vra->log_guest_addr; - -- DPRINT("Setting virtq addresses:\n"); -- DPRINT(" vring_desc at %p\n", vq->vring.desc); -- DPRINT(" vring_used at %p\n", vq->vring.used); -- DPRINT(" vring_avail at %p\n", vq->vring.avail); - -- if (!(vq->vring.desc && vq->vring.used && vq->vring.avail)) { -+ if (map_ring(dev, vq)) { - vu_panic(dev, "Invalid vring_addr message"); - return false; - } -diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h -index 1844b6f8d4..5cb7708559 100644 ---- a/contrib/libvhost-user/libvhost-user.h -+++ b/contrib/libvhost-user/libvhost-user.h -@@ -327,6 +327,9 @@ typedef struct VuVirtq { - int err_fd; - unsigned int enable; - bool started; -+ -+ /* Guest addresses of our ring */ -+ struct vhost_vring_addr vra; - } VuVirtq; - - enum VuWatchCondtion { --- -2.27.0 - diff --git a/libvhost-user-fix-SLAVE_SEND_FD-handling.patch b/libvhost-user-fix-SLAVE_SEND_FD-handling.patch deleted file mode 100644 index 71cbf7baa7b59006c74a8eadb9b74b10079a9a9d..0000000000000000000000000000000000000000 --- a/libvhost-user-fix-SLAVE_SEND_FD-handling.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 28a9a3558a427493049723fff390add7026653eb Mon Sep 17 00:00:00 2001 -From: Johannes Berg -Date: Tue, 3 Sep 2019 23:04:22 +0300 -Subject: [PATCH] libvhost-user: fix SLAVE_SEND_FD handling - -It doesn't look like this could possibly work properly since -VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD is defined to 10, but the -dev->protocol_features has a bitmap. I suppose the peer this -was tested with also supported VHOST_USER_PROTOCOL_F_LOG_SHMFD, -in which case the test would always be false, but nevertheless -the code seems wrong. - -Use has_feature() to fix this. - -Fixes: d84599f56c82 ("libvhost-user: support host notifier") -Signed-off-by: Johannes Berg -Message-Id: <20190903200422.11693-1-johannes@sipsolutions.net> -Reviewed-by: Tiwei Bie -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 8726b70b449896f1211f869ec4f608904f027207) -Signed-off-by: Michael Roth ---- - contrib/libvhost-user/libvhost-user.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c -index 4b36e35a82..cb5f5770e4 100644 ---- a/contrib/libvhost-user/libvhost-user.c -+++ b/contrib/libvhost-user/libvhost-user.c -@@ -1097,7 +1097,8 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, - - vmsg.fd_num = fd_num; - -- if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) { -+ if (!has_feature(dev->protocol_features, -+ VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD)) { - return false; - } - --- -2.23.0 diff --git a/linux-headers-Update-against-Add-migration-support-f.patch b/linux-headers-Update-against-Add-migration-support-f.patch deleted file mode 100644 index 1bfef98c0c9b6771ccbe2fbd700a233e09cd9baf..0000000000000000000000000000000000000000 --- a/linux-headers-Update-against-Add-migration-support-f.patch +++ /dev/null @@ -1,517 +0,0 @@ -From 7ab9ce4016ec48e0af8010f742ee39fc84342d00 Mon Sep 17 00:00:00 2001 -From: Jinhao Gao -Date: Fri, 23 Jul 2021 14:55:12 +0800 -Subject: [PATCH] linux headers: Update against "Add migration support for VFIO - devices" - -Update linux-headers/linux/vfio.h against Linux 5.9-rc7 for the -VFIO migration support series. - -Signed-off-by: Jinhao Gao -Signed-off-by: Shenming Lu ---- - linux-headers/linux/vfio.h | 420 +++++++++++++++++++++++++++++++++++-- - 1 file changed, 405 insertions(+), 15 deletions(-) - -diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h -index 24f505199f..a90672494d 100644 ---- a/linux-headers/linux/vfio.h -+++ b/linux-headers/linux/vfio.h -@@ -295,15 +295,39 @@ struct vfio_region_info_cap_type { - __u32 subtype; /* type specific */ - }; - -+/* -+ * List of region types, global per bus driver. -+ * If you introduce a new type, please add it here. -+ */ -+ -+/* PCI region type containing a PCI vendor part */ - #define VFIO_REGION_TYPE_PCI_VENDOR_TYPE (1 << 31) - #define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff) -+#define VFIO_REGION_TYPE_GFX (1) -+#define VFIO_REGION_TYPE_CCW (2) -+#define VFIO_REGION_TYPE_MIGRATION (3) -+ -+/* sub-types for VFIO_REGION_TYPE_PCI_* */ - --/* 8086 Vendor sub-types */ -+/* 8086 vendor PCI sub-types */ - #define VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION (1) - #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) - #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) - --#define VFIO_REGION_TYPE_GFX (1) -+/* 10de vendor PCI sub-types */ -+/* -+ * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space. -+ */ -+#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1) -+ -+/* 1014 vendor PCI sub-types */ -+/* -+ * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU -+ * to do TLB invalidation on a GPU. -+ */ -+#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1) -+ -+/* sub-types for VFIO_REGION_TYPE_GFX */ - #define VFIO_REGION_SUBTYPE_GFX_EDID (1) - - /** -@@ -353,24 +377,237 @@ struct vfio_region_gfx_edid { - #define VFIO_DEVICE_GFX_LINK_STATE_DOWN 2 - }; - --#define VFIO_REGION_TYPE_CCW (2) --/* ccw sub-types */ -+/* sub-types for VFIO_REGION_TYPE_CCW */ - #define VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD (1) -+#define VFIO_REGION_SUBTYPE_CCW_SCHIB (2) -+#define VFIO_REGION_SUBTYPE_CCW_CRW (3) - --/* -- * 10de vendor sub-type -- * -- * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space. -- */ --#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1) -+/* sub-types for VFIO_REGION_TYPE_MIGRATION */ -+#define VFIO_REGION_SUBTYPE_MIGRATION (1) - - /* -- * 1014 vendor sub-type -+ * The structure vfio_device_migration_info is placed at the 0th offset of -+ * the VFIO_REGION_SUBTYPE_MIGRATION region to get and set VFIO device related -+ * migration information. Field accesses from this structure are only supported -+ * at their native width and alignment. Otherwise, the result is undefined and -+ * vendor drivers should return an error. - * -- * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU -- * to do TLB invalidation on a GPU. -+ * device_state: (read/write) -+ * - The user application writes to this field to inform the vendor driver -+ * about the device state to be transitioned to. -+ * - The vendor driver should take the necessary actions to change the -+ * device state. After successful transition to a given state, the -+ * vendor driver should return success on write(device_state, state) -+ * system call. If the device state transition fails, the vendor driver -+ * should return an appropriate -errno for the fault condition. -+ * - On the user application side, if the device state transition fails, -+ * that is, if write(device_state, state) returns an error, read -+ * device_state again to determine the current state of the device from -+ * the vendor driver. -+ * - The vendor driver should return previous state of the device unless -+ * the vendor driver has encountered an internal error, in which case -+ * the vendor driver may report the device_state VFIO_DEVICE_STATE_ERROR. -+ * - The user application must use the device reset ioctl to recover the -+ * device from VFIO_DEVICE_STATE_ERROR state. If the device is -+ * indicated to be in a valid device state by reading device_state, the -+ * user application may attempt to transition the device to any valid -+ * state reachable from the current state or terminate itself. -+ * -+ * device_state consists of 3 bits: -+ * - If bit 0 is set, it indicates the _RUNNING state. If bit 0 is clear, -+ * it indicates the _STOP state. When the device state is changed to -+ * _STOP, driver should stop the device before write() returns. -+ * - If bit 1 is set, it indicates the _SAVING state, which means that the -+ * driver should start gathering device state information that will be -+ * provided to the VFIO user application to save the device's state. -+ * - If bit 2 is set, it indicates the _RESUMING state, which means that -+ * the driver should prepare to resume the device. Data provided through -+ * the migration region should be used to resume the device. -+ * Bits 3 - 31 are reserved for future use. To preserve them, the user -+ * application should perform a read-modify-write operation on this -+ * field when modifying the specified bits. -+ * -+ * +------- _RESUMING -+ * |+------ _SAVING -+ * ||+----- _RUNNING -+ * ||| -+ * 000b => Device Stopped, not saving or resuming -+ * 001b => Device running, which is the default state -+ * 010b => Stop the device & save the device state, stop-and-copy state -+ * 011b => Device running and save the device state, pre-copy state -+ * 100b => Device stopped and the device state is resuming -+ * 101b => Invalid state -+ * 110b => Error state -+ * 111b => Invalid state -+ * -+ * State transitions: -+ * -+ * _RESUMING _RUNNING Pre-copy Stop-and-copy _STOP -+ * (100b) (001b) (011b) (010b) (000b) -+ * 0. Running or default state -+ * | -+ * -+ * 1. Normal Shutdown (optional) -+ * |------------------------------------->| -+ * -+ * 2. Save the state or suspend -+ * |------------------------->|---------->| -+ * -+ * 3. Save the state during live migration -+ * |----------->|------------>|---------->| -+ * -+ * 4. Resuming -+ * |<---------| -+ * -+ * 5. Resumed -+ * |--------->| -+ * -+ * 0. Default state of VFIO device is _RUNNNG when the user application starts. -+ * 1. During normal shutdown of the user application, the user application may -+ * optionally change the VFIO device state from _RUNNING to _STOP. This -+ * transition is optional. The vendor driver must support this transition but -+ * must not require it. -+ * 2. When the user application saves state or suspends the application, the -+ * device state transitions from _RUNNING to stop-and-copy and then to _STOP. -+ * On state transition from _RUNNING to stop-and-copy, driver must stop the -+ * device, save the device state and send it to the application through the -+ * migration region. The sequence to be followed for such transition is given -+ * below. -+ * 3. In live migration of user application, the state transitions from _RUNNING -+ * to pre-copy, to stop-and-copy, and to _STOP. -+ * On state transition from _RUNNING to pre-copy, the driver should start -+ * gathering the device state while the application is still running and send -+ * the device state data to application through the migration region. -+ * On state transition from pre-copy to stop-and-copy, the driver must stop -+ * the device, save the device state and send it to the user application -+ * through the migration region. -+ * Vendor drivers must support the pre-copy state even for implementations -+ * where no data is provided to the user before the stop-and-copy state. The -+ * user must not be required to consume all migration data before the device -+ * transitions to a new state, including the stop-and-copy state. -+ * The sequence to be followed for above two transitions is given below. -+ * 4. To start the resuming phase, the device state should be transitioned from -+ * the _RUNNING to the _RESUMING state. -+ * In the _RESUMING state, the driver should use the device state data -+ * received through the migration region to resume the device. -+ * 5. After providing saved device data to the driver, the application should -+ * change the state from _RESUMING to _RUNNING. -+ * -+ * reserved: -+ * Reads on this field return zero and writes are ignored. -+ * -+ * pending_bytes: (read only) -+ * The number of pending bytes still to be migrated from the vendor driver. -+ * -+ * data_offset: (read only) -+ * The user application should read data_offset field from the migration -+ * region. The user application should read the device data from this -+ * offset within the migration region during the _SAVING state or write -+ * the device data during the _RESUMING state. See below for details of -+ * sequence to be followed. -+ * -+ * data_size: (read/write) -+ * The user application should read data_size to get the size in bytes of -+ * the data copied in the migration region during the _SAVING state and -+ * write the size in bytes of the data copied in the migration region -+ * during the _RESUMING state. -+ * -+ * The format of the migration region is as follows: -+ * ------------------------------------------------------------------ -+ * |vfio_device_migration_info| data section | -+ * | | /////////////////////////////// | -+ * ------------------------------------------------------------------ -+ * ^ ^ -+ * offset 0-trapped part data_offset -+ * -+ * The structure vfio_device_migration_info is always followed by the data -+ * section in the region, so data_offset will always be nonzero. The offset -+ * from where the data is copied is decided by the kernel driver. The data -+ * section can be trapped, mmapped, or partitioned, depending on how the kernel -+ * driver defines the data section. The data section partition can be defined -+ * as mapped by the sparse mmap capability. If mmapped, data_offset must be -+ * page aligned, whereas initial section which contains the -+ * vfio_device_migration_info structure, might not end at the offset, which is -+ * page aligned. The user is not required to access through mmap regardless -+ * of the capabilities of the region mmap. -+ * The vendor driver should determine whether and how to partition the data -+ * section. The vendor driver should return data_offset accordingly. -+ * -+ * The sequence to be followed while in pre-copy state and stop-and-copy state -+ * is as follows: -+ * a. Read pending_bytes, indicating the start of a new iteration to get device -+ * data. Repeated read on pending_bytes at this stage should have no side -+ * effects. -+ * If pending_bytes == 0, the user application should not iterate to get data -+ * for that device. -+ * If pending_bytes > 0, perform the following steps. -+ * b. Read data_offset, indicating that the vendor driver should make data -+ * available through the data section. The vendor driver should return this -+ * read operation only after data is available from (region + data_offset) -+ * to (region + data_offset + data_size). -+ * c. Read data_size, which is the amount of data in bytes available through -+ * the migration region. -+ * Read on data_offset and data_size should return the offset and size of -+ * the current buffer if the user application reads data_offset and -+ * data_size more than once here. -+ * d. Read data_size bytes of data from (region + data_offset) from the -+ * migration region. -+ * e. Process the data. -+ * f. Read pending_bytes, which indicates that the data from the previous -+ * iteration has been read. If pending_bytes > 0, go to step b. -+ * -+ * The user application can transition from the _SAVING|_RUNNING -+ * (pre-copy state) to the _SAVING (stop-and-copy) state regardless of the -+ * number of pending bytes. The user application should iterate in _SAVING -+ * (stop-and-copy) until pending_bytes is 0. -+ * -+ * The sequence to be followed while _RESUMING device state is as follows: -+ * While data for this device is available, repeat the following steps: -+ * a. Read data_offset from where the user application should write data. -+ * b. Write migration data starting at the migration region + data_offset for -+ * the length determined by data_size from the migration source. -+ * c. Write data_size, which indicates to the vendor driver that data is -+ * written in the migration region. Vendor driver must return this write -+ * operations on consuming data. Vendor driver should apply the -+ * user-provided migration region data to the device resume state. -+ * -+ * If an error occurs during the above sequences, the vendor driver can return -+ * an error code for next read() or write() operation, which will terminate the -+ * loop. The user application should then take the next necessary action, for -+ * example, failing migration or terminating the user application. -+ * -+ * For the user application, data is opaque. The user application should write -+ * data in the same order as the data is received and the data should be of -+ * same transaction size at the source. - */ --#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1) -+ -+struct vfio_device_migration_info { -+ __u32 device_state; /* VFIO device state */ -+#define VFIO_DEVICE_STATE_STOP (0) -+#define VFIO_DEVICE_STATE_RUNNING (1 << 0) -+#define VFIO_DEVICE_STATE_SAVING (1 << 1) -+#define VFIO_DEVICE_STATE_RESUMING (1 << 2) -+#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_RUNNING | \ -+ VFIO_DEVICE_STATE_SAVING | \ -+ VFIO_DEVICE_STATE_RESUMING) -+ -+#define VFIO_DEVICE_STATE_VALID(state) \ -+ (state & VFIO_DEVICE_STATE_RESUMING ? \ -+ (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_RESUMING : 1) -+ -+#define VFIO_DEVICE_STATE_IS_ERROR(state) \ -+ ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_SAVING | \ -+ VFIO_DEVICE_STATE_RESUMING)) -+ -+#define VFIO_DEVICE_STATE_SET_ERROR(state) \ -+ ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_SATE_SAVING | \ -+ VFIO_DEVICE_STATE_RESUMING) -+ -+ __u32 reserved; -+ __u64 pending_bytes; -+ __u64 data_offset; -+ __u64 data_size; -+}; - - /* - * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped -@@ -570,6 +807,7 @@ enum { - - enum { - VFIO_CCW_IO_IRQ_INDEX, -+ VFIO_CCW_CRW_IRQ_INDEX, - VFIO_CCW_NUM_IRQS - }; - -@@ -700,6 +938,43 @@ struct vfio_device_ioeventfd { - - #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) - -+/** -+ * VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17, -+ * struct vfio_device_feature) -+ * -+ * Get, set, or probe feature data of the device. The feature is selected -+ * using the FEATURE_MASK portion of the flags field. Support for a feature -+ * can be probed by setting both the FEATURE_MASK and PROBE bits. A probe -+ * may optionally include the GET and/or SET bits to determine read vs write -+ * access of the feature respectively. Probing a feature will return success -+ * if the feature is supported and all of the optionally indicated GET/SET -+ * methods are supported. The format of the data portion of the structure is -+ * specific to the given feature. The data portion is not required for -+ * probing. GET and SET are mutually exclusive, except for use with PROBE. -+ * -+ * Return 0 on success, -errno on failure. -+ */ -+struct vfio_device_feature { -+ __u32 argsz; -+ __u32 flags; -+#define VFIO_DEVICE_FEATURE_MASK (0xffff) /* 16-bit feature index */ -+#define VFIO_DEVICE_FEATURE_GET (1 << 16) /* Get feature into data[] */ -+#define VFIO_DEVICE_FEATURE_SET (1 << 17) /* Set feature from data[] */ -+#define VFIO_DEVICE_FEATURE_PROBE (1 << 18) /* Probe feature support */ -+ __u8 data[]; -+}; -+ -+#define VFIO_DEVICE_FEATURE _IO(VFIO_TYPE, VFIO_BASE + 17) -+ -+/* -+ * Provide support for setting a PCI VF Token, which is used as a shared -+ * secret between PF and VF drivers. This feature may only be set on a -+ * PCI SR-IOV PF when SR-IOV is enabled on the PF and there are no existing -+ * open VFs. Data provided when setting this feature is a 16-byte array -+ * (__u8 b[16]), representing a UUID. -+ */ -+#define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) -+ - /* -------- API for Type1 VFIO IOMMU -------- */ - - /** -@@ -714,7 +989,54 @@ struct vfio_iommu_type1_info { - __u32 argsz; - __u32 flags; - #define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */ -- __u64 iova_pgsizes; /* Bitmap of supported page sizes */ -+#define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */ -+ __u64 iova_pgsizes; /* Bitmap of supported page sizes */ -+ __u32 cap_offset; /* Offset within info struct of first cap */ -+}; -+ -+/* -+ * The IOVA capability allows to report the valid IOVA range(s) -+ * excluding any non-relaxable reserved regions exposed by -+ * devices attached to the container. Any DMA map attempt -+ * outside the valid iova range will return error. -+ * -+ * The structures below define version 1 of this capability. -+ */ -+#define VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE 1 -+ -+struct vfio_iova_range { -+ __u64 start; -+ __u64 end; -+}; -+ -+struct vfio_iommu_type1_info_cap_iova_range { -+ struct vfio_info_cap_header header; -+ __u32 nr_iovas; -+ __u32 reserved; -+ struct vfio_iova_range iova_ranges[]; -+}; -+ -+/* -+ * The migration capability allows to report supported features for migration. -+ * -+ * The structures below define version 1 of this capability. -+ * -+ * The existence of this capability indicates that IOMMU kernel driver supports -+ * dirty page logging. -+ * -+ * pgsize_bitmap: Kernel driver returns bitmap of supported page sizes for dirty -+ * page logging. -+ * max_dirty_bitmap_size: Kernel driver returns maximum supported dirty bitmap -+ * size in bytes that can be used by user applications when getting the dirty -+ * bitmap. -+ */ -+#define VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION 2 -+ -+struct vfio_iommu_type1_info_cap_migration { -+ struct vfio_info_cap_header header; -+ __u32 flags; -+ __u64 pgsize_bitmap; -+ __u64 max_dirty_bitmap_size; /* in bytes */ - }; - - #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) -@@ -737,6 +1059,12 @@ struct vfio_iommu_type1_dma_map { - - #define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13) - -+struct vfio_bitmap { -+ __u64 pgsize; /* page size for bitmap in bytes */ -+ __u64 size; /* in bytes */ -+ __u64 *data; /* one bit per page */ -+}; -+ - /** - * VFIO_IOMMU_UNMAP_DMA - _IOWR(VFIO_TYPE, VFIO_BASE + 14, - * struct vfio_dma_unmap) -@@ -746,12 +1074,23 @@ struct vfio_iommu_type1_dma_map { - * field. No guarantee is made to the user that arbitrary unmaps of iova - * or size different from those used in the original mapping call will - * succeed. -+ * VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap -+ * before unmapping IO virtual addresses. When this flag is set, the user must -+ * provide a struct vfio_bitmap in data[]. User must provide zero-allocated -+ * memory via vfio_bitmap.data and its size in the vfio_bitmap.size field. -+ * A bit in the bitmap represents one page, of user provided page size in -+ * vfio_bitmap.pgsize field, consecutively starting from iova offset. Bit set -+ * indicates that the page at that offset from iova is dirty. A Bitmap of the -+ * pages in the range of unmapped size is returned in the user-provided -+ * vfio_bitmap.data. - */ - struct vfio_iommu_type1_dma_unmap { - __u32 argsz; - __u32 flags; -+#define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0) - __u64 iova; /* IO virtual address */ - __u64 size; /* Size of mapping (bytes) */ -+ __u8 data[]; - }; - - #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) -@@ -763,6 +1102,57 @@ struct vfio_iommu_type1_dma_unmap { - #define VFIO_IOMMU_ENABLE _IO(VFIO_TYPE, VFIO_BASE + 15) - #define VFIO_IOMMU_DISABLE _IO(VFIO_TYPE, VFIO_BASE + 16) - -+/** -+ * VFIO_IOMMU_DIRTY_PAGES - _IOWR(VFIO_TYPE, VFIO_BASE + 17, -+ * struct vfio_iommu_type1_dirty_bitmap) -+ * IOCTL is used for dirty pages logging. -+ * Caller should set flag depending on which operation to perform, details as -+ * below: -+ * -+ * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_START flag set, instructs -+ * the IOMMU driver to log pages that are dirtied or potentially dirtied by -+ * the device; designed to be used when a migration is in progress. Dirty pages -+ * are logged until logging is disabled by user application by calling the IOCTL -+ * with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag. -+ * -+ * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag set, instructs -+ * the IOMMU driver to stop logging dirtied pages. -+ * -+ * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP flag set -+ * returns the dirty pages bitmap for IOMMU container for a given IOVA range. -+ * The user must specify the IOVA range and the pgsize through the structure -+ * vfio_iommu_type1_dirty_bitmap_get in the data[] portion. This interface -+ * supports getting a bitmap of the smallest supported pgsize only and can be -+ * modified in future to get a bitmap of any specified supported pgsize. The -+ * user must provide a zeroed memory area for the bitmap memory and specify its -+ * size in bitmap.size. One bit is used to represent one page consecutively -+ * starting from iova offset. The user should provide page size in bitmap.pgsize -+ * field. A bit set in the bitmap indicates that the page at that offset from -+ * iova is dirty. The caller must set argsz to a value including the size of -+ * structure vfio_iommu_type1_dirty_bitmap_get, but excluding the size of the -+ * actual bitmap. If dirty pages logging is not enabled, an error will be -+ * returned. -+ * -+ * Only one of the flags _START, _STOP and _GET may be specified at a time. -+ * -+ */ -+struct vfio_iommu_type1_dirty_bitmap { -+ __u32 argsz; -+ __u32 flags; -+#define VFIO_IOMMU_DIRTY_PAGES_FLAG_START (1 << 0) -+#define VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP (1 << 1) -+#define VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP (1 << 2) -+ __u8 data[]; -+}; -+ -+struct vfio_iommu_type1_dirty_bitmap_get { -+ __u64 iova; /* IO virtual address */ -+ __u64 size; /* Size of iova range */ -+ struct vfio_bitmap bitmap; -+}; -+ -+#define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) -+ - /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ - - /* --- -2.27.0 - diff --git a/linux-headers-Update-headers-to-Linux-5.18-rc6.patch b/linux-headers-Update-headers-to-Linux-5.18-rc6.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d066072dade0af8c64143d61aba34197210bb1c --- /dev/null +++ b/linux-headers-Update-headers-to-Linux-5.18-rc6.patch @@ -0,0 +1,31 @@ +From f639ed71c4baa5e40281ff9baa3ef312f37cf985 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 14 May 2022 12:11:04 +0800 +Subject: [PATCH 1/7] linux-headers: Update headers to Linux 5.18-rc6 + +Update headers to 5.18-rc6. I need latest vhost changes. + +Signed-off-by: Longpeng +--- + linux-headers/linux/vhost.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index c998860d7b..5d99e7c242 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -150,4 +150,11 @@ + /* Get the valid iova range */ + #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ + struct vhost_vdpa_iova_range) ++ ++/* Get the config size */ ++#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) ++ ++/* Get the count of all virtqueues */ ++#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) ++ + #endif +-- +2.27.0 + diff --git a/linux-headers-include-missing-changes-from-5.17.patch b/linux-headers-include-missing-changes-from-5.17.patch new file mode 100644 index 0000000000000000000000000000000000000000..1461d59624cbb8fb7c64b24a6fc12789e104316b --- /dev/null +++ b/linux-headers-include-missing-changes-from-5.17.patch @@ -0,0 +1,65 @@ +From d6398243714a7a775c64e74dbd63c00863cb7e83 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 22 Feb 2022 17:58:11 +0100 +Subject: [PATCH 01/10] linux-headers: include missing changes from 5.17 + +mainline inclusion +from mainline-v7.0.0-rc0 +commit 1ea5208febcc068449b63282d72bb719ab67a466 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 1ea5208febcc ("linux-headers: include missing changes from 5.17") + +------------------------------------------------ + +linux-headers: include missing changes from 5.17 + +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + linux-headers/asm-x86/kvm.h | 3 +++ + linux-headers/linux/kvm.h | 7 +++++++ + 2 files changed, 10 insertions(+) + +diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h +index a6c327f8ad..2ab4f1818a 100644 +--- a/linux-headers/asm-x86/kvm.h ++++ b/linux-headers/asm-x86/kvm.h +@@ -437,6 +437,9 @@ struct kvm_sync_regs { + + #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001 + ++/* attributes for system fd (group 0) */ ++#define KVM_X86_XCOMP_GUEST_SUPP 0 ++ + struct kvm_vmx_nested_state_data { + __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; + __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 5d8e42b8f8..7870cd0280 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1112,6 +1112,10 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_BINARY_STATS_FD 203 + #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 + #define KVM_CAP_ARM_MTE 205 ++#define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 ++#define KVM_CAP_VM_GPA_BITS 207 ++#define KVM_CAP_XSAVE2 208 ++#define KVM_CAP_SYS_ATTRIBUTES 209 + + #define KVM_CAP_ARM_CPU_FEATURE 555 + +@@ -2006,4 +2010,7 @@ struct kvm_stats_desc { + + #define KVM_GET_STATS_FD _IO(KVMIO, 0xce) + ++/* Available with KVM_CAP_XSAVE2 */ ++#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) ++ + #endif /* __LINUX_KVM_H */ +-- +2.27.0 + diff --git a/linux-headers-include-missing-changes-from-6.0.patch b/linux-headers-include-missing-changes-from-6.0.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d2ccc41df3a388eaa9ce4d7cb4fef04578ce853 --- /dev/null +++ b/linux-headers-include-missing-changes-from-6.0.patch @@ -0,0 +1,80 @@ +From 1e54d0c7bca44e2cf58c769e420c5ffcefb58ea1 Mon Sep 17 00:00:00 2001 +From: Jason Zeng +Date: Wed, 22 Feb 2023 13:59:37 +0800 +Subject: [PATCH] linux-headers: include missing changes from 6.0 + +Signed-off-by: Jason Zeng +--- + linux-headers/asm-x86/kvm.h | 6 +++++- + linux-headers/linux/kvm.h | 12 ++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h +index 2ab4f1818a..46e730b62f 100644 +--- a/linux-headers/asm-x86/kvm.h ++++ b/linux-headers/asm-x86/kvm.h +@@ -324,6 +324,7 @@ struct kvm_reinject_control { + #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 + #define KVM_VCPUEVENT_VALID_SMM 0x00000008 + #define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 ++#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT 0x00000020 + + /* Interrupt shadow states */ + #define KVM_X86_SHADOW_INT_MOV_SS 0x01 +@@ -358,7 +359,10 @@ struct kvm_vcpu_events { + __u8 smm_inside_nmi; + __u8 latched_init; + } smi; +- __u8 reserved[27]; ++ struct { ++ __u8 pending; ++ } triple_fault; ++ __u8 reserved[26]; + __u8 exception_has_payload; + __u64 exception_payload; + }; +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 7870cd0280..cda9016d49 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -269,6 +269,7 @@ struct kvm_xen_exit { + #define KVM_EXIT_AP_RESET_HOLD 32 + #define KVM_EXIT_X86_BUS_LOCK 33 + #define KVM_EXIT_XEN 34 ++#define KVM_EXIT_NOTIFY 37 + + /* For KVM_EXIT_INTERNAL_ERROR */ + /* Emulate instruction failed. */ +@@ -469,6 +470,11 @@ struct kvm_run { + } msr; + /* KVM_EXIT_XEN */ + struct kvm_xen_exit xen; ++ /* KVM_EXIT_NOTIFY */ ++ struct { ++#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) ++ __u32 flags; ++ } notify; + /* Fix the size of the union. */ + char padding[256]; + }; +@@ -1116,6 +1122,8 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_VM_GPA_BITS 207 + #define KVM_CAP_XSAVE2 208 + #define KVM_CAP_SYS_ATTRIBUTES 209 ++#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 ++#define KVM_CAP_X86_NOTIFY_VMEXIT 219 + + #define KVM_CAP_ARM_CPU_FEATURE 555 + +@@ -2013,4 +2021,8 @@ struct kvm_stats_desc { + /* Available with KVM_CAP_XSAVE2 */ + #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) + ++/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */ ++#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0) ++#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1) ++ + #endif /* __LINUX_KVM_H */ +-- +2.27.0 + diff --git a/linux-headers-update-against-5.10-and-manual-clear-v.patch b/linux-headers-update-against-5.10-and-manual-clear-v.patch index 0315fc2c1a30be23b4643c30d783e5259ef11931..93d300675cb54678121161bfb63e0a35bfaffc6f 100644 --- a/linux-headers-update-against-5.10-and-manual-clear-v.patch +++ b/linux-headers-update-against-5.10-and-manual-clear-v.patch @@ -1,4 +1,4 @@ -From 79efeccd41d761b68946df68e5431eff399ccbd5 Mon Sep 17 00:00:00 2001 +From 40512773625a4f8ddd96a5af924f119b89a14706 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Sat, 8 May 2021 17:31:03 +0800 Subject: [PATCH] linux-headers: update against 5.10 and manual clear vfio @@ -12,16 +12,16 @@ the kernel, update the header to add them. Signed-off-by: Zenghui Yu Signed-off-by: Kunkun Jiang --- - linux-headers/linux/vfio.h | 37 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 36 insertions(+), 1 deletion(-) + linux-headers/linux/vfio.h | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h -index a90672494d..120387ba58 100644 +index e680594f27..f4ff038e8c 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h -@@ -46,6 +46,16 @@ - */ - #define VFIO_NOIOMMU_IOMMU 8 +@@ -52,6 +52,16 @@ + /* Supports the vaddr flag for DMA map and unmap */ + #define VFIO_UPDATE_VADDR 10 +/* + * The vfio_iommu driver may support user clears dirty log manually, which means @@ -36,15 +36,7 @@ index a90672494d..120387ba58 100644 /* * The IOCTL interface is designed for extensibility by embedding the * structure length (argsz) and flags into structures passed between -@@ -1074,6 +1084,7 @@ struct vfio_bitmap { - * field. No guarantee is made to the user that arbitrary unmaps of iova - * or size different from those used in the original mapping call will - * succeed. -+ * - * VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap - * before unmapping IO virtual addresses. When this flag is set, the user must - * provide a struct vfio_bitmap in data[]. User must provide zero-allocated -@@ -1133,8 +1144,30 @@ struct vfio_iommu_type1_dma_unmap { +@@ -1196,8 +1206,30 @@ struct vfio_iommu_type1_dma_unmap { * actual bitmap. If dirty pages logging is not enabled, an error will be * returned. * @@ -76,7 +68,7 @@ index a90672494d..120387ba58 100644 */ struct vfio_iommu_type1_dirty_bitmap { __u32 argsz; -@@ -1142,6 +1175,8 @@ struct vfio_iommu_type1_dirty_bitmap { +@@ -1205,6 +1237,8 @@ struct vfio_iommu_type1_dirty_bitmap { #define VFIO_IOMMU_DIRTY_PAGES_FLAG_START (1 << 0) #define VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP (1 << 1) #define VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP (1 << 2) diff --git a/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch b/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch deleted file mode 100644 index 731d06a74024c81bcc1ececeb79da2b873c2546f..0000000000000000000000000000000000000000 --- a/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 27a9f40b308efd8ddcb81e286441865b5a0cb541 Mon Sep 17 00:00:00 2001 -From: Zenghui Yu -Date: Tue, 14 Apr 2020 21:52:42 +0800 -Subject: [PATCH] linux headers: update against "KVM/ARM: Fix >256 vcpus" - -This is part of upstream commit f363d039e883 ("linux headers: update -against v5.4-rc1"), authored by Eric Auger . - -Signed-off-by: Zenghui Yu ---- - linux-headers/asm-arm/kvm.h | 4 +++- - linux-headers/asm-arm64/kvm.h | 4 +++- - linux-headers/linux/kvm.h | 1 + - 3 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h -index e1f8b745..137a2730 100644 ---- a/linux-headers/asm-arm/kvm.h -+++ b/linux-headers/asm-arm/kvm.h -@@ -254,8 +254,10 @@ struct kvm_vcpu_events { - #define KVM_DEV_ARM_ITS_CTRL_RESET 4 - - /* KVM_IRQ_LINE irq field index values */ -+#define KVM_ARM_IRQ_VCPU2_SHIFT 28 -+#define KVM_ARM_IRQ_VCPU2_MASK 0xf - #define KVM_ARM_IRQ_TYPE_SHIFT 24 --#define KVM_ARM_IRQ_TYPE_MASK 0xff -+#define KVM_ARM_IRQ_TYPE_MASK 0xf - #define KVM_ARM_IRQ_VCPU_SHIFT 16 - #define KVM_ARM_IRQ_VCPU_MASK 0xff - #define KVM_ARM_IRQ_NUM_SHIFT 0 -diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h -index 2431ec35..cdfd5f33 100644 ---- a/linux-headers/asm-arm64/kvm.h -+++ b/linux-headers/asm-arm64/kvm.h -@@ -308,8 +308,10 @@ struct kvm_vcpu_events { - #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 - - /* KVM_IRQ_LINE irq field index values */ -+#define KVM_ARM_IRQ_VCPU2_SHIFT 28 -+#define KVM_ARM_IRQ_VCPU2_MASK 0xf - #define KVM_ARM_IRQ_TYPE_SHIFT 24 --#define KVM_ARM_IRQ_TYPE_MASK 0xff -+#define KVM_ARM_IRQ_TYPE_MASK 0xf - #define KVM_ARM_IRQ_VCPU_SHIFT 16 - #define KVM_ARM_IRQ_VCPU_MASK 0xff - #define KVM_ARM_IRQ_NUM_SHIFT 0 -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index c8423e76..744e888e 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_ARM_VM_IPA_SIZE 165 - #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 /* Obsolete */ - #define KVM_CAP_HYPERV_CPUID 167 -+#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174 - #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 168 - #define KVM_CAP_PPC_IRQ_XIVE 169 - #define KVM_CAP_ARM_SVE 170 --- -2.23.0 diff --git a/linux-user-Add-strace-output-for-timer_settime64-sys.patch b/linux-user-Add-strace-output-for-timer_settime64-sys.patch new file mode 100644 index 0000000000000000000000000000000000000000..c940890f253d0fecd7f54f38e419a8430dc0419a --- /dev/null +++ b/linux-user-Add-strace-output-for-timer_settime64-sys.patch @@ -0,0 +1,37 @@ +From 685f5a507be1f79b1a78fcff38923bc0670f0dc4 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Fri, 9 Dec 2022 15:39:52 +0800 +Subject: [PATCH 1/2] linux-user: Add strace output for timer_settime64() + syscall + +Add missing timer_settime64() strace output and specify format for +timer_settime(). + +Signed-off-by: Helge Deller + +Message-Id: +Signed-off-by: Laurent Vivier +Signed-off-by: tangzhongrui +--- + linux-user/strace.list | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/linux-user/strace.list b/linux-user/strace.list +index 278596acd1..544869f1ab 100644 +--- a/linux-user/strace.list ++++ b/linux-user/strace.list +@@ -1522,7 +1522,10 @@ + { TARGET_NR_timer_gettime, "timer_gettime" , NULL, NULL, NULL }, + #endif + #ifdef TARGET_NR_timer_settime +-{ TARGET_NR_timer_settime, "timer_settime" , NULL, NULL, NULL }, ++{ TARGET_NR_timer_settime, "timer_settime" , "%s(%d,%d,%p,%p)", NULL, NULL }, ++#endif ++#ifdef TARGET_NR_timer_settime64 ++{ TARGET_NR_timer_settime64, "timer_settime64" , "%s(%d,%d,%p,%p)", NULL, NULL }, + #endif + #ifdef TARGET_NR_timerfd + { TARGET_NR_timerfd, "timerfd" , NULL, NULL, NULL }, +-- +2.27.0 + diff --git a/linux-user-always-translate-cmsg-when-recvmsg.patch b/linux-user-always-translate-cmsg-when-recvmsg.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa2c965f41ca49c45780ea24db529f9b7afcd651 --- /dev/null +++ b/linux-user-always-translate-cmsg-when-recvmsg.patch @@ -0,0 +1,36 @@ +From eb2a5f2f73e4cfaf20246fb3d3fb1b8bd5716606 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Tue, 22 Nov 2022 17:10:35 +0800 +Subject: [PATCH 03/29] linux-user: always translate cmsg when recvmsg + +It's possible that a message contains both normal payload and ancillary +data in the same message, and even if no ancillary data is available +this information should be passed to the target, otherwise the target +cmsghdr will be left uninitialized and the target is going to access +uninitialized memory if it expects cmsg. +Always call the function that translate cmsg when recvmsg, because that +function should be empty-cmsg-safe(it creates an empty cmsg in the target). + +Signed-off-by: Icenowy Zheng +Signed-off-by: jianchunfu +--- + linux-user/syscall.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index f1cfcc8104..fce2c03259 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3296,7 +3296,8 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, + if (fd_trans_host_to_target_data(fd)) { + ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base, + MIN(msg.msg_iov->iov_len, len)); +- } else { ++ } ++ if (!is_error(ret)) { + ret = host_to_target_cmsg(msgp, &msg); + } + if (!is_error(ret)) { +-- +2.27.0 + diff --git a/linux-user-fix-sockaddr_in6-endianness.patch b/linux-user-fix-sockaddr_in6-endianness.patch new file mode 100644 index 0000000000000000000000000000000000000000..104dfc9531a9011e6ea387593fe8f2e568484c40 --- /dev/null +++ b/linux-user-fix-sockaddr_in6-endianness.patch @@ -0,0 +1,42 @@ +From fd2a1eeeaeaba0ca23efd37fa00631ed39081d08 Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 11:59:32 +0000 +Subject: [PATCH] linux-user: fix sockaddr_in6 endianness +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The sin6_scope_id field uses the host byte order, so there is a +conversion to be made when host and target endianness differ. + +cheery-pick from 44cf6731d6b9a48bcd57392e8cd6f0f712aaa677 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Mathis Marion +Reviewed-by: Laurent Vivier +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20230307154256.101528-2-Mathis.Marion@silabs.com> +Signed-off-by: Laurent Vivier +--- + linux-user/syscall.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index a544d04524..92df0f9d8c 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -1701,6 +1701,11 @@ static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr, + lladdr = (struct target_sockaddr_ll *)addr; + lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex); + lladdr->sll_hatype = tswap16(lladdr->sll_hatype); ++ } else if (sa_family == AF_INET6) { ++ struct sockaddr_in6 *in6addr; ++ ++ in6addr = (struct sockaddr_in6 *)addr; ++ in6addr->sin6_scope_id = tswap32(in6addr->sin6_scope_id); + } + unlock_user(target_saddr, target_addr, 0); + +-- +2.27.0 + diff --git a/linux-user-fix-strace-build-w-out-munlockall.patch b/linux-user-fix-strace-build-w-out-munlockall.patch new file mode 100644 index 0000000000000000000000000000000000000000..f3e17ce1e47dbbf292796de5f9116ab105336422 --- /dev/null +++ b/linux-user-fix-strace-build-w-out-munlockall.patch @@ -0,0 +1,44 @@ +From c51eaedcf9833a6edfcee1993e6651046fad1f59 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 30 Mar 2023 18:07:11 +0800 +Subject: [PATCH] linux-user: fix strace build w/out munlockall +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from d237b416b9499441b6833b91609ec840efd832b6 + +Signed-off-by: qihao_yewu +Signed-off-by: Mike Frysinger +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20230118090144.31155-1-vapier@gentoo.org> +Signed-off-by: Laurent Vivier +--- + linux-user/strace.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/linux-user/strace.c b/linux-user/strace.c +index 2cdbf030ba..37d66d0dff 100644 +--- a/linux-user/strace.c ++++ b/linux-user/strace.c +@@ -1368,7 +1368,8 @@ UNUSED static struct flags termios_lflags[] = { + FLAG_END, + }; + +-UNUSED static struct flags mlockall_flags[] = { ++#ifdef TARGET_NR_mlockall ++static struct flags mlockall_flags[] = { + FLAG_TARGET(MCL_CURRENT), + FLAG_TARGET(MCL_FUTURE), + #ifdef MCL_ONFAULT +@@ -1376,6 +1377,7 @@ UNUSED static struct flags mlockall_flags[] = { + #endif + FLAG_END, + }; ++#endif + + /* IDs of the various system clocks */ + #define TARGET_CLOCK_REALTIME 0 +-- +2.27.0 + diff --git a/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch b/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch deleted file mode 100644 index 2d0c6abf3d233a0694cec23a2097011c39d4fd1f..0000000000000000000000000000000000000000 --- a/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 7b4aded3f772ef43e2b600594f755eadd5da5958 Mon Sep 17 00:00:00 2001 -From: Jonathan Marler -Date: Sat, 2 May 2020 10:12:25 -0600 -Subject: [PATCH 3/5] linux-user/mmap.c: fix integer underflow in target_mremap - -Fixes: https://bugs.launchpad.net/bugs/1876373 - -This code path in mmap occurs when a page size is decreased with mremap. When a section of pages is shrunk, qemu calls mmap_reserve on the pages that were released. However, it has the diff operation reversed, subtracting the larger old_size from the smaller new_size. Instead, it should be subtracting the smaller new_size from the larger old_size. You can also see in the previous line of the change that this mmap_reserve call only occurs when old_size > new_size. - -Bug: https://bugs.launchpad.net/qemu/+bug/1876373 -Signed-off-by: Jonathan Marler -Reviewded-by: Laurent Vivier -Message-Id: <20200502161225.14346-1-johnnymarler@gmail.com> -Signed-off-by: Laurent Vivier ---- - linux-user/mmap.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/linux-user/mmap.c b/linux-user/mmap.c -index 46a6e3a7..2a9ca0c3 100644 ---- a/linux-user/mmap.c -+++ b/linux-user/mmap.c -@@ -740,7 +740,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, - if (prot == 0) { - host_addr = mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { -- mmap_reserve(old_addr + old_size, new_size - old_size); -+ mmap_reserve(old_addr + old_size, old_size - new_size); - } - } else { - errno = ENOMEM; --- -2.23.0 - diff --git a/lm32-do-not-leak-memory-on-object_new-object_unref.patch b/lm32-do-not-leak-memory-on-object_new-object_unref.patch deleted file mode 100644 index 7ccc53684bb3d3224757209a4c1710883214fcc8..0000000000000000000000000000000000000000 --- a/lm32-do-not-leak-memory-on-object_new-object_unref.patch +++ /dev/null @@ -1,77 +0,0 @@ -From d50be5295c49be1b6024f5902948b52e683b4c23 Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 14:18:35 +0800 -Subject: [PATCH] lm32: do not leak memory on object_new/object_unref -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Bottom halves and ptimers are malloced, but nothing in these -files is freeing memory allocated by instance_init. Since -these are sysctl devices that are never unrealized, just moving -the allocations to realize is enough to avoid the leak in -practice (and also to avoid upsetting asan when running -device-introspect-test). - -Signed-off-by: Paolo Bonzini -Reviewed-by: Philippe Mathieu-Daudé ---- - hw/timer/lm32_timer.c | 6 +++--- - hw/timer/milkymist-sysctl.c | 10 +++++----- - 2 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c -index 6ce876c6..13f15825 100644 ---- a/hw/timer/lm32_timer.c -+++ b/hw/timer/lm32_timer.c -@@ -184,9 +184,6 @@ static void lm32_timer_init(Object *obj) - - sysbus_init_irq(dev, &s->irq); - -- s->bh = qemu_bh_new(timer_hit, s); -- s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); -- - memory_region_init_io(&s->iomem, obj, &timer_ops, s, - "timer", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); -@@ -196,6 +193,9 @@ static void lm32_timer_realize(DeviceState *dev, Error **errp) - { - LM32TimerState *s = LM32_TIMER(dev); - -+ s->bh = qemu_bh_new(timer_hit, s); -+ s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); -+ - ptimer_set_freq(s->ptimer, s->freq_hz); - } - -diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c -index a9d25087..2f1ecc6d 100644 ---- a/hw/timer/milkymist-sysctl.c -+++ b/hw/timer/milkymist-sysctl.c -@@ -280,11 +280,6 @@ static void milkymist_sysctl_init(Object *obj) - sysbus_init_irq(dev, &s->timer0_irq); - sysbus_init_irq(dev, &s->timer1_irq); - -- s->bh0 = qemu_bh_new(timer0_hit, s); -- s->bh1 = qemu_bh_new(timer1_hit, s); -- s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); -- s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); -- - memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, - "milkymist-sysctl", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -@@ -294,6 +289,11 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) - { - MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - -+ s->bh0 = qemu_bh_new(timer0_hit, s); -+ s->bh1 = qemu_bh_new(timer1_hit, s); -+ s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); -+ s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); -+ - ptimer_set_freq(s->ptimer0, s->freq_hz); - ptimer_set_freq(s->ptimer1, s->freq_hz); - } --- -2.19.1 - diff --git a/log-Add-log-at-boot-cpu-init-for-aarch64.patch b/log-Add-log-at-boot-cpu-init-for-aarch64.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e76bcffa4e89fbb6182946802ef38c08b9c9722 --- /dev/null +++ b/log-Add-log-at-boot-cpu-init-for-aarch64.patch @@ -0,0 +1,67 @@ +From 2d3abbcc8f6c6db582d931ba194b26dd7148849f Mon Sep 17 00:00:00 2001 +From: "wanghaibin.wang" +Date: Mon, 16 Oct 2017 18:01:59 +0800 +Subject: [PATCH 1/3] log: Add log at boot & cpu init for aarch64 + +Add log at boot & cpu init for aarch64 + +Signed-off-by: miaoyubo +Signed-off-by: Jingyi Wang +--- + hw/arm/boot.c | 4 ++++ + hw/arm/virt.c | 3 +++ + 2 files changed, 7 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 74ad397b1f..21024f7999 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -12,6 +12,7 @@ + #include "qemu/datadir.h" + #include "qemu/error-report.h" + #include "qapi/error.h" ++#include "qemu/log.h" + #include + #include "hw/arm/boot.h" + #include "hw/arm/linux-boot-if.h" +@@ -1317,6 +1318,9 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info) + * doesn't support secure. + */ + assert(!(info->secure_board_setup && kvm_enabled())); ++ ++ qemu_log("load the kernel\n"); ++ + info->kernel_filename = ms->kernel_filename; + info->kernel_cmdline = ms->kernel_cmdline; + info->initrd_filename = ms->initrd_filename; +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 0538d258fa..47e98f09e8 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -33,6 +33,7 @@ + #include "qemu/datadir.h" + #include "qemu/units.h" + #include "qemu/option.h" ++#include "qemu/log.h" + #include "monitor/qdev.h" + #include "qapi/error.h" + #include "hw/sysbus.h" +@@ -971,6 +972,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque) + { + VirtMachineState *s = container_of(n, VirtMachineState, powerdown_notifier); + ++ qemu_log("send powerdown to vm.\n"); + if (s->acpi_dev) { + acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS); + } else { +@@ -2072,6 +2074,7 @@ static void machvirt_init(MachineState *machine) + } + + create_fdt(vms); ++ qemu_log("cpu init start\n"); + + possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len == max_cpus); +-- +2.30.0 + diff --git a/log-Add-some-logs-on-VM-runtime-path.patch b/log-Add-some-logs-on-VM-runtime-path.patch index 80eb8c39b4bcc4884c5a8fbfa43f28b808efb912..90408a3a2a9971f29abee70b9907aa1e45ad22cf 100644 --- a/log-Add-some-logs-on-VM-runtime-path.patch +++ b/log-Add-some-logs-on-VM-runtime-path.patch @@ -1,25 +1,25 @@ -From 0c83403e6e3ab21a01941be4ec57b02388eeb9c4 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Fri, 22 May 2020 18:56:09 +0800 +From d0ed3afacd2af1cbfcfb615471ade3c8c4185c00 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Tue, 8 Feb 2022 15:48:01 +0800 Subject: [PATCH] log: Add some logs on VM runtime path Add logs on VM runtime path, to make it easier to do trouble shooting. Signed-off-by: Ying Fang +Signed-off-by: Yan Wang +--- + hw/virtio/virtio-pci.c | 2 ++ + hw/virtio/virtio.c | 14 ++++++++++++-- + monitor/monitor.c | 9 +++++++++ + qapi/qmp-dispatch.c | 15 +++++++++++++++ + softmmu/qdev-monitor.c | 4 +++- + 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index f6d2223..b4b0ed2 100644 +index 750aa47ec1..38a5dc1ba8 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c -@@ -32,6 +32,7 @@ - #include "qemu/range.h" - #include "hw/virtio/virtio-bus.h" - #include "qapi/visitor.h" -+#include "qemu/log.h" - - #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) - -@@ -1659,7 +1660,9 @@ static void virtio_pci_device_unplugged(DeviceState *d) +@@ -1772,7 +1772,9 @@ static void virtio_pci_device_unplugged(DeviceState *d) VirtIOPCIProxy *proxy = VIRTIO_PCI(d); bool modern = virtio_pci_modern(proxy); bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; @@ -30,10 +30,10 @@ index f6d2223..b4b0ed2 100644 if (modern) { diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index 7c3822c..79c2dcf 100644 +index ea7c079fb0..9b4ac58a16 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c -@@ -1172,7 +1172,14 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) +@@ -1945,7 +1945,14 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) k->set_status(vdev, val); } vdev->status = val; @@ -49,7 +49,7 @@ index 7c3822c..79c2dcf 100644 return 0; } -@@ -1614,8 +1621,11 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, +@@ -2389,8 +2396,11 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, break; } @@ -63,62 +63,60 @@ index 7c3822c..79c2dcf 100644 vdev->vq[i].vring.num = queue_size; vdev->vq[i].vring.num_default = queue_size; diff --git a/monitor/monitor.c b/monitor/monitor.c -index 3ef2817..6f726e8 100644 +index 21c7a68758..013c628695 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c -@@ -28,6 +28,7 @@ +@@ -29,6 +29,7 @@ #include "qapi/qapi-emit-events.h" + #include "qapi/qapi-visit-control.h" #include "qapi/qmp/qdict.h" - #include "qapi/qmp/qstring.h" +#include "qapi/qmp/qjson.h" #include "qemu/error-report.h" #include "qemu/option.h" #include "sysemu/qtest.h" -@@ -254,6 +255,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) +@@ -318,6 +319,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) { Monitor *mon; MonitorQMP *qmp_mon; -+ QString *json; ++ GString *json; trace_monitor_protocol_event_emit(event, qdict); QTAILQ_FOREACH(mon, &mon_list, entry) { -@@ -264,6 +266,13 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) +@@ -328,6 +330,13 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) qmp_mon = container_of(mon, MonitorQMP, common); if (qmp_mon->commands != &qmp_cap_negotiation_commands) { qmp_send_response(qmp_mon, qdict); + json = qobject_to_json(QOBJECT(qdict)); + if (json) { -+ if (!strstr(json->string, "RTC_CHANGE")) { -+ qemu_log("%s\n", qstring_get_str(json)); ++ if (!strstr(json->str, "RTC_CHANGE")) { ++ qemu_log("%s\n", json->str); + } -+ qobject_unref(json); ++ g_string_free(json, true); + } } } } diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c -index e2c366e..6dfdad5 100644 +index d378bccac7..bb005594d3 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c -@@ -17,7 +17,9 @@ - #include "qapi/qmp/qdict.h" - #include "qapi/qmp/qjson.h" +@@ -25,6 +25,7 @@ #include "qapi/qmp/qbool.h" -+#include "qapi/qmp/qstring.h" - #include "sysemu/sysemu.h" + #include "qemu/coroutine.h" + #include "qemu/main-loop.h" +#include "qemu/log.h" - static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, - Error **errp) -@@ -83,6 +85,7 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, - const char *command; - QDict *args, *dict; - QmpCommand *cmd; -+ QString *json; + Visitor *qobject_input_visitor_new_qmp(QObject *obj) + { +@@ -147,6 +148,7 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, + QObject *id; QObject *ret = NULL; + QDict *rsp = NULL; ++ GString *json; - dict = qmp_dispatch_check_obj(request, allow_oob, errp); -@@ -128,6 +131,19 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + dict = qobject_to(QDict, request); + if (!dict) { +@@ -204,6 +206,19 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, qobject_ref(args); } @@ -130,27 +128,27 @@ index e2c366e..6dfdad5 100644 + && (strcmp(command, "query-balloon") != 0) + && (strcmp(command, "set_password") != 0)) { + qemu_log("qmp_cmd_name: %s, arguments: %s\n", -+ command, qstring_get_str(json)); ++ command, json->str); + } -+ qobject_unref(json); ++ g_string_free(json, true); + } + - cmd->fn(args, &ret, &local_err); - if (local_err) { - error_propagate(errp, local_err); -diff --git a/qdev-monitor.c b/qdev-monitor.c -index 58222c2..c6c1d3f 100644 ---- a/qdev-monitor.c -+++ b/qdev-monitor.c -@@ -34,6 +34,7 @@ + assert(!(oob && qemu_in_coroutine())); + assert(monitor_cur() == NULL); + if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) { +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 01f3834db5..dfd6429bf3 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -36,6 +36,7 @@ + #include "qemu/option.h" #include "qemu/qemu-print.h" + #include "qemu/option_int.h" ++#include "qemu/log.h" #include "sysemu/block-backend.h" #include "migration/misc.h" -+#include "qemu/log.h" - - /* - * Aliases were a bad idea from the start. Let's keep them -@@ -586,6 +587,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + #include "migration/migration.h" +@@ -635,6 +636,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, if (path != NULL) { bus = qbus_find(path, errp); if (!bus) { @@ -158,24 +156,15 @@ index 58222c2..c6c1d3f 100644 return NULL; } if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) { -@@ -627,6 +629,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - - /* set properties */ - if (qemu_opt_foreach(opts, set_property, dev, &err)) { -+ error_setg(errp, "the bus %s -driver %s set property failed", -+ bus ? bus->name : "None", driver); +@@ -707,7 +709,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, + if (*errp) { goto err_del_dev; } - -@@ -636,6 +640,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - dev->opts = NULL; +- ++ qemu_log("add qdev %s:%s success\n", driver, dev->id ? dev->id : "none"); + if (!qdev_realize(DEVICE(dev), bus, errp)) { goto err_del_dev; } -+ qemu_log("add qdev %s:%s success\n", driver, -+ qemu_opts_id(opts) ? qemu_opts_id(opts) : "none"); - return dev; - - err_del_dev: -- -1.8.3.1 +2.27.0 diff --git a/log-Delete-redudant-qemu_log.patch b/log-Delete-redudant-qemu_log.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc9baab1c5be346226688063c857804ccbc8844f --- /dev/null +++ b/log-Delete-redudant-qemu_log.patch @@ -0,0 +1,40 @@ +From 4b195103bc1e38c05eb67cd230051463b6dff03f Mon Sep 17 00:00:00 2001 +From: Jingyi Wang +Date: Mon, 14 Feb 2022 14:42:05 +0800 +Subject: [PATCH] log: Delete redudant qemu_log + +Delete redudant qemu_log in qmp_dispatch() + +Signed-off-by: Jingyi Wang +--- + qapi/qmp-dispatch.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index 392ddb097c..e9ea5a70d4 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -222,20 +222,6 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, + + assert(!(oob && qemu_in_coroutine())); + assert(monitor_cur() == NULL); +- +- json = qobject_to_json(QOBJECT(args)); +- if (json) { +- if ((strcmp(command, "query-block-jobs") != 0) +- && (strcmp(command, "query-migrate") != 0) +- && (strcmp(command, "query-blockstats") != 0) +- && (strcmp(command, "query-balloon") != 0) +- && (strcmp(command, "set_password") != 0)) { +- qemu_log("qmp_cmd_name: %s, arguments: %s\n", +- command, json->str); +- } +- g_string_free(json, true); +- } +- + if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) { + monitor_set_cur(qemu_coroutine_self(), cur_mon); + cmd->fn(args, &ret, &err); +-- +2.27.0 + diff --git a/make-check-unit-use-after-free-in-test-opts-visitor.patch b/make-check-unit-use-after-free-in-test-opts-visitor.patch deleted file mode 100644 index 590970004769b464b68977639a0e5e823bb9b9ac..0000000000000000000000000000000000000000 --- a/make-check-unit-use-after-free-in-test-opts-visitor.patch +++ /dev/null @@ -1,102 +0,0 @@ -From e3dfb5d2848975e9e947cb894afac87ce386a2bc Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 15:18:52 +0800 -Subject: [PATCH] make check-unit: use after free in test-opts-visitor - -In the struct OptsVisitor, the 'repeated_opts' member points to a list -in the 'unprocessed_opts' hash table after the list has been destroyed. -A subsequent call to visit_type_int() references the deleted list. -It results in use-after-free issue reproduced by running the test case -under the Valgrind: valgrind tests/test-opts-visitor. -A new mode ListMode::LM_TRAVERSED is declared to mark the list -traversal completed. - -Suggested-by: Markus Armbruster -Signed-off-by: Andrey Shinkevich -Message-Id: <1565024586-387112-1-git-send-email-andrey.shinkevich@virtuozzo.com> ---- - qapi/opts-visitor.c | 26 ++++++++++++++++++++++---- - 1 file changed, 22 insertions(+), 4 deletions(-) - -diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c -index 324b1974..42d87df6 100644 ---- a/qapi/opts-visitor.c -+++ b/qapi/opts-visitor.c -@@ -24,7 +24,8 @@ enum ListMode - { - LM_NONE, /* not traversing a list of repeated options */ - -- LM_IN_PROGRESS, /* opts_next_list() ready to be called. -+ LM_IN_PROGRESS, /* -+ * opts_next_list() ready to be called. - * - * Generating the next list link will consume the most - * recently parsed QemuOpt instance of the repeated -@@ -36,7 +37,8 @@ enum ListMode - * LM_UNSIGNED_INTERVAL. - */ - -- LM_SIGNED_INTERVAL, /* opts_next_list() has been called. -+ LM_SIGNED_INTERVAL, /* -+ * opts_next_list() has been called. - * - * Generating the next list link will consume the most - * recently stored element from the signed interval, -@@ -48,7 +50,14 @@ enum ListMode - * next element of the signed interval. - */ - -- LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */ -+ LM_UNSIGNED_INTERVAL, /* Same as above, only for an unsigned interval. */ -+ -+ LM_TRAVERSED /* -+ * opts_next_list() has been called. -+ * -+ * No more QemuOpt instance in the list. -+ * The traversal has been completed. -+ */ - }; - - typedef enum ListMode ListMode; -@@ -238,6 +247,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) - OptsVisitor *ov = to_ov(v); - - switch (ov->list_mode) { -+ case LM_TRAVERSED: -+ return NULL; - case LM_SIGNED_INTERVAL: - case LM_UNSIGNED_INTERVAL: - if (ov->list_mode == LM_SIGNED_INTERVAL) { -@@ -258,6 +269,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) - opt = g_queue_pop_head(ov->repeated_opts); - if (g_queue_is_empty(ov->repeated_opts)) { - g_hash_table_remove(ov->unprocessed_opts, opt->name); -+ ov->repeated_opts = NULL; -+ ov->list_mode = LM_TRAVERSED; - return NULL; - } - break; -@@ -289,7 +302,8 @@ opts_end_list(Visitor *v, void **obj) - - assert(ov->list_mode == LM_IN_PROGRESS || - ov->list_mode == LM_SIGNED_INTERVAL || -- ov->list_mode == LM_UNSIGNED_INTERVAL); -+ ov->list_mode == LM_UNSIGNED_INTERVAL || -+ ov->list_mode == LM_TRAVERSED); - ov->repeated_opts = NULL; - ov->list_mode = LM_NONE; - } -@@ -306,6 +320,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) - list = lookup_distinct(ov, name, errp); - return list ? g_queue_peek_tail(list) : NULL; - } -+ if (ov->list_mode == LM_TRAVERSED) { -+ error_setg(errp, "Fewer list elements than expected"); -+ return NULL; -+ } - assert(ov->list_mode == LM_IN_PROGRESS); - return g_queue_peek_head(ov->repeated_opts); - } --- -2.19.1 - diff --git a/make-release-pull-in-edk2-submodules-so-we-can-build.patch b/make-release-pull-in-edk2-submodules-so-we-can-build.patch deleted file mode 100644 index 70bcc864d0fd976919e540165bc7167e5026c46e..0000000000000000000000000000000000000000 --- a/make-release-pull-in-edk2-submodules-so-we-can-build.patch +++ /dev/null @@ -1,60 +0,0 @@ -From c5c9b1362d1652a9d0f79f6d9ae2f80d4b5fe432 Mon Sep 17 00:00:00 2001 -From: Michael Roth -Date: Thu, 12 Sep 2019 18:12:01 -0500 -Subject: [PATCH] make-release: pull in edk2 submodules so we can build it from - tarballs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The `make efi` target added by 536d2173 is built from the roms/edk2 -submodule, which in turn relies on additional submodules nested under -roms/edk2. - -The make-release script currently only pulls in top-level submodules, -so these nested submodules are missing in the resulting tarball. - -We could try to address this situation more generally by recursively -pulling in all submodules, but this doesn't necessarily ensure the -end-result will build properly (this case also required other changes). - -Additionally, due to the nature of submodules, we may not always have -control over how these sorts of things are dealt with, so for now we -continue to handle it on a case-by-case in the make-release script. - -Cc: Laszlo Ersek -Cc: Bruce Rogers -Cc: qemu-stable@nongnu.org # v4.1.0 -Reported-by: Bruce Rogers -Reviewed-by: Philippe Mathieu-Daudé -Tested-by: Philippe Mathieu-Daudé -Signed-off-by: Michael Roth -Message-Id: <20190912231202.12327-2-mdroth@linux.vnet.ibm.com> -Signed-off-by: Philippe Mathieu-Daudé -(cherry picked from commit 45c61c6c23918e3b05ed9ecac5b2328ebae5f774) -Signed-off-by: Michael Roth ---- - scripts/make-release | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/scripts/make-release b/scripts/make-release -index b4af9c9e52..a2a8cda33c 100755 ---- a/scripts/make-release -+++ b/scripts/make-release -@@ -20,6 +20,14 @@ git checkout "v${version}" - git submodule update --init - (cd roms/seabios && git describe --tags --long --dirty > .version) - (cd roms/skiboot && ./make_version.sh > .version) -+# Fetch edk2 submodule's submodules, since it won't have access to them via -+# the tarball later. -+# -+# A more uniform way to handle this sort of situation would be nice, but we -+# don't necessarily have much control over how a submodule handles its -+# submodule dependencies, so we continue to handle these on a case-by-case -+# basis for now. -+(cd roms/edk2 && git submodule update --init) - popd - tar --exclude=.git -cjf ${destination}.tar.bz2 ${destination} - rm -rf ${destination} --- -2.23.0 diff --git a/mcf5208-fix-leak-from-qemu_allocate_irqs.patch b/mcf5208-fix-leak-from-qemu_allocate_irqs.patch deleted file mode 100644 index 7e254f577e4f08bc332bb94dda769ce9a584c623..0000000000000000000000000000000000000000 --- a/mcf5208-fix-leak-from-qemu_allocate_irqs.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 07b7cdb648124748c34be299fbfdfe3b6e38a521 Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 14:53:00 +0800 -Subject: [PATCH] mcf5208: fix leak from qemu_allocate_irqs - -The array returned by qemu_allocate_irqs is malloced, free it. - -Signed-off-by: Paolo Bonzini -Reviewed-by: Thomas Huth ---- - hw/m68k/mcf5208.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c -index 6f6efae9..cc765eac 100644 ---- a/hw/m68k/mcf5208.c -+++ b/hw/m68k/mcf5208.c -@@ -270,6 +270,8 @@ static void mcf5208evb_init(MachineState *machine) - 0xfc030000, pic + 36); - } - -+ g_free(pic); -+ - /* 0xfc000000 SCM. */ - /* 0xfc004000 XBS. */ - /* 0xfc008000 FlexBus CS. */ --- -2.19.1 - diff --git a/megasas-avoid-NULL-pointer-dereference.patch b/megasas-avoid-NULL-pointer-dereference.patch deleted file mode 100644 index c7bc95901d82110b49e65ccab6cd9a84dc562aa0..0000000000000000000000000000000000000000 --- a/megasas-avoid-NULL-pointer-dereference.patch +++ /dev/null @@ -1,36 +0,0 @@ -From cf7f42b21aaa7694c6232a9a5027de9df341f299 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 14 May 2020 00:55:39 +0530 -Subject: [PATCH 5/9] megasas: avoid NULL pointer dereference - -While in megasas_handle_frame(), megasas_enqueue_frame() may -set a NULL frame into MegasasCmd object for a given 'frame_addr' -address. Add check to avoid a NULL pointer dereference issue. - -Reported-by: Alexander Bulekov -Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 -Signed-off-by: Prasad J Pandit -Acked-by: Alexander Bulekov -Reviewed-by: Darren Kenny -Message-Id: <20200513192540.1583887-3-ppandit@redhat.com> -Signed-off-by: Paolo Bonzini ---- - hw/scsi/megasas.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 7ee331d9da..5923ffbd22 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -503,7 +503,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, - cmd->pa = frame; - /* Map all possible frames */ - cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0); -- if (frame_size_p != frame_size) { -+ if (!cmd->frame || frame_size_p != frame_size) { - trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); - if (cmd->frame) { - megasas_unmap_frame(s, cmd); --- -2.25.1 - diff --git a/megasas-use-unsigned-type-for-positive-numeric-field.patch b/megasas-use-unsigned-type-for-positive-numeric-field.patch deleted file mode 100644 index 7e194395193623e061917b0a5e6315d6b8564a61..0000000000000000000000000000000000000000 --- a/megasas-use-unsigned-type-for-positive-numeric-field.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 7bad515189482d289d3efe4133c8af9f184662e4 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 14 May 2020 00:55:40 +0530 -Subject: [PATCH 6/9] megasas: use unsigned type for positive numeric fields - -Use unsigned type for the MegasasState fields which hold positive -numeric values. - -Signed-off-by: Prasad J Pandit -Reviewed-by: Darren Kenny -Message-Id: <20200513192540.1583887-4-ppandit@redhat.com> -Signed-off-by: Paolo Bonzini ---- - hw/scsi/megasas.c | 38 +++++++++++++++++++------------------- - 1 file changed, 19 insertions(+), 19 deletions(-) - -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 5923ffbd22..94469e8169 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -85,34 +85,34 @@ typedef struct MegasasState { - MemoryRegion queue_io; - uint32_t frame_hi; - -- int fw_state; -+ uint32_t fw_state; - uint32_t fw_sge; - uint32_t fw_cmds; - uint32_t flags; -- int fw_luns; -- int intr_mask; -- int doorbell; -- int busy; -- int diag; -- int adp_reset; -+ uint32_t fw_luns; -+ uint32_t intr_mask; -+ uint32_t doorbell; -+ uint32_t busy; -+ uint32_t diag; -+ uint32_t adp_reset; - OnOffAuto msi; - OnOffAuto msix; - - MegasasCmd *event_cmd; -- int event_locale; -+ uint16_t event_locale; - int event_class; -- int event_count; -- int shutdown_event; -- int boot_event; -+ uint32_t event_count; -+ uint32_t shutdown_event; -+ uint32_t boot_event; - - uint64_t sas_addr; - char *hba_serial; - - uint64_t reply_queue_pa; - void *reply_queue; -- int reply_queue_len; -+ uint16_t reply_queue_len; - uint16_t reply_queue_head; -- int reply_queue_tail; -+ uint16_t reply_queue_tail; - uint64_t consumer_pa; - uint64_t producer_pa; - -@@ -2258,9 +2258,9 @@ static const VMStateDescription vmstate_megasas_gen1 = { - VMSTATE_PCI_DEVICE(parent_obj, MegasasState), - VMSTATE_MSIX(parent_obj, MegasasState), - -- VMSTATE_INT32(fw_state, MegasasState), -- VMSTATE_INT32(intr_mask, MegasasState), -- VMSTATE_INT32(doorbell, MegasasState), -+ VMSTATE_UINT32(fw_state, MegasasState), -+ VMSTATE_UINT32(intr_mask, MegasasState), -+ VMSTATE_UINT32(doorbell, MegasasState), - VMSTATE_UINT64(reply_queue_pa, MegasasState), - VMSTATE_UINT64(consumer_pa, MegasasState), - VMSTATE_UINT64(producer_pa, MegasasState), -@@ -2277,9 +2277,9 @@ static const VMStateDescription vmstate_megasas_gen2 = { - VMSTATE_PCI_DEVICE(parent_obj, MegasasState), - VMSTATE_MSIX(parent_obj, MegasasState), - -- VMSTATE_INT32(fw_state, MegasasState), -- VMSTATE_INT32(intr_mask, MegasasState), -- VMSTATE_INT32(doorbell, MegasasState), -+ VMSTATE_UINT32(fw_state, MegasasState), -+ VMSTATE_UINT32(intr_mask, MegasasState), -+ VMSTATE_UINT32(doorbell, MegasasState), - VMSTATE_UINT64(reply_queue_pa, MegasasState), - VMSTATE_UINT64(consumer_pa, MegasasState), - VMSTATE_UINT64(producer_pa, MegasasState), --- -2.25.1 - diff --git a/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch b/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch deleted file mode 100644 index 507aeafb6911562d542f06f91c75a3dd90f43478..0000000000000000000000000000000000000000 --- a/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch +++ /dev/null @@ -1,51 +0,0 @@ -From e081fb1058e357d4d7adc30201013a46123fe2ae Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 14 May 2020 00:55:38 +0530 -Subject: [PATCH 4/9] megasas: use unsigned type for reply_queue_head and check - index - -A guest user may set 'reply_queue_head' field of MegasasState to -a negative value. Later in 'megasas_lookup_frame' it is used to -index into s->frames[] array. Use unsigned type to avoid OOB -access issue. - -Also check that 'index' value stays within s->frames[] bounds -through the while() loop in 'megasas_lookup_frame' to avoid OOB -access. - -Reported-by: Ren Ding -Reported-by: Hanqing Zhao -Reported-by: Alexander Bulekov -Signed-off-by: Prasad J Pandit -Acked-by: Alexander Bulekov -Message-Id: <20200513192540.1583887-2-ppandit@redhat.com> -Signed-off-by: Paolo Bonzini ---- - hw/scsi/megasas.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 0c4399930a..7ee331d9da 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -111,7 +111,7 @@ typedef struct MegasasState { - uint64_t reply_queue_pa; - void *reply_queue; - int reply_queue_len; -- int reply_queue_head; -+ uint16_t reply_queue_head; - int reply_queue_tail; - uint64_t consumer_pa; - uint64_t producer_pa; -@@ -444,7 +444,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s, - - index = s->reply_queue_head; - -- while (num < s->fw_cmds) { -+ while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) { - if (s->frames[index].pa && s->frames[index].pa == frame) { - cmd = &s->frames[index]; - break; --- -2.25.1 - diff --git a/memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch b/memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch index c67de46045dcbdca04a8a78d8ca0d44b27a794c2..b06bc2514357ceda3aeff221ef2095f43885ada1 100644 --- a/memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch +++ b/memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch @@ -1,4 +1,4 @@ -From b7f4f3b71a179a21a90ca32ef7d6ea000fb0e3bd Mon Sep 17 00:00:00 2001 +From 062923fd4e6d11e1b724f2dd059f8b0c6e65bf7a Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 25 Mar 2019 16:35:05 +0100 Subject: [PATCH] memory: Add IOMMU_ATTR_MSI_TRANSLATE IOMMU memory region @@ -16,17 +16,17 @@ Signed-off-by: Kunkun Jiang 1 file changed, 1 insertion(+) diff --git a/include/exec/memory.h b/include/exec/memory.h -index 74606e14aa..716b07e115 100644 +index 864bcaeb01..76ef99ed27 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h -@@ -242,6 +242,7 @@ struct MemoryRegionOps { +@@ -323,6 +323,7 @@ typedef struct MemoryRegionClass { enum IOMMUMemoryRegionAttr { IOMMU_ATTR_SPAPR_TCE_FD, IOMMU_ATTR_VFIO_NESTED, + IOMMU_ATTR_MSI_TRANSLATE, }; - /** + /* -- 2.27.0 diff --git a/memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch b/memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch index 3932161dc8aeb2377a64f77c1ccc2e8a5c0d9a6a..bb27247096c8d16f63ff7c55a7cb2a6827dccd16 100644 --- a/memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch +++ b/memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch @@ -1,4 +1,4 @@ -From 5f4291f431add76b8754a5fb2d62ab4108ece73f Mon Sep 17 00:00:00 2001 +From b380e3e0c30fb68dbbfb1397f3c374adfff77ac4 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2019 11:30:30 +0200 Subject: [PATCH] memory: Add IOMMU_ATTR_VFIO_NESTED IOMMU memory region @@ -24,11 +24,11 @@ Signed-off-by: Kunkun Jiang 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 0ef1ca376c..55eed5189e 100644 +index da5dac1ba5..9b87d16217 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c -@@ -1531,6 +1531,17 @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, - } +@@ -1589,6 +1589,17 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + return 0; } +static int smmuv3_get_attr(IOMMUMemoryRegion *iommu, @@ -45,7 +45,7 @@ index 0ef1ca376c..55eed5189e 100644 static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, void *data) { -@@ -1538,6 +1549,7 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, +@@ -1596,6 +1607,7 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, imrc->translate = smmuv3_translate; imrc->notify_flag_changed = smmuv3_notify_flag_changed; @@ -54,11 +54,11 @@ index 0ef1ca376c..55eed5189e 100644 static const TypeInfo smmuv3_type_info = { diff --git a/include/exec/memory.h b/include/exec/memory.h -index 3c5206dce6..74606e14aa 100644 +index c3180075e1..864bcaeb01 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h -@@ -240,7 +240,8 @@ struct MemoryRegionOps { - }; +@@ -321,7 +321,8 @@ typedef struct MemoryRegionClass { + enum IOMMUMemoryRegionAttr { - IOMMU_ATTR_SPAPR_TCE_FD @@ -66,7 +66,7 @@ index 3c5206dce6..74606e14aa 100644 + IOMMU_ATTR_VFIO_NESTED, }; - /** + /* -- 2.27.0 diff --git a/memory-Add-new-fields-in-IOTLBEntry.patch b/memory-Add-new-fields-in-IOTLBEntry.patch index d76ff3bcd7321b32c9a57b6862f68b19f1216daa..5a85dbfd61ecea58ff1942d24a004b2ed82e6fdd 100644 --- a/memory-Add-new-fields-in-IOTLBEntry.patch +++ b/memory-Add-new-fields-in-IOTLBEntry.patch @@ -1,4 +1,4 @@ -From 5a77056573d946eb9220b90dd1edce1f6f925c42 Mon Sep 17 00:00:00 2001 +From da97cef20d4ee5a8f3942953836b35e7f7dd974f Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 4 Sep 2018 08:43:05 -0400 Subject: [PATCH] memory: Add new fields in IOTLBEntry @@ -19,17 +19,117 @@ translation are required to be invalidated. A flag field is introduced to inform whether those fields are set. +To enforce all existing users do not use those new fields, +initialize the IOMMUTLBEvents when needed. + Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - include/exec/memory.h | 36 +++++++++++++++++++++++++++++++++++- - 1 file changed, 35 insertions(+), 1 deletion(-) + hw/arm/smmu-common.c | 2 +- + hw/arm/smmuv3.c | 2 +- + hw/i386/intel_iommu.c | 6 +++--- + hw/ppc/spapr_iommu.c | 2 +- + hw/virtio/virtio-iommu.c | 4 ++-- + include/exec/memory.h | 36 +++++++++++++++++++++++++++++++++++- + 6 files changed, 43 insertions(+), 9 deletions(-) +diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c +index 0459850a93..3a1ecf81d6 100644 +--- a/hw/arm/smmu-common.c ++++ b/hw/arm/smmu-common.c +@@ -470,7 +470,7 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) + /* Unmap the whole notifier's range */ + static void smmu_unmap_notifier_range(IOMMUNotifier *n) + { +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + + event.type = IOMMU_NOTIFIER_UNMAP; + event.entry.target_as = &address_space_memory; +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index 01b60bee49..94e2c658f8 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -802,7 +802,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + uint8_t tg, uint64_t num_pages) + { + SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + uint8_t granule; + + if (!tg) { +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index f584449d8d..fae282ef5e 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1193,7 +1193,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + uint32_t offset; + uint64_t slpte; + uint64_t subpage_size, subpage_mask; +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + uint64_t iova = start; + uint64_t iova_next; + int ret = 0; +@@ -2425,7 +2425,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) + { + VTDAddressSpace *vtd_dev_as; +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + struct VTDBus *vtd_bus; + hwaddr addr; + uint64_t sz; +@@ -3481,7 +3481,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + size = remain = end - start + 1; + + while (remain >= VTD_PAGE_SIZE) { +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + uint64_t mask = dma_aligned_pow2_mask(start, end, s->aw_bits); + uint64_t size = mask + 1; + +diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c +index db01071858..454df25d44 100644 +--- a/hw/ppc/spapr_iommu.c ++++ b/hw/ppc/spapr_iommu.c +@@ -449,7 +449,7 @@ static void spapr_tce_reset(DeviceState *dev) + static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba, + target_ulong tce) + { +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift); + unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift; + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index 1b23e8e18c..83ed2b82e6 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -129,7 +129,7 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, + hwaddr virt_end, hwaddr paddr, + uint32_t flags) + { +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + IOMMUAccessFlags perm = IOMMU_ACCESS_FLAG(flags & VIRTIO_IOMMU_MAP_F_READ, + flags & VIRTIO_IOMMU_MAP_F_WRITE); + +@@ -154,7 +154,7 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, + static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, + hwaddr virt_end) + { +- IOMMUTLBEvent event; ++ IOMMUTLBEvent event = {}; + uint64_t delta = virt_end - virt_start; + + if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) { diff --git a/include/exec/memory.h b/include/exec/memory.h -index dca8184277..3c5206dce6 100644 +index 20f1b27377..c3180075e1 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h -@@ -66,14 +66,48 @@ typedef enum { +@@ -113,14 +113,48 @@ typedef enum { IOMMU_RW = 3, } IOMMUAccessFlags; @@ -43,7 +143,7 @@ index dca8184277..3c5206dce6 100644 #define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | ((w) ? IOMMU_WO : 0)) +/** -+ * IOMMUTLBEntry - IOMMU TLB entry ++ * struct IOMMUTLBEntry - IOMMU TLB entry + * + * Structure used when performing a translation or when notifying MAP or + * UNMAP (invalidation) events diff --git a/memory-Align-MemoryRegionSections-fields.patch b/memory-Align-MemoryRegionSections-fields.patch deleted file mode 100644 index c363a026a5f2d071950d6d9749511166432d59e4..0000000000000000000000000000000000000000 --- a/memory-Align-MemoryRegionSections-fields.patch +++ /dev/null @@ -1,45 +0,0 @@ -From aebd98d0799d6dd9bb4dd4bf73f0b75c5f4e665d Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 14 Aug 2019 18:55:33 +0100 -Subject: [PATCH] memory: Align MemoryRegionSections fields -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -MemoryRegionSection includes an Int128 'size' field; -on some platforms the compiler causes an alignment of this to -a 128bit boundary, leaving 8 bytes of dead space. -This deadspace can be filled with junk. - -Move the size field to the top avoiding unnecessary alignment. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Philippe Mathieu-Daudé -Message-Id: <20190814175535.2023-2-dgilbert@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 44f85d3276397cfa2cfa379c61430405dad4e644) -Signed-off-by: Michael Roth ---- - include/exec/memory.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 1625913..f0f0767 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -484,10 +484,10 @@ static inline FlatView *address_space_to_flatview(AddressSpace *as) - * @nonvolatile: this section is non-volatile - */ - struct MemoryRegionSection { -+ Int128 size; - MemoryRegion *mr; - FlatView *fv; - hwaddr offset_within_region; -- Int128 size; - hwaddr offset_within_address_space; - bool readonly; - bool nonvolatile; --- -1.8.3.1 - diff --git a/memory-Fix-wrong-end-address-dump.patch b/memory-Fix-wrong-end-address-dump.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6b073c8715e057e797c6003bcec219567670f1e --- /dev/null +++ b/memory-Fix-wrong-end-address-dump.patch @@ -0,0 +1,62 @@ +From de10e9df6bcb2d56dcfd2017e66593e6e62dbb22 Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Tue, 22 Nov 2022 09:56:55 +0000 +Subject: [PATCH 01/29] memory: Fix wrong end address dump mainline inclusion + from mainline-v7.2.0-rc1 commit f9c307c3f9dfda64355fd2c6d73b002913d6752c + category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +-------------------------------- + +The end address of memory region section isn't correctly calculated +which leads to overflowed mtree dump: + + Dispatch + Physical sections + ...... + #70 @0000000000002000..0000000000011fff io [ROOT] + #71 @0000000000005000..0000000000005fff (noname) + #72 @0000000000005000..0000000000014fff io [ROOT] + #73 @0000000000005658..0000000000005658 vmport + #74 @0000000000005659..0000000000015658 io [ROOT] + #75 @0000000000006000..0000000000015fff io [ROOT] + +After fix: + #70 @0000000000002000..0000000000004fff io [ROOT] + #71 @0000000000005000..0000000000005fff (noname) + #72 @0000000000005000..0000000000005657 io [ROOT] + #73 @0000000000005658..0000000000005658 vmport + #74 @0000000000005659..0000000000005fff io [ROOT] + #75 @0000000000006000..000000000000ffff io [ROOT] + +Fixes: 5e8fd94 ("memory: Rework "info mtree" to print flat views and dispatch trees") +Signed-off-by: Zhenzhong Duan +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Xu +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220622095912.3430583-1-zhenzhong.duan@intel.com> +Signed-off-by: Philippe Mathieu-Daudé + +Signed-off-by: cmss_dx +--- + softmmu/physmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index 0e709ae384..e5c3557d54 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -3719,7 +3719,7 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root) + " %s%s%s%s%s", + i, + s->offset_within_address_space, +- s->offset_within_address_space + MR_SIZE(s->mr->size), ++ s->offset_within_address_space + MR_SIZE(s->size), + s->mr->name ? s->mr->name : "(noname)", + i < ARRAY_SIZE(names) ? names[i] : "", + s->mr == root ? " [ROOT]" : "", +-- +2.27.0 + diff --git a/memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch b/memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch index 7cecd31a9765fb0926a4de993b38e0d5e68dfd6b..e541d9e69d716560a8d5636a25d072b3d05c765f 100644 --- a/memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch +++ b/memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch @@ -1,4 +1,4 @@ -From 497e055ed89e3cb5286dde2b05b7d7fd67e69331 Mon Sep 17 00:00:00 2001 +From d2dce19165f133935ff72e209f19bc43ab4d1421 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 13 Sep 2018 14:13:04 +0200 Subject: [PATCH] memory: Introduce IOMMU Memory Region inject_faults API @@ -9,16 +9,16 @@ the IOMMU memory region. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - include/exec/memory.h | 25 +++++++++++++++++++++++++ - memory.c | 10 ++++++++++ - 2 files changed, 35 insertions(+) + include/exec/memory.h | 24 ++++++++++++++++++++++++ + softmmu/memory.c | 10 ++++++++++ + 2 files changed, 34 insertions(+) diff --git a/include/exec/memory.h b/include/exec/memory.h -index 716b07e115..ffd4282f14 100644 +index 76ef99ed27..3e84d62e40 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h -@@ -56,6 +56,8 @@ struct MemoryRegionMmio { - CPUWriteMemoryFunc *write[3]; +@@ -103,6 +103,8 @@ struct MemoryRegionSection { + bool nonvolatile; }; +struct iommu_fault; @@ -26,10 +26,10 @@ index 716b07e115..ffd4282f14 100644 typedef struct IOMMUTLBEntry IOMMUTLBEntry; /* See address_space_translate: bit 0 is read, bit 1 is write. */ -@@ -378,6 +380,19 @@ typedef struct IOMMUMemoryRegionClass { - * @iommu: the IOMMUMemoryRegion - */ - int (*num_indexes)(IOMMUMemoryRegion *iommu); +@@ -523,6 +525,19 @@ struct IOMMUMemoryRegionClass { + int (*iommu_set_page_size_mask)(IOMMUMemoryRegion *iommu, + uint64_t page_size_mask, + Error **errp); + + /* + * Inject @count faults into the IOMMU memory region @@ -43,13 +43,13 @@ index 716b07e115..ffd4282f14 100644 + */ + int (*inject_faults)(IOMMUMemoryRegion *iommu, int count, + struct iommu_fault *buf); - } IOMMUMemoryRegionClass; - - typedef struct CoalescedMemoryRange CoalescedMemoryRange; -@@ -1182,6 +1197,16 @@ int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr, - */ - int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr); + }; + typedef struct RamDiscardListener RamDiscardListener; +@@ -1819,6 +1834,15 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr); + int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr, + uint64_t page_size_mask, + Error **errp); +/** + * memory_region_inject_faults : inject @count faults stored in @buf + * @@ -59,16 +59,15 @@ index 716b07e115..ffd4282f14 100644 + */ +int memory_region_inject_faults(IOMMUMemoryRegion *iommu_mr, int count, + struct iommu_fault *buf); -+ + /** * memory_region_name: get a memory region's name - * -diff --git a/memory.c b/memory.c -index 708b3dff3d..623f89baa4 100644 ---- a/memory.c -+++ b/memory.c -@@ -2017,6 +2017,16 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr) - return imrc->num_indexes(iommu_mr); +diff --git a/softmmu/memory.c b/softmmu/memory.c +index 7340e19ff5..9f98209ab2 100644 +--- a/softmmu/memory.c ++++ b/softmmu/memory.c +@@ -2111,6 +2111,16 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, + rdmc->unregister_listener(rdm, rdl); } +int memory_region_inject_faults(IOMMUMemoryRegion *iommu_mr, int count, diff --git a/memory-Provide-an-equality-function-for-MemoryRegion.patch b/memory-Provide-an-equality-function-for-MemoryRegion.patch deleted file mode 100644 index 9d81f489a7fc516ba95aa411bccbc0a67397d389..0000000000000000000000000000000000000000 --- a/memory-Provide-an-equality-function-for-MemoryRegion.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 026ef4aabd2d533d1d2f206bd3312fb1b1674058 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 14 Aug 2019 18:55:34 +0100 -Subject: [PATCH] memory: Provide an equality function for MemoryRegionSections -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Provide a comparison function that checks all the fields are the same. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Philippe Mathieu-Daudé -Message-Id: <20190814175535.2023-3-dgilbert@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 9366cf02e4e31c2a8128904d4d8290a0fad5f888) -Signed-off-by: Michael Roth ---- - include/exec/memory.h | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/include/exec/memory.h b/include/exec/memory.h -index f0f0767..ba0ce25 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -493,6 +493,18 @@ struct MemoryRegionSection { - bool nonvolatile; - }; - -+static inline bool MemoryRegionSection_eq(MemoryRegionSection *a, -+ MemoryRegionSection *b) -+{ -+ return a->mr == b->mr && -+ a->fv == b->fv && -+ a->offset_within_region == b->offset_within_region && -+ a->offset_within_address_space == b->offset_within_address_space && -+ int128_eq(a->size, b->size) && -+ a->readonly == b->readonly && -+ a->nonvolatile == b->nonvolatile; -+} -+ - /** - * memory_region_init: Initialize a memory region - * --- -1.8.3.1 - diff --git a/memory-Set-DIRTY_MEMORY_MIGRATION-when-IOMMU-is-enab.patch b/memory-Set-DIRTY_MEMORY_MIGRATION-when-IOMMU-is-enab.patch deleted file mode 100644 index 2c4052639c2c104de23c1a6d99674ec036e675af..0000000000000000000000000000000000000000 --- a/memory-Set-DIRTY_MEMORY_MIGRATION-when-IOMMU-is-enab.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0ae8b3e05294fee99870efa9b58e22e16f31caf9 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:20 +0530 -Subject: [PATCH] memory: Set DIRTY_MEMORY_MIGRATION when IOMMU is enabled - -mr->ram_block is NULL when mr->is_iommu is true, then fr.dirty_log_mask -wasn't set correctly due to which memory listener's log_sync doesn't -get called. -This patch returns log_mask with DIRTY_MEMORY_MIGRATION set when -IOMMU is enabled. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Yan Zhao -Acked-by: Paolo Bonzini -Signed-off-by: Alex Williamson ---- - memory.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/memory.c b/memory.c -index 5d8c9a9234..44713efc66 100644 ---- a/memory.c -+++ b/memory.c -@@ -1825,7 +1825,7 @@ bool memory_region_is_ram_device(MemoryRegion *mr) - uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) - { - uint8_t mask = mr->dirty_log_mask; -- if (global_dirty_log && mr->ram_block) { -+ if (global_dirty_log && (mr->ram_block || memory_region_is_iommu(mr))) { - mask |= (1 << DIRTY_MEMORY_MIGRATION); - } - return mask; --- -2.27.0 - diff --git a/memory-Skip-dirty-tracking-for-un-migratable-memory-.patch b/memory-Skip-dirty-tracking-for-un-migratable-memory-.patch deleted file mode 100644 index 8a25d177e1349ef0faca9b9280e70bb43dfd2837..0000000000000000000000000000000000000000 --- a/memory-Skip-dirty-tracking-for-un-migratable-memory-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From d0d816682b790b7d8a9caf17c32eadde7756ac9c Mon Sep 17 00:00:00 2001 -From: Zenghui Yu -Date: Mon, 16 Nov 2020 21:22:10 +0800 -Subject: [PATCH] memory: Skip dirty tracking for un-migratable memory regions - -It makes no sense to track dirty pages for those un-migratable memory -regions (e.g., Memory BAR region of the VFIO PCI device) and doing so -will potentially lead to some unpleasant issues during migration [1]. - -Skip dirty tracking for those regions by evaluating if the region is -migratable before setting dirty_log_mask (DIRTY_MEMORY_MIGRATION). - -[1] https://lists.gnu.org/archive/html/qemu-devel/2020-11/msg03757.html - -Signed-off-by: Zenghui Yu -Message-Id: <20201116132210.1730-1-yuzenghui@huawei.com> -Reviewed-by: Cornelia Huck -Signed-off-by: Paolo Bonzini -Signed-off-by: Kunkun Jiang ---- - memory.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/memory.c b/memory.c -index 44713efc66..708b3dff3d 100644 ---- a/memory.c -+++ b/memory.c -@@ -1825,7 +1825,10 @@ bool memory_region_is_ram_device(MemoryRegion *mr) - uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) - { - uint8_t mask = mr->dirty_log_mask; -- if (global_dirty_log && (mr->ram_block || memory_region_is_iommu(mr))) { -+ RAMBlock *rb = mr->ram_block; -+ -+ if (global_dirty_log && ((rb && qemu_ram_is_migratable(rb)) || -+ memory_region_is_iommu(mr))) { - mask |= (1 << DIRTY_MEMORY_MIGRATION); - } - return mask; --- -2.27.0 - diff --git a/memory-clamp-cached-translation-in-case-it-points-to.patch b/memory-clamp-cached-translation-in-case-it-points-to.patch deleted file mode 100644 index c4f74d4e094c937f8b415683dc06997c3ce6cc90..0000000000000000000000000000000000000000 --- a/memory-clamp-cached-translation-in-case-it-points-to.patch +++ /dev/null @@ -1,72 +0,0 @@ -From e07e9fc9d97e9cae3d6316b7286b504398a6fc80 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 13 Jan 2021 14:50:59 +0800 -Subject: [PATCH] memory: clamp cached translation in case it points to an MMIO - region - -In using the address_space_translate_internal API, address_space_cache_init -forgot one piece of advice that can be found in the code for -address_space_translate_internal: - - /* MMIO registers can be expected to perform full-width accesses based only - * on their address, without considering adjacent registers that could - * decode to completely different MemoryRegions. When such registers - * exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO - * regions overlap wildly. For this reason we cannot clamp the accesses - * here. - * - * If the length is small (as is the case for address_space_ldl/stl), - * everything works fine. If the incoming length is large, however, - * the caller really has to do the clamping through memory_access_size. - */ - -address_space_cache_init is exactly one such case where "the incoming length -is large", therefore we need to clamp the resulting length---not to -memory_access_size though, since we are not doing an access yet, but to -the size of the resulting section. This ensures that subsequent accesses -to the cached MemoryRegionSection will be in range. - -With this patch, the enclosed testcase notices that the used ring does -not fit into the MSI-X table and prints a "qemu-system-x86_64: Cannot map used" -error. - -Signed-off-by: Paolo Bonzini -(cherry-picked from 4bfb024b) -Fix CVE-2020-27821 -Signed-off-by: Alex Chen ---- - exec.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/exec.c b/exec.c -index 85c6d80353..8822c241d8 100644 ---- a/exec.c -+++ b/exec.c -@@ -3834,6 +3834,7 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, - AddressSpaceDispatch *d; - hwaddr l; - MemoryRegion *mr; -+ Int128 diff; - - assert(len > 0); - -@@ -3842,6 +3843,16 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, - d = flatview_to_dispatch(cache->fv); - cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); - -+ /* -+ * cache->xlat is now relative to cache->mrs.mr, not to the section itself. -+ * Take that into account to compute how many bytes are there between -+ * cache->xlat and the end of the section. -+ */ -+ -+ diff = int128_sub(cache->mrs.size, -+ int128_make64(cache->xlat - cache->mrs.offset_within_region)); -+ l = int128_get64(int128_min(diff, int128_make64(l))); -+ - mr = cache->mrs.mr; - memory_region_ref(mr); - if (memory_access_is_direct(mr, is_write)) { --- -2.27.0 - diff --git a/memory-prevent-dma-reentracy-issues.patch b/memory-prevent-dma-reentracy-issues.patch new file mode 100644 index 0000000000000000000000000000000000000000..913dd18be939a9b35e9378a3047074bd584401ab --- /dev/null +++ b/memory-prevent-dma-reentracy-issues.patch @@ -0,0 +1,132 @@ +From 26bda91b2bc6d880f75344f0a8efd3f3af8a358f Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov +Date: Thu, 27 Apr 2023 17:10:06 -0400 +Subject: [PATCH] memory: prevent dma-reentracy issues + +Add a flag to the DeviceState, when a device is engaged in PIO/MMIO/DMA. +This flag is set/checked prior to calling a device's MemoryRegion +handlers, and set when device code initiates DMA. The purpose of this +flag is to prevent two types of DMA-based reentrancy issues: + +1.) mmio -> dma -> mmio case +2.) bh -> dma write -> mmio case + +These issues have led to problems such as stack-exhaustion and +use-after-frees. + +Summary of the problem from Peter Maydell: +https://lore.kernel.org/qemu-devel/CAFEAcA_23vc7hE3iaM-JVA6W38LK4hJoWae5KcknhPRD5fPBZA@mail.gmail.com + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/62 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/540 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/541 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/556 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/557 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/827 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1282 +Resolves: CVE-2023-0330 + +Signed-off-by: Alexander Bulekov +Reviewed-by: Thomas Huth +Message-Id: <20230427211013.2994127-2-alxndr@bu.edu> +[thuth: Replace warn_report() with warn_report_once()] +Signed-off-by: Thomas Huth +Signed-off-by: liuxiangdong +--- + include/exec/memory.h | 5 +++++ + include/hw/qdev-core.h | 7 +++++++ + softmmu/memory.c | 16 ++++++++++++++++ + 3 files changed, 28 insertions(+) + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index abb838f194..bbf1468d59 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -737,6 +737,8 @@ struct MemoryRegion { + bool is_iommu; + RAMBlock *ram_block; + Object *owner; ++ /* owner as TYPE_DEVICE. Used for re-entrancy checks in MR access hotpath */ ++ DeviceState *dev; + + const MemoryRegionOps *ops; + void *opaque; +@@ -760,6 +762,9 @@ struct MemoryRegion { + unsigned ioeventfd_nb; + MemoryRegionIoeventfd *ioeventfds; + RamDiscardManager *rdm; /* Only for RAM */ ++ ++ /* For devices designed to perform re-entrant IO into their own IO MRs */ ++ bool disable_reentrancy_guard; + }; + + struct IOMMUMemoryRegion { +diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h +index 83774a1c68..45b1aec86b 100644 +--- a/include/hw/qdev-core.h ++++ b/include/hw/qdev-core.h +@@ -162,6 +162,10 @@ struct NamedClockList { + QLIST_ENTRY(NamedClockList) node; + }; + ++typedef struct { ++ bool engaged_in_io; ++} MemReentrancyGuard; ++ + /** + * DeviceState: + * @realized: Indicates whether the device has been fully constructed. +@@ -193,6 +197,9 @@ struct DeviceState { + int instance_id_alias; + int alias_required_for_version; + ResettableState reset; ++ ++ /* Is the device currently in mmio/pio/dma? Used to prevent re-entrancy */ ++ MemReentrancyGuard mem_reentrancy_guard; + }; + + struct DeviceListener { +diff --git a/softmmu/memory.c b/softmmu/memory.c +index 7340e19ff5..102f0a4248 100644 +--- a/softmmu/memory.c ++++ b/softmmu/memory.c +@@ -541,6 +541,18 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, + access_size_max = 4; + } + ++ /* Do not allow more than one simultaneous access to a device's IO Regions */ ++ if (mr->dev && !mr->disable_reentrancy_guard && ++ !mr->ram_device && !mr->ram && !mr->rom_device && !mr->readonly) { ++ if (mr->dev->mem_reentrancy_guard.engaged_in_io) { ++ warn_report_once("Blocked re-entrant IO on MemoryRegion: " ++ "%s at addr: 0x%" HWADDR_PRIX, ++ memory_region_name(mr), addr); ++ return MEMTX_ACCESS_ERROR; ++ } ++ mr->dev->mem_reentrancy_guard.engaged_in_io = true; ++ } ++ + /* FIXME: support unaligned access? */ + access_size = MAX(MIN(size, access_size_max), access_size_min); + access_mask = MAKE_64BIT_MASK(0, access_size * 8); +@@ -555,6 +567,9 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, + access_mask, attrs); + } + } ++ if (mr->dev) { ++ mr->dev->mem_reentrancy_guard.engaged_in_io = false; ++ } + return r; + } + +@@ -1169,6 +1184,7 @@ static void memory_region_do_init(MemoryRegion *mr, + } + mr->name = g_strdup(name); + mr->owner = owner; ++ mr->dev = (DeviceState *) object_dynamic_cast(mr->owner, TYPE_DEVICE); + mr->ram_block = NULL; + + if (name) { +-- +2.27.0 + diff --git a/microblaze-fix-leak-of-fdevice-tree-blob.patch b/microblaze-fix-leak-of-fdevice-tree-blob.patch deleted file mode 100644 index dd845e80cef5f3315e44417f3b7eeaa60ce6b8bb..0000000000000000000000000000000000000000 --- a/microblaze-fix-leak-of-fdevice-tree-blob.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2ff9c28e2b72cd359a0c4e931412e355baee8e1e Mon Sep 17 00:00:00 2001 -From: lizhengui -Date: Wed, 9 Sep 2020 14:55:11 +0800 -Subject: [PATCH] microblaze: fix leak of fdevice tree blob -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The device tree blob returned by load_device_tree is malloced. -Free it before returning. - -Signed-off-by: Paolo Bonzini -Reviewed-by: Philippe Mathieu-Daudé ---- - hw/microblaze/boot.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c -index a7af4c07..0fcc4e9d 100644 ---- a/hw/microblaze/boot.c -+++ b/hw/microblaze/boot.c -@@ -99,6 +99,7 @@ static int microblaze_load_dtb(hwaddr addr, - } - - cpu_physical_memory_write(addr, fdt, fdt_size); -+ g_free(fdt); - return fdt_size; - } - --- -2.19.1 - diff --git a/migration-Add-compress_level-sanity-check.patch b/migration-Add-compress_level-sanity-check.patch index 8513384f438612de27e6c4508d3f38d22edcd897..0839f6a467edb5b0f9adfd457edbcf8604a4f8d3 100644 --- a/migration-Add-compress_level-sanity-check.patch +++ b/migration-Add-compress_level-sanity-check.patch @@ -1,23 +1,24 @@ -From 90c8ce0b3bcf4a3140bc4b500da9b55a694e1bde Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From 84780210ac31e430d59b0c6d3d9f522c626b6380 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 16:23:15 +0800 -Subject: [PATCH] migration: Add compress_level sanity check +Subject: [PATCH 13/14] migration: Add compress_level sanity check Zlib compression has level from 1 to 9. However Zstd compression has level from 1 to 22 (level >= 20 not recommanded). Let's do sanity check here to make sure a vaild compress_level is given by user. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- - migration/migration.c | 32 ++++++++++++++++++++++++++++---- - 1 file changed, 28 insertions(+), 4 deletions(-) + migration/migration.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c -index 67425fde7a..17a5c16c79 100644 +index 07dc059251..f86dd8cccd 100644 --- a/migration/migration.c +++ b/migration/migration.c -@@ -1111,16 +1111,40 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, +@@ -1320,14 +1320,40 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, } } @@ -56,12 +57,10 @@ index 67425fde7a..17a5c16c79 100644 { - if (params->has_compress_level && - (params->compress_level > 9)) { -- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level", -- "is invalid, it should be in the range of 0 to 9"); + if (params->has_compress_level && !compress_level_check(params, errp)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level", + "a value between 0 and 9"); return false; - } - -- 2.27.0 diff --git a/migration-Add-multi-thread-compress-method.patch b/migration-Add-multi-thread-compress-method.patch index e900a729ea9779862318e0d2c192f88d8cf81c44..b25d78785979829b5ff7c75d3cea72ee87cdbc3b 100644 --- a/migration-Add-multi-thread-compress-method.patch +++ b/migration-Add-multi-thread-compress-method.patch @@ -1,74 +1,31 @@ -From b0cabc67e16d9b4e1e749b0359dd8f3874e0968d Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From 39d851b5d5517fbcecc8d16229ae72ca152899b7 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 14:57:54 +0800 -Subject: [PATCH] migration: Add multi-thread compress method +Subject: [PATCH 09/14] migration: Add multi-thread compress method A multi-thread compress method parameter is added to hold the method we are going to use. By default the 'zlib' method is used to maintain the compatibility as before. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- - hw/core/qdev-prop-internal.h | 18 ++++++++++++++++++ - hw/core/qdev-properties-system.c | 13 +++++++++++++ - hw/core/qdev-properties.c | 14 +++++++++++--- + hw/core/qdev-properties-system.c | 11 +++++++++++ include/hw/qdev-properties.h | 4 ++++ - migration/migration.c | 15 +++++++++++++++ - migration/qemu-file.c | 9 +++++++++ + migration/migration.c | 11 +++++++++++ monitor/hmp-cmds.c | 13 +++++++++++++ qapi/migration.json | 26 +++++++++++++++++++++++++- - 8 files changed, 108 insertions(+), 4 deletions(-) - create mode 100644 hw/core/qdev-prop-internal.h + 5 files changed, 64 insertions(+), 1 deletion(-) -diff --git a/hw/core/qdev-prop-internal.h b/hw/core/qdev-prop-internal.h -new file mode 100644 -index 0000000000..a4a7eaf078 ---- /dev/null -+++ b/hw/core/qdev-prop-internal.h -@@ -0,0 +1,18 @@ -+/* -+ * qdev property parsing -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef HW_CORE_QDEV_PROP_INTERNAL_H -+#define HW_CORE_QDEV_PROP_INTERNAL_H -+ -+void get_enum(Object *obj, Visitor *v, const char *name, void *opaque, -+ Error **errp); -+void set_enum(Object *obj, Visitor *v, const char *name, void *opaque, -+ Error **errp); -+ -+void set_default_value_enum(Object *obj, const Property *prop); -+ -+#endif diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c -index ba412dd2ca..67ed89b406 100644 +index a91f60567a..8c265bed6f 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c -@@ -15,6 +15,7 @@ - #include "hw/qdev.h" - #include "qapi/error.h" - #include "qapi/qmp/qerror.h" -+#include "qapi/qapi-types-migration.h" - #include "sysemu/block-backend.h" - #include "sysemu/blockdev.h" - #include "hw/block/block.h" -@@ -23,6 +24,7 @@ - #include "chardev/char-fe.h" - #include "sysemu/iothread.h" - #include "sysemu/tpm_backend.h" -+#include "qdev-prop-internal.h" - - static void get_pointer(Object *obj, Visitor *v, Property *prop, - char *(*print)(void *ptr), -@@ -399,3 +401,14 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) - } - nd->instantiated = 1; - } +@@ -1119,3 +1119,14 @@ const PropertyInfo qdev_prop_uuid = { + .set = set_uuid, + .set_default_value = set_default_uuid_auto, + }; + +/* --- CompressMethod --- */ +const PropertyInfo qdev_prop_compress_method = { @@ -76,107 +33,54 @@ index ba412dd2ca..67ed89b406 100644 + .description = "multi-thread compression method, " + "zlib", + .enum_table = &CompressMethod_lookup, -+ .get = get_enum, -+ .set = set_enum, -+ .set_default_value = set_default_value_enum, ++ .get = qdev_propinfo_get_enum, ++ .set = qdev_propinfo_set_enum, ++ .set_default_value = qdev_propinfo_set_default_value_enum, +}; -diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c -index 81c97f48a7..709f9e0f9d 100644 ---- a/hw/core/qdev-properties.c -+++ b/hw/core/qdev-properties.c -@@ -11,6 +11,7 @@ - #include "qapi/visitor.h" - #include "chardev/char.h" - #include "qemu/uuid.h" -+#include "qdev-prop-internal.h" - - void qdev_prop_set_after_realize(DeviceState *dev, const char *name, - Error **errp) -@@ -46,7 +47,7 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) - return ptr; - } - --static void get_enum(Object *obj, Visitor *v, const char *name, void *opaque, -+void get_enum(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) - { - DeviceState *dev = DEVICE(obj); -@@ -56,7 +57,7 @@ static void get_enum(Object *obj, Visitor *v, const char *name, void *opaque, - visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp); - } - --static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque, -+void set_enum(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) - { - DeviceState *dev = DEVICE(obj); -@@ -71,7 +72,7 @@ static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque, - visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp); - } - --static void set_default_value_enum(Object *obj, const Property *prop) -+void set_default_value_enum(Object *obj, const Property *prop) - { - object_property_set_str(obj, - qapi_enum_lookup(prop->info->enum_table, -@@ -79,6 +80,13 @@ static void set_default_value_enum(Object *obj, const Property *prop) - prop->name, &error_abort); - } - -+const PropertyInfo qdev_prop_enum = { -+ .name = "enum", -+ .get = get_enum, -+ .set = set_enum, -+ .set_default_value = set_default_value_enum, -+}; -+ - /* Bit */ - - static uint32_t qdev_get_prop_mask(Property *prop) diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h -index 1eae5ab056..a22a532eb8 100644 +index f7925f67d0..ea129d65a6 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h -@@ -23,6 +23,7 @@ extern const PropertyInfo qdev_prop_tpm; - extern const PropertyInfo qdev_prop_ptr; - extern const PropertyInfo qdev_prop_macaddr; +@@ -58,6 +58,7 @@ extern const PropertyInfo qdev_prop_int64; + extern const PropertyInfo qdev_prop_size; + extern const PropertyInfo qdev_prop_string; extern const PropertyInfo qdev_prop_on_off_auto; +extern const PropertyInfo qdev_prop_compress_method; - extern const PropertyInfo qdev_prop_losttickpolicy; - extern const PropertyInfo qdev_prop_blockdev_on_error; - extern const PropertyInfo qdev_prop_bios_chs_trans; -@@ -205,6 +206,9 @@ extern const PropertyInfo qdev_prop_pcie_link_width; - DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) + extern const PropertyInfo qdev_prop_size32; + extern const PropertyInfo qdev_prop_arraylen; + extern const PropertyInfo qdev_prop_link; +@@ -161,6 +162,9 @@ extern const PropertyInfo qdev_prop_link; + DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) #define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_on_off_auto, OnOffAuto) +#define DEFINE_PROP_COMPRESS_METHOD(_n, _s, _f, _d) \ + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_compress_method, \ + CompressMethod) - #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ - DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ - LostTickPolicy) + #define DEFINE_PROP_SIZE32(_n, _s, _f, _d) \ + DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size32, uint32_t) + diff --git a/migration/migration.c b/migration/migration.c -index 0e396f22b4..c79bf09269 100644 +index abaf6f9e3d..fa3db87d75 100644 --- a/migration/migration.c +++ b/migration/migration.c -@@ -71,6 +71,7 @@ +@@ -83,6 +83,7 @@ #define DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT 2 /*0: means nocompress, 1: best speed, ... 9: best compress ratio */ #define DEFAULT_MIGRATE_COMPRESS_LEVEL 1 +#define DEFAULT_MIGRATE_COMPRESS_METHOD COMPRESS_METHOD_ZLIB /* Define default autoconverge cpu throttle migration parameters */ + #define DEFAULT_MIGRATE_THROTTLE_TRIGGER_THRESHOLD 50 #define DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL 20 - #define DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT 10 -@@ -748,6 +749,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) +@@ -855,6 +856,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->compress_wait_thread = s->parameters.compress_wait_thread; params->has_decompress_threads = true; params->decompress_threads = s->parameters.decompress_threads; + params->has_compress_method = true; + params->compress_method = s->parameters.compress_method; + params->has_throttle_trigger_threshold = true; + params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold; params->has_cpu_throttle_initial = true; - params->cpu_throttle_initial = s->parameters.cpu_throttle_initial; - params->has_cpu_throttle_increment = true; -@@ -1250,6 +1253,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params, +@@ -1491,6 +1494,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->decompress_threads = params->decompress_threads; } @@ -184,81 +88,50 @@ index 0e396f22b4..c79bf09269 100644 + dest->compress_method = params->compress_method; + } + - if (params->has_cpu_throttle_initial) { - dest->cpu_throttle_initial = params->cpu_throttle_initial; + if (params->has_throttle_trigger_threshold) { + dest->throttle_trigger_threshold = params->throttle_trigger_threshold; } -@@ -1331,6 +1338,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) - s->parameters.decompress_threads = params->decompress_threads; - } - -+ if (params->has_compress_method) { -+ s->parameters.compress_method = params->compress_method; -+ } -+ - if (params->has_cpu_throttle_initial) { - s->parameters.cpu_throttle_initial = params->cpu_throttle_initial; - } -@@ -3436,6 +3447,9 @@ static Property migration_properties[] = { +@@ -4159,6 +4166,9 @@ static Property migration_properties[] = { DEFINE_PROP_UINT8("x-decompress-threads", MigrationState, parameters.decompress_threads, DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT), + DEFINE_PROP_COMPRESS_METHOD("compress-method", MigrationState, + parameters.compress_method, + DEFAULT_MIGRATE_COMPRESS_METHOD), - DEFINE_PROP_UINT8("x-cpu-throttle-initial", MigrationState, - parameters.cpu_throttle_initial, - DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL), -@@ -3535,6 +3549,7 @@ static void migration_instance_init(Object *obj) + DEFINE_PROP_UINT8("x-throttle-trigger-threshold", MigrationState, + parameters.throttle_trigger_threshold, + DEFAULT_MIGRATE_THROTTLE_TRIGGER_THRESHOLD), +@@ -4275,6 +4285,7 @@ static void migration_instance_init(Object *obj) params->has_compress_level = true; params->has_compress_threads = true; params->has_decompress_threads = true; + params->has_compress_method = true; + params->has_throttle_trigger_threshold = true; params->has_cpu_throttle_initial = true; params->has_cpu_throttle_increment = true; - params->has_max_bandwidth = true; -diff --git a/migration/qemu-file.c b/migration/qemu-file.c -index cd96d04e9a..be0d6c8ca8 100644 ---- a/migration/qemu-file.c -+++ b/migration/qemu-file.c -@@ -382,6 +382,15 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size, - } - } - -+static void add_buf_to_iovec(QEMUFile *f, size_t len) -+{ -+ add_to_iovec(f, f->buf + f->buf_index, len, false); -+ f->buf_index += len; -+ if (f->buf_index == IO_BUF_SIZE) { -+ qemu_fflush(f); -+ } -+} -+ - void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size, - bool may_free) - { diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c -index fc5d6b92c4..e5a7a88ba2 100644 +index 9c91bf93e9..294652034e 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c -@@ -41,6 +41,7 @@ - #include "qapi/qapi-commands-tpm.h" - #include "qapi/qapi-commands-ui.h" +@@ -45,6 +45,7 @@ #include "qapi/qapi-visit-net.h" -+#include "qapi/qapi-visit-migration.h" + #include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qdict.h" ++#include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qerror.h" #include "qapi/string-input-visitor.h" -@@ -426,6 +427,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) + #include "qapi/string-output-visitor.h" +@@ -429,6 +430,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS), params->decompress_threads); - assert(params->has_cpu_throttle_initial); + assert(params->has_throttle_trigger_threshold); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_METHOD), + CompressMethod_str(params->compress_method)); monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL), - params->cpu_throttle_initial); -@@ -1756,6 +1760,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) + MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD), + params->throttle_trigger_threshold); +@@ -1191,6 +1195,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) MigrateSetParameters *p = g_new0(MigrateSetParameters, 1); uint64_t valuebw = 0; uint64_t cache_size; @@ -266,9 +139,9 @@ index fc5d6b92c4..e5a7a88ba2 100644 Error *err = NULL; int val, ret; -@@ -1781,6 +1786,14 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) +@@ -1216,6 +1221,14 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->has_decompress_threads = true; - visit_type_int(v, param, &p->decompress_threads, &err); + visit_type_uint8(v, param, &p->decompress_threads, &err); break; + case MIGRATION_PARAMETER_COMPRESS_METHOD: + p->has_compress_method = true; @@ -278,16 +151,16 @@ index fc5d6b92c4..e5a7a88ba2 100644 + } + p->compress_method = compress_method; + break; - case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL: - p->has_cpu_throttle_initial = true; - visit_type_int(v, param, &p->cpu_throttle_initial, &err); + case MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD: + p->has_throttle_trigger_threshold = true; + visit_type_uint8(v, param, &p->throttle_trigger_threshold, &err); diff --git a/qapi/migration.json b/qapi/migration.json -index 6844ddfab3..b0e8c493ee 100644 +index bbfd48cf0b..3a76907ea9 100644 --- a/qapi/migration.json +++ b/qapi/migration.json -@@ -482,6 +482,19 @@ - ## - { 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus']} +@@ -596,6 +596,19 @@ + 'bitmaps': [ 'BitmapMigrationBitmapAlias' ] + } } +## +# @CompressMethod: @@ -305,61 +178,61 @@ index 6844ddfab3..b0e8c493ee 100644 ## # @MigrationParameter: # -@@ -518,6 +531,9 @@ - # compression, so set the decompress-threads to the number about 1/4 - # of compress-threads is adequate. +@@ -632,6 +645,9 @@ + # compression, so set the decompress-threads to the number about 1/4 + # of compress-threads is adequate. # +# @compress-method: Which multi-thread compression method to use. +# Defaults to none. (Since 5.0) +# - # @cpu-throttle-initial: Initial percentage of time guest cpus are throttled - # when migration auto-converge is activated. The - # default value is 20. (Since 2.7) -@@ -586,7 +602,7 @@ + # @throttle-trigger-threshold: The ratio of bytes_dirty_period and bytes_xfer_period + # to trigger throttling. It is expressed as percentage. + # The default value is 50. (Since 5.0) +@@ -758,7 +774,7 @@ 'data': ['announce-initial', 'announce-max', 'announce-rounds', 'announce-step', 'compress-level', 'compress-threads', 'decompress-threads', -- 'compress-wait-thread', -+ 'compress-wait-thread', 'compress-method', +- 'compress-wait-thread', 'throttle-trigger-threshold', ++ 'compress-wait-thread', 'compress-method', 'throttle-trigger-threshold', 'cpu-throttle-initial', 'cpu-throttle-increment', + 'cpu-throttle-tailslow', 'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth', - 'downtime-limit', 'x-checkpoint-delay', 'block-incremental', -@@ -620,6 +636,9 @@ +@@ -797,6 +813,9 @@ # # @decompress-threads: decompression thread count # +# @compress-method: Set compression method to use in multi-thread compression. +# Defaults to none. (Since 5.0) +# - # @cpu-throttle-initial: Initial percentage of time guest cpus are - # throttled when migration auto-converge is activated. - # The default value is 20. (Since 2.7) -@@ -695,6 +714,7 @@ - '*compress-threads': 'int', + # @throttle-trigger-threshold: The ratio of bytes_dirty_period and bytes_xfer_period + # to trigger throttling. It is expressed as percentage. + # The default value is 50. (Since 5.0) +@@ -930,6 +949,7 @@ + '*compress-threads': 'uint8', '*compress-wait-thread': 'bool', - '*decompress-threads': 'int', + '*decompress-threads': 'uint8', + '*compress-method': 'CompressMethod', - '*cpu-throttle-initial': 'int', - '*cpu-throttle-increment': 'int', - '*tls-creds': 'StrOrNull', -@@ -753,6 +773,9 @@ + '*throttle-trigger-threshold': 'uint8', + '*cpu-throttle-initial': 'uint8', + '*cpu-throttle-increment': 'uint8', +@@ -995,6 +1015,9 @@ # # @decompress-threads: decompression thread count # +# @compress-method: Which multi-thread compression method to use. +# Defaults to none. (Since 5.0) +# - # @cpu-throttle-initial: Initial percentage of time guest cpus are - # throttled when migration auto-converge is activated. - # (Since 2.7) -@@ -828,6 +851,7 @@ + # @throttle-trigger-threshold: The ratio of bytes_dirty_period and bytes_xfer_period + # to trigger throttling. It is expressed as percentage. + # The default value is 50. (Since 5.0) +@@ -1128,6 +1151,7 @@ '*compress-threads': 'uint8', '*compress-wait-thread': 'bool', '*decompress-threads': 'uint8', + '*compress-method': 'CompressMethod', + '*throttle-trigger-threshold': 'uint8', '*cpu-throttle-initial': 'uint8', '*cpu-throttle-increment': 'uint8', - '*tls-creds': 'str', -- 2.27.0 diff --git a/migration-Add-multi-thread-compress-ops.patch b/migration-Add-multi-thread-compress-ops.patch index 043d9f9b3379a4664e01b9153ccc7ecf3a702c6d..6e3b6c178ae40a9b16df95dab7859a0434663d38 100644 --- a/migration-Add-multi-thread-compress-ops.patch +++ b/migration-Add-multi-thread-compress-ops.patch @@ -1,11 +1,12 @@ -From 99fddf2ffeefc99ab15b3428dbd2b46476be3e7e Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From 5e4bc7ceaf81a4932c92e479e9add947b698395b Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 15:57:31 +0800 -Subject: [PATCH] migration: Add multi-thread compress ops +Subject: [PATCH 11/14] migration: Add multi-thread compress ops Add the MigrationCompressOps and MigrationDecompressOps structures to make the compression method configurable for multi-thread compression migration. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- @@ -15,10 +16,10 @@ Signed-off-by: Ying Fang 3 files changed, 201 insertions(+), 78 deletions(-) diff --git a/migration/migration.c b/migration/migration.c -index c79bf09269..67425fde7a 100644 +index fa3db87d75..07dc059251 100644 --- a/migration/migration.c +++ b/migration/migration.c -@@ -2143,6 +2143,15 @@ int migrate_decompress_threads(void) +@@ -2456,6 +2456,15 @@ int migrate_decompress_threads(void) return s->parameters.decompress_threads; } @@ -35,19 +36,19 @@ index c79bf09269..67425fde7a 100644 { MigrationState *s; diff --git a/migration/migration.h b/migration/migration.h -index f2bd4ebe33..4aa72297fc 100644 +index 8130b703eb..4ed4f555da 100644 --- a/migration/migration.h +++ b/migration/migration.h -@@ -319,6 +319,7 @@ int migrate_compress_level(void); +@@ -355,6 +355,7 @@ int migrate_compress_level(void); int migrate_compress_threads(void); int migrate_compress_wait_thread(void); int migrate_decompress_threads(void); +CompressMethod migrate_compress_method(void); bool migrate_use_events(void); bool migrate_postcopy_blocktime(void); - + bool migrate_background_snapshot(void); diff --git a/migration/ram.c b/migration/ram.c -index f78a681ca2..3ed808a4ca 100644 +index 1176816fba..069560e7f9 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -417,6 +417,9 @@ struct CompressParam { @@ -288,7 +289,7 @@ index f78a681ca2..3ed808a4ca 100644 g_free(comp_param[i].originbuf); goto exit; } -@@ -2208,50 +2385,6 @@ static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, +@@ -1338,50 +1515,6 @@ static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, return 1; } @@ -339,7 +340,7 @@ index f78a681ca2..3ed808a4ca 100644 static bool do_compress_ram_page(CompressParam *param, RAMBlock *block) { RAMState *rs = ram_state; -@@ -2274,7 +2407,7 @@ static bool do_compress_ram_page(CompressParam *param, RAMBlock *block) +@@ -1404,7 +1537,7 @@ static bool do_compress_ram_page(CompressParam *param, RAMBlock *block) * decompression */ memcpy(param->originbuf, p, TARGET_PAGE_SIZE); @@ -348,7 +349,7 @@ index f78a681ca2..3ed808a4ca 100644 if (ret < 0) { qemu_file_set_error(migrate_get_current()->to_dst_file, ret); error_report("compressed data failed!"); -@@ -3965,32 +4098,6 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) +@@ -3413,32 +3546,6 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) } } @@ -381,7 +382,7 @@ index f78a681ca2..3ed808a4ca 100644 static void *do_data_decompress(void *opaque) { DecompressParam *param = opaque; -@@ -4004,7 +4111,7 @@ static void *do_data_decompress(void *opaque) +@@ -3452,7 +3559,7 @@ static void *do_data_decompress(void *opaque) param->des = 0; qemu_mutex_unlock(¶m->mutex); @@ -390,7 +391,7 @@ index f78a681ca2..3ed808a4ca 100644 if (ret < 0 && migrate_get_current()->decompress_error_check) { error_report("decompress data failed"); qemu_file_set_error(decomp_file, ret); -@@ -4074,7 +4181,7 @@ static void compress_threads_load_cleanup(void) +@@ -3522,7 +3629,7 @@ static void compress_threads_load_cleanup(void) qemu_thread_join(decompress_threads + i); qemu_mutex_destroy(&decomp_param[i].mutex); qemu_cond_destroy(&decomp_param[i].cond); @@ -399,7 +400,7 @@ index f78a681ca2..3ed808a4ca 100644 g_free(decomp_param[i].compbuf); decomp_param[i].compbuf = NULL; } -@@ -4083,6 +4190,7 @@ static void compress_threads_load_cleanup(void) +@@ -3531,6 +3638,7 @@ static void compress_threads_load_cleanup(void) decompress_threads = NULL; decomp_param = NULL; decomp_file = NULL; @@ -407,7 +408,7 @@ index f78a681ca2..3ed808a4ca 100644 } static int compress_threads_load_setup(QEMUFile *f) -@@ -4093,6 +4201,11 @@ static int compress_threads_load_setup(QEMUFile *f) +@@ -3541,6 +3649,11 @@ static int compress_threads_load_setup(QEMUFile *f) return 0; } @@ -419,7 +420,7 @@ index f78a681ca2..3ed808a4ca 100644 thread_count = migrate_decompress_threads(); decompress_threads = g_new0(QemuThread, thread_count); decomp_param = g_new0(DecompressParam, thread_count); -@@ -4100,7 +4213,7 @@ static int compress_threads_load_setup(QEMUFile *f) +@@ -3548,7 +3661,7 @@ static int compress_threads_load_setup(QEMUFile *f) qemu_cond_init(&decomp_done_cond); decomp_file = f; for (i = 0; i < thread_count; i++) { @@ -428,7 +429,7 @@ index f78a681ca2..3ed808a4ca 100644 goto exit; } -@@ -4642,7 +4755,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) +@@ -4156,7 +4269,7 @@ static int ram_load_precopy(QEMUFile *f) case RAM_SAVE_FLAG_COMPRESS_PAGE: len = qemu_get_be32(f); diff --git a/migration-Add-zstd-support-in-multi-thread-compressi.patch b/migration-Add-zstd-support-in-multi-thread-compressi.patch index a84bb368ebe5a81e223c805c151ea4896ccc4e51..416e2becfe69b9f00a9fa89a0fe5f998405274df 100644 --- a/migration-Add-zstd-support-in-multi-thread-compressi.patch +++ b/migration-Add-zstd-support-in-multi-thread-compressi.patch @@ -1,47 +1,49 @@ -From 54a1b546e0bd0cc41669bf7ade806c6c777c96ad Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From bafba05f7405ba31213120d99679cc4b6c1be68e Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 16:15:10 +0800 -Subject: [PATCH] migration: Add zstd support in multi-thread compression +Subject: [PATCH 12/14] migration: Add zstd support in multi-thread compression This patch enables zstd option in multi-thread compression. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- hw/core/qdev-properties-system.c | 2 +- - migration/ram.c | 130 ++++++++++++++++++++++++++++++- - qapi/migration.json | 2 +- - 3 files changed, 130 insertions(+), 4 deletions(-) + migration/ram.c | 131 ++++++++++++++++++++++++++++++- + qapi/migration.json | 3 +- + 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c -index 67ed89b406..6d48903c87 100644 +index 8c265bed6f..6a6ff03be7 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c -@@ -406,7 +406,7 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) +@@ -1124,7 +1124,7 @@ const PropertyInfo qdev_prop_uuid = { const PropertyInfo qdev_prop_compress_method = { .name = "CompressMethod", .description = "multi-thread compression method, " - "zlib", + "zlib/zstd", .enum_table = &CompressMethod_lookup, - .get = get_enum, - .set = set_enum, + .get = qdev_propinfo_get_enum, + .set = qdev_propinfo_set_enum, diff --git a/migration/ram.c b/migration/ram.c -index 3ed808a4ca..ba1e729c39 100644 +index 069560e7f9..c3484ee1a9 100644 --- a/migration/ram.c +++ b/migration/ram.c -@@ -59,6 +59,10 @@ - #include "savevm.h" - #include "qemu/iov.h" +@@ -62,6 +62,11 @@ + #include "qemu/userfaultfd.h" + #endif /* defined(__linux__) */ +#ifdef CONFIG_ZSTD +#include +#include +#endif ++ /***********************************************************/ /* ram save/restore */ -@@ -415,11 +419,16 @@ struct CompressParam { +@@ -415,11 +420,16 @@ struct CompressParam { ram_addr_t offset; /* internally used fields */ @@ -59,7 +61,7 @@ index 3ed808a4ca..ba1e729c39 100644 }; typedef struct CompressParam CompressParam; -@@ -434,6 +443,11 @@ struct DecompressParam { +@@ -434,6 +444,11 @@ struct DecompressParam { /* for zlib compression */ z_stream stream; @@ -71,7 +73,7 @@ index 3ed808a4ca..ba1e729c39 100644 }; typedef struct DecompressParam DecompressParam; -@@ -482,7 +496,7 @@ static int zlib_save_setup(CompressParam *param) +@@ -482,7 +497,7 @@ static int zlib_save_setup(CompressParam *param) } static ssize_t zlib_compress_data(CompressParam *param, size_t size) @@ -80,7 +82,7 @@ index 3ed808a4ca..ba1e729c39 100644 int err; uint8_t *dest = NULL; z_stream *stream = ¶m->stream; -@@ -567,6 +581,103 @@ static int zlib_check_len(int len) +@@ -567,6 +582,103 @@ static int zlib_check_len(int len) return len < 0 || len > compressBound(TARGET_PAGE_SIZE); } @@ -184,7 +186,7 @@ index 3ed808a4ca..ba1e729c39 100644 static int set_compress_ops(void) { compress_ops = g_new0(MigrationCompressOps, 1); -@@ -577,6 +688,13 @@ static int set_compress_ops(void) +@@ -577,6 +689,13 @@ static int set_compress_ops(void) compress_ops->save_cleanup = zlib_save_cleanup; compress_ops->compress_data = zlib_compress_data; break; @@ -198,7 +200,7 @@ index 3ed808a4ca..ba1e729c39 100644 default: return -1; } -@@ -595,6 +713,14 @@ static int set_decompress_ops(void) +@@ -595,6 +714,14 @@ static int set_decompress_ops(void) decompress_ops->decompress_data = zlib_decompress_data; decompress_ops->check_len = zlib_check_len; break; @@ -214,15 +216,21 @@ index 3ed808a4ca..ba1e729c39 100644 return -1; } diff --git a/qapi/migration.json b/qapi/migration.json -index b0e8c493ee..587ef65872 100644 +index 3a76907ea9..d4ebc5f028 100644 --- a/qapi/migration.json +++ b/qapi/migration.json -@@ -493,7 +493,7 @@ +@@ -602,12 +602,13 @@ + # An enumeration of multi-thread compression methods. + # + # @zlib: use zlib compression method. ++# @zstd: use zstd compression method. + # + # Since: 5.0 # ## { 'enum': 'CompressMethod', - 'data': [ 'zlib' ] } -+ 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } ++ 'data': [ 'zlib', { 'name': 'zstd', 'if': 'CONFIG_ZSTD' } ] } ## # @MigrationParameter: diff --git a/migration-Change-SaveStateEntry.instance_id-into-uin.patch b/migration-Change-SaveStateEntry.instance_id-into-uin.patch deleted file mode 100644 index 3eb83b3996ccd7b934d7ca5c65800ead9c0ae3bd..0000000000000000000000000000000000000000 --- a/migration-Change-SaveStateEntry.instance_id-into-uin.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 2eadc5c611ca8cc916f74c0f393f1fd942903ef7 Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 16 Oct 2019 10:29:31 +0800 -Subject: [PATCH 6/8] migration: Change SaveStateEntry.instance_id into - uint32_t - -It was always used as 32bit, so define it as used to be clear. -Instead of using -1 as the auto-gen magic value, we switch to -UINT32_MAX. We also make sure that we don't auto-gen this value to -avoid overflowed instance IDs without being noticed. - -Suggested-by: Juan Quintela -Signed-off-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - hw/intc/apic_common.c | 2 +- - include/migration/register.h | 2 +- - include/migration/vmstate.h | 2 +- - migration/savevm.c | 18 ++++++++++-------- - stubs/vmstate.c | 2 +- - 5 files changed, 14 insertions(+), 12 deletions(-) - -diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c -index faea1af..07adba0 100644 ---- a/hw/intc/apic_common.c -+++ b/hw/intc/apic_common.c -@@ -313,7 +313,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp) - APICCommonState *s = APIC_COMMON(dev); - APICCommonClass *info; - static DeviceState *vapic; -- int instance_id = s->id; -+ uint32_t instance_id = s->id; - - info = APIC_COMMON_GET_CLASS(s); - info->realize(dev, errp); -diff --git a/include/migration/register.h b/include/migration/register.h -index 3d0b983..8b2bc5b 100644 ---- a/include/migration/register.h -+++ b/include/migration/register.h -@@ -70,7 +70,7 @@ typedef struct SaveVMHandlers { - - int register_savevm_live(DeviceState *dev, - const char *idstr, -- int instance_id, -+ uint32_t instance_id, - int version_id, - const SaveVMHandlers *ops, - void *opaque); -diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h -index 92f531a..8abd2e3 100644 ---- a/include/migration/vmstate.h -+++ b/include/migration/vmstate.h -@@ -1117,7 +1117,7 @@ bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque); - #define VMSTATE_INSTANCE_ID_ANY -1 - - /* Returns: 0 on success, -1 on failure */ --int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, -+int vmstate_register_with_alias_id(DeviceState *dev, uint32_t instance_id, - const VMStateDescription *vmsd, - void *base, int alias_id, - int required_for_version, -diff --git a/migration/savevm.c b/migration/savevm.c -index 62552ab..7d89c57 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -229,7 +229,7 @@ typedef struct CompatEntry { - typedef struct SaveStateEntry { - QTAILQ_ENTRY(SaveStateEntry) entry; - char idstr[256]; -- int instance_id; -+ uint32_t instance_id; - int alias_id; - int version_id; - /* version id read from the stream */ -@@ -616,10 +616,10 @@ void dump_vmstate_json_to_file(FILE *out_file) - fclose(out_file); - } - --static int calculate_new_instance_id(const char *idstr) -+static uint32_t calculate_new_instance_id(const char *idstr) - { - SaveStateEntry *se; -- int instance_id = 0; -+ uint32_t instance_id = 0; - - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - if (strcmp(idstr, se->idstr) == 0 -@@ -627,6 +627,8 @@ static int calculate_new_instance_id(const char *idstr) - instance_id = se->instance_id + 1; - } - } -+ /* Make sure we never loop over without being noticed */ -+ assert(instance_id != VMSTATE_INSTANCE_ID_ANY); - return instance_id; - } - -@@ -682,7 +684,7 @@ static void savevm_state_handler_insert(SaveStateEntry *nse) - distinguishing id for all instances of your device class. */ - int register_savevm_live(DeviceState *dev, - const char *idstr, -- int instance_id, -+ uint32_t instance_id, - int version_id, - const SaveVMHandlers *ops, - void *opaque) -@@ -756,7 +758,7 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque) - } - } - --int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, -+int vmstate_register_with_alias_id(DeviceState *dev, uint32_t instance_id, - const VMStateDescription *vmsd, - void *opaque, int alias_id, - int required_for_version, -@@ -1507,7 +1509,7 @@ int qemu_save_device_state(QEMUFile *f) - return qemu_file_get_error(f); - } - --static SaveStateEntry *find_se(const char *idstr, int instance_id) -+static SaveStateEntry *find_se(const char *idstr, uint32_t instance_id) - { - SaveStateEntry *se; - -@@ -2187,7 +2189,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis) - /* Find savevm section */ - se = find_se(idstr, instance_id); - if (se == NULL) { -- error_report("Unknown savevm section or instance '%s' %d. " -+ error_report("Unknown savevm section or instance '%s' %"PRIu32". " - "Make sure that your current VM setup matches your " - "saved VM setup, including any hotplugged devices", - idstr, instance_id); -@@ -2211,7 +2213,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis) - - ret = vmstate_load(f, se); - if (ret < 0) { -- error_report("error while loading state for instance 0x%x of" -+ error_report("error while loading state for instance 0x%"PRIx32" of" - " device '%s'", instance_id, idstr); - return ret; - } -diff --git a/stubs/vmstate.c b/stubs/vmstate.c -index e1e89b8..4ed5cc6 100644 ---- a/stubs/vmstate.c -+++ b/stubs/vmstate.c -@@ -4,7 +4,7 @@ - const VMStateDescription vmstate_dummy = {}; - - int vmstate_register_with_alias_id(DeviceState *dev, -- int instance_id, -+ uint32_t instance_id, - const VMStateDescription *vmsd, - void *base, int alias_id, - int required_for_version, --- -1.8.3.1 - diff --git a/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch b/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch deleted file mode 100644 index 79548949d7f449db1c57df2b747e347d7b220db5..0000000000000000000000000000000000000000 --- a/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 79d722679731233ccb1aa775d896a4bf21e13d44 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 27 May 2020 10:02:06 +0800 -Subject: [PATCH] migration: Compat virtual timer adjust for v4.0.1 and v4.1.0 - -Vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime -is introduced in openEuler qemu-4.1.0. To maintain the compatibility -and enable cross version migration, let's enable vtimer adjust only -if kvm_adjvtime is not enabled, otherwise there may be conflicts -between vtimer adjust and kvm_adjvtime. - -After this modification: -1: openEuler qemu-4.0.1 use vtimer as the default virtual timer -2: openEuler qemu-4.1.0 use kvm_adjvtime as the defaut virtual timer - -Migration from openEuler qemu-4.0.1 to openEuler qemu-4.1.0 will -be ok, but migration path from upstream qemu-4.0.1 to openEuler -qemu-4..0.1 will be broken. - -Since openEuler qemu-4.1.0, kvm_adjvtime is used as the default -virtual timer. So please upgrade to openEuler qemu-4.1.0 and -use the virt-4.1 machine. - -Signed-off-by: Ying Fang - -diff --git a/cpus.c b/cpus.c -index b9aa51f8..6a28bdef 100644 ---- a/cpus.c -+++ b/cpus.c -@@ -1067,6 +1067,12 @@ void cpu_synchronize_all_pre_loadvm(void) - } - - #ifdef __aarch64__ -+static bool kvm_adjvtime_enabled(CPUState *cs) -+{ -+ ARMCPU *cpu = ARM_CPU(cs); -+ return cpu->kvm_adjvtime == true; -+} -+ - static void get_vcpu_timer_tick(CPUState *cs) - { - CPUARMState *env = &ARM_CPU(cs)->env; -@@ -1096,7 +1102,13 @@ static int do_vm_stop(RunState state, bool send_stop) - cpu_disable_ticks(); - pause_all_vcpus(); - #ifdef __aarch64__ -- if (first_cpu) { -+ /* vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime -+ * is introduced in openEuler qemu-4.1.0. To maintain the compatibility -+ * and enable cross version migration, let's enable vtimer adjust only -+ * if kvm_adjvtime is not enabled, otherwise there may be conflicts -+ * between vtimer adjust and kvm_adjvtime. -+ */ -+ if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { - get_vcpu_timer_tick(first_cpu); - } - #endif -@@ -1946,6 +1958,7 @@ void cpu_resume(CPUState *cpu) - } - - #ifdef __aarch64__ -+ - static void set_vcpu_timer_tick(CPUState *cs) - { - CPUARMState *env = &ARM_CPU(cs)->env; -@@ -1977,7 +1990,10 @@ void resume_all_vcpus(void) - - qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); - #ifdef __aarch64__ -- if (first_cpu) { -+ /* Enable vtimer adjust only if kvm_adjvtime is not enabled, otherwise -+ * there may be conflicts between vtimer adjust and kvm_adjvtime. -+ */ -+ if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { - set_vcpu_timer_tick(first_cpu); - } - #endif --- -2.23.0 - diff --git a/migration-Count-new_dirty-instead-of-real_dirty.patch b/migration-Count-new_dirty-instead-of-real_dirty.patch deleted file mode 100644 index a9ff297ffac9fb42ce63ef8a256e648adf1166dd..0000000000000000000000000000000000000000 --- a/migration-Count-new_dirty-instead-of-real_dirty.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 63320ae36834e4ff2f0d139f205c464caa3887b4 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Mon, 22 Jun 2020 11:20:37 +0800 -Subject: [PATCH 04/11] migration: Count new_dirty instead of real_dirty - -real_dirty_pages becomes equal to total ram size after dirty log sync -in ram_init_bitmaps, the reason is that the bitmap of ramblock is -initialized to be all set, so old path counts them as "real dirty" at -beginning. - -This causes wrong dirty rate and false positive throttling. - -Signed-off-by: Keqian Zhu -Message-Id: <20200622032037.31112-1-zhukeqian1@huawei.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: BiaoXiang Ye ---- - include/exec/ram_addr.h | 5 +---- - migration/ram.c | 8 +++++--- - 2 files changed, 6 insertions(+), 7 deletions(-) - -diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h -index b7b2e60f..52344066 100644 ---- a/include/exec/ram_addr.h -+++ b/include/exec/ram_addr.h -@@ -485,8 +485,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, - static inline - uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, - ram_addr_t start, -- ram_addr_t length, -- uint64_t *real_dirty_pages) -+ ram_addr_t length) - { - ram_addr_t addr; - unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS); -@@ -512,7 +511,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, - if (src[idx][offset]) { - unsigned long bits = atomic_xchg(&src[idx][offset], 0); - unsigned long new_dirty; -- *real_dirty_pages += ctpopl(bits); - new_dirty = ~dest[k]; - dest[k] |= bits; - new_dirty &= bits; -@@ -545,7 +543,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, - start + addr + offset, - TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { -- *real_dirty_pages += 1; - long k = (start + addr) >> TARGET_PAGE_BITS; - if (!test_and_set_bit(k, dest)) { - num_dirty++; -diff --git a/migration/ram.c b/migration/ram.c -index 840e3548..83cabec6 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1765,9 +1765,11 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, - static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb, - ram_addr_t length) - { -- rs->migration_dirty_pages += -- cpu_physical_memory_sync_dirty_bitmap(rb, 0, length, -- &rs->num_dirty_pages_period); -+ uint64_t new_dirty_pages = -+ cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length); -+ -+ rs->migration_dirty_pages += new_dirty_pages; -+ rs->num_dirty_pages_period += new_dirty_pages; - } - - /** --- -2.27.0.dirty - diff --git a/migration-Create-migration_is_running.patch b/migration-Create-migration_is_running.patch deleted file mode 100644 index 86f0e6d3db2a2a51c25ebe9d6f0f4d6c48dc2de0..0000000000000000000000000000000000000000 --- a/migration-Create-migration_is_running.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 3d75adce1b9b465c45a9e841d285b3524e19cd7d Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:39:46 +0800 -Subject: [PATCH] migration: Create migration_is_running() - -This function returns true if we are in the middle of a migration. -It is like migration_is_setup_or_active() with CANCELLING and COLO. -Adapt all callers that are needed. - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert ---- - migration/migration.c | 28 +++++++++++++++++++++++----- - migration/migration.h | 1 + - migration/savevm.c | 4 +--- - 3 files changed, 25 insertions(+), 8 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 993d77b7d6..923a1d9d3f 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -822,6 +822,26 @@ bool migration_is_setup_or_active(int state) - } - } - -+bool migration_is_running(int state) -+{ -+ switch (state) { -+ case MIGRATION_STATUS_ACTIVE: -+ case MIGRATION_STATUS_POSTCOPY_ACTIVE: -+ case MIGRATION_STATUS_POSTCOPY_PAUSED: -+ case MIGRATION_STATUS_POSTCOPY_RECOVER: -+ case MIGRATION_STATUS_SETUP: -+ case MIGRATION_STATUS_PRE_SWITCHOVER: -+ case MIGRATION_STATUS_DEVICE: -+ case MIGRATION_STATUS_CANCELLING: -+ case MIGRATION_STATUS_COLO: -+ return true; -+ -+ default: -+ return false; -+ -+ } -+} -+ - static void populate_ram_info(MigrationInfo *info, MigrationState *s) - { - info->has_ram = true; -@@ -1074,7 +1094,7 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, - MigrationCapabilityStatusList *cap; - bool cap_list[MIGRATION_CAPABILITY__MAX]; - -- if (migration_is_setup_or_active(s->state)) { -+ if (migration_is_running(s->state)) { - error_setg(errp, QERR_MIGRATION_ACTIVE); - return; - } -@@ -1588,7 +1608,7 @@ static void migrate_fd_cancel(MigrationState *s) - - do { - old_state = s->state; -- if (!migration_is_setup_or_active(old_state)) { -+ if (!migration_is_running(old_state)) { - break; - } - /* If the migration is paused, kick it out of the pause */ -@@ -1873,9 +1893,7 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, - return true; - } - -- if (migration_is_setup_or_active(s->state) || -- s->state == MIGRATION_STATUS_CANCELLING || -- s->state == MIGRATION_STATUS_COLO) { -+ if (migration_is_running(s->state)) { - error_setg(errp, QERR_MIGRATION_ACTIVE); - return false; - } -diff --git a/migration/migration.h b/migration/migration.h -index e5aaf2ef70..f2bd4ebe33 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -282,6 +282,7 @@ void migrate_fd_error(MigrationState *s, const Error *error); - void migrate_fd_connect(MigrationState *s, Error *error_in); - - bool migration_is_setup_or_active(int state); -+bool migration_is_running(int state); - - void migrate_init(MigrationState *s); - bool migration_is_blocked(Error **errp); -diff --git a/migration/savevm.c b/migration/savevm.c -index 8163de7f21..f0974380e5 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -1414,9 +1414,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) - MigrationState *ms = migrate_get_current(); - MigrationStatus status; - -- if (migration_is_setup_or_active(ms->state) || -- ms->state == MIGRATION_STATUS_CANCELLING || -- ms->state == MIGRATION_STATUS_COLO) { -+ if (migration_is_running(ms->state)) { - error_setg(errp, QERR_MIGRATION_ACTIVE); - return -EINVAL; - } --- -2.27.0 - diff --git a/migration-Define-VMSTATE_INSTANCE_ID_ANY.patch b/migration-Define-VMSTATE_INSTANCE_ID_ANY.patch deleted file mode 100644 index cd32b04997c14345aa7f488cd1a960a106d9aa15..0000000000000000000000000000000000000000 --- a/migration-Define-VMSTATE_INSTANCE_ID_ANY.patch +++ /dev/null @@ -1,237 +0,0 @@ -From 21e049e2941b108df45c9089cbf7539caae538e6 Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 16 Oct 2019 10:29:30 +0800 -Subject: [PATCH 5/8] migration: Define VMSTATE_INSTANCE_ID_ANY - -Define the new macro VMSTATE_INSTANCE_ID_ANY for callers who wants to -auto-generate the vmstate instance ID. Previously it was hard coded -as -1 instead of this macro. It helps to change this default value in -the follow up patches. No functional change. - -Signed-off-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - hw/arm/stellaris.c | 2 +- - hw/core/qdev.c | 4 +++- - hw/display/ads7846.c | 2 +- - hw/i2c/core.c | 2 +- - hw/input/stellaris_input.c | 3 ++- - hw/intc/apic_common.c | 2 +- - hw/misc/max111x.c | 3 ++- - hw/net/eepro100.c | 3 ++- - hw/pci/pci.c | 2 +- - hw/ppc/spapr.c | 2 +- - hw/timer/arm_timer.c | 2 +- - hw/tpm/tpm_emulator.c | 3 ++- - include/migration/vmstate.h | 2 ++ - migration/savevm.c | 8 ++++---- - 14 files changed, 24 insertions(+), 16 deletions(-) - -diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c -index 499035f..3432033 100644 ---- a/hw/arm/stellaris.c -+++ b/hw/arm/stellaris.c -@@ -705,7 +705,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq, - memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000); - memory_region_add_subregion(get_system_memory(), base, &s->iomem); - ssys_reset(s); -- vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_stellaris_sys, s); - return 0; - } - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 94ebc0a..4b32f2f 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -848,7 +848,9 @@ static void device_set_realized(Object *obj, bool value, Error **errp) - dev->canonical_path = object_get_canonical_path(OBJECT(dev)); - - if (qdev_get_vmsd(dev)) { -- if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, -+ if (vmstate_register_with_alias_id(dev, -+ VMSTATE_INSTANCE_ID_ANY, -+ qdev_get_vmsd(dev), dev, - dev->instance_id_alias, - dev->alias_required_for_version, - &local_err) < 0) { -diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c -index 1a97e97..be1802e 100644 ---- a/hw/display/ads7846.c -+++ b/hw/display/ads7846.c -@@ -152,7 +152,7 @@ static void ads7846_realize(SSISlave *d, Error **errp) - - ads7846_int_update(s); - -- vmstate_register(NULL, -1, &vmstate_ads7846, s); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s); - } - - static void ads7846_class_init(ObjectClass *klass, void *data) -diff --git a/hw/i2c/core.c b/hw/i2c/core.c -index 20f36f1..186702b 100644 ---- a/hw/i2c/core.c -+++ b/hw/i2c/core.c -@@ -59,7 +59,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name) - - bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name)); - QLIST_INIT(&bus->current_devs); -- vmstate_register(NULL, -1, &vmstate_i2c_bus, bus); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus); - return bus; - } - -diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c -index 3a666d6..6c5b6d8 100644 ---- a/hw/input/stellaris_input.c -+++ b/hw/input/stellaris_input.c -@@ -86,5 +86,6 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) - } - s->num_buttons = n; - qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); -- vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, -+ &vmstate_stellaris_gamepad, s); - } -diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c -index e764a2b..faea1af 100644 ---- a/hw/intc/apic_common.c -+++ b/hw/intc/apic_common.c -@@ -329,7 +329,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp) - } - - if (s->legacy_instance_id) { -- instance_id = -1; -+ instance_id = VMSTATE_INSTANCE_ID_ANY; - } - vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common, - s, -1, 0, NULL); -diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c -index d373ece..364cb01 100644 ---- a/hw/misc/max111x.c -+++ b/hw/misc/max111x.c -@@ -144,7 +144,8 @@ static int max111x_init(SSISlave *d, int inputs) - s->input[7] = 0x80; - s->com = 0; - -- vmstate_register(dev, -1, &vmstate_max111x, s); -+ vmstate_register(dev, VMSTATE_INSTANCE_ID_ANY, -+ &vmstate_max111x, s); - return 0; - } - -diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c -index 6607c91..03edd25 100644 ---- a/hw/net/eepro100.c -+++ b/hw/net/eepro100.c -@@ -1872,7 +1872,8 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp) - - s->vmstate = g_memdup(&vmstate_eepro100, sizeof(vmstate_eepro100)); - s->vmstate->name = qemu_get_queue(s->nic)->model; -- vmstate_register(&pci_dev->qdev, -1, s->vmstate, s); -+ vmstate_register(&pci_dev->qdev, VMSTATE_INSTANCE_ID_ANY, -+ s->vmstate, s); - } - - static void eepro100_instance_init(Object *obj) -diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index 8076a80..e74143c 100644 ---- a/hw/pci/pci.c -+++ b/hw/pci/pci.c -@@ -118,7 +118,7 @@ static void pci_bus_realize(BusState *qbus, Error **errp) - bus->machine_done.notify = pcibus_machine_done; - qemu_add_machine_init_done_notifier(&bus->machine_done); - -- vmstate_register(NULL, -1, &vmstate_pcibus, bus); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_pcibus, bus); - } - - static void pcie_bus_realize(BusState *qbus, Error **errp) -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 12ed4b0..b0f37c3 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3069,7 +3069,7 @@ static void spapr_machine_init(MachineState *machine) - * interface, this is a legacy from the sPAPREnvironment structure - * which predated MachineState but had a similar function */ - vmstate_register(NULL, 0, &vmstate_spapr, spapr); -- register_savevm_live(NULL, "spapr/htab", -1, 1, -+ register_savevm_live(NULL, "spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, - &savevm_htab_handlers, spapr); - - qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine), -diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c -index f0a7534..1ce4e01 100644 ---- a/hw/timer/arm_timer.c -+++ b/hw/timer/arm_timer.c -@@ -172,7 +172,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) - - bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); -- vmstate_register(NULL, -1, &vmstate_arm_timer, s); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s); - return s; - } - -diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c -index 38bf5fd..836c489 100644 ---- a/hw/tpm/tpm_emulator.c -+++ b/hw/tpm/tpm_emulator.c -@@ -914,7 +914,8 @@ static void tpm_emulator_inst_init(Object *obj) - tpm_emu->cur_locty_number = ~0; - qemu_mutex_init(&tpm_emu->mutex); - -- vmstate_register(NULL, -1, &vmstate_tpm_emulator, obj); -+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, -+ &vmstate_tpm_emulator, obj); - } - - /* -diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h -index c2bfa7a..92f531a 100644 ---- a/include/migration/vmstate.h -+++ b/include/migration/vmstate.h -@@ -1114,6 +1114,8 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, - - bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque); - -+#define VMSTATE_INSTANCE_ID_ANY -1 -+ - /* Returns: 0 on success, -1 on failure */ - int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, - const VMStateDescription *vmsd, -diff --git a/migration/savevm.c b/migration/savevm.c -index 480c511..62552ab 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -722,7 +722,7 @@ int register_savevm_live(DeviceState *dev, - } - pstrcat(se->idstr, sizeof(se->idstr), idstr); - -- if (instance_id == -1) { -+ if (instance_id == VMSTATE_INSTANCE_ID_ANY) { - se->instance_id = calculate_new_instance_id(se->idstr); - } else { - se->instance_id = instance_id; -@@ -789,14 +789,14 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, - - se->compat = g_new0(CompatEntry, 1); - pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name); -- se->compat->instance_id = instance_id == -1 ? -+ se->compat->instance_id = instance_id == VMSTATE_INSTANCE_ID_ANY ? - calculate_compat_instance_id(vmsd->name) : instance_id; -- instance_id = -1; -+ instance_id = VMSTATE_INSTANCE_ID_ANY; - } - } - pstrcat(se->idstr, sizeof(se->idstr), vmsd->name); - -- if (instance_id == -1) { -+ if (instance_id == VMSTATE_INSTANCE_ID_ANY) { - se->instance_id = calculate_new_instance_id(se->idstr); - } else { - se->instance_id = instance_id; --- -1.8.3.1 - diff --git a/migration-Don-t-send-data-if-we-have-stopped.patch b/migration-Don-t-send-data-if-we-have-stopped.patch deleted file mode 100644 index 08d5d3bbbdd0b8a6f7d3dbc485cc3814a830e483..0000000000000000000000000000000000000000 --- a/migration-Don-t-send-data-if-we-have-stopped.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 855404b4766ddda851035587aa1b84768abbaf11 Mon Sep 17 00:00:00 2001 -From: Juan Quintela -Date: Wed, 22 Jan 2020 11:36:12 +0100 -Subject: [PATCH] migration: Don't send data if we have stopped - -If we do a cancel, we got out without one error, but we can't do the -rest of the output as in a normal situation. - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert ---- - migration/ram.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index b74929542d..dc9831d7f3 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -3686,7 +3686,8 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) - ram_control_after_iterate(f, RAM_CONTROL_ROUND); - - out: -- if (ret >= 0) { -+ if (ret >= 0 -+ && migration_is_setup_or_active(migrate_get_current()->state)) { - multifd_send_sync_main(rs); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); --- -2.27.0 - diff --git a/migration-Make-global-sem_sync-semaphore-by-channel.patch b/migration-Make-global-sem_sync-semaphore-by-channel.patch deleted file mode 100644 index d9dbab23e4f83d88595956668c61385618864fd7..0000000000000000000000000000000000000000 --- a/migration-Make-global-sem_sync-semaphore-by-channel.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 8c3794d709eefdae777477bef7ff3511d55bf418 Mon Sep 17 00:00:00 2001 -From: Juan Quintela -Date: Wed, 14 Aug 2019 04:02:14 +0200 -Subject: [PATCH 05/10] migration: Make global sem_sync semaphore by channel - -This makes easy to debug things because when you want for all threads -to arrive at that semaphore, you know which one your are waiting for. - -Change-Id: I533af8cdc68f619b68eff8e4e573c4de371a3954 -Signed-off-by: Juan Quintela -Message-Id: <20190814020218.1868-3-quintela@redhat.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index c75716bb..51811c2d 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -661,6 +661,8 @@ typedef struct { - uint64_t num_packets; - /* pages sent through this channel */ - uint64_t num_pages; -+ /* syncs main thread and channels */ -+ QemuSemaphore sem_sync; - } MultiFDSendParams; - - typedef struct { -@@ -896,8 +898,6 @@ struct { - MultiFDSendParams *params; - /* array of pages to sent */ - MultiFDPages_t *pages; -- /* syncs main thread and channels */ -- QemuSemaphore sem_sync; - /* global number of generated multifd packets */ - uint64_t packet_num; - /* send channels ready */ -@@ -1037,6 +1037,7 @@ void multifd_save_cleanup(void) - p->c = NULL; - qemu_mutex_destroy(&p->mutex); - qemu_sem_destroy(&p->sem); -+ qemu_sem_destroy(&p->sem_sync); - g_free(p->name); - p->name = NULL; - multifd_pages_clear(p->pages); -@@ -1046,7 +1047,6 @@ void multifd_save_cleanup(void) - p->packet = NULL; - } - qemu_sem_destroy(&multifd_send_state->channels_ready); -- qemu_sem_destroy(&multifd_send_state->sem_sync); - g_free(multifd_send_state->params); - multifd_send_state->params = NULL; - multifd_pages_clear(multifd_send_state->pages); -@@ -1096,7 +1096,7 @@ static void multifd_send_sync_main(RAMState *rs) - MultiFDSendParams *p = &multifd_send_state->params[i]; - - trace_multifd_send_sync_main_wait(p->id); -- qemu_sem_wait(&multifd_send_state->sem_sync); -+ qemu_sem_wait(&p->sem_sync); - } - trace_multifd_send_sync_main(multifd_send_state->packet_num); - } -@@ -1156,7 +1156,7 @@ static void *multifd_send_thread(void *opaque) - qemu_mutex_unlock(&p->mutex); - - if (flags & MULTIFD_FLAG_SYNC) { -- qemu_sem_post(&multifd_send_state->sem_sync); -+ qemu_sem_post(&p->sem_sync); - } - qemu_sem_post(&multifd_send_state->channels_ready); - } else if (p->quit) { -@@ -1179,7 +1179,7 @@ out: - */ - if (ret != 0) { - if (flags & MULTIFD_FLAG_SYNC) { -- qemu_sem_post(&multifd_send_state->sem_sync); -+ qemu_sem_post(&p->sem_sync); - } - qemu_sem_post(&multifd_send_state->channels_ready); - } -@@ -1225,7 +1225,6 @@ int multifd_save_setup(void) - multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); - multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); - multifd_send_state->pages = multifd_pages_init(page_count); -- qemu_sem_init(&multifd_send_state->sem_sync, 0); - qemu_sem_init(&multifd_send_state->channels_ready, 0); - - for (i = 0; i < thread_count; i++) { -@@ -1233,6 +1232,7 @@ int multifd_save_setup(void) - - qemu_mutex_init(&p->mutex); - qemu_sem_init(&p->sem, 0); -+ qemu_sem_init(&p->sem_sync, 0); - p->quit = false; - p->pending_job = 0; - p->id = i; --- -2.19.1 diff --git a/migration-Make-sure-that-we-don-t-call-write-in-case.patch b/migration-Make-sure-that-we-don-t-call-write-in-case.patch deleted file mode 100644 index 73e3fe41d0ee74e22d7e5434ca89b421bbce0708..0000000000000000000000000000000000000000 --- a/migration-Make-sure-that-we-don-t-call-write-in-case.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 2898f8669445d38d4a6a8986c1e6d94381a7e869 Mon Sep 17 00:00:00 2001 -From: Juan Quintela -Date: Tue, 3 Mar 2020 14:51:35 +0000 -Subject: [PATCH] migration: Make sure that we don't call write() in case of - error - -RH-Author: Juan Quintela -Message-id: <20200303145143.149290-3-quintela@redhat.com> -Patchwork-id: 94113 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH v2 02/10] migration: Make sure that we don't call write() in case of error -Bugzilla: 1738451 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Peter Xu -RH-Acked-by: Dr. David Alan Gilbert - -If we are exiting due to an error/finish/.... Just don't try to even -touch the channel with one IO operation. - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Juan Quintela -(cherry picked from commit 4d65a6216bfc44891ac298b74a6921d479805131) -Signed-off-by: Danilo C. L. de Paula ---- - migration/ram.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index d4ac696899..27585a4f3e 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1195,6 +1195,12 @@ struct { - uint64_t packet_num; - /* send channels ready */ - QemuSemaphore channels_ready; -+ /* -+ * Have we already run terminate threads. There is a race when it -+ * happens that we got one error while we are exiting. -+ * We will use atomic operations. Only valid values are 0 and 1. -+ */ -+ int exiting; - } *multifd_send_state; - - /* -@@ -1223,6 +1229,10 @@ static int multifd_send_pages(RAMState *rs) - MultiFDPages_t *pages = multifd_send_state->pages; - uint64_t transferred; - -+ if (atomic_read(&multifd_send_state->exiting)) { -+ return -1; -+ } -+ - qemu_sem_wait(&multifd_send_state->channels_ready); - /* - * next_channel can remain from a previous migration that was -@@ -1308,6 +1318,16 @@ static void multifd_send_terminate_threads(Error *err) - } - } - -+ /* -+ * We don't want to exit each threads twice. Depending on where -+ * we get the error, or if there are two independent errors in two -+ * threads at the same time, we can end calling this function -+ * twice. -+ */ -+ if (atomic_xchg(&multifd_send_state->exiting, 1)) { -+ return; -+ } -+ - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - -@@ -1425,6 +1445,10 @@ static void *multifd_send_thread(void *opaque) - - while (true) { - qemu_sem_wait(&p->sem); -+ -+ if (atomic_read(&multifd_send_state->exiting)) { -+ break; -+ } - qemu_mutex_lock(&p->mutex); - - if (p->pending_job) { -@@ -1655,6 +1679,7 @@ int multifd_save_setup(void) - multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); - multifd_send_state->pages = multifd_pages_init(page_count); - qemu_sem_init(&multifd_send_state->channels_ready, 0); -+ atomic_set(&multifd_send_state->exiting, 0); - - for (i = 0; i < thread_count; i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; --- -2.27.0 - diff --git a/migration-Maybe-VM-is-paused-when-migration-is-cance.patch b/migration-Maybe-VM-is-paused-when-migration-is-cance.patch deleted file mode 100644 index 6c918f3c17ca619dfb88e1856d3d26625419f465..0000000000000000000000000000000000000000 --- a/migration-Maybe-VM-is-paused-when-migration-is-cance.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 5e99e1329fa52dce8ab784a960e64a3e19b429aa Mon Sep 17 00:00:00 2001 -From: Zhimin Feng -Date: Tue, 14 Jan 2020 17:43:09 +0800 -Subject: [PATCH 07/10] migration: Maybe VM is paused when migration is - cancelled - -If the migration is cancelled when it is in the completion phase, -the migration state is set to MIGRATION_STATUS_CANCELLING. -The VM maybe wait for the 'pause_sem' semaphore in migration_maybe_pause -function, so that VM always is paused. - -Change-Id: Ib2f2f42ee1edbb14da269ee19ba1fe16dd363822 -Reported-by: Euler Robot -Signed-off-by: Zhimin Feng -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/migration.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index bea9b1d7..114c33a1 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -2731,14 +2731,22 @@ static int migration_maybe_pause(MigrationState *s, - /* This block intentionally left blank */ - } - -- qemu_mutex_unlock_iothread(); -- migrate_set_state(&s->state, *current_active_state, -- MIGRATION_STATUS_PRE_SWITCHOVER); -- qemu_sem_wait(&s->pause_sem); -- migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, -- new_state); -- *current_active_state = new_state; -- qemu_mutex_lock_iothread(); -+ /* -+ * If the migration is cancelled when it is in the completion phase, -+ * the migration state is set to MIGRATION_STATUS_CANCELLING. -+ * So we don't need to wait a semaphore, otherwise we would always -+ * wait for the 'pause_sem' semaphore. -+ */ -+ if (s->state != MIGRATION_STATUS_CANCELLING) { -+ qemu_mutex_unlock_iothread(); -+ migrate_set_state(&s->state, *current_active_state, -+ MIGRATION_STATUS_PRE_SWITCHOVER); -+ qemu_sem_wait(&s->pause_sem); -+ migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, -+ new_state); -+ *current_active_state = new_state; -+ qemu_mutex_lock_iothread(); -+ } - - return s->state == new_state ? 0 : -EINVAL; - } --- -2.19.1 diff --git a/migration-Rate-limit-inside-host-pages.patch b/migration-Rate-limit-inside-host-pages.patch deleted file mode 100644 index 17eb46f82ce18a6e2e17583ea6a77879178bc9bc..0000000000000000000000000000000000000000 --- a/migration-Rate-limit-inside-host-pages.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 3e8a587b055f0e3cabf91921fca0777fe7e349f5 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Tue, 17 Mar 2020 17:05:18 +0000 -Subject: [PATCH] migration: Rate limit inside host pages - -RH-Author: Laurent Vivier -Message-id: <20200317170518.9303-1-lvivier@redhat.com> -Patchwork-id: 94374 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH] migration: Rate limit inside host pages -Bugzilla: 1814336 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert - -From: "Dr. David Alan Gilbert" - -When using hugepages, rate limiting is necessary within each huge -page, since a 1G huge page can take a significant time to send, so -you end up with bursty behaviour. - -Fixes: 4c011c37ecb3 ("postcopy: Send whole huge pages") -Reported-by: Lin Ma -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Juan Quintela -Reviewed-by: Peter Xu -Signed-off-by: Juan Quintela -(cherry picked from commit 97e1e06780e70f6e98a0d2df881e0c0927d3aeb6) -Signed-off-by: Laurent Vivier - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1814336 -BRANCH: rhel-av-8.2.0 -UPSTREAM: Merged -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=27283241 -TESTED: Tested that the migration abort doesn't trigger an error message in - the kernel logs on P9 - -Signed-off-by: Danilo C. L. de Paula ---- - migration/migration.c | 57 ++++++++++++++++++++++++------------------ - migration/migration.h | 1 + - migration/ram.c | 2 ++ - migration/trace-events | 4 +-- - 4 files changed, 37 insertions(+), 27 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index fd7d81d4b6..b0b9430822 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -3260,6 +3260,37 @@ void migration_consume_urgent_request(void) - qemu_sem_wait(&migrate_get_current()->rate_limit_sem); - } - -+/* Returns true if the rate limiting was broken by an urgent request */ -+bool migration_rate_limit(void) -+{ -+ int64_t now = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -+ MigrationState *s = migrate_get_current(); -+ -+ bool urgent = false; -+ migration_update_counters(s, now); -+ if (qemu_file_rate_limit(s->to_dst_file)) { -+ /* -+ * Wait for a delay to do rate limiting OR -+ * something urgent to post the semaphore. -+ */ -+ int ms = s->iteration_start_time + BUFFER_DELAY - now; -+ trace_migration_rate_limit_pre(ms); -+ if (qemu_sem_timedwait(&s->rate_limit_sem, ms) == 0) { -+ /* -+ * We were woken by one or more urgent things but -+ * the timedwait will have consumed one of them. -+ * The service routine for the urgent wake will dec -+ * the semaphore itself for each item it consumes, -+ * so add this one we just eat back. -+ */ -+ qemu_sem_post(&s->rate_limit_sem); -+ urgent = true; -+ } -+ trace_migration_rate_limit_post(urgent); -+ } -+ return urgent; -+} -+ - /* - * Master migration thread on the source VM. - * It drives the migration and pumps the data down the outgoing channel. -@@ -3313,8 +3344,6 @@ static void *migration_thread(void *opaque) - trace_migration_thread_setup_complete(); - - while (migration_is_active(s)) { -- int64_t current_time; -- - if (urgent || !qemu_file_rate_limit(s->to_dst_file)) { - MigIterateState iter_state = migration_iteration_run(s); - if (iter_state == MIG_ITERATE_SKIP) { -@@ -3341,29 +3370,7 @@ static void *migration_thread(void *opaque) - update_iteration_initial_status(s); - } - -- current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -- -- migration_update_counters(s, current_time); -- -- urgent = false; -- if (qemu_file_rate_limit(s->to_dst_file)) { -- /* Wait for a delay to do rate limiting OR -- * something urgent to post the semaphore. -- */ -- int ms = s->iteration_start_time + BUFFER_DELAY - current_time; -- trace_migration_thread_ratelimit_pre(ms); -- if (qemu_sem_timedwait(&s->rate_limit_sem, ms) == 0) { -- /* We were worken by one or more urgent things but -- * the timedwait will have consumed one of them. -- * The service routine for the urgent wake will dec -- * the semaphore itself for each item it consumes, -- * so add this one we just eat back. -- */ -- qemu_sem_post(&s->rate_limit_sem); -- urgent = true; -- } -- trace_migration_thread_ratelimit_post(urgent); -- } -+ urgent = migration_rate_limit(); - } - - trace_migration_thread_after_loop(); -diff --git a/migration/migration.h b/migration/migration.h -index 4aa72297fc..ff8a0bf12d 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -345,6 +345,7 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); - - void migration_make_urgent_request(void); - void migration_consume_urgent_request(void); -+bool migration_rate_limit(void); - - int migration_send_initial_packet(QIOChannel *c, uint8_t id, Error **errp); - int migration_recv_initial_packet(QIOChannel *c, Error **errp); -diff --git a/migration/ram.c b/migration/ram.c -index 27585a4f3e..d6657a8093 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -3076,6 +3076,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - } - - pss->page++; -+ /* Allow rate limiting to happen in the middle of huge pages */ -+ migration_rate_limit(); - } while ((pss->page & (pagesize_bits - 1)) && - offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); - -diff --git a/migration/trace-events b/migration/trace-events -index c0640cd424..b4d85229d9 100644 ---- a/migration/trace-events -+++ b/migration/trace-events -@@ -131,12 +131,12 @@ migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi6 - migration_completion_file_err(void) "" - migration_completion_postcopy_end(void) "" - migration_completion_postcopy_end_after_complete(void) "" -+migration_rate_limit_pre(int ms) "%d ms" -+migration_rate_limit_post(int urgent) "urgent: %d" - migration_return_path_end_before(void) "" - migration_return_path_end_after(int rp_error) "%d" - migration_thread_after_loop(void) "" - migration_thread_file_err(void) "" --migration_thread_ratelimit_pre(int ms) "%d ms" --migration_thread_ratelimit_post(int urgent) "urgent: %d" - migration_thread_setup_complete(void) "" - open_return_path_on_source(void) "" - open_return_path_on_source_continue(void) "" --- -2.27.0 - diff --git a/migration-Refactoring-multi-thread-compress-migratio.patch b/migration-Refactoring-multi-thread-compress-migratio.patch index d3ab4d0d97a8a1cf1c945a38b97b47a33277ab9b..35f697bd5b2bbe079e4fd3886365064c5b710be4 100644 --- a/migration-Refactoring-multi-thread-compress-migratio.patch +++ b/migration-Refactoring-multi-thread-compress-migratio.patch @@ -1,7 +1,7 @@ -From 524d8cee48006918cf181f2817e4ec3ce5a3bb12 Mon Sep 17 00:00:00 2001 -From: Zeyu Jin +From b871594aa1798ddcc7f5124e5b3e1c5d858c155c Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Sat, 30 Jan 2021 15:21:17 +0800 -Subject: [PATCH] migration: Refactoring multi-thread compress migration +Subject: [PATCH 10/14] migration: Refactoring multi-thread compress migration Code refactor for the compression procedure which includes: @@ -13,19 +13,20 @@ with qemu-file. Besides, the decompression code is located at ram.c only. Wrap the input into the param structure which already exists. This change also makes the function much more flexible for other compression methods. +Signed-off-by: Chuan Zheng Signed-off-by: Zeyu Jin Signed-off-by: Ying Fang --- - migration/qemu-file.c | 78 ++++++--------------------------------- + migration/qemu-file.c | 61 ++++++------------------------- migration/qemu-file.h | 4 +- migration/ram.c | 85 +++++++++++++++++++++++++++++++------------ - 3 files changed, 75 insertions(+), 92 deletions(-) + 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c -index be0d6c8ca8..3bba694ed4 100644 +index 6338d8e2ff..e07026da4f 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c -@@ -695,72 +695,6 @@ uint64_t qemu_get_be64(QEMUFile *f) +@@ -745,55 +745,6 @@ uint64_t qemu_get_be64(QEMUFile *f) return v; } @@ -56,11 +57,8 @@ index be0d6c8ca8..3bba694ed4 100644 -/* Compress size bytes of data start at p and store the compressed - * data to the buffer of f. - * -- * When f is not writable, return -1 if f has no space to save the -- * compressed data. -- * When f is wirtable and it has no space to save the compressed data, -- * do fflush first, if f still has no space to save the compressed -- * data, return -1. +- * Since the file is dummy file with empty_ops, return -1 if f has no space to +- * save the compressed data. - */ -ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream, - const uint8_t *p, size_t size) @@ -68,14 +66,7 @@ index be0d6c8ca8..3bba694ed4 100644 - ssize_t blen = IO_BUF_SIZE - f->buf_index - sizeof(int32_t); - - if (blen < compressBound(size)) { -- if (!qemu_file_is_writable(f)) { -- return -1; -- } -- qemu_fflush(f); -- blen = IO_BUF_SIZE - sizeof(int32_t); -- if (blen < compressBound(size)) { -- return -1; -- } +- return -1; - } - - blen = qemu_compress_data(stream, f->buf + f->buf_index + sizeof(int32_t), @@ -85,22 +76,15 @@ index be0d6c8ca8..3bba694ed4 100644 - } - - qemu_put_be32(f, blen); -- if (f->ops->writev_buffer) { -- add_to_iovec(f, f->buf + f->buf_index, blen, false); -- } -- f->buf_index += blen; -- if (f->buf_index == IO_BUF_SIZE) { -- qemu_fflush(f); -- } +- add_buf_to_iovec(f, blen); - return blen + sizeof(int32_t); -} -- + /* Put the data in the buffer of f_src to the buffer of f_des, and * then reset the buf_index of f_src to 0. - */ -@@ -820,3 +754,15 @@ void qemu_file_set_blocking(QEMUFile *f, bool block) - f->ops->set_blocking(f->opaque, block); - } +@@ -866,3 +817,15 @@ QIOChannel *qemu_file_get_ioc(QEMUFile *file) + { + return file->has_ioc ? QIO_CHANNEL(file->opaque) : NULL; } + +ssize_t qemu_put_compress_start(QEMUFile *f, uint8_t **dest_ptr) @@ -115,10 +99,10 @@ index be0d6c8ca8..3bba694ed4 100644 + add_buf_to_iovec(f, v); +} diff --git a/migration/qemu-file.h b/migration/qemu-file.h -index 5de9fa2e96..6570e53e13 100644 +index 3f36d4dc8c..617a1373ad 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h -@@ -134,8 +134,6 @@ bool qemu_file_is_writable(QEMUFile *f); +@@ -139,8 +139,6 @@ bool qemu_file_is_writable(QEMUFile *f); size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset); size_t qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size); @@ -127,7 +111,7 @@ index 5de9fa2e96..6570e53e13 100644 int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src); /* -@@ -162,6 +160,8 @@ void ram_control_before_iterate(QEMUFile *f, uint64_t flags); +@@ -167,6 +165,8 @@ void ram_control_before_iterate(QEMUFile *f, uint64_t flags); void ram_control_after_iterate(QEMUFile *f, uint64_t flags); void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); @@ -137,7 +121,7 @@ index 5de9fa2e96..6570e53e13 100644 * will be passed to ram_control_load_hook in the incoming-migration * side. This lets before_ram_iterate/after_ram_iterate add diff --git a/migration/ram.c b/migration/ram.c -index 92ce1a53e7..f78a681ca2 100644 +index 863035d235..1176816fba 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -449,26 +449,22 @@ static QemuThread *decompress_threads; @@ -169,7 +153,7 @@ index 92ce1a53e7..f78a681ca2 100644 qemu_mutex_lock(&comp_done_lock); param->done = true; -@@ -2212,28 +2208,73 @@ static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, +@@ -1342,28 +1338,73 @@ static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, return 1; } @@ -249,7 +233,7 @@ index 92ce1a53e7..f78a681ca2 100644 if (ret < 0) { qemu_file_set_error(migrate_get_current()->to_dst_file, ret); error_report("compressed data failed!"); -@@ -3926,19 +3967,20 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) +@@ -3374,19 +3415,20 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) /* return the size after decompression, or negative value on error */ static int @@ -275,7 +259,7 @@ index 92ce1a53e7..f78a681ca2 100644 stream->next_out = dest; err = inflate(stream, Z_NO_FLUSH); -@@ -3952,22 +3994,17 @@ qemu_uncompress_data(z_stream *stream, uint8_t *dest, size_t dest_len, +@@ -3400,22 +3442,17 @@ qemu_uncompress_data(z_stream *stream, uint8_t *dest, size_t dest_len, static void *do_data_decompress(void *opaque) { DecompressParam *param = opaque; diff --git a/migration-Set-downtime_start-even-for-postcopy.patch b/migration-Set-downtime_start-even-for-postcopy.patch new file mode 100644 index 0000000000000000000000000000000000000000..8aa72cb45c29beb8604b2910a892100f5fd04ae4 --- /dev/null +++ b/migration-Set-downtime_start-even-for-postcopy.patch @@ -0,0 +1,57 @@ +From 9708192479d7f6507392a338f8f43b3be4c8188d Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 18 Dec 2023 15:19:48 +0800 +Subject: [PATCH] migration: Set downtime_start even for postcopy + +cheery-pick from 62f5da7dd10a594fb30cebb5569dc738456f7131 + +Postcopy calculates its downtime separately. It always sets +MigrationState.downtime properly, but not MigrationState.downtime_start. + +Make postcopy do the same as other modes on properly recording the +timestamp when the VM is going to be stopped. Drop the temporary variable +in postcopy_start() along the way. + +Signed-off-by: Peter Xu +Reviewed-by: Fabiano Rosas +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Message-ID: <20231030163346.765724-2-peterx@redhat.com> +Signed-off-by: qihao_yewu +--- + migration/migration.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 6b5445853a..7ca5b58839 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2989,7 +2989,6 @@ static int postcopy_start(MigrationState *ms) + int ret; + QIOChannelBuffer *bioc; + QEMUFile *fb; +- int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + int64_t bandwidth = migrate_max_postcopy_bandwidth(); + bool restart_block = false; + int cur_state = MIGRATION_STATUS_ACTIVE; +@@ -3002,6 +3001,8 @@ static int postcopy_start(MigrationState *ms) + qemu_mutex_lock_iothread(); + trace_postcopy_start_set_run(); + ++ ms->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ++ + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); + global_state_store(); + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); +@@ -3112,7 +3113,7 @@ static int postcopy_start(MigrationState *ms) + ms->postcopy_after_devices = true; + notifier_list_notify(&migration_state_notifiers, ms); + +- ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - time_at_stop; ++ ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - ms->downtime_start; + + qemu_mutex_unlock_iothread(); + +-- +2.27.0 + diff --git a/migration-add-qemu_file_update_transfer-interface.patch b/migration-add-qemu_file_update_transfer-interface.patch deleted file mode 100644 index 4222fd0adb202051cd57a3f0cab01e5ad52f8248..0000000000000000000000000000000000000000 --- a/migration-add-qemu_file_update_transfer-interface.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 7572495245a437da717e6829a9ce852cc3f229c9 Mon Sep 17 00:00:00 2001 -From: Zheng Chuan -Date: Mon, 20 Apr 2020 15:13:47 +0800 -Subject: [PATCH 02/10] migration: add qemu_file_update_transfer interface - -Add qemu_file_update_transfer for just update bytes_xfer for speed -limitation. This will be used for further migration feature such as -multifd migration. - -Change-Id: I969aa15305c961254b6fb9805b0ed2d65826cc5d -Signed-off-by: Ivan Ren -Reviewed-by: Wei Yang -Reviewed-by: Juan Quintela -Message-Id: <1564464816-21804-2-git-send-email-ivanren@tencent.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/qemu-file.c | 5 +++++ - migration/qemu-file.h | 1 + - 2 files changed, 6 insertions(+) - -diff --git a/migration/qemu-file.c b/migration/qemu-file.c -index 04315855..18f48052 100644 ---- a/migration/qemu-file.c -+++ b/migration/qemu-file.c -@@ -615,6 +615,11 @@ void qemu_file_reset_rate_limit(QEMUFile *f) - f->bytes_xfer = 0; - } - -+void qemu_file_update_transfer(QEMUFile *f, int64_t len) -+{ -+ f->bytes_xfer += len; -+} -+ - void qemu_put_be16(QEMUFile *f, unsigned int v) - { - qemu_put_byte(f, v >> 8); -diff --git a/migration/qemu-file.h b/migration/qemu-file.h -index 13baf896..5de9fa2e 100644 ---- a/migration/qemu-file.h -+++ b/migration/qemu-file.h -@@ -147,6 +147,7 @@ int qemu_peek_byte(QEMUFile *f, int offset); - void qemu_file_skip(QEMUFile *f, int size); - void qemu_update_position(QEMUFile *f, size_t size); - void qemu_file_reset_rate_limit(QEMUFile *f); -+void qemu_file_update_transfer(QEMUFile *f, int64_t len); - void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); - int64_t qemu_file_get_rate_limit(QEMUFile *f); - void qemu_file_set_error(QEMUFile *f, int ret); --- -2.19.1 diff --git a/migration-add-speed-limit-for-multifd-migration.patch b/migration-add-speed-limit-for-multifd-migration.patch deleted file mode 100644 index 690d9c9cf095cafdb2ff18025d70ee57a2527de2..0000000000000000000000000000000000000000 --- a/migration-add-speed-limit-for-multifd-migration.patch +++ /dev/null @@ -1,127 +0,0 @@ -From bc5780480db9e38699df0b4697e60a9f36258dc4 Mon Sep 17 00:00:00 2001 -From: Ivan Ren -Date: Tue, 30 Jul 2019 13:33:35 +0800 -Subject: [PATCH 03/10] migration: add speed limit for multifd migration - -Limit the speed of multifd migration through common speed limitation -qemu file. - -Change-Id: Id2abfc7ea85679bd53130a43043cc70179a52e87 -Signed-off-by: Ivan Ren -Message-Id: <1564464816-21804-3-git-send-email-ivanren@tencent.com> -Reviewed-by: Wei Yang -Reviewed-by: Juan Quintela -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 22 ++++++++++++---------- - 1 file changed, 12 insertions(+), 10 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 889148dd..88ddd2bb 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -922,7 +922,7 @@ struct { - * false. - */ - --static int multifd_send_pages(void) -+static int multifd_send_pages(RAMState *rs) - { - int i; - static int next_channel; -@@ -954,6 +954,7 @@ static int multifd_send_pages(void) - multifd_send_state->pages = p->pages; - p->pages = pages; - transferred = ((uint64_t) pages->used) * TARGET_PAGE_SIZE + p->packet_len; -+ qemu_file_update_transfer(rs->f, transferred); - ram_counters.multifd_bytes += transferred; - ram_counters.transferred += transferred;; - qemu_mutex_unlock(&p->mutex); -@@ -962,7 +963,7 @@ static int multifd_send_pages(void) - return 1; - } - --static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) -+static int multifd_queue_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) - { - MultiFDPages_t *pages = multifd_send_state->pages; - -@@ -981,12 +982,12 @@ static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) - } - } - -- if (multifd_send_pages() < 0) { -+ if (multifd_send_pages(rs) < 0) { - return -1; - } - - if (pages->block != block) { -- return multifd_queue_page(block, offset); -+ return multifd_queue_page(rs, block, offset); - } - - return 1; -@@ -1054,7 +1055,7 @@ void multifd_save_cleanup(void) - multifd_send_state = NULL; - } - --static void multifd_send_sync_main(void) -+static void multifd_send_sync_main(RAMState *rs) - { - int i; - -@@ -1062,7 +1063,7 @@ static void multifd_send_sync_main(void) - return; - } - if (multifd_send_state->pages->used) { -- if (multifd_send_pages() < 0) { -+ if (multifd_send_pages(rs) < 0) { - error_report("%s: multifd_send_pages fail", __func__); - return; - } -@@ -1083,6 +1084,7 @@ static void multifd_send_sync_main(void) - p->packet_num = multifd_send_state->packet_num++; - p->flags |= MULTIFD_FLAG_SYNC; - p->pending_job++; -+ qemu_file_update_transfer(rs->f, p->packet_len); - qemu_mutex_unlock(&p->mutex); - qemu_sem_post(&p->sem); - } -@@ -2079,7 +2081,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) - static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, - ram_addr_t offset) - { -- if (multifd_queue_page(block, offset) < 0) { -+ if (multifd_queue_page(rs, block, offset) < 0) { - return -1; - } - ram_counters.normal++; -@@ -3482,7 +3484,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) - ram_control_before_iterate(f, RAM_CONTROL_SETUP); - ram_control_after_iterate(f, RAM_CONTROL_SETUP); - -- multifd_send_sync_main(); -+ multifd_send_sync_main(*rsp); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); - -@@ -3570,7 +3572,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) - ram_control_after_iterate(f, RAM_CONTROL_ROUND); - - out: -- multifd_send_sync_main(); -+ multifd_send_sync_main(rs); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); - ram_counters.transferred += 8; -@@ -3629,7 +3631,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - - rcu_read_unlock(); - -- multifd_send_sync_main(); -+ multifd_send_sync_main(rs); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); - --- -2.19.1 diff --git a/migration-always-initialise-ram_counters-for-a-new-m.patch b/migration-always-initialise-ram_counters-for-a-new-m.patch deleted file mode 100644 index ccd0db9ab87204ca41e17c1120618748eb4383fe..0000000000000000000000000000000000000000 --- a/migration-always-initialise-ram_counters-for-a-new-m.patch +++ /dev/null @@ -1,125 +0,0 @@ -From af2aa4f553565ae6b2248204c154748f38ec4746 Mon Sep 17 00:00:00 2001 -From: Ivan Ren -Date: Fri, 2 Aug 2019 18:18:41 +0800 -Subject: [PATCH 01/10] migration: always initialise ram_counters for a new - migration - -This patch fix a multifd migration bug in migration speed calculation, this -problem can be reproduced as follows: -1. start a vm and give a heavy memory write stress to prevent the vm be - successfully migrated to destination -2. begin a migration with multifd -3. migrate for a long time [actually, this can be measured by transferred bytes] -4. migrate cancel -5. begin a new migration with multifd, the migration will directly run into - migration_completion phase - -Reason as follows: - -Migration update bandwidth and s->threshold_size in function -migration_update_counters after BUFFER_DELAY time: - - current_bytes = migration_total_bytes(s); - transferred = current_bytes - s->iteration_initial_bytes; - time_spent = current_time - s->iteration_start_time; - bandwidth = (double)transferred / time_spent; - s->threshold_size = bandwidth * s->parameters.downtime_limit; - -In multifd migration, migration_total_bytes function return -qemu_ftell(s->to_dst_file) + ram_counters.multifd_bytes. -s->iteration_initial_bytes will be initialized to 0 at every new migration, -but ram_counters is a global variable, and history migration data will be -accumulated. So if the ram_counters.multifd_bytes is big enough, it may lead -pending_size >= s->threshold_size become false in migration_iteration_run -after the first migration_update_counters. - -Change-Id: Ib153d8676a5b82650bfb1156060e09f0d29f3ac6 -Signed-off-by: Ivan Ren -Reviewed-by: Juan Quintela -Reviewed-by: Wei Yang -Suggested-by: Wei Yang -Message-Id: <1564741121-1840-1-git-send-email-ivanren@tencent.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/migration.c | 25 +++++++++++++++++++------ - migration/savevm.c | 1 + - 2 files changed, 20 insertions(+), 6 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 8a607fe1..bea9b1d7 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1908,6 +1908,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, - } - - migrate_init(s); -+ /* -+ * set ram_counters memory to zero for a -+ * new migration -+ */ -+ memset(&ram_counters, 0, sizeof(ram_counters)); - - return true; - } -@@ -3025,6 +3030,17 @@ static void migration_calculate_complete(MigrationState *s) - } - } - -+static void update_iteration_initial_status(MigrationState *s) -+{ -+ /* -+ * Update these three fields at the same time to avoid mismatch info lead -+ * wrong speed calculation. -+ */ -+ s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -+ s->iteration_initial_bytes = migration_total_bytes(s); -+ s->iteration_initial_pages = ram_get_total_transferred_pages(); -+} -+ - static void migration_update_counters(MigrationState *s, - int64_t current_time) - { -@@ -3060,9 +3076,7 @@ static void migration_update_counters(MigrationState *s, - - qemu_file_reset_rate_limit(s->to_dst_file); - -- s->iteration_start_time = current_time; -- s->iteration_initial_bytes = current_bytes; -- s->iteration_initial_pages = ram_get_total_transferred_pages(); -+ update_iteration_initial_status(s); - - trace_migrate_transferred(transferred, time_spent, - bandwidth, s->threshold_size); -@@ -3186,7 +3200,7 @@ static void *migration_thread(void *opaque) - rcu_register_thread(); - - object_ref(OBJECT(s)); -- s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -+ update_iteration_initial_status(s); - - qemu_savevm_state_header(s->to_dst_file); - -@@ -3251,8 +3265,7 @@ static void *migration_thread(void *opaque) - * the local variables. This is important to avoid - * breaking transferred_bytes and bandwidth calculation - */ -- s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -- s->iteration_initial_bytes = 0; -+ update_iteration_initial_status(s); - } - - current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -diff --git a/migration/savevm.c b/migration/savevm.c -index 79ed44d4..480c511b 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -1424,6 +1424,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) - } - - migrate_init(ms); -+ memset(&ram_counters, 0, sizeof(ram_counters)); - ms->to_dst_file = f; - - qemu_mutex_unlock_iothread(); --- -2.19.1 diff --git a/migration-colo-More-accurate-update-checkpoint-time.patch b/migration-colo-More-accurate-update-checkpoint-time.patch new file mode 100644 index 0000000000000000000000000000000000000000..21a4aad3d6658494bfcfd01464eaf09af55d8837 --- /dev/null +++ b/migration-colo-More-accurate-update-checkpoint-time.patch @@ -0,0 +1,44 @@ +From 3577b5c059bd3f83d47f72ef400e85160d56bc58 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Fri, 1 Dec 2023 11:11:43 +0800 +Subject: [PATCH] migration/colo: More accurate update checkpoint time + +cherry picked from commit 0e0f0479e28c6c1a1d024b2e5200cade479d6901 + +Previous operation(like vm_start and replication_start_all) will consume +extra time before update the timer, so reduce time in this patch. + +Signed-off-by: Zhang Chen +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Luo Yifan +--- + migration/colo.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/migration/colo.c b/migration/colo.c +index 2415325262..c8fadae956 100644 +--- a/migration/colo.c ++++ b/migration/colo.c +@@ -530,7 +530,6 @@ static void colo_process_checkpoint(MigrationState *s) + { + QIOChannelBuffer *bioc; + QEMUFile *fb = NULL; +- int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); + Error *local_err = NULL; + int ret; + +@@ -578,8 +577,8 @@ static void colo_process_checkpoint(MigrationState *s) + qemu_mutex_unlock_iothread(); + trace_colo_vm_state_change("stop", "run"); + +- timer_mod(s->colo_delay_timer, +- current_time + s->parameters.x_checkpoint_delay); ++ timer_mod(s->colo_delay_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) + ++ s->parameters.x_checkpoint_delay); + + while (s->state == MIGRATION_STATUS_COLO) { + if (failover_get_state() != FAILOVER_STATUS_NONE) { +-- +2.27.0 + diff --git a/migration-colo-fix-use-after-free-of-local_err.patch b/migration-colo-fix-use-after-free-of-local_err.patch deleted file mode 100644 index c03ceb5120bc3069ac123cc9c2702653c4d2da17..0000000000000000000000000000000000000000 --- a/migration-colo-fix-use-after-free-of-local_err.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 663e9b5f25d22834260a0686f77a27c957cd7b2f Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 24 Mar 2020 18:36:28 +0300 -Subject: [PATCH 07/14] migration/colo: fix use after free of local_err - -local_err is used again in secondary_vm_do_failover() after -replication_stop_all(), so we must zero it. Otherwise try to set -non-NULL local_err will crash. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200324153630.11882-5-vsementsov@virtuozzo.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Peng Liang ---- - migration/colo.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/migration/colo.c b/migration/colo.c -index 9f84b1fa3c0f..761b3544d472 100644 ---- a/migration/colo.c -+++ b/migration/colo.c -@@ -89,6 +89,7 @@ static void secondary_vm_do_failover(void) - replication_stop_all(true, &local_err); - if (local_err) { - error_report_err(local_err); -+ local_err = NULL; - } - - /* Notify all filters of all NIC to do checkpoint */ --- -2.26.2 - diff --git a/migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch b/migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch deleted file mode 100644 index 8028a29dd7141ce2fc2e139559c1a54661b31109..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 17b0582ebba622afbd8f454bbee8141ed2785f13 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:21:58 +0800 -Subject: [PATCH] migration/dirtyrate: Add RamblockDirtyInfo to store sampled - page info - -Add RamblockDirtyInfo to store sampled page info of each ramblock. - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: David Edmondson -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-4-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.h | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h -index 84ab9409ac..8707df852d 100644 ---- a/migration/dirtyrate.h -+++ b/migration/dirtyrate.h -@@ -19,10 +19,28 @@ - */ - #define DIRTYRATE_DEFAULT_SAMPLE_PAGES 512 - -+/* -+ * Record ramblock idstr -+ */ -+#define RAMBLOCK_INFO_MAX_LEN 256 -+ - struct DirtyRateConfig { - uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ - int64_t sample_period_seconds; /* time duration between two sampling */ - }; - -+/* -+ * Store dirtypage info for each ramblock. -+ */ -+struct RamblockDirtyInfo { -+ char idstr[RAMBLOCK_INFO_MAX_LEN]; /* idstr for each ramblock */ -+ uint8_t *ramblock_addr; /* base address of ramblock we measure */ -+ uint64_t ramblock_pages; /* ramblock size in TARGET_PAGE_SIZE */ -+ uint64_t *sample_page_vfn; /* relative offset address for sampled page */ -+ uint64_t sample_pages_count; /* count of sampled pages */ -+ uint64_t sample_dirty_count; /* count of dirty pages we measure */ -+ uint32_t *hash_result; /* array of hash result for sampled pages */ -+}; -+ - void *get_dirtyrate_thread(void *arg); - #endif --- -2.27.0 - diff --git a/migration-dirtyrate-Add-dirtyrate-statistics-series-.patch b/migration-dirtyrate-Add-dirtyrate-statistics-series-.patch deleted file mode 100644 index 1d56f8029ca9b35243e87984538c93113cd4513a..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Add-dirtyrate-statistics-series-.patch +++ /dev/null @@ -1,93 +0,0 @@ -From d1340703e127c02e9a586143039507ba10d73cfb Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:21:59 +0800 -Subject: [PATCH] migration/dirtyrate: Add dirtyrate statistics series - functions - -Add dirtyrate statistics functions to record/update dirtyrate info. - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-5-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 32 ++++++++++++++++++++++++++++++++ - migration/dirtyrate.h | 12 ++++++++++++ - 2 files changed, 44 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 44a60bf10d..cbb323d6ec 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -23,6 +23,7 @@ - #include "dirtyrate.h" - - static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; -+static struct DirtyRateStat DirtyStat; - - static int dirtyrate_set_state(int *state, int old_state, int new_state) - { -@@ -34,6 +35,37 @@ static int dirtyrate_set_state(int *state, int old_state, int new_state) - } - } - -+static void reset_dirtyrate_stat(void) -+{ -+ DirtyStat.total_dirty_samples = 0; -+ DirtyStat.total_sample_count = 0; -+ DirtyStat.total_block_mem_MB = 0; -+ DirtyStat.dirty_rate = -1; -+ DirtyStat.start_time = 0; -+ DirtyStat.calc_time = 0; -+} -+ -+static void update_dirtyrate_stat(struct RamblockDirtyInfo *info) -+{ -+ DirtyStat.total_dirty_samples += info->sample_dirty_count; -+ DirtyStat.total_sample_count += info->sample_pages_count; -+ /* size of total pages in MB */ -+ DirtyStat.total_block_mem_MB += (info->ramblock_pages * -+ TARGET_PAGE_SIZE) >> 20; -+} -+ -+static void update_dirtyrate(uint64_t msec) -+{ -+ uint64_t dirtyrate; -+ uint64_t total_dirty_samples = DirtyStat.total_dirty_samples; -+ uint64_t total_sample_count = DirtyStat.total_sample_count; -+ uint64_t total_block_mem_MB = DirtyStat.total_block_mem_MB; -+ -+ dirtyrate = total_dirty_samples * total_block_mem_MB * -+ 1000 / (total_sample_count * msec); -+ -+ DirtyStat.dirty_rate = dirtyrate; -+} - - static void calculate_dirtyrate(struct DirtyRateConfig config) - { -diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h -index 8707df852d..312debca6f 100644 ---- a/migration/dirtyrate.h -+++ b/migration/dirtyrate.h -@@ -42,5 +42,17 @@ struct RamblockDirtyInfo { - uint32_t *hash_result; /* array of hash result for sampled pages */ - }; - -+/* -+ * Store calculation statistics for each measure. -+ */ -+struct DirtyRateStat { -+ uint64_t total_dirty_samples; /* total dirty sampled page */ -+ uint64_t total_sample_count; /* total sampled pages */ -+ uint64_t total_block_mem_MB; /* size of total sampled pages in MB */ -+ int64_t dirty_rate; /* dirty rate in MB/s */ -+ int64_t start_time; /* calculation start time in units of second */ -+ int64_t calc_time; /* time duration of two sampling in units of second */ -+}; -+ - void *get_dirtyrate_thread(void *arg); - #endif --- -2.27.0 - diff --git a/migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch b/migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch deleted file mode 100644 index 79d825c8a34d1229876b03e1ca64e464d7e0d91c..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 8a36332d38c0c0ba6b7d8c096367a4ec7c94e522 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:07 +0800 -Subject: [PATCH] migration/dirtyrate: Add trace_calls to make it easier to - debug - -Add trace_calls to make it easier to debug - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: David Edmondson -Message-Id: <1600237327-33618-13-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 9 +++++++++ - migration/trace-events | 8 ++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 9d9155f8ab..80936a4ca6 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -22,6 +22,7 @@ - #include "qapi/qapi-commands-migration.h" - #include "migration.h" - #include "ram.h" -+#include "trace.h" - #include "dirtyrate.h" - - static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; -@@ -54,6 +55,7 @@ static bool is_sample_period_valid(int64_t sec) - static int dirtyrate_set_state(int *state, int old_state, int new_state) - { - assert(new_state < DIRTY_RATE_STATUS__MAX); -+ trace_dirtyrate_set_state(DirtyRateStatus_str(new_state)); - if (atomic_cmpxchg(state, old_state, new_state) == old_state) { - return 0; - } else { -@@ -76,6 +78,8 @@ static struct DirtyRateInfo *query_dirty_rate_info(void) - info->start_time = DirtyStat.start_time; - info->calc_time = DirtyStat.calc_time; - -+ trace_query_dirty_rate_info(DirtyRateStatus_str(CalculatingState)); -+ - return info; - } - -@@ -123,6 +127,7 @@ static uint32_t get_ramblock_vfn_hash(struct RamblockDirtyInfo *info, - crc = crc32(0, (info->ramblock_addr + - vfn * TARGET_PAGE_SIZE), TARGET_PAGE_SIZE); - -+ trace_get_ramblock_vfn_hash(info->idstr, vfn, crc); - return crc; - } - -@@ -201,6 +206,8 @@ static bool skip_sample_ramblock(RAMBlock *block) - * Sample only blocks larger than MIN_RAMBLOCK_SIZE. - */ - if (qemu_ram_get_used_length(block) < (MIN_RAMBLOCK_SIZE << 10)) { -+ trace_skip_sample_ramblock(block->idstr, -+ qemu_ram_get_used_length(block)); - return true; - } - -@@ -260,6 +267,7 @@ static void calc_page_dirty_rate(struct RamblockDirtyInfo *info) - for (i = 0; i < info->sample_pages_count; i++) { - crc = get_ramblock_vfn_hash(info, info->sample_page_vfn[i]); - if (crc != info->hash_result[i]) { -+ trace_calc_page_dirty_rate(info->idstr, crc, info->hash_result[i]); - info->sample_dirty_count++; - } - } -@@ -285,6 +293,7 @@ find_block_matched(RAMBlock *block, int count, - if (infos[i].ramblock_addr != qemu_ram_get_host_addr(block) || - infos[i].ramblock_pages != - (qemu_ram_get_used_length(block) >> TARGET_PAGE_BITS)) { -+ trace_find_page_matched(block->idstr); - return NULL; - } - -diff --git a/migration/trace-events b/migration/trace-events -index d8e54c367a..69620c43c2 100644 ---- a/migration/trace-events -+++ b/migration/trace-events -@@ -296,3 +296,11 @@ dirty_bitmap_load_bits_zeroes(void) "" - dirty_bitmap_load_header(uint32_t flags) "flags 0x%x" - dirty_bitmap_load_enter(void) "" - dirty_bitmap_load_success(void) "" -+ -+# dirtyrate.c -+dirtyrate_set_state(const char *new_state) "new state %s" -+query_dirty_rate_info(const char *new_state) "current state %s" -+get_ramblock_vfn_hash(const char *idstr, uint64_t vfn, uint32_t crc) "ramblock name: %s, vfn: %"PRIu64 ", crc: %" PRIu32 -+calc_page_dirty_rate(const char *idstr, uint32_t new_crc, uint32_t old_crc) "ramblock name: %s, new crc: %" PRIu32 ", old crc: %" PRIu32 -+skip_sample_ramblock(const char *idstr, uint64_t ramblock_size) "ramblock name: %s, ramblock size: %" PRIu64 -+find_page_matched(const char *idstr) "ramblock %s addr or size changed" --- -2.27.0 - diff --git a/migration-dirtyrate-Compare-page-hash-results-for-re.patch b/migration-dirtyrate-Compare-page-hash-results-for-re.patch deleted file mode 100644 index b9277d5faa65a35cc1d044023683ea37e452fc65..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Compare-page-hash-results-for-re.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 949612c5bbc5414970aed7d7ec9390a058ee2246 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:02 +0800 -Subject: [PATCH] migration/dirtyrate: Compare page hash results for recorded - sampled page - -Compare page hash results for recorded sampled page. - -Signed-off-by: Chuan Zheng -Signed-off-by: YanYing Zhuang -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-8-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 63 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 63 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index f93601f8ab..0412f825dc 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -177,6 +177,69 @@ out: - return ret; - } - -+static void calc_page_dirty_rate(struct RamblockDirtyInfo *info) -+{ -+ uint32_t crc; -+ int i; -+ -+ for (i = 0; i < info->sample_pages_count; i++) { -+ crc = get_ramblock_vfn_hash(info, info->sample_page_vfn[i]); -+ if (crc != info->hash_result[i]) { -+ info->sample_dirty_count++; -+ } -+ } -+} -+ -+static struct RamblockDirtyInfo * -+find_block_matched(RAMBlock *block, int count, -+ struct RamblockDirtyInfo *infos) -+{ -+ int i; -+ struct RamblockDirtyInfo *matched; -+ -+ for (i = 0; i < count; i++) { -+ if (!strcmp(infos[i].idstr, qemu_ram_get_idstr(block))) { -+ break; -+ } -+ } -+ -+ if (i == count) { -+ return NULL; -+ } -+ -+ if (infos[i].ramblock_addr != qemu_ram_get_host_addr(block) || -+ infos[i].ramblock_pages != -+ (qemu_ram_get_used_length(block) >> TARGET_PAGE_BITS)) { -+ return NULL; -+ } -+ -+ matched = &infos[i]; -+ -+ return matched; -+} -+ -+static bool compare_page_hash_info(struct RamblockDirtyInfo *info, -+ int block_count) -+{ -+ struct RamblockDirtyInfo *block_dinfo = NULL; -+ RAMBlock *block = NULL; -+ -+ RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ block_dinfo = find_block_matched(block, block_count, info); -+ if (block_dinfo == NULL) { -+ continue; -+ } -+ calc_page_dirty_rate(block_dinfo); -+ update_dirtyrate_stat(block_dinfo); -+ } -+ -+ if (DirtyStat.total_sample_count == 0) { -+ return false; -+ } -+ -+ return true; -+} -+ - static void calculate_dirtyrate(struct DirtyRateConfig config) - { - /* todo */ --- -2.27.0 - diff --git a/migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch b/migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch deleted file mode 100644 index 1fcb2c07c2bfd83d91ee582ec79c39d759c8335b..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 18102266fb18c4bfcdd4760e7111ca03a7520588 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:05 +0800 -Subject: [PATCH] migration/dirtyrate: Implement calculate_dirtyrate() function - -Implement calculate_dirtyrate() function. - -Signed-off-by: Chuan Zheng -Signed-off-by: YanYing Zhuang -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-11-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 45 +++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 43 insertions(+), 2 deletions(-) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 485d6467c9..c7a389a527 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -162,6 +162,21 @@ static void get_ramblock_dirty_info(RAMBlock *block, - strcpy(info->idstr, qemu_ram_get_idstr(block)); - } - -+static void free_ramblock_dirty_info(struct RamblockDirtyInfo *infos, int count) -+{ -+ int i; -+ -+ if (!infos) { -+ return; -+ } -+ -+ for (i = 0; i < count; i++) { -+ g_free(infos[i].sample_page_vfn); -+ g_free(infos[i].hash_result); -+ } -+ g_free(infos); -+} -+ - static bool skip_sample_ramblock(RAMBlock *block) - { - /* -@@ -287,8 +302,34 @@ static bool compare_page_hash_info(struct RamblockDirtyInfo *info, - - static void calculate_dirtyrate(struct DirtyRateConfig config) - { -- /* todo */ -- return; -+ struct RamblockDirtyInfo *block_dinfo = NULL; -+ int block_count = 0; -+ int64_t msec = 0; -+ int64_t initial_time; -+ -+ rcu_register_thread(); -+ reset_dirtyrate_stat(); -+ rcu_read_lock(); -+ initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -+ if (!record_ramblock_hash_info(&block_dinfo, config, &block_count)) { -+ goto out; -+ } -+ rcu_read_unlock(); -+ -+ msec = config.sample_period_seconds * 1000; -+ msec = set_sample_page_period(msec, initial_time); -+ -+ rcu_read_lock(); -+ if (!compare_page_hash_info(block_dinfo, block_count)) { -+ goto out; -+ } -+ -+ update_dirtyrate(msec); -+ -+out: -+ rcu_read_unlock(); -+ free_ramblock_dirty_info(block_dinfo, block_count); -+ rcu_unregister_thread(); - } - - void *get_dirtyrate_thread(void *arg) --- -2.27.0 - diff --git a/migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch b/migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch deleted file mode 100644 index 04893d36e579d9c4b78dfa9d1bd488d3a842cddb..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 1f5f7156988cee6e678eff253df0e79788c950d7 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:06 +0800 -Subject: [PATCH] migration/dirtyrate: Implement - qmp_cal_dirty_rate()/qmp_get_dirty_rate() function - -Implement qmp_cal_dirty_rate()/qmp_get_dirty_rate() function which could be called - -Signed-off-by: Chuan Zheng -Message-Id: <1600237327-33618-12-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert - atomic function fixup - Wording fixup in migration.json based on Eric's review ---- - migration/dirtyrate.c | 62 +++++++++++++++++++++++++++++++++++++++++++ - qapi/migration.json | 50 ++++++++++++++++++++++++++++++++++ - 2 files changed, 112 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index c7a389a527..9d9155f8ab 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -61,6 +61,24 @@ static int dirtyrate_set_state(int *state, int old_state, int new_state) - } - } - -+static struct DirtyRateInfo *query_dirty_rate_info(void) -+{ -+ int64_t dirty_rate = DirtyStat.dirty_rate; -+ struct DirtyRateInfo *info = g_malloc0(sizeof(DirtyRateInfo)); -+ -+ if (atomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) { -+ info->dirty_rate = dirty_rate; -+ } else { -+ info->dirty_rate = -1; -+ } -+ -+ info->status = CalculatingState; -+ info->start_time = DirtyStat.start_time; -+ info->calc_time = DirtyStat.calc_time; -+ -+ return info; -+} -+ - static void reset_dirtyrate_stat(void) - { - DirtyStat.total_dirty_samples = 0; -@@ -318,6 +336,8 @@ static void calculate_dirtyrate(struct DirtyRateConfig config) - - msec = config.sample_period_seconds * 1000; - msec = set_sample_page_period(msec, initial_time); -+ DirtyStat.start_time = initial_time / 1000; -+ DirtyStat.calc_time = msec / 1000; - - rcu_read_lock(); - if (!compare_page_hash_info(block_dinfo, block_count)) { -@@ -353,3 +373,45 @@ void *get_dirtyrate_thread(void *arg) - } - return NULL; - } -+ -+void qmp_calc_dirty_rate(int64_t calc_time, Error **errp) -+{ -+ static struct DirtyRateConfig config; -+ QemuThread thread; -+ int ret; -+ -+ /* -+ * If the dirty rate is already being measured, don't attempt to start. -+ */ -+ if (atomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURING) { -+ error_setg(errp, "the dirty rate is already being measured."); -+ return; -+ } -+ -+ if (!is_sample_period_valid(calc_time)) { -+ error_setg(errp, "calc-time is out of range[%d, %d].", -+ MIN_FETCH_DIRTYRATE_TIME_SEC, -+ MAX_FETCH_DIRTYRATE_TIME_SEC); -+ return; -+ } -+ -+ /* -+ * Init calculation state as unstarted. -+ */ -+ ret = dirtyrate_set_state(&CalculatingState, CalculatingState, -+ DIRTY_RATE_STATUS_UNSTARTED); -+ if (ret == -1) { -+ error_setg(errp, "init dirty rate calculation state failed."); -+ return; -+ } -+ -+ config.sample_period_seconds = calc_time; -+ config.sample_pages_per_gigabytes = DIRTYRATE_DEFAULT_SAMPLE_PAGES; -+ qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread, -+ (void *)&config, QEMU_THREAD_DETACHED); -+} -+ -+struct DirtyRateInfo *qmp_query_dirty_rate(Error **errp) -+{ -+ return query_dirty_rate_info(); -+} -diff --git a/qapi/migration.json b/qapi/migration.json -index fdddde0af7..76f5b42493 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -1462,3 +1462,53 @@ - ## - { 'enum': 'DirtyRateStatus', - 'data': [ 'unstarted', 'measuring', 'measured'] } -+ -+## -+# @DirtyRateInfo: -+# -+# Information about current dirty page rate of vm. -+# -+# @dirty-rate: @dirtyrate describing the dirty page rate of vm -+# in units of MB/s. -+# If this field returns '-1', it means querying has not -+# yet started or completed. -+# -+# @status: status containing dirtyrate query status includes -+# 'unstarted' or 'measuring' or 'measured' -+# -+# @start-time: start time in units of second for calculation -+# -+# @calc-time: time in units of second for sample dirty pages -+# -+# Since: 5.2 -+# -+## -+{ 'struct': 'DirtyRateInfo', -+ 'data': {'dirty-rate': 'int64', -+ 'status': 'DirtyRateStatus', -+ 'start-time': 'int64', -+ 'calc-time': 'int64'} } -+ -+## -+# @calc-dirty-rate: -+# -+# start calculating dirty page rate for vm -+# -+# @calc-time: time in units of second for sample dirty pages -+# -+# Since: 5.2 -+# -+# Example: -+# {"command": "calc-dirty-rate", "data": {"calc-time": 1} } -+# -+## -+{ 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64'} } -+ -+## -+# @query-dirty-rate: -+# -+# query dirty page rate in units of MB/s for vm -+# -+# Since: 5.2 -+## -+{ 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' } --- -2.27.0 - diff --git a/migration-dirtyrate-Implement-set_sample_page_period.patch b/migration-dirtyrate-Implement-set_sample_page_period.patch deleted file mode 100644 index fdb9c22431a0d74a4055f01839a42beaa2fa1f51..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Implement-set_sample_page_period.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 905082a502e0600d40e784df2443ae99948cf52d Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:04 +0800 -Subject: [PATCH] migration/dirtyrate: Implement set_sample_page_period() and - is_sample_period_valid() - -Implement is_sample_period_valid() to check if the sample period is vaild and -do set_sample_page_period() to sleep specific time between sample actions. - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: David Edmondson -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-10-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 24 ++++++++++++++++++++++++ - migration/dirtyrate.h | 6 ++++++ - 2 files changed, 30 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 97bb883850..485d6467c9 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -27,6 +27,30 @@ - static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; - static struct DirtyRateStat DirtyStat; - -+static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) -+{ -+ int64_t current_time; -+ -+ current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); -+ if ((current_time - initial_time) >= msec) { -+ msec = current_time - initial_time; -+ } else { -+ g_usleep((msec + initial_time - current_time) * 1000); -+ } -+ -+ return msec; -+} -+ -+static bool is_sample_period_valid(int64_t sec) -+{ -+ if (sec < MIN_FETCH_DIRTYRATE_TIME_SEC || -+ sec > MAX_FETCH_DIRTYRATE_TIME_SEC) { -+ return false; -+ } -+ -+ return true; -+} -+ - static int dirtyrate_set_state(int *state, int old_state, int new_state) - { - assert(new_state < DIRTY_RATE_STATUS__MAX); -diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h -index be5b8ec2b1..6ec429534d 100644 ---- a/migration/dirtyrate.h -+++ b/migration/dirtyrate.h -@@ -29,6 +29,12 @@ - */ - #define MIN_RAMBLOCK_SIZE 128 - -+/* -+ * Take 1s as minimum time for calculation duration -+ */ -+#define MIN_FETCH_DIRTYRATE_TIME_SEC 1 -+#define MAX_FETCH_DIRTYRATE_TIME_SEC 60 -+ - struct DirtyRateConfig { - uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ - int64_t sample_period_seconds; /* time duration between two sampling */ --- -2.27.0 - diff --git a/migration-dirtyrate-Record-hash-results-for-each-sam.patch b/migration-dirtyrate-Record-hash-results-for-each-sam.patch deleted file mode 100644 index 5a5a8a9476155c56c740941143b899e80b5a2472..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-Record-hash-results-for-each-sam.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 751dbc44b4ac0e0c0bce2f53d2ee79a6e6318188 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:01 +0800 -Subject: [PATCH] migration/dirtyrate: Record hash results for each sampled - page - -Record hash results for each sampled page, crc32 is taken to calculate -hash results for each sampled length in TARGET_PAGE_SIZE. - -Signed-off-by: Chuan Zheng -Signed-off-by: YanYing Zhuang -Reviewed-by: David Edmondson -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-7-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 109 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 109 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 1ccc71077d..f93601f8ab 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -10,6 +10,7 @@ - * See the COPYING file in the top-level directory. - */ - -+#include - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "cpu.h" -@@ -68,6 +69,114 @@ static void update_dirtyrate(uint64_t msec) - DirtyStat.dirty_rate = dirtyrate; - } - -+/* -+ * get hash result for the sampled memory with length of TARGET_PAGE_SIZE -+ * in ramblock, which starts from ramblock base address. -+ */ -+static uint32_t get_ramblock_vfn_hash(struct RamblockDirtyInfo *info, -+ uint64_t vfn) -+{ -+ uint32_t crc; -+ -+ crc = crc32(0, (info->ramblock_addr + -+ vfn * TARGET_PAGE_SIZE), TARGET_PAGE_SIZE); -+ -+ return crc; -+} -+ -+static bool save_ramblock_hash(struct RamblockDirtyInfo *info) -+{ -+ unsigned int sample_pages_count; -+ int i; -+ GRand *rand; -+ -+ sample_pages_count = info->sample_pages_count; -+ -+ /* ramblock size less than one page, return success to skip this ramblock */ -+ if (unlikely(info->ramblock_pages == 0 || sample_pages_count == 0)) { -+ return true; -+ } -+ -+ info->hash_result = g_try_malloc0_n(sample_pages_count, -+ sizeof(uint32_t)); -+ if (!info->hash_result) { -+ return false; -+ } -+ -+ info->sample_page_vfn = g_try_malloc0_n(sample_pages_count, -+ sizeof(uint64_t)); -+ if (!info->sample_page_vfn) { -+ g_free(info->hash_result); -+ return false; -+ } -+ -+ rand = g_rand_new(); -+ for (i = 0; i < sample_pages_count; i++) { -+ info->sample_page_vfn[i] = g_rand_int_range(rand, 0, -+ info->ramblock_pages - 1); -+ info->hash_result[i] = get_ramblock_vfn_hash(info, -+ info->sample_page_vfn[i]); -+ } -+ g_rand_free(rand); -+ -+ return true; -+} -+ -+static void get_ramblock_dirty_info(RAMBlock *block, -+ struct RamblockDirtyInfo *info, -+ struct DirtyRateConfig *config) -+{ -+ uint64_t sample_pages_per_gigabytes = config->sample_pages_per_gigabytes; -+ -+ /* Right shift 30 bits to calc ramblock size in GB */ -+ info->sample_pages_count = (qemu_ram_get_used_length(block) * -+ sample_pages_per_gigabytes) >> 30; -+ /* Right shift TARGET_PAGE_BITS to calc page count */ -+ info->ramblock_pages = qemu_ram_get_used_length(block) >> -+ TARGET_PAGE_BITS; -+ info->ramblock_addr = qemu_ram_get_host_addr(block); -+ strcpy(info->idstr, qemu_ram_get_idstr(block)); -+} -+ -+static bool record_ramblock_hash_info(struct RamblockDirtyInfo **block_dinfo, -+ struct DirtyRateConfig config, -+ int *block_count) -+{ -+ struct RamblockDirtyInfo *info = NULL; -+ struct RamblockDirtyInfo *dinfo = NULL; -+ RAMBlock *block = NULL; -+ int total_count = 0; -+ int index = 0; -+ bool ret = false; -+ -+ RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ total_count++; -+ } -+ -+ dinfo = g_try_malloc0_n(total_count, sizeof(struct RamblockDirtyInfo)); -+ if (dinfo == NULL) { -+ goto out; -+ } -+ -+ RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ if (index >= total_count) { -+ break; -+ } -+ info = &dinfo[index]; -+ get_ramblock_dirty_info(block, info, &config); -+ if (!save_ramblock_hash(info)) { -+ goto out; -+ } -+ index++; -+ } -+ ret = true; -+ -+out: -+ *block_count = index; -+ *block_dinfo = dinfo; -+ return ret; -+} -+ - static void calculate_dirtyrate(struct DirtyRateConfig config) - { - /* todo */ --- -2.27.0 - diff --git a/migration-dirtyrate-Refactor-dirty-page-rate-calcula.patch b/migration-dirtyrate-Refactor-dirty-page-rate-calcula.patch new file mode 100644 index 0000000000000000000000000000000000000000..28097efe8306024337ef04bb3c44d6497abbfbec --- /dev/null +++ b/migration-dirtyrate-Refactor-dirty-page-rate-calcula.patch @@ -0,0 +1,399 @@ +From b6d1e022b7bb06faf2dcad3062b7061b59ef68a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:32 +0800 +Subject: [PATCH 3/3] migration/dirtyrate: Refactor dirty page rate calculation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +abstract out dirty log change logic into function +global_dirty_log_change. + +abstract out dirty page rate calculation logic via +dirty-ring into function vcpu_calculate_dirtyrate. + +abstract out mathematical dirty page rate calculation +into do_calculate_dirtyrate, decouple it from DirtyStat. + +rename set_sample_page_period to dirty_stat_wait, which +is well-understood and will be reused in dirtylimit. + +handle cpu hotplug/unplug scenario during measurement of +dirty page rate. + +export util functions outside migration. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Peter Xu +Message-Id: <7b6f6f4748d5b3d017b31a0429e630229ae97538.1656177590.git.huangy81@chinatelecom.cn> +Signed-off-by: Dr. David Alan Gilbert +--- + include/sysemu/dirtyrate.h | 28 +++++ + migration/dirtyrate.c | 227 +++++++++++++++++++++++-------------- + migration/dirtyrate.h | 7 +- + 3 files changed, 174 insertions(+), 88 deletions(-) + create mode 100644 include/sysemu/dirtyrate.h + +diff --git a/include/sysemu/dirtyrate.h b/include/sysemu/dirtyrate.h +new file mode 100644 +index 0000000000..4d3b9a4902 +--- /dev/null ++++ b/include/sysemu/dirtyrate.h +@@ -0,0 +1,28 @@ ++/* ++ * dirty page rate helper functions ++ * ++ * Copyright (c) 2022 CHINA TELECOM CO.,LTD. ++ * ++ * Authors: ++ * Hyman Huang(黄勇) ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef QEMU_DIRTYRATE_H ++#define QEMU_DIRTYRATE_H ++ ++typedef struct VcpuStat { ++ int nvcpu; /* number of vcpu */ ++ DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */ ++} VcpuStat; ++ ++int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms, ++ VcpuStat *stat, ++ unsigned int flag, ++ bool one_shot); ++ ++void global_dirty_log_change(unsigned int flag, ++ bool start); ++#endif +diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c +index 8043bc7946..c449095fc3 100644 +--- a/migration/dirtyrate.c ++++ b/migration/dirtyrate.c +@@ -46,7 +46,7 @@ static struct DirtyRateStat DirtyStat; + static DirtyRateMeasureMode dirtyrate_mode = + DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; + +-static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) ++static int64_t dirty_stat_wait(int64_t msec, int64_t initial_time) + { + int64_t current_time; + +@@ -60,6 +60,132 @@ static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) + return msec; + } + ++static inline void record_dirtypages(DirtyPageRecord *dirty_pages, ++ CPUState *cpu, bool start) ++{ ++ if (start) { ++ dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages; ++ } else { ++ dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages; ++ } ++} ++ ++static int64_t do_calculate_dirtyrate(DirtyPageRecord dirty_pages, ++ int64_t calc_time_ms) ++{ ++ uint64_t memory_size_MB; ++ uint64_t increased_dirty_pages = ++ dirty_pages.end_pages - dirty_pages.start_pages; ++ ++ memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20; ++ ++ return memory_size_MB * 1000 / calc_time_ms; ++} ++ ++void global_dirty_log_change(unsigned int flag, bool start) ++{ ++ qemu_mutex_lock_iothread(); ++ if (start) { ++ memory_global_dirty_log_start(flag); ++ } else { ++ memory_global_dirty_log_stop(flag); ++ } ++ qemu_mutex_unlock_iothread(); ++} ++ ++/* ++ * global_dirty_log_sync ++ * 1. sync dirty log from kvm ++ * 2. stop dirty tracking if needed. ++ */ ++static void global_dirty_log_sync(unsigned int flag, bool one_shot) ++{ ++ qemu_mutex_lock_iothread(); ++ memory_global_dirty_log_sync(); ++ if (one_shot) { ++ memory_global_dirty_log_stop(flag); ++ } ++ qemu_mutex_unlock_iothread(); ++} ++ ++static DirtyPageRecord *vcpu_dirty_stat_alloc(VcpuStat *stat) ++{ ++ CPUState *cpu; ++ DirtyPageRecord *records; ++ int nvcpu = 0; ++ ++ CPU_FOREACH(cpu) { ++ nvcpu++; ++ } ++ ++ stat->nvcpu = nvcpu; ++ stat->rates = g_malloc0(sizeof(DirtyRateVcpu) * nvcpu); ++ ++ records = g_malloc0(sizeof(DirtyPageRecord) * nvcpu); ++ ++ return records; ++} ++ ++static void vcpu_dirty_stat_collect(VcpuStat *stat, ++ DirtyPageRecord *records, ++ bool start) ++{ ++ CPUState *cpu; ++ ++ CPU_FOREACH(cpu) { ++ record_dirtypages(records, cpu, start); ++ } ++} ++ ++int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms, ++ VcpuStat *stat, ++ unsigned int flag, ++ bool one_shot) ++{ ++ DirtyPageRecord *records; ++ int64_t init_time_ms; ++ int64_t duration; ++ int64_t dirtyrate; ++ int i = 0; ++ unsigned int gen_id; ++ ++retry: ++ init_time_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ++ ++ cpu_list_lock(); ++ gen_id = cpu_list_generation_id_get(); ++ records = vcpu_dirty_stat_alloc(stat); ++ vcpu_dirty_stat_collect(stat, records, true); ++ cpu_list_unlock(); ++ ++ duration = dirty_stat_wait(calc_time_ms, init_time_ms); ++ ++ global_dirty_log_sync(flag, one_shot); ++ ++ cpu_list_lock(); ++ if (gen_id != cpu_list_generation_id_get()) { ++ g_free(records); ++ g_free(stat->rates); ++ cpu_list_unlock(); ++ goto retry; ++ } ++ vcpu_dirty_stat_collect(stat, records, false); ++ cpu_list_unlock(); ++ ++ for (i = 0; i < stat->nvcpu; i++) { ++ dirtyrate = do_calculate_dirtyrate(records[i], duration); ++ ++ stat->rates[i].id = i; ++ stat->rates[i].dirty_rate = dirtyrate; ++ ++ trace_dirtyrate_do_calculate_vcpu(i, dirtyrate); ++ } ++ ++ g_free(records); ++ ++ return duration; ++} ++ + static bool is_sample_period_valid(int64_t sec) + { + if (sec < MIN_FETCH_DIRTYRATE_TIME_SEC || +@@ -396,44 +522,6 @@ static bool compare_page_hash_info(struct RamblockDirtyInfo *info, + return true; + } + +-static inline void record_dirtypages(DirtyPageRecord *dirty_pages, +- CPUState *cpu, bool start) +-{ +- if (start) { +- dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages; +- } else { +- dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages; +- } +-} +- +-static void dirtyrate_global_dirty_log_start(void) +-{ +- qemu_mutex_lock_iothread(); +- memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE); +- qemu_mutex_unlock_iothread(); +-} +- +-static void dirtyrate_global_dirty_log_stop(void) +-{ +- qemu_mutex_lock_iothread(); +- memory_global_dirty_log_sync(); +- memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE); +- qemu_mutex_unlock_iothread(); +-} +- +-static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages) +-{ +- uint64_t memory_size_MB; +- int64_t time_s; +- uint64_t increased_dirty_pages = +- dirty_pages.end_pages - dirty_pages.start_pages; +- +- memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20; +- time_s = DirtyStat.calc_time; +- +- return memory_size_MB / time_s; +-} +- + static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages, + bool start) + { +@@ -444,11 +532,6 @@ static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages, + } + } + +-static void do_calculate_dirtyrate_bitmap(DirtyPageRecord dirty_pages) +-{ +- DirtyStat.dirty_rate = do_calculate_dirtyrate_vcpu(dirty_pages); +-} +- + static inline void dirtyrate_manual_reset_protect(void) + { + RAMBlock *block = NULL; +@@ -492,71 +575,49 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) + DirtyStat.start_time = start_time / 1000; + + msec = config.sample_period_seconds * 1000; +- msec = set_sample_page_period(msec, start_time); ++ msec = dirty_stat_wait(msec, start_time); + DirtyStat.calc_time = msec / 1000; + + /* +- * dirtyrate_global_dirty_log_stop do two things. ++ * do two things. + * 1. fetch dirty bitmap from kvm + * 2. stop dirty tracking + */ +- dirtyrate_global_dirty_log_stop(); ++ global_dirty_log_sync(GLOBAL_DIRTY_DIRTY_RATE, true); + + record_dirtypages_bitmap(&dirty_pages, false); + +- do_calculate_dirtyrate_bitmap(dirty_pages); ++ DirtyStat.dirty_rate = do_calculate_dirtyrate(dirty_pages, msec); + } + + static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) + { +- CPUState *cpu; +- int64_t msec = 0; +- int64_t start_time; ++ int64_t duration; + uint64_t dirtyrate = 0; + uint64_t dirtyrate_sum = 0; +- DirtyPageRecord *dirty_pages; +- int nvcpu = 0; + int i = 0; + +- CPU_FOREACH(cpu) { +- nvcpu++; +- } +- +- dirty_pages = g_new(DirtyPageRecord, nvcpu); +- +- DirtyStat.dirty_ring.nvcpu = nvcpu; +- DirtyStat.dirty_ring.rates = g_new(DirtyRateVcpu, nvcpu); +- +- dirtyrate_global_dirty_log_start(); +- +- CPU_FOREACH(cpu) { +- record_dirtypages(dirty_pages, cpu, true); +- } +- +- start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); +- DirtyStat.start_time = start_time / 1000; ++ /* start log sync */ ++ global_dirty_log_change(GLOBAL_DIRTY_DIRTY_RATE, true); + +- msec = config.sample_period_seconds * 1000; +- msec = set_sample_page_period(msec, start_time); +- DirtyStat.calc_time = msec / 1000; ++ DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; + +- dirtyrate_global_dirty_log_stop(); ++ /* calculate vcpu dirtyrate */ ++ duration = vcpu_calculate_dirtyrate(config.sample_period_seconds * 1000, ++ &DirtyStat.dirty_ring, ++ GLOBAL_DIRTY_DIRTY_RATE, ++ true); + +- CPU_FOREACH(cpu) { +- record_dirtypages(dirty_pages, cpu, false); +- } ++ DirtyStat.calc_time = duration / 1000; + ++ /* calculate vm dirtyrate */ + for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) { +- dirtyrate = do_calculate_dirtyrate_vcpu(dirty_pages[i]); +- trace_dirtyrate_do_calculate_vcpu(i, dirtyrate); +- +- DirtyStat.dirty_ring.rates[i].id = i; ++ dirtyrate = DirtyStat.dirty_ring.rates[i].dirty_rate; + DirtyStat.dirty_ring.rates[i].dirty_rate = dirtyrate; + dirtyrate_sum += dirtyrate; + } + + DirtyStat.dirty_rate = dirtyrate_sum; +- g_free(dirty_pages); + } + + static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) +@@ -574,7 +635,7 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) + rcu_read_unlock(); + + msec = config.sample_period_seconds * 1000; +- msec = set_sample_page_period(msec, initial_time); ++ msec = dirty_stat_wait(msec, initial_time); + DirtyStat.start_time = initial_time / 1000; + DirtyStat.calc_time = msec / 1000; + +diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h +index 69d4c5b865..594a5c0bb6 100644 +--- a/migration/dirtyrate.h ++++ b/migration/dirtyrate.h +@@ -13,6 +13,8 @@ + #ifndef QEMU_MIGRATION_DIRTYRATE_H + #define QEMU_MIGRATION_DIRTYRATE_H + ++#include "sysemu/dirtyrate.h" ++ + /* + * Sample 512 pages per GB as default. + */ +@@ -65,11 +67,6 @@ typedef struct SampleVMStat { + uint64_t total_block_mem_MB; /* size of total sampled pages in MB */ + } SampleVMStat; + +-typedef struct VcpuStat { +- int nvcpu; /* number of vcpu */ +- DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */ +-} VcpuStat; +- + /* + * Store calculation statistics for each measure. + */ +-- +2.27.0 + diff --git a/migration-dirtyrate-Replace-malloc-with-g_new.patch b/migration-dirtyrate-Replace-malloc-with-g_new.patch new file mode 100644 index 0000000000000000000000000000000000000000..9e146a4a40b05ca9c747b3fd82854b7f82ac0209 --- /dev/null +++ b/migration-dirtyrate-Replace-malloc-with-g_new.patch @@ -0,0 +1,48 @@ +From 7cb2d342b9073ec9548202df6e1fb25fa4997d71 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 30 Jun 2022 11:34:50 +0000 +Subject: [PATCH] migration/dirtyrate: Replace malloc with g_new Using macro + g_new() to handling potential memory allocation failures in dirtyrate. + +--- + migration/dirtyrate.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c +index d65e744af9..8043bc7946 100644 +--- a/migration/dirtyrate.c ++++ b/migration/dirtyrate.c +@@ -157,7 +157,7 @@ static void cleanup_dirtyrate_stat(struct DirtyRateConfig config) + { + /* last calc-dirty-rate qmp use dirty ring mode */ + if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { +- free(DirtyStat.dirty_ring.rates); ++ g_free(DirtyStat.dirty_ring.rates); + DirtyStat.dirty_ring.rates = NULL; + } + } +@@ -522,10 +522,10 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) + nvcpu++; + } + +- dirty_pages = malloc(sizeof(*dirty_pages) * nvcpu); ++ dirty_pages = g_new(DirtyPageRecord, nvcpu); + + DirtyStat.dirty_ring.nvcpu = nvcpu; +- DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu); ++ DirtyStat.dirty_ring.rates = g_new(DirtyRateVcpu, nvcpu); + + dirtyrate_global_dirty_log_start(); + +@@ -556,7 +556,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) + } + + DirtyStat.dirty_rate = dirtyrate_sum; +- free(dirty_pages); ++ g_free(dirty_pages); + } + + static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) +-- +2.27.0 + diff --git a/migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch b/migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch deleted file mode 100644 index e0ebb2a70e3771da65a340b081094e63318d42fe..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 466b3eee340f022e53478e706e8d4dc02136b1e1 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:21:57 +0800 -Subject: [PATCH] migration/dirtyrate: add DirtyRateStatus to denote - calculation status - -add DirtyRateStatus to denote calculating status. - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-3-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert - atomic name fixup ---- - migration/dirtyrate.c | 26 ++++++++++++++++++++++++++ - qapi/migration.json | 17 +++++++++++++++++ - 2 files changed, 43 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 29ef663acb..44a60bf10d 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -22,6 +22,19 @@ - #include "migration.h" - #include "dirtyrate.h" - -+static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; -+ -+static int dirtyrate_set_state(int *state, int old_state, int new_state) -+{ -+ assert(new_state < DIRTY_RATE_STATUS__MAX); -+ if (atomic_cmpxchg(state, old_state, new_state) == old_state) { -+ return 0; -+ } else { -+ return -1; -+ } -+} -+ -+ - static void calculate_dirtyrate(struct DirtyRateConfig config) - { - /* todo */ -@@ -31,8 +44,21 @@ static void calculate_dirtyrate(struct DirtyRateConfig config) - void *get_dirtyrate_thread(void *arg) - { - struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg; -+ int ret; -+ -+ ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_UNSTARTED, -+ DIRTY_RATE_STATUS_MEASURING); -+ if (ret == -1) { -+ error_report("change dirtyrate state failed."); -+ return NULL; -+ } - - calculate_dirtyrate(config); - -+ ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_MEASURING, -+ DIRTY_RATE_STATUS_MEASURED); -+ if (ret == -1) { -+ error_report("change dirtyrate state failed."); -+ } - return NULL; - } -diff --git a/qapi/migration.json b/qapi/migration.json -index 9cfbaf8c6c..fdddde0af7 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -1445,3 +1445,20 @@ - # Since: 3.0 - ## - { 'command': 'migrate-pause', 'allow-oob': true } -+ -+## -+# @DirtyRateStatus: -+# -+# An enumeration of dirtyrate status. -+# -+# @unstarted: the dirtyrate thread has not been started. -+# -+# @measuring: the dirtyrate thread is measuring. -+# -+# @measured: the dirtyrate thread has measured and results are available. -+# -+# Since: 5.2 -+# -+## -+{ 'enum': 'DirtyRateStatus', -+ 'data': [ 'unstarted', 'measuring', 'measured'] } --- -2.27.0 - diff --git a/migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch b/migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch deleted file mode 100644 index 16660d7dd46f4ec3712f9714de37c41a3c3554f4..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 1cee10fe37193c6b5ed4e765a2a6d1e6c1411922 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:00 +0800 -Subject: [PATCH] migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into - ram.h - -RAMBLOCK_FOREACH_MIGRATABLE is need in dirtyrate measure, -move the existing definition up into migration/ram.h - -Signed-off-by: Chuan Zheng -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: David Edmondson -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-6-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 1 + - migration/ram.c | 11 +---------- - migration/ram.h | 10 ++++++++++ - 3 files changed, 12 insertions(+), 10 deletions(-) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index cbb323d6ec..1ccc71077d 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -20,6 +20,7 @@ - #include "qemu/rcu_queue.h" - #include "qapi/qapi-commands-migration.h" - #include "migration.h" -+#include "ram.h" - #include "dirtyrate.h" - - static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; -diff --git a/migration/ram.c b/migration/ram.c -index 848059d9fb..1a33c7b3e2 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -159,21 +159,12 @@ out: - return ret; - } - --static bool ramblock_is_ignored(RAMBlock *block) -+bool ramblock_is_ignored(RAMBlock *block) - { - return !qemu_ram_is_migratable(block) || - (migrate_ignore_shared() && qemu_ram_is_shared(block)); - } - --/* Should be holding either ram_list.mutex, or the RCU lock. */ --#define RAMBLOCK_FOREACH_NOT_IGNORED(block) \ -- INTERNAL_RAMBLOCK_FOREACH(block) \ -- if (ramblock_is_ignored(block)) {} else -- --#define RAMBLOCK_FOREACH_MIGRATABLE(block) \ -- INTERNAL_RAMBLOCK_FOREACH(block) \ -- if (!qemu_ram_is_migratable(block)) {} else -- - #undef RAMBLOCK_FOREACH - - int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque) -diff --git a/migration/ram.h b/migration/ram.h -index a788ff0e8e..565ec86b1f 100644 ---- a/migration/ram.h -+++ b/migration/ram.h -@@ -37,6 +37,16 @@ extern MigrationStats ram_counters; - extern XBZRLECacheStats xbzrle_counters; - extern CompressionStats compression_counters; - -+bool ramblock_is_ignored(RAMBlock *block); -+/* Should be holding either ram_list.mutex, or the RCU lock. */ -+#define RAMBLOCK_FOREACH_NOT_IGNORED(block) \ -+ INTERNAL_RAMBLOCK_FOREACH(block) \ -+ if (ramblock_is_ignored(block)) {} else -+ -+#define RAMBLOCK_FOREACH_MIGRATABLE(block) \ -+ INTERNAL_RAMBLOCK_FOREACH(block) \ -+ if (!qemu_ram_is_migratable(block)) {} else -+ - int xbzrle_cache_resize(int64_t new_size, Error **errp); - uint64_t ram_bytes_remaining(void); - uint64_t ram_bytes_total(void); --- -2.27.0 - diff --git a/migration-dirtyrate-present-dirty-rate-only-when-que.patch b/migration-dirtyrate-present-dirty-rate-only-when-que.patch deleted file mode 100644 index d6d5dd423913c89888c29e530b18009bf1f63f50..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-present-dirty-rate-only-when-que.patch +++ /dev/null @@ -1,69 +0,0 @@ -From ba399ad806d195f31d0b76fa55363a4147459a5b Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Tue, 29 Sep 2020 11:42:18 +0800 -Subject: [PATCH] migration/dirtyrate: present dirty rate only when querying - the rate has completed - -Make dirty_rate field optional, present dirty rate only when querying -the rate has completed. -The qmp results is shown as follow: -@unstarted: -{"return":{"status":"unstarted","start-time":0,"calc-time":0},"id":"libvirt-12"} -@measuring: -{"return":{"status":"measuring","start-time":102931,"calc-time":1},"id":"libvirt-85"} -@measured: -{"return":{"status":"measured","dirty-rate":4,"start-time":150146,"calc-time":1},"id":"libvirt-15"} - -Signed-off-by: Chuan Zheng -Reviewed-by: David Edmondson -Message-Id: <1601350938-128320-3-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 3 +-- - qapi/migration.json | 8 +++----- - 2 files changed, 4 insertions(+), 7 deletions(-) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index f1c007d569..00c8085456 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -69,9 +69,8 @@ static struct DirtyRateInfo *query_dirty_rate_info(void) - struct DirtyRateInfo *info = g_malloc0(sizeof(DirtyRateInfo)); - - if (atomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) { -+ info->has_dirty_rate = true; - info->dirty_rate = dirty_rate; -- } else { -- info->dirty_rate = -1; - } - - info->status = CalculatingState; -diff --git a/qapi/migration.json b/qapi/migration.json -index 76f5b42493..6844ddfab3 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -1468,10 +1468,8 @@ - # - # Information about current dirty page rate of vm. - # --# @dirty-rate: @dirtyrate describing the dirty page rate of vm --# in units of MB/s. --# If this field returns '-1', it means querying has not --# yet started or completed. -+# @dirty-rate: an estimate of the dirty page rate of the VM in units of -+# MB/s, present only when estimating the rate has completed. - # - # @status: status containing dirtyrate query status includes - # 'unstarted' or 'measuring' or 'measured' -@@ -1484,7 +1482,7 @@ - # - ## - { 'struct': 'DirtyRateInfo', -- 'data': {'dirty-rate': 'int64', -+ 'data': {'*dirty-rate': 'int64', - 'status': 'DirtyRateStatus', - 'start-time': 'int64', - 'calc-time': 'int64'} } --- -2.27.0 - diff --git a/migration-dirtyrate-record-start_time-and-calc_time-.patch b/migration-dirtyrate-record-start_time-and-calc_time-.patch deleted file mode 100644 index a4a4fed2c90eb99565d7712a6565c2284331b29c..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-record-start_time-and-calc_time-.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 5de3e40a6c1a4afcc2612ac109326956e7cded63 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Tue, 29 Sep 2020 11:42:17 +0800 -Subject: [PATCH] migration/dirtyrate: record start_time and calc_time while at - the measuring state - -Querying could include both the start-time and the calc-time while at the measuring -state, allowing a caller to determine when they should expect to come back looking -for a result. - -Signed-off-by: Chuan Zheng -Message-Id: <1601350938-128320-2-git-send-email-zhengchuan@huawei.com> -Reviewed-by: David Edmondson -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 80936a4ca6..f1c007d569 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -83,14 +83,14 @@ static struct DirtyRateInfo *query_dirty_rate_info(void) - return info; - } - --static void reset_dirtyrate_stat(void) -+static void init_dirtyrate_stat(int64_t start_time, int64_t calc_time) - { - DirtyStat.total_dirty_samples = 0; - DirtyStat.total_sample_count = 0; - DirtyStat.total_block_mem_MB = 0; - DirtyStat.dirty_rate = -1; -- DirtyStat.start_time = 0; -- DirtyStat.calc_time = 0; -+ DirtyStat.start_time = start_time; -+ DirtyStat.calc_time = calc_time; - } - - static void update_dirtyrate_stat(struct RamblockDirtyInfo *info) -@@ -335,7 +335,6 @@ static void calculate_dirtyrate(struct DirtyRateConfig config) - int64_t initial_time; - - rcu_register_thread(); -- reset_dirtyrate_stat(); - rcu_read_lock(); - initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - if (!record_ramblock_hash_info(&block_dinfo, config, &block_count)) { -@@ -365,6 +364,8 @@ void *get_dirtyrate_thread(void *arg) - { - struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg; - int ret; -+ int64_t start_time; -+ int64_t calc_time; - - ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_UNSTARTED, - DIRTY_RATE_STATUS_MEASURING); -@@ -373,6 +374,10 @@ void *get_dirtyrate_thread(void *arg) - return NULL; - } - -+ start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; -+ calc_time = config.sample_period_seconds; -+ init_dirtyrate_stat(start_time, calc_time); -+ - calculate_dirtyrate(config); - - ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_MEASURING, --- -2.27.0 - diff --git a/migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch b/migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch deleted file mode 100644 index f4a2b4ff12bf88e0f37211df631867d0ee6f6a6d..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 18dbd0efc14aa190b2f4c364fa614b0994af5af0 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:21:56 +0800 -Subject: [PATCH] migration/dirtyrate: setup up query-dirtyrate framwork - -Add get_dirtyrate_thread() functions to setup query-dirtyrate -framework. - -Signed-off-by: Chuan Zheng -Signed-off-by: YanYing Zhuang -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: David Edmondson -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-2-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - Makefile.target | 1 + - migration/dirtyrate.c | 38 ++++++++++++++++++++++++++++++++++++++ - migration/dirtyrate.h | 28 ++++++++++++++++++++++++++++ - 3 files changed, 67 insertions(+) - create mode 100644 migration/dirtyrate.c - create mode 100644 migration/dirtyrate.h - -diff --git a/Makefile.target b/Makefile.target -index 933b27453a..5ea840964c 100644 ---- a/Makefile.target -+++ b/Makefile.target -@@ -161,6 +161,7 @@ obj-y += qapi/ - obj-y += memory.o - obj-y += memory_mapping.o - obj-y += migration/ram.o -+obj-y += migration/dirtyrate.o - LIBS := $(libs_softmmu) $(LIBS) - - # Hardware support -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -new file mode 100644 -index 0000000000..29ef663acb ---- /dev/null -+++ b/migration/dirtyrate.c -@@ -0,0 +1,38 @@ -+/* -+ * Dirtyrate implement code -+ * -+ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD. -+ * -+ * Authors: -+ * Chuan Zheng -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "cpu.h" -+#include "qemu/config-file.h" -+#include "exec/memory.h" -+#include "exec/ram_addr.h" -+#include "exec/target_page.h" -+#include "qemu/rcu_queue.h" -+#include "qapi/qapi-commands-migration.h" -+#include "migration.h" -+#include "dirtyrate.h" -+ -+static void calculate_dirtyrate(struct DirtyRateConfig config) -+{ -+ /* todo */ -+ return; -+} -+ -+void *get_dirtyrate_thread(void *arg) -+{ -+ struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg; -+ -+ calculate_dirtyrate(config); -+ -+ return NULL; -+} -diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h -new file mode 100644 -index 0000000000..84ab9409ac ---- /dev/null -+++ b/migration/dirtyrate.h -@@ -0,0 +1,28 @@ -+/* -+ * Dirtyrate common functions -+ * -+ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. -+ * -+ * Authors: -+ * Chuan Zheng -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef QEMU_MIGRATION_DIRTYRATE_H -+#define QEMU_MIGRATION_DIRTYRATE_H -+ -+/* -+ * Sample 512 pages per GB as default. -+ * TODO: Make it configurable. -+ */ -+#define DIRTYRATE_DEFAULT_SAMPLE_PAGES 512 -+ -+struct DirtyRateConfig { -+ uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ -+ int64_t sample_period_seconds; /* time duration between two sampling */ -+}; -+ -+void *get_dirtyrate_thread(void *arg); -+#endif --- -2.27.0 - diff --git a/migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch b/migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch deleted file mode 100644 index 3bdb51b5d936d3a51bc9321815f98b742070b3ab..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 91eed005e1af25f49ab38732cd3c9ea8071331b0 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Fri, 30 Oct 2020 11:58:01 +0800 -Subject: [PATCH] migration/dirtyrate: simplify includes in dirtyrate.c - -Remove redundant blank line which is left by Commit 662770af7c6e8c, -also take this opportunity to remove redundant includes in dirtyrate.c. - -Signed-off-by: Chuan Zheng -Message-Id: <1604030281-112946-1-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 00c8085456..9a6d0e2cc6 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -10,17 +10,16 @@ - * See the COPYING file in the top-level directory. - */ - --#include - #include "qemu/osdep.h" -+#include - #include "qapi/error.h" - #include "cpu.h" --#include "qemu/config-file.h" - #include "exec/memory.h" - #include "exec/ram_addr.h" - #include "exec/target_page.h" - #include "qemu/rcu_queue.h" -+#include "qemu/error-report.h" - #include "qapi/qapi-commands-migration.h" --#include "migration.h" - #include "ram.h" - #include "trace.h" - #include "dirtyrate.h" --- -2.27.0 - diff --git a/migration-dirtyrate-skip-sampling-ramblock-with-size.patch b/migration-dirtyrate-skip-sampling-ramblock-with-size.patch deleted file mode 100644 index 0e649e3cdef1a3283d1ed0fde909902d5f3274a7..0000000000000000000000000000000000000000 --- a/migration-dirtyrate-skip-sampling-ramblock-with-size.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0fcff073292e78e08ee24eb784783156b2974f4a Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Wed, 16 Sep 2020 14:22:03 +0800 -Subject: [PATCH] migration/dirtyrate: skip sampling ramblock with size below - MIN_RAMBLOCK_SIZE - -In order to sample real RAM, skip ramblock with size below MIN_RAMBLOCK_SIZE -which is set as 128M. - -Signed-off-by: Chuan Zheng -Reviewed-by: David Edmondson -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Li Qiang -Message-Id: <1600237327-33618-9-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/dirtyrate.c | 21 +++++++++++++++++++++ - migration/dirtyrate.h | 5 +++++ - 2 files changed, 26 insertions(+) - -diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c -index 0412f825dc..97bb883850 100644 ---- a/migration/dirtyrate.c -+++ b/migration/dirtyrate.c -@@ -138,6 +138,18 @@ static void get_ramblock_dirty_info(RAMBlock *block, - strcpy(info->idstr, qemu_ram_get_idstr(block)); - } - -+static bool skip_sample_ramblock(RAMBlock *block) -+{ -+ /* -+ * Sample only blocks larger than MIN_RAMBLOCK_SIZE. -+ */ -+ if (qemu_ram_get_used_length(block) < (MIN_RAMBLOCK_SIZE << 10)) { -+ return true; -+ } -+ -+ return false; -+} -+ - static bool record_ramblock_hash_info(struct RamblockDirtyInfo **block_dinfo, - struct DirtyRateConfig config, - int *block_count) -@@ -150,6 +162,9 @@ static bool record_ramblock_hash_info(struct RamblockDirtyInfo **block_dinfo, - bool ret = false; - - RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ if (skip_sample_ramblock(block)) { -+ continue; -+ } - total_count++; - } - -@@ -159,6 +174,9 @@ static bool record_ramblock_hash_info(struct RamblockDirtyInfo **block_dinfo, - } - - RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ if (skip_sample_ramblock(block)) { -+ continue; -+ } - if (index >= total_count) { - break; - } -@@ -225,6 +243,9 @@ static bool compare_page_hash_info(struct RamblockDirtyInfo *info, - RAMBlock *block = NULL; - - RAMBLOCK_FOREACH_MIGRATABLE(block) { -+ if (skip_sample_ramblock(block)) { -+ continue; -+ } - block_dinfo = find_block_matched(block, block_count, info); - if (block_dinfo == NULL) { - continue; -diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h -index 312debca6f..be5b8ec2b1 100644 ---- a/migration/dirtyrate.h -+++ b/migration/dirtyrate.h -@@ -24,6 +24,11 @@ - */ - #define RAMBLOCK_INFO_MAX_LEN 256 - -+/* -+ * Minimum RAMBlock size to sample, in megabytes. -+ */ -+#define MIN_RAMBLOCK_SIZE 128 -+ - struct DirtyRateConfig { - uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ - int64_t sample_period_seconds; /* time duration between two sampling */ --- -2.27.0 - diff --git a/migration-fix-COLO-broken-caused-by-a-previous-commi.patch b/migration-fix-COLO-broken-caused-by-a-previous-commi.patch deleted file mode 100644 index 3ac65d9c79a43e8233c80d633dc02835e9f8344c..0000000000000000000000000000000000000000 --- a/migration-fix-COLO-broken-caused-by-a-previous-commi.patch +++ /dev/null @@ -1,39 +0,0 @@ -From c635692b4e75db3f9547f6d4ed9d73d1cdb34989 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:43:45 +0800 -Subject: [PATCH] migration: fix COLO broken caused by a previous commit - -This commit "migration: Create migration_is_running()" broke -COLO. Becuase there is a process broken by this commit. - -colo_process_checkpoint - ->colo_do_checkpoint_transaction - ->migrate_set_block_enabled - ->qmp_migrate_set_capabilities - -It can be fixed by make COLO process as an exception, -Maybe we need a better way to fix it. - -Cc: Juan Quintela -Signed-off-by: zhanghailiang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/migration.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 923a1d9d3f..0e396f22b4 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -833,7 +833,6 @@ bool migration_is_running(int state) - case MIGRATION_STATUS_PRE_SWITCHOVER: - case MIGRATION_STATUS_DEVICE: - case MIGRATION_STATUS_CANCELLING: -- case MIGRATION_STATUS_COLO: - return true; - - default: --- -2.27.0 - diff --git a/migration-fix-RAMBlock-add-NULL-check.patch b/migration-fix-RAMBlock-add-NULL-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..88cd6302d3f9e1a30451484121effcc9c5687a10 --- /dev/null +++ b/migration-fix-RAMBlock-add-NULL-check.patch @@ -0,0 +1,41 @@ +From 03569a14e7ae428bad59a4e11637c900ff436816 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Mon, 18 Dec 2023 16:56:15 +0800 +Subject: [PATCH] migration: fix RAMBlock add NULL check + +qemu_ram_block_from_host() may return NULL, which will be dereferenced w/o +check. Usualy return value is checked for this function. +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +cheery-pick from f75ed59f40bed3ce94adad4b3ebbb7bfacfdf4ab + +Signed-off-by: jipengfei_yewu +Signed-off-by: Dmitry Frolov +Reviewed-by: Fabiano Rosas +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Message-ID: <20231010104851.802947-1-frolov@swemel.ru> +--- + migration/ram.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 862955f5b2..c245b04cf2 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -4679,6 +4679,11 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, + RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset); + Error *err = NULL; + ++ if (!rb) { ++ error_report("RAM block not found"); ++ return; ++ } ++ + if (ramblock_is_ignored(rb)) { + return; + } +-- +2.27.0 + diff --git a/migration-fix-cleanup_bh-leak-on-resume.patch b/migration-fix-cleanup_bh-leak-on-resume.patch deleted file mode 100644 index 6b75ed01b8faa4c3d5b9d1e17e6d3d205daa2396..0000000000000000000000000000000000000000 --- a/migration-fix-cleanup_bh-leak-on-resume.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 1d7c227bbb24665cea03f96a984ad6be223ac40c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 25 Mar 2020 19:47:21 +0100 -Subject: [PATCH 2/5] migration: fix cleanup_bh leak on resume -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since commit 8c6b0356b53977bcfdea5299db07884915425b0c ("util/async: -make bh_aio_poll() O(1)"), migration-test reveals a leak: - -QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 -tests/qtest/migration-test -p /x86_64/migration/postcopy/recovery -tests/qtest/libqtest.c:140: kill_qemu() tried to terminate QEMU -process but encountered exit status 1 (expected 0) - -================================================================= -==2082571==ERROR: LeakSanitizer: detected memory leaks - -Direct leak of 40 byte(s) in 1 object(s) allocated from: - #0 0x7f25971dfc58 in __interceptor_malloc (/lib64/libasan.so.5+0x10dc58) - #1 0x7f2596d08358 in g_malloc (/lib64/libglib-2.0.so.0+0x57358) - #2 0x560970d006f8 in qemu_bh_new /home/elmarco/src/qemu/util/main-loop.c:532 - #3 0x5609704afa02 in migrate_fd_connect -/home/elmarco/src/qemu/migration/migration.c:3407 - #4 0x5609704b6b6f in migration_channel_connect -/home/elmarco/src/qemu/migration/channel.c:92 - #5 0x5609704b2bfb in socket_outgoing_migration -/home/elmarco/src/qemu/migration/socket.c:108 - #6 0x560970b9bd6c in qio_task_complete /home/elmarco/src/qemu/io/task.c:196 - #7 0x560970b9aa97 in qio_task_thread_result -/home/elmarco/src/qemu/io/task.c:111 - #8 0x7f2596cfee3a (/lib64/libglib-2.0.so.0+0x4de3a) - -Signed-off-by: Marc-André Lureau -Message-Id: <20200325184723.2029630-2-marcandre.lureau@redhat.com> -Reviewed-by: Juan Quintela -Signed-off-by: Paolo Bonzini -Signed-off-by: Zhenyu Ye ---- - migration/migration.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 8f2fc2b4..7949f2a4 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -3313,7 +3313,12 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) - bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED; - - s->expected_downtime = s->parameters.downtime_limit; -- s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup_bh, s); -+ if (resume) { -+ assert(s->cleanup_bh); -+ } else { -+ assert(!s->cleanup_bh); -+ s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup_bh, s); -+ } - if (error_in) { - migrate_fd_error(s, error_in); - migrate_fd_cleanup(s); --- -2.22.0.windows.1 - diff --git a/migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch b/migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch deleted file mode 100644 index 46775ae5ee200005e5d56f10ccd2c02e75685c7a..0000000000000000000000000000000000000000 --- a/migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch +++ /dev/null @@ -1,78 +0,0 @@ -From d65b5b20f4ada9e6c5af37b0fb59fa4709c4bdc9 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Fri, 5 Mar 2021 16:06:52 +0800 -Subject: [PATCH] migration: fix memory leak in qmp_migrate_set_parameters - -"tmp.tls_hostname" and "tmp.tls_creds" allocated by migrate_params_test_apply() -is forgot to free at the end of qmp_migrate_set_parameters(). Fix that. - -The leak stack: -Direct leak of 2 byte(s) in 2 object(s) allocated from: - #0 0xffffb597c20b in __interceptor_malloc (/usr/lib64/libasan.so.4+0xd320b) - #1 0xffffb52dcb1b in g_malloc (/usr/lib64/libglib-2.0.so.0+0x58b1b) - #2 0xffffb52f8143 in g_strdup (/usr/lib64/libglib-2.0.so.0+0x74143) - #3 0xaaaac52447fb in migrate_params_test_apply (/usr/src/debug/qemu-4.1.0/migration/migration.c:1377) - #4 0xaaaac52fdca7 in qmp_migrate_set_parameters (/usr/src/debug/qemu-4.1.0/qapi/qapi-commands-migration.c:192) - #5 0xaaaac551d543 in qmp_dispatch (/usr/src/debug/qemu-4.1.0/qapi/qmp-dispatch.c:165) - #6 0xaaaac52a0a8f in qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:125) - #7 0xaaaac52a1c7f in monitor_qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:214) - #8 0xaaaac55cb0cf in aio_bh_call (/usr/src/debug/qemu-4.1.0/util/async.c:117) - #9 0xaaaac55d4543 in aio_bh_poll (/usr/src/debug/qemu-4.1.0/util/aio-posix.c:459) - #10 0xaaaac55cae0f in aio_dispatch (/usr/src/debug/qemu-4.1.0/util/async.c:268) - #11 0xffffb52d6a7b in g_main_context_dispatch (/usr/lib64/libglib-2.0.so.0+0x52a7b) - #12 0xaaaac55d1e3b(/usr/bin/qemu-kvm-4.1.0+0x1622e3b) - #13 0xaaaac4e314bb(/usr/bin/qemu-kvm-4.1.0+0xe824bb) - #14 0xaaaac47f45ef(/usr/bin/qemu-kvm-4.1.0+0x8455ef) - #15 0xffffb4bfef3f in __libc_start_main (/usr/lib64/libc.so.6+0x23f3f) - #16 0xaaaac47ffacb(/usr/bin/qemu-kvm-4.1.0+0x850acb) - -Direct leak of 2 byte(s) in 2 object(s) allocated from: - #0 0xffffb597c20b in __interceptor_malloc (/usr/lib64/libasan.so.4+0xd320b) - #1 0xffffb52dcb1b in g_malloc (/usr/lib64/libglib-2.0.so.0+0x58b1b) - #2 0xffffb52f8143 in g_strdup (/usr/lib64/libglib-2.0.so.0+0x74143) - #3 0xaaaac5244893 in migrate_params_test_apply (/usr/src/debug/qemu-4.1.0/migration/migration.c:1382) - #4 0xaaaac52fdca7 in qmp_migrate_set_parameters (/usr/src/debug/qemu-4.1.0/qapi/qapi-commands-migration.c:192) - #5 0xaaaac551d543 in qmp_dispatch (/usr/src/debug/qemu-4.1.0/qapi/qmp-dispatch.c) - #6 0xaaaac52a0a8f in qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:125) - #7 0xaaaac52a1c7f in monitor_qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:214) - #8 0xaaaac55cb0cf in aio_bh_call (/usr/src/debug/qemu-4.1.0/util/async.c:117) - #9 0xaaaac55d4543 in aio_bh_poll (/usr/src/debug/qemu-4.1.0/util/aio-posix.c:459) - #10 0xaaaac55cae0f in in aio_dispatch (/usr/src/debug/qemu-4.1.0/util/async.c:268) - #11 0xffffb52d6a7b in g_main_context_dispatch (/usr/lib64/libglib-2.0.so.0+0x52a7b) - #12 0xaaaac55d1e3b(/usr/bin/qemu-kvm-4.1.0+0x1622e3b) - #13 0xaaaac4e314bb(/usr/bin/qemu-kvm-4.1.0+0xe824bb) - #14 0xaaaac47f45ef (/usr/bin/qemu-kvm-4.1.0+0x8455ef) - #15 0xffffb4bfef3f in __libc_start_main (/usr/lib64/libc.so.6+0x23f3f) - #16 0xaaaac47ffacb(/usr/bin/qemu-kvm-4.1.0+0x850acb) - -Signed-off-by: Chuan Zheng -Reviewed-by: KeQian Zhu -Reviewed-by: HaiLiang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/migration.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 17a5c16c79..9b40380d7c 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1291,12 +1291,12 @@ static void migrate_params_test_apply(MigrateSetParameters *params, - - if (params->has_tls_creds) { - assert(params->tls_creds->type == QTYPE_QSTRING); -- dest->tls_creds = g_strdup(params->tls_creds->u.s); -+ dest->tls_creds = params->tls_creds->u.s; - } - - if (params->has_tls_hostname) { - assert(params->tls_hostname->type == QTYPE_QSTRING); -- dest->tls_hostname = g_strdup(params->tls_hostname->u.s); -+ dest->tls_hostname = params->tls_hostname->u.s; - } - - if (params->has_max_bandwidth) { --- -2.27.0 - diff --git a/migration-fix-multifd_send_pages-next-channel.patch b/migration-fix-multifd_send_pages-next-channel.patch deleted file mode 100644 index 4bb113c644c4175386636e02a5d7188e8c2e408c..0000000000000000000000000000000000000000 --- a/migration-fix-multifd_send_pages-next-channel.patch +++ /dev/null @@ -1,50 +0,0 @@ -From c11a23b92334ae86eddfdc2b155d404293891985 Mon Sep 17 00:00:00 2001 -From: alexchen -Date: Tue, 8 Sep 2020 11:18:50 +0000 -Subject: [PATCH 08/11] migration: fix multifd_send_pages() next channel - -multifd_send_pages() loops around the available channels, -the next channel to use between two calls to multifd_send_pages() is stored -inside a local static variable, next_channel. - -It works well, except if the number of channels decreases between two calls -to multifd_send_pages(). In this case, the loop can try to access the -data of a channel that doesn't exist anymore. - -The problem can be triggered if we start a migration with a given number of -channels and then we cancel the migration to restart it with a lower number. -This ends generally with an error like: -qemu-system-ppc64: .../util/qemu-thread-posix.c:77: qemu_mutex_lock_impl: Assertion `mutex->initialized' failed. - -This patch fixes the error by capping next_channel with the current number -of channels before using it. - -Signed-off-by: Laurent Vivier -Message-Id: <20200617113154.593233-1-lvivier@redhat.com> -Reviewed-by: Juan Quintela -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: BiaoXiang Ye ---- - migration/ram.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 83cabec6..ac033f22 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -931,6 +931,12 @@ static int multifd_send_pages(RAMState *rs) - uint64_t transferred; - - qemu_sem_wait(&multifd_send_state->channels_ready); -+ /* -+ * next_channel can remain from a previous migration that was -+ * using more channels, so ensure it doesn't overflow if the -+ * limit is lower now. -+ */ -+ next_channel %= migrate_multifd_channels(); - for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { - p = &multifd_send_state->params[i]; - --- -2.27.0.dirty - diff --git a/migration-fix-populate_vfio_info.patch b/migration-fix-populate_vfio_info.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ac94db08e51ac914f150acab64e5d6be82061ff --- /dev/null +++ b/migration-fix-populate_vfio_info.patch @@ -0,0 +1,49 @@ +From bae3be01cc25c5532806c3255dbae19393e95686 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Tue, 4 Apr 2023 20:16:33 +0800 +Subject: [PATCH] migration: fix populate_vfio_info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Include CONFIG_DEVICES so that populate_vfio_info is instantiated for +CONFIG_VFIO. Without it, the 'info migrate' command never returns +info about vfio. + +Fixes: 43bd0bf30f ("migration: Move populate_vfio_info() into a separate file") + +cheery-pick from fa76c854ae837328187bef41d80af5d1ad36681f + +Signed-off-by: jipengfei_yewu +Reviewed-by: Marc-André Lureau +Reviewed-by: Thomas Huth +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + migration/target.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/target.c b/migration/target.c +index 907ebf0a0a..00ca007f97 100644 +--- a/migration/target.c ++++ b/migration/target.c +@@ -8,6 +8,7 @@ + #include "qemu/osdep.h" + #include "qapi/qapi-types-migration.h" + #include "migration.h" ++#include CONFIG_DEVICES + + #ifdef CONFIG_VFIO + #include "hw/vfio/vfio-common.h" +@@ -17,7 +18,6 @@ void populate_vfio_info(MigrationInfo *info) + { + #ifdef CONFIG_VFIO + if (vfio_mig_active()) { +- info->has_vfio = true; + info->vfio = g_malloc0(sizeof(*info->vfio)); + info->vfio->transferred = vfio_mig_bytes_transferred(); + } +-- +2.27.0 + diff --git a/migration-multifd-Remove-unnecessary-usage-of-local-.patch b/migration-multifd-Remove-unnecessary-usage-of-local-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f7a04ee2ad226146d7020177ca9902ee519fed4 --- /dev/null +++ b/migration-multifd-Remove-unnecessary-usage-of-local-.patch @@ -0,0 +1,61 @@ +From 8046e5c70d22eba8a1ca71ba622fa8b8c74c355f Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 16 Jan 2024 17:52:03 +0800 +Subject: [PATCH] migration/multifd: Remove unnecessary usage of local Error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 3fc58efa938338a82e4d5c0c031e7e9c98e9544f + +According to Error API, usage of ERRP_GUARD() or a local Error instead +of errp is needed if errp is passed to void functions, where it is later +dereferenced to see if an error occurred. + +There are several places in multifd.c that use local Error although it +is not needed. Change these places to use errp directly. + +Signed-off-by: Avihai Horon +Reviewed-by: Philippe Mathieu-Daudé +Link: https://lore.kernel.org/r/20231231093016.14204-12-avihaih@nvidia.com +Signed-off-by: Peter Xu +Signed-off-by: qihao_yewu +--- + migration/multifd.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 0d3f66537c..4befde5cad 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -929,12 +929,10 @@ int multifd_save_setup(Error **errp) + + for (i = 0; i < thread_count; i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; +- Error *local_err = NULL; + int ret; + +- ret = multifd_send_state->ops->send_setup(p, &local_err); ++ ret = multifd_send_state->ops->send_setup(p, errp); + if (ret) { +- error_propagate(errp, local_err); + return ret; + } + } +@@ -1167,12 +1165,10 @@ int multifd_load_setup(Error **errp) + + for (i = 0; i < thread_count; i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; +- Error *local_err = NULL; + int ret; + +- ret = multifd_recv_state->ops->recv_setup(p, &local_err); ++ ret = multifd_recv_state->ops->recv_setup(p, errp); + if (ret) { +- error_propagate(errp, local_err); + return ret; + } + } +-- +2.27.0 + diff --git a/migration-multifd-clean-pages-after-filling-packet.patch b/migration-multifd-clean-pages-after-filling-packet.patch deleted file mode 100644 index 596c5244691dc0a60a486598a74e23466a62645b..0000000000000000000000000000000000000000 --- a/migration-multifd-clean-pages-after-filling-packet.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0f7e704a4faa661583ea6d82659f206e561f23d4 Mon Sep 17 00:00:00 2001 -From: Wei Yang -Date: Sat, 26 Oct 2019 07:19:59 +0800 -Subject: [PATCH 3/8] migration/multifd: clean pages after filling packet - -This is a preparation for the next patch: - - not use multifd during postcopy. - -Without enabling postcopy, everything looks good. While after enabling -postcopy, migration may fail even not use multifd during postcopy. The -reason is the pages is not properly cleared and *old* target page will -continue to be transferred. - -After clean pages, migration succeeds. - -Signed-off-by: Wei Yang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/ram.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 840e354..c2eb1ed 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -947,10 +947,10 @@ static int multifd_send_pages(RAMState *rs) - } - qemu_mutex_unlock(&p->mutex); - } -- p->pages->used = 0; -+ assert(!p->pages->used); -+ assert(!p->pages->block); - - p->packet_num = multifd_send_state->packet_num++; -- p->pages->block = NULL; - multifd_send_state->pages = p->pages; - p->pages = pages; - transferred = ((uint64_t) pages->used) * TARGET_PAGE_SIZE + p->packet_len; -@@ -1137,6 +1137,7 @@ static void *multifd_send_thread(void *opaque) - p->num_packets++; - p->num_pages += used; - p->pages->used = 0; -+ p->pages->block = NULL; - qemu_mutex_unlock(&p->mutex); - - trace_multifd_send(p->id, packet_num, used, flags, --- -1.8.3.1 - diff --git a/migration-multifd-fix-destroyed-mutex-access-in-term.patch b/migration-multifd-fix-destroyed-mutex-access-in-term.patch deleted file mode 100644 index a927ea533c253ff242c5867cde1055453668c1c5..0000000000000000000000000000000000000000 --- a/migration-multifd-fix-destroyed-mutex-access-in-term.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 34d797aa134a33c1d67ca85d9d9f996d58162276 Mon Sep 17 00:00:00 2001 -From: Jiahui Cen -Date: Wed, 23 Oct 2019 11:47:37 +0800 -Subject: [PATCH 09/10] migration/multifd: fix destroyed mutex access in - terminating multifd threads - -One multifd will lock all the other multifds' IOChannel mutex to inform them -to quit by setting p->quit or shutting down p->c. In this senario, if some -multifds had already been terminated and multifd_load_cleanup/multifd_save_cleanup -had destroyed their mutex, it could cause destroyed mutex access when trying -lock their mutex. - -Here is the coredump stack: - #0 0x00007f81a2794437 in raise () from /usr/lib64/libc.so.6 - #1 0x00007f81a2795b28 in abort () from /usr/lib64/libc.so.6 - #2 0x00007f81a278d1b6 in __assert_fail_base () from /usr/lib64/libc.so.6 - #3 0x00007f81a278d262 in __assert_fail () from /usr/lib64/libc.so.6 - #4 0x000055eb1bfadbd3 in qemu_mutex_lock_impl (mutex=0x55eb1e2d1988, file=, line=) at util/qemu-thread-posix.c:64 - #5 0x000055eb1bb4564a in multifd_send_terminate_threads (err=) at migration/ram.c:1015 - #6 0x000055eb1bb4bb7f in multifd_send_thread (opaque=0x55eb1e2d19f8) at migration/ram.c:1171 - #7 0x000055eb1bfad628 in qemu_thread_start (args=0x55eb1e170450) at util/qemu-thread-posix.c:502 - #8 0x00007f81a2b36df5 in start_thread () from /usr/lib64/libpthread.so.0 - #9 0x00007f81a286048d in clone () from /usr/lib64/libc.so.6 - -To fix it up, let's destroy the mutex after all the other multifd threads had -been terminated. - -Change-Id: I4124d43e8558ba302052bdc53fdae7cfcf9d8687 -Signed-off-by: Jiahui Cen -Signed-off-by: Ying Fang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/ram.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 029f1cdf..d7d2d5ec 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1033,6 +1033,10 @@ void multifd_save_cleanup(void) - if (p->running) { - qemu_thread_join(&p->thread); - } -+ } -+ for (i = 0; i < migrate_multifd_channels(); i++) { -+ MultiFDSendParams *p = &multifd_send_state->params[i]; -+ - socket_send_channel_destroy(p->c); - p->c = NULL; - qemu_mutex_destroy(&p->mutex); -@@ -1306,6 +1310,10 @@ int multifd_load_cleanup(Error **errp) - qemu_sem_post(&p->sem_sync); - qemu_thread_join(&p->thread); - } -+ } -+ for (i = 0; i < migrate_multifd_channels(); i++) { -+ MultiFDRecvParams *p = &multifd_recv_state->params[i]; -+ - object_unref(OBJECT(p->c)); - p->c = NULL; - qemu_mutex_destroy(&p->mutex); --- -2.19.1 diff --git a/migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch b/migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch deleted file mode 100644 index 021fbcf8a6e4053b5e051ce3885b677d678259ca..0000000000000000000000000000000000000000 --- a/migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 26ffadd08711aa4ef62932ac0ecf5048518b2801 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:50:12 +0800 -Subject: [PATCH] migration/multifd: fix hangup with TLS-Multifd due to - blocking handshake -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The qemu main loop could hang up forever when we enable TLS+Multifd. -The Src multifd_send_0 invokes tls handshake, it sends hello to sever -and wait response. -However, the Dst main qemu loop has been waiting recvmsg() for multifd_recv_1. -Both of Src and Dst main qemu loop are blocking and waiting for reponse which -results in hanging up forever. - -Src: (multifd_send_0) Dst: (multifd_recv_1) -multifd_channel_connect migration_channel_process_incoming - multifd_tls_channel_connect migration_tls_channel_process_incoming - multifd_tls_channel_connect qio_channel_tls_handshake_task - qio_channel_tls_handshake gnutls_handshake - qio_channel_tls_handshake_task ... - qcrypto_tls_session_handshake ... - gnutls_handshake ... - ... ... - recvmsg (Blocking I/O waiting for response) recvmsg (Blocking I/O waiting for response) - -Fix this by offloadinig handshake work to a background thread. - -Reported-by: Yan Jin -Suggested-by: Daniel P. Berrangé -Signed-off-by: Chuan Zheng -Message-Id: <1604643893-8223-1-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 23 +++++++++++++++++------ - 1 file changed, 17 insertions(+), 6 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index dc9831d7f3..a37dbfc049 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1220,6 +1220,19 @@ static void multifd_tls_outgoing_handshake(QIOTask *task, - multifd_channel_connect(p, ioc, err); - } - -+static void *multifd_tls_handshake_thread(void *opaque) -+{ -+ MultiFDSendParams *p = opaque; -+ QIOChannelTLS *tioc = QIO_CHANNEL_TLS(p->c); -+ -+ qio_channel_tls_handshake(tioc, -+ multifd_tls_outgoing_handshake, -+ p, -+ NULL, -+ NULL); -+ return NULL; -+} -+ - static void multifd_tls_channel_connect(MultiFDSendParams *p, - QIOChannel *ioc, - Error **errp) -@@ -1235,12 +1248,10 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, - - trace_multifd_tls_outgoing_handshake_start(ioc, tioc, hostname); - qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); -- qio_channel_tls_handshake(tioc, -- multifd_tls_outgoing_handshake, -- p, -- NULL, -- NULL); -- -+ p->c = QIO_CHANNEL(tioc); -+ qemu_thread_create(&p->thread, "multifd-tls-handshake-worker", -+ multifd_tls_handshake_thread, p, -+ QEMU_THREAD_JOINABLE); - } - - static bool multifd_channel_connect(MultiFDSendParams *p, --- -2.27.0 - diff --git a/migration-multifd-fix-nullptr-access-in-multifd_send.patch b/migration-multifd-fix-nullptr-access-in-multifd_send.patch deleted file mode 100644 index f2d278a135434e3b0838be7876b1fe2a616816cd..0000000000000000000000000000000000000000 --- a/migration-multifd-fix-nullptr-access-in-multifd_send.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 6a08ee257a95d9f2514bd995e90ddf46d3f78b41 Mon Sep 17 00:00:00 2001 -From: Zheng Chuan -Date: Tue, 21 Apr 2020 19:49:26 +0800 -Subject: [PATCH 10/10] migration/multifd: fix nullptr access in - multifd_send_terminate_threads - -If the multifd_send_threads is not created when migration is failed, -multifd_save_cleanup would be called twice. In this senario, the -multifd_send_state is accessed after it has been released, the result -is that the source VM is crashing down. - -Here is the coredump stack: - Program received signal SIGSEGV, Segmentation fault. - 0x00005629333a78ef in multifd_send_terminate_threads (err=err@entry=0x0) at migration/ram.c:1012 - 1012 MultiFDSendParams *p = &multifd_send_state->params[i]; - #0 0x00005629333a78ef in multifd_send_terminate_threads (err=err@entry=0x0) at migration/ram.c:1012 - #1 0x00005629333ab8a9 in multifd_save_cleanup () at migration/ram.c:1028 - #2 0x00005629333abaea in multifd_new_send_channel_async (task=0x562935450e70, opaque=) at migration/ram.c:1202 - #3 0x000056293373a562 in qio_task_complete (task=task@entry=0x562935450e70) at io/task.c:196 - #4 0x000056293373a6e0 in qio_task_thread_result (opaque=0x562935450e70) at io/task.c:111 - #5 0x00007f475d4d75a7 in g_idle_dispatch () from /usr/lib64/libglib-2.0.so.0 - #6 0x00007f475d4da9a9 in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 - #7 0x0000562933785b33 in glib_pollfds_poll () at util/main-loop.c:219 - #8 os_host_main_loop_wait (timeout=) at util/main-loop.c:242 - #9 main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:518 - #10 0x00005629334c5acf in main_loop () at vl.c:1810 - #11 0x000056293334d7bb in main (argc=, argv=, envp=) at vl.c:4471 - -If the multifd_send_threads is not created when migration is failed. -In this senario, we don't call multifd_save_cleanup in multifd_new_send_channel_async. - -Change-Id: I7441efe2ed542054ecd2a4da8146e2652824b452 -Signed-off-by: Zhimin Feng -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/ram.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index d7d2d5ec..1858d66c 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1205,7 +1205,15 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - - if (qio_task_propagate_error(task, &local_err)) { - migrate_set_error(migrate_get_current(), local_err); -- multifd_save_cleanup(); -+ /* Error happen, we need to tell who pay attention to me */ -+ qemu_sem_post(&multifd_send_state->channels_ready); -+ qemu_sem_post(&p->sem_sync); -+ /* -+ * Although multifd_send_thread is not created, but main migration -+ * thread neet to judge whether it is running, so we need to mark -+ * its status. -+ */ -+ p->quit = true; - } else { - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); --- -2.19.1 diff --git a/migration-multifd-fix-nullptr-access-in-terminating-m.patch b/migration-multifd-fix-nullptr-access-in-terminating-m.patch deleted file mode 100644 index d403b28f28a708a94d7799618053e53c7d75b939..0000000000000000000000000000000000000000 --- a/migration-multifd-fix-nullptr-access-in-terminating-m.patch +++ /dev/null @@ -1,75 +0,0 @@ -From d9a847f0982fcca6f63031215065c346fcc27bbc Mon Sep 17 00:00:00 2001 -From: Zheng Chuan -Date: Fri, 24 Apr 2020 11:58:33 +0800 -Subject: [PATCH 06/10] migration/multifd: fix nullptr access in terminating - multifd threads - -One multifd channel will shutdown all the other multifd's IOChannel when it -fails to receive an IOChannel. In this senario, if some multifds had not -received its IOChannel yet, it would try to shutdown its IOChannel which could -cause nullptr access at qio_channel_shutdown. - -Here is the coredump stack: - #0 object_get_class (obj=obj@entry=0x0) at qom/object.c:908 - #1 0x00005563fdbb8f4a in qio_channel_shutdown (ioc=0x0, how=QIO_CHANNEL_SHUTDOWN_BOTH, errp=0x0) at io/channel.c:355 - #2 0x00005563fd7b4c5f in multifd_recv_terminate_threads (err=) at migration/ram.c:1280 - #3 0x00005563fd7bc019 in multifd_recv_new_channel (ioc=ioc@entry=0x556400255610, errp=errp@entry=0x7ffec07dce00) at migration/ram.c:1478 - #4 0x00005563fda82177 in migration_ioc_process_incoming (ioc=ioc@entry=0x556400255610, errp=errp@entry=0x7ffec07dce30) at migration/migration.c:605 - #5 0x00005563fda8567d in migration_channel_process_incoming (ioc=0x556400255610) at migration/channel.c:44 - #6 0x00005563fda83ee0 in socket_accept_incoming_migration (listener=0x5563fff6b920, cioc=0x556400255610, opaque=) at migration/socket -.c:166 - #7 0x00005563fdbc25cd in qio_net_listener_channel_func (ioc=, condition=, opaque=) at io/net-listener.c:54 - #8 0x00007f895b6fe9a9 in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 - #9 0x00005563fdc18136 in glib_pollfds_poll () at util/main-loop.c:218 - #10 0x00005563fdc181b5 in os_host_main_loop_wait (timeout=1000000000) at util/main-loop.c:241 - #11 0x00005563fdc183a2 in main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:517 - #12 0x00005563fd8edb37 in main_loop () at vl.c:1791 - #13 0x00005563fd74fd45 in main (argc=, argv=, envp=) at vl.c:4473 - -To fix it up, let's check p->c before calling qio_channel_shutdown. - -Change-Id: Ib36c1b3d866a3ad92d1460512df840cfb8736ab6 -Signed-off-by: Jiahui Cen -Signed-off-by: Ying Fang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/ram.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 51811c2d..756a525f 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1112,6 +1112,7 @@ static void *multifd_send_thread(void *opaque) - rcu_register_thread(); - - if (multifd_send_initial_packet(p, &local_err) < 0) { -+ ret = -1; - goto out; - } - /* initial packet */ -@@ -1178,9 +1179,7 @@ out: - * who pay attention to me. - */ - if (ret != 0) { -- if (flags & MULTIFD_FLAG_SYNC) { -- qemu_sem_post(&p->sem_sync); -- } -+ qemu_sem_post(&p->sem_sync); - qemu_sem_post(&multifd_send_state->channels_ready); - } - -@@ -1279,7 +1278,9 @@ static void multifd_recv_terminate_threads(Error *err) - - normal quit, i.e. everything went fine, just finished - - error quit: We close the channels so the channel threads - finish the qio_channel_read_all_eof() */ -- qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -+ if (p->c) { -+ qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -+ } - qemu_mutex_unlock(&p->mutex); - } - } --- -2.19.1 diff --git a/migration-multifd-fix-potential-wrong-acception-orde.patch b/migration-multifd-fix-potential-wrong-acception-orde.patch deleted file mode 100644 index 6b8f18ce71abccf8987fb9261817654b3b10d631..0000000000000000000000000000000000000000 --- a/migration-multifd-fix-potential-wrong-acception-orde.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 71f3e496c128b46f803cc4776154b02a5e505cb2 Mon Sep 17 00:00:00 2001 -From: Zheng Chuan -Date: Wed, 22 Apr 2020 13:45:39 +0800 -Subject: [PATCH] migration/multifd: fix potential wrong acception order of - IOChannel - -Multifd assumes the migration thread IOChannel is always established before -the multifd IOChannels, but this assumption will be broken in many situations -like network packet loss. - -For example: -Step1: Source (migration thread IOChannel) --SYN--> Destination -Step2: Source (migration thread IOChannel) <--SYNACK Destination -Step3: Source (migration thread IOChannel, lost) --ACK-->X Destination -Step4: Source (multifd IOChannel) --SYN--> Destination -Step5: Source (multifd IOChannel) <--SYNACK Destination -Step6: Source (multifd IOChannel, ESTABLISHED) --ACK--> Destination -Step7: Destination accepts multifd IOChannel -Step8: Source (migration thread IOChannel, ESTABLISHED) -ACK,DATA-> Destination -Step9: Destination accepts migration thread IOChannel - -The above situation can be reproduced by creating a weak network environment, -such as "tc qdisc add dev eth0 root netem loss 50%". The wrong acception order -will cause magic check failure and thus lead to migration failure. - -This patch fixes this issue by sending a migration IOChannel initial packet with -a unique id when using multifd migration. Since the multifd IOChannels will also -send initial packets, the destination can judge whether the processing IOChannel -belongs to multifd by checking the id in the initial packet. This mechanism can -ensure that different IOChannels will go to correct branches in our test. - -Change-Id: I63d1c32c7b66063bd6a3c5e7d63500555bd148b9 -Signed-off-by: Jiahui Cen -Signed-off-by: Ying Fang - -diff --git a/migration/channel.c b/migration/channel.c -index 20e4c8e2..74621814 100644 ---- a/migration/channel.c -+++ b/migration/channel.c -@@ -82,6 +82,15 @@ void migration_channel_connect(MigrationState *s, - return; - } - } else { -+ if (migrate_use_multifd()) { -+ /* multifd migration cannot distinguish migration IOChannel -+ * from multifd IOChannels, so we need to send an initial packet -+ * to show it is migration IOChannel -+ */ -+ migration_send_initial_packet(ioc, -+ migrate_multifd_channels(), -+ &error); -+ } - QEMUFile *f = qemu_fopen_channel_output(ioc); - - qemu_mutex_lock(&s->qemu_file_lock); -diff --git a/migration/migration.c b/migration/migration.c -index 114c33a1..8f2fc2b4 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -517,12 +517,6 @@ static void migration_incoming_setup(QEMUFile *f) - { - MigrationIncomingState *mis = migration_incoming_get_current(); - -- if (multifd_load_setup() != 0) { -- /* We haven't been able to create multifd threads -- nothing better to do */ -- exit(EXIT_FAILURE); -- } -- - if (!mis->from_src_file) { - mis->from_src_file = f; - } -@@ -580,36 +574,41 @@ void migration_fd_process_incoming(QEMUFile *f) - void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) - { - MigrationIncomingState *mis = migration_incoming_get_current(); -- bool start_migration; -- -- if (!mis->from_src_file) { -- /* The first connection (multifd may have multiple) */ -- QEMUFile *f = qemu_fopen_channel_input(ioc); -+ Error *local_err = NULL; -+ int id = 0; - -- /* If it's a recovery, we're done */ -- if (postcopy_try_recover(f)) { -- return; -- } -+ if (migrate_use_multifd()) { -+ id = migration_recv_initial_packet(ioc, &local_err); -+ } -+ if (!migrate_use_multifd() || id == migrate_multifd_channels()) { -+ if (!mis->from_src_file) { -+ /* The migration connection (multifd may have multiple) */ -+ QEMUFile *f = qemu_fopen_channel_input(ioc); - -- migration_incoming_setup(f); -+ /* If it's a recovery, we're done */ -+ if (postcopy_try_recover(f)) { -+ return; -+ } - -- /* -- * Common migration only needs one channel, so we can start -- * right now. Multifd needs more than one channel, we wait. -- */ -- start_migration = !migrate_use_multifd(); -- } else { -- Error *local_err = NULL; -+ migration_incoming_setup(f); -+ } -+ } else if (id >= 0) { - /* Multiple connections */ - assert(migrate_use_multifd()); -- start_migration = multifd_recv_new_channel(ioc, &local_err); -+ multifd_recv_new_channel(ioc, id, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -+ } else { -+ /* Bad connections */ -+ multifd_recv_terminate_threads(local_err); -+ error_propagate(errp, local_err); -+ return; - } - -- if (start_migration) { -+ /* Once we have all the channels we need, we can start migration */ -+ if (migration_has_all_channels()) { - migration_incoming_process(); - } - } -diff --git a/migration/migration.h b/migration/migration.h -index 1fdd7b21..feb34430 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -339,4 +339,7 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); - void migration_make_urgent_request(void); - void migration_consume_urgent_request(void); - -+int migration_send_initial_packet(QIOChannel *c, uint8_t id, Error **errp); -+int migration_recv_initial_packet(QIOChannel *c, Error **errp); -+ - #endif -diff --git a/migration/ram.c b/migration/ram.c -index 756a525f..029f1cdf 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -593,7 +593,7 @@ typedef struct { - uint8_t id; - uint8_t unused1[7]; /* Reserved for future use */ - uint64_t unused2[4]; /* Reserved for future use */ --} __attribute__((packed)) MultiFDInit_t; -+} __attribute__((packed)) MigrationInit_t; - - typedef struct { - uint32_t magic; -@@ -702,26 +702,26 @@ typedef struct { - QemuSemaphore sem_sync; - } MultiFDRecvParams; - --static int multifd_send_initial_packet(MultiFDSendParams *p, Error **errp) -+int migration_send_initial_packet(QIOChannel *c, uint8_t id, Error **errp) - { -- MultiFDInit_t msg; -+ MigrationInit_t msg; - int ret; - - msg.magic = cpu_to_be32(MULTIFD_MAGIC); - msg.version = cpu_to_be32(MULTIFD_VERSION); -- msg.id = p->id; -+ msg.id = id; - memcpy(msg.uuid, &qemu_uuid.data, sizeof(msg.uuid)); - -- ret = qio_channel_write_all(p->c, (char *)&msg, sizeof(msg), errp); -+ ret = qio_channel_write_all(c, (char *)&msg, sizeof(msg), errp); - if (ret != 0) { - return -1; - } - return 0; - } - --static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) -+int migration_recv_initial_packet(QIOChannel *c, Error **errp) - { -- MultiFDInit_t msg; -+ MigrationInit_t msg; - int ret; - - ret = qio_channel_read_all(c, (char *)&msg, sizeof(msg), errp); -@@ -756,8 +756,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) - } - - if (msg.id > migrate_multifd_channels()) { -- error_setg(errp, "multifd: received channel version %d " -- "expected %d", msg.version, MULTIFD_VERSION); -+ error_setg(errp, "multifd: received channel id %d " -+ "expected [0-%d]", msg.id, migrate_multifd_channels()); - return -1; - } - -@@ -1111,7 +1111,7 @@ static void *multifd_send_thread(void *opaque) - trace_multifd_send_thread_start(p->id); - rcu_register_thread(); - -- if (multifd_send_initial_packet(p, &local_err) < 0) { -+ if (migration_send_initial_packet(p->c, p->id, &local_err) < 0) { - ret = -1; - goto out; - } -@@ -1255,7 +1255,7 @@ struct { - uint64_t packet_num; - } *multifd_recv_state; - --static void multifd_recv_terminate_threads(Error *err) -+void multifd_recv_terminate_threads(Error *err) - { - int i; - -@@ -1470,21 +1470,10 @@ bool multifd_recv_all_channels_created(void) - * - Return false and do not set @errp when correctly receiving the current one; - * - Return false and set @errp when failing to receive the current channel. - */ --bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) -+void multifd_recv_new_channel(QIOChannel *ioc, int id, Error **errp) - { - MultiFDRecvParams *p; - Error *local_err = NULL; -- int id; -- -- id = multifd_recv_initial_packet(ioc, &local_err); -- if (id < 0) { -- multifd_recv_terminate_threads(local_err); -- error_propagate_prepend(errp, local_err, -- "failed to receive packet" -- " via multifd channel %d: ", -- atomic_read(&multifd_recv_state->count)); -- return false; -- } - - p = &multifd_recv_state->params[id]; - if (p->c != NULL) { -@@ -1492,7 +1481,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) - id); - multifd_recv_terminate_threads(local_err); - error_propagate(errp, local_err); -- return false; -+ return; - } - p->c = ioc; - object_ref(OBJECT(ioc)); -@@ -1503,8 +1492,6 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) - qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, - QEMU_THREAD_JOINABLE); - atomic_inc(&multifd_recv_state->count); -- return atomic_read(&multifd_recv_state->count) == -- migrate_multifd_channels(); - } - - /** -diff --git a/migration/ram.h b/migration/ram.h -index bd0eee79..a788ff0e 100644 ---- a/migration/ram.h -+++ b/migration/ram.h -@@ -46,7 +46,8 @@ void multifd_save_cleanup(void); - int multifd_load_setup(void); - int multifd_load_cleanup(Error **errp); - bool multifd_recv_all_channels_created(void); --bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); -+void multifd_recv_new_channel(QIOChannel *ioc, int id, Error **errp); -+void multifd_recv_terminate_threads(Error *err); - - uint64_t ram_pagesize_summary(void); - int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len); -diff --git a/migration/socket.c b/migration/socket.c -index 98efdc02..093b956b 100644 ---- a/migration/socket.c -+++ b/migration/socket.c -@@ -22,6 +22,7 @@ - #include "channel.h" - #include "socket.h" - #include "migration.h" -+#include "ram.h" - #include "qemu-file.h" - #include "io/channel-socket.h" - #include "io/net-listener.h" -@@ -181,6 +182,12 @@ static void socket_start_incoming_migration(SocketAddress *saddr, - - qio_net_listener_set_name(listener, "migration-socket-listener"); - -+ if (multifd_load_setup() != 0) { -+ /* We haven't been able to create multifd threads -+ nothing better to do */ -+ exit(EXIT_FAILURE); -+ } -+ - if (qio_net_listener_open_sync(listener, saddr, errp) < 0) { - object_unref(OBJECT(listener)); - return; --- -2.23.0 diff --git a/migration-multifd-not-use-multifd-during-postcopy.patch b/migration-multifd-not-use-multifd-during-postcopy.patch deleted file mode 100644 index 6df61bfdd8d637854acea0e13e787db04dbdeca2..0000000000000000000000000000000000000000 --- a/migration-multifd-not-use-multifd-during-postcopy.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 7331554bd6ab230404b20d612aed20a95c20eba6 Mon Sep 17 00:00:00 2001 -From: Wei Yang -Date: Sat, 26 Oct 2019 07:20:00 +0800 -Subject: [PATCH 4/8] migration/multifd: not use multifd during postcopy - -We don't support multifd during postcopy, but user still could enable -both multifd and postcopy. This leads to migration failure. - -Skip multifd during postcopy. - -Signed-off-by: Wei Yang -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela ---- - migration/ram.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index c2eb1ed..aace3a5 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2571,10 +2571,13 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, - } - - /* -- * do not use multifd for compression as the first page in the new -- * block should be posted out before sending the compressed page -+ * Do not use multifd for: -+ * 1. Compression as the first page in the new block should be posted out -+ * before sending the compressed page -+ * 2. In postcopy as one whole host page should be placed - */ -- if (!save_page_use_compression(rs) && migrate_use_multifd()) { -+ if (!save_page_use_compression(rs) && migrate_use_multifd() -+ && !migration_in_postcopy()) { - return ram_save_multifd_page(rs, block, offset); - } - --- -1.8.3.1 - diff --git a/migration-ram-Do-error_free-after-migrate_set_error-.patch b/migration-ram-Do-error_free-after-migrate_set_error-.patch deleted file mode 100644 index 0039f43d86d5506bfca2953904a215d3f178526a..0000000000000000000000000000000000000000 --- a/migration-ram-Do-error_free-after-migrate_set_error-.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 05d1fbd2390d441e5acb606dba3d308d506a8eb1 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Tue, 5 May 2020 11:44:20 +0800 -Subject: [PATCH 1/3] migration/ram: Do error_free after migrate_set_error to - avoid memleaks - -If local_err is not NULL, it use error_copy to set migrate error in -multifd_send_terminate_threads. Thus, we should free it. - -Similarly, fix another leak in multifd_recv_thread. - -The leak stack: -Direct leak of 96 byte(s) in 2 object(s) allocated from: - #0 0xfffdd97fe938 in __interceptor_calloc (/lib64/libasan.so.4+0xee938) - #1 0xfffdd85a8bb0 in g_malloc0 (/lib64/libglib-2.0.so.0+0x58bb0) - #2 0xaaadfc6e41c4 in error_setv util/error.c:61 - #3 0xaaadfc6e4880 in error_setg_errno_internal util/error.c:109 - #4 0xaaadfc6192a8 in qio_channel_socket_writev io/channel-socket.c:552 - #5 0xaaadfc614604 in qio_channel_writev_all io/channel.c:171 - #6 0xaaadfc6147ec in qio_channel_write_all io/channel.c:257 - #7 0xaaadfbaec5fc in multifd_send_thread /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1145 - #8 0xaaadfc6db768 in qemu_thread_start util/qemu-thread-posix.c:502 - #9 0xfffdd79a88c8 (/lib64/libpthread.so.0+0x88c8) - #10 0xfffdd78e9578 (/lib64/libc.so.6+0xd9578) - -Indirect leak of 104 byte(s) in 2 object(s) allocated from: - #0 0xfffdd97feb40 in realloc (/lib64/libasan.so.4+0xeeb40) - #1 0xfffdd78fa6e0 in __vasprintf_chk (/lib64/libc.so.6+0xea6e0) - #2 0xfffdd85ee710 in g_vasprintf (/lib64/libglib-2.0.so.0+0x9e710) - #3 0xfffdd85c45c4 in g_strdup_vprintf (/lib64/libglib-2.0.so.0+0x745c4) - #4 0xfffdd85c4674 in g_strdup_printf (/lib64/libglib-2.0.so.0+0x74674) - #5 0xaaadfc6e4214 in error_setv util/error.c:65 - #6 0xaaadfc6e4880 in error_setg_errno_internal util/error.c:109 - #7 0xaaadfc6192a8 in qio_channel_socket_writev io/channel-socket.c:552 - #8 0xaaadfc614604 in qio_channel_writev_all io/channel.c:171 - #9 0xaaadfc6147ec in qio_channel_write_all io/channel.c:257 - #10 0xaaadfbaec5fc in multifd_send_thread /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1145 - #11 0xaaadfc6db768 in qemu_thread_start util/qemu-thread-posix.c:502 - #12 0xfffdd79a88c8 (/lib64/libpthread.so.0+0x88c8) - #13 0xfffdd78e9578 (/lib64/libc.so.6+0xd9578) - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - migration/ram.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 1858d66c..6baf1412 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1176,6 +1176,7 @@ static void *multifd_send_thread(void *opaque) - out: - if (local_err) { - multifd_send_terminate_threads(local_err); -+ error_free(local_err); - } - - /* -@@ -1427,6 +1428,7 @@ static void *multifd_recv_thread(void *opaque) - - if (local_err) { - multifd_recv_terminate_threads(local_err); -+ error_free(local_err); - } - qemu_mutex_lock(&p->mutex); - p->running = false; --- -2.23.0 diff --git a/migration-ram-Fix-error-handling-in-ram_write_tracki.patch b/migration-ram-Fix-error-handling-in-ram_write_tracki.patch new file mode 100644 index 0000000000000000000000000000000000000000..73664338daf96c29244651ec53955a20ed628241 --- /dev/null +++ b/migration-ram-Fix-error-handling-in-ram_write_tracki.patch @@ -0,0 +1,50 @@ +From 93fc70a80b9734301472bb827cf3685366bfeb19 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Fri, 28 Jul 2023 10:39:55 +0800 +Subject: [PATCH] migration/ram: Fix error handling in + ram_write_tracking_start() + +cherry picked from commit 72ef3a370836aa07261ad7aaeea27ed5cbcee342 + +If something goes wrong during uffd_change_protection(), we would miss +to unregister uffd-wp and not release our reference. Fix it by +performing the uffd_change_protection(true) last. + +Note that a uffd_change_protection(false) on the recovery path without a +prior uffd_change_protection(false) is fine. + +Fixes: 278e2f551a09 ("migration: support UFFD write fault processing in ram_save_iterate()") +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Signed-off-by: David Hildenbrand +Signed-off-by: Juan Quintela +Signed-off-by: qihao_yewu +--- + migration/ram.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 12b8c653d8..f422fd0bc2 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2140,13 +2140,14 @@ int ram_write_tracking_start(void) + block->max_length, UFFDIO_REGISTER_MODE_WP, NULL)) { + goto fail; + } ++ block->flags |= RAM_UF_WRITEPROTECT; ++ memory_region_ref(block->mr); ++ + /* Apply UFFD write protection to the block memory range */ + if (uffd_change_protection(rs->uffdio_fd, block->host, + block->max_length, true, false)) { + goto fail; + } +- block->flags |= RAM_UF_WRITEPROTECT; +- memory_region_ref(block->mr); + + trace_ram_write_tracking_ramblock_start(block->idstr, block->page_size, + block->host, block->max_length); +-- +2.41.0.windows.1 + diff --git a/migration-ram-Fix-populate_read_range.patch b/migration-ram-Fix-populate_read_range.patch new file mode 100644 index 0000000000000000000000000000000000000000..97e1488d65881a7d9422cbda96699abffae37a37 --- /dev/null +++ b/migration-ram-Fix-populate_read_range.patch @@ -0,0 +1,46 @@ +From 069ad2e6d5ce48c96519ff55ace2ca2bcdac94d5 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 27 Jul 2023 13:26:21 +0800 +Subject: [PATCH] migration/ram: Fix populate_read_range() + +cheery-pick from 5f19a4491941fdc5c5b50ce4ade6ffffe0f591b4 + +Unfortunately, commit f7b9dcfbcf44 broke populate_read_range(): the loop +end condition is very wrong, resulting in that function not populating the +full range. Lets' fix that. + +Fixes: f7b9dcfbcf44 ("migration/ram: Factor out populating pages readable in ram_block_populate_pages()") +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Signed-off-by: David Hildenbrand +Signed-off-by: Juan Quintela +Signed-off-by: qihao_yewu +--- + migration/ram.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 12b8c653d8..444b6a7aa2 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2020,13 +2020,15 @@ out: + static inline void populate_read_range(RAMBlock *block, ram_addr_t offset, + ram_addr_t size) + { ++ const ram_addr_t end = offset + size; ++ + /* + * We read one byte of each page; this will preallocate page tables if + * required and populate the shared zeropage on MAP_PRIVATE anonymous memory + * where no page was populated yet. This might require adaption when + * supporting other mappings, like shmem. + */ +- for (; offset < size; offset += block->page_size) { ++ for (; offset < end; offset += block->page_size) { + char tmp = *((char *)block->host + offset); + + /* Don't optimize the read out */ +-- +2.41.0.windows.1 + diff --git a/migration-ram-Optimize-ram_save_host_page.patch b/migration-ram-Optimize-ram_save_host_page.patch deleted file mode 100644 index c58a6dcb6a5f3dc85be056f1c6ffd3a0bf3ba972..0000000000000000000000000000000000000000 --- a/migration-ram-Optimize-ram_save_host_page.patch +++ /dev/null @@ -1,95 +0,0 @@ -From ae1a8506aa45266f2bf77a8d428f5ccd970a9b13 Mon Sep 17 00:00:00 2001 -From: Kunkun Jiang -Date: Tue, 16 Mar 2021 20:57:16 +0800 -Subject: [PATCH] migration/ram: Optimize ram_save_host_page() - -Starting from pss->page, ram_save_host_page() will check every page -and send the dirty pages up to the end of the current host page or -the boundary of used_length of the block. If the host page size is -a huge page, the step "check" will take a lot of time. - -It will improve performance to use migration_bitmap_find_dirty(). - -Tested on Kunpeng 920; VM parameters: 1U 4G (page size 1G) -The time of ram_save_host_page() in the last round of ram saving: -before optimize: 9250us after optimize: 34us - -Signed-off-by: Keqian Zhu -Signed-off-by: Kunkun Jiang -Reviewed-by: Peter Xu -Message-Id: <20210316125716.1243-3-jiangkunkun@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 43 +++++++++++++++++++++---------------------- - 1 file changed, 21 insertions(+), 22 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 22063e00b4..1bd99ff9e5 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -3052,6 +3052,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - int tmppages, pages = 0; - size_t pagesize_bits = - qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; -+ unsigned long hostpage_boundary = -+ QEMU_ALIGN_UP(pss->page + 1, pagesize_bits); - - if (ramblock_is_ignored(pss->block)) { - error_report("block %s should not be migrated !", pss->block->idstr); -@@ -3060,34 +3062,31 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - - do { - /* Check the pages is dirty and if it is send it */ -- if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { -- pss->page++; -- continue; -- } -- -- tmppages = ram_save_target_page(rs, pss, last_stage); -- if (tmppages < 0) { -- return tmppages; -- } -+ if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { -+ tmppages = ram_save_target_page(rs, pss, last_stage); -+ if (tmppages < 0) { -+ return tmppages; -+ } - -- pages += tmppages; -- if (pss->block->unsentmap) { -- clear_bit(pss->page, pss->block->unsentmap); -- } -+ pages += tmppages; -+ if (pss->block->unsentmap) { -+ clear_bit(pss->page, pss->block->unsentmap); -+ } - -- pss->page++; -- /* -- * Allow rate limiting to happen in the middle of huge pages if -- * something is sent in the current iteration. -- */ -- if (pagesize_bits > 1 && tmppages > 0) { -- migration_rate_limit(); -+ /* -+ * Allow rate limiting to happen in the middle of huge pages if -+ * something is sent in the current iteration. -+ */ -+ if (pagesize_bits > 1 && tmppages > 0) { -+ migration_rate_limit(); -+ } - } -+ pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page); - } while ((pss->page & (pagesize_bits - 1)) && - offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); - -- /* The offset we leave with is the last one we looked at */ -- pss->page--; -+ /* The offset we leave with is the min boundary of host page and block */ -+ pss->page = MIN(pss->page, hostpage_boundary) - 1; - return pages; - } - --- -2.27.0 - diff --git a/migration-ram-Reduce-unnecessary-rate-limiting.patch b/migration-ram-Reduce-unnecessary-rate-limiting.patch deleted file mode 100644 index 64374dd3e255224e650c8de3e93669db04a6c413..0000000000000000000000000000000000000000 --- a/migration-ram-Reduce-unnecessary-rate-limiting.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 338d691c985ad5b3624ef36e4beaac82982c8f0a Mon Sep 17 00:00:00 2001 -From: Kunkun Jiang -Date: Tue, 16 Mar 2021 20:57:15 +0800 -Subject: [PATCH] migration/ram: Reduce unnecessary rate limiting - -When the host page is a huge page and something is sent in the -current iteration, migration_rate_limit() should be executed. -If not, it can be omitted. - -Signed-off-by: Keqian Zhu -Signed-off-by: Kunkun Jiang -Reviewed-by: David Edmondson -Reviewed-by: Dr. David Alan Gilbert -Message-Id: <20210316125716.1243-2-jiangkunkun@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 2077ba5be4..22063e00b4 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -3076,8 +3076,13 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - } - - pss->page++; -- /* Allow rate limiting to happen in the middle of huge pages */ -- migration_rate_limit(); -+ /* -+ * Allow rate limiting to happen in the middle of huge pages if -+ * something is sent in the current iteration. -+ */ -+ if (pagesize_bits > 1 && tmppages > 0) { -+ migration_rate_limit(); -+ } - } while ((pss->page & (pagesize_bits - 1)) && - offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); - --- -2.27.0 - diff --git a/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch b/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch deleted file mode 100644 index f9cb2bf652b90968144c673fd6c59655acfd785f..0000000000000000000000000000000000000000 --- a/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 4d456b243a41a8e91535b2820fd6ed4f6fb4a194 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Tue, 5 May 2020 15:50:54 +0800 -Subject: [PATCH 2/3] migration/ram: fix memleaks in - multifd_new_send_channel_async - -When error happen in multifd_new_send_channel_async, 'sioc' will not be used -to create the multifd_send_thread. Let's free it to avoid a memleak. And also -do error_free after migrate_set_error() to avoid another leak in the same place. - -The leak stack: -Direct leak of 2160 byte(s) in 6 object(s) allocated from: - #0 0xfffdd97fe754 in malloc (/lib64/libasan.so.4+0xee754) - #1 0xfffdd85a8b48 in g_malloc (/lib64/libglib-2.0.so.0+0x58b48) - #2 0xaaadfc4e2b10 in object_new_with_type qom/object.c:634 - #3 0xaaadfc619468 in qio_channel_socket_new io/channel-socket.c:56 - #4 0xaaadfc3d3e74 in socket_send_channel_create migration/socket.c:37 - #5 0xaaadfbaed6f4 in multifd_save_setup /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1255 - #6 0xaaadfc3d2f78 in migrate_fd_connect migration/migration.c:3359 - #7 0xaaadfc3d6240 in migration_channel_connect migration/channel.c:101 - #8 0xaaadfc3d3590 in socket_outgoing_migration migration/socket.c:108 - #9 0xaaadfc625a64 in qio_task_complete io/task.c:195 - #10 0xaaadfc625ed0 in qio_task_thread_result io/task.c:111 - #11 0xfffdd859edec (/lib64/libglib-2.0.so.0+0x4edec) - #12 0xfffdd85a2a78 in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x52a78) - #13 0xaaadfc6d3b84 in glib_pollfds_poll util/main-loop.c:218 - #14 0xaaadfc6d3b84 in os_host_main_loop_wait util/main-loop.c:241 - #15 0xaaadfc6d3b84 in main_loop_wait util/main-loop.c:517 - #16 0xaaadfbf9206c in main_loop /usr/src/debug/qemu-4.1.0-4_asan.aarch64/vl.c:1791 - #17 0xaaadfba1b124 in main /usr/src/debug/qemu-4.1.0-4_asan.aarch64/vl.c:4473 - #18 0xfffdd7833f5c in __libc_start_main (/lib64/libc.so.6+0x23f5c) - #19 0xaaadfba26360 (/usr/libexec/qemu-kvm+0x886360) - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - migration/ram.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 6baf1412..840e3548 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1215,6 +1215,8 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - * its status. - */ - p->quit = true; -+ object_unref(OBJECT(sioc)); -+ error_free(local_err); - } else { - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); --- -2.23.0 diff --git a/migration-ram-fix-use-after-free-of-local_err.patch b/migration-ram-fix-use-after-free-of-local_err.patch deleted file mode 100644 index f74e3b18df98ae0e5a88ff9224fa06c8ea24197a..0000000000000000000000000000000000000000 --- a/migration-ram-fix-use-after-free-of-local_err.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 019526f7f7b42a7d1b8a74e1db6a8050adf9e1fb Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 24 Mar 2020 18:36:29 +0300 -Subject: [PATCH 08/14] migration/ram: fix use after free of local_err - -local_err is used again in migration_bitmap_sync_precopy() after -precopy_notify(), so we must zero it. Otherwise try to set -non-NULL local_err will crash. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200324153630.11882-6-vsementsov@virtuozzo.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Peng Liang ---- - migration/ram.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 840e35480b04..5d1ae7570018 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1912,6 +1912,7 @@ static void migration_bitmap_sync_precopy(RAMState *rs) - */ - if (precopy_notify(PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC, &local_err)) { - error_report_err(local_err); -+ local_err = NULL; - } - - migration_bitmap_sync(rs); --- -2.26.2 - diff --git a/migration-rdma-cleanup-rdma-context-before-g_free-to.patch b/migration-rdma-cleanup-rdma-context-before-g_free-to.patch deleted file mode 100644 index a39894ada540a713645b0735b719eb4d5a3edbff..0000000000000000000000000000000000000000 --- a/migration-rdma-cleanup-rdma-context-before-g_free-to.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 9867dc6fc3f131324b73664b9617376270d8d013 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Fri, 8 May 2020 06:07:55 -0400 -Subject: [PATCH 4/5] migration/rdma: cleanup rdma context before g_free to - avoid memleaks - -When error happen in initializing 'rdma_return_path', we should cleanup rdma context -before g_free(rdma) to avoid some memleaks. This patch fix that. - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Message-Id: <20200508100755.7875-3-pannengyuan@huawei.com> -Reviewed-by: Juan Quintela -Signed-off-by: Dr. David Alan Gilbert ---- - migration/rdma.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/migration/rdma.c b/migration/rdma.c -index 3036221e..bb24dac5 100644 ---- a/migration/rdma.c -+++ b/migration/rdma.c -@@ -4103,20 +4103,20 @@ void rdma_start_outgoing_migration(void *opaque, - rdma_return_path = qemu_rdma_data_init(host_port, errp); - - if (rdma_return_path == NULL) { -- goto err; -+ goto return_path_err; - } - - ret = qemu_rdma_source_init(rdma_return_path, - s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); - - if (ret) { -- goto err; -+ goto return_path_err; - } - - ret = qemu_rdma_connect(rdma_return_path, errp); - - if (ret) { -- goto err; -+ goto return_path_err; - } - - rdma->return_path = rdma_return_path; -@@ -4129,6 +4129,8 @@ void rdma_start_outgoing_migration(void *opaque, - s->to_dst_file = qemu_fopen_rdma(rdma, "wb"); - migrate_fd_connect(s, NULL); - return; -+return_path_err: -+ qemu_rdma_cleanup(rdma); - err: - g_free(rdma); - g_free(rdma_return_path); --- -2.23.0 - diff --git a/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch b/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch deleted file mode 100644 index 5e0fb101d827377551a7858f225cf365367e12b7..0000000000000000000000000000000000000000 --- a/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 8ae2e3b8be812bcbdeb6151c685026bcaedd4a4b Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Sat, 9 May 2020 15:25:42 +0800 -Subject: [PATCH 3/3] migration/rdma: fix a memleak on error path in - rdma_start_incoming_migration - -'rdma->host' is malloced in qemu_rdma_data_init, but forgot to free on the error -path in rdma_start_incoming_migration(), this patch fix that. - -Direct leak of 2 byte(s) in 1 object(s) allocated from: - #0 0xfffce56d34fb in __interceptor_malloc (/lib64/libasan.so.4+0xd34fb) - #1 0xfffce5158aa3 in g_malloc (/lib64/libglib-2.0.so.0+0x58aa3) - #2 0xfffce5174213 in g_strdup (/lib64/libglib-2.0.so.0+0x74213) - #3 0xaaad7c569ddf in qemu_rdma_data_init /Images/qemu/migration/rdma.c:2647 - #4 0xaaad7c57c99f in rdma_start_incoming_migration /Images/qemu/migration/rdma.c:4020 - #5 0xaaad7c52b35f in qemu_start_incoming_migration /Images/qemu/migration/migration.c:371 - #6 0xaaad7be173bf in qemu_init /Images/qemu/softmmu/vl.c:4464 - #7 0xaaad7bb29843 in main /Images/qemu/softmmu/main.c:48 - #8 0xfffce3713f5f in __libc_start_main (/lib64/libc.so.6+0x23f5f) - #9 0xaaad7bb2bf73 (/Images/qemu/build/aarch64-softmmu/qemu-system-aarch64+0x8fbf73) - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - migration/rdma.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/migration/rdma.c b/migration/rdma.c -index 3036221e..b5fdb6a7 100644 ---- a/migration/rdma.c -+++ b/migration/rdma.c -@@ -4068,6 +4068,9 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) - return; - err: - error_propagate(errp, local_err); -+ if (rdma) { -+ g_free(rdma->host); -+ } - g_free(rdma); - g_free(rdma_return_path); - } --- -2.23.0 diff --git a/migration-rdma-zore-out-head.repeat-to-make-the-erro.patch b/migration-rdma-zore-out-head.repeat-to-make-the-erro.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6a630aea9df6ff570ba8c35e1050279a8ae0b92 --- /dev/null +++ b/migration-rdma-zore-out-head.repeat-to-make-the-erro.patch @@ -0,0 +1,43 @@ +From e65dfad1fd7832fc206f3a22479169fcb4527317 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 9 Oct 2023 18:11:54 +0800 +Subject: [PATCH] migration/rdma: zore out head.repeat to make the error more + clear + +cheery-pick from 2ada4b63f1764d13a2b9ca9cbeb5feda46ab6851 + +Previously, we got a confusion error that complains +the RDMAControlHeader.repeat: +qemu-system-x86_64: rdma: Too many requests in this message (3638950032).Bailing. + +Actually, it's caused by an unexpected RDMAControlHeader.type. +After this patch, error will become: +qemu-system-x86_64: Unknown control message QEMU FILE + +Reviewed-by: Fabiano Rosas +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Signed-off-by: Li Zhijian +Signed-off-by: Juan Quintela +Message-ID: <20230926100103.201564-2-lizhijian@fujitsu.com> +Signed-off-by: qihao_yewu +--- + migration/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/rdma.c b/migration/rdma.c +index f5d3bbe7e9..60c856dd2f 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -2866,7 +2866,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, + size_t remaining = iov[i].iov_len; + uint8_t * data = (void *)iov[i].iov_base; + while (remaining) { +- RDMAControlHeader head; ++ RDMAControlHeader head = {}; + + len = MIN(remaining, RDMA_SEND_INCREMENT); + remaining -= len; +-- +2.41.0.windows.1 + diff --git a/migration-register_savevm_live-doesn-t-need-dev.patch b/migration-register_savevm_live-doesn-t-need-dev.patch deleted file mode 100644 index a980deccbcac98d709a35e62f41c7d52e39b0d11..0000000000000000000000000000000000000000 --- a/migration-register_savevm_live-doesn-t-need-dev.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 0f7cde69416f85ec3d3f57769ae38db3d72fda8c Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 22 Aug 2019 12:54:33 +0100 -Subject: [PATCH] migration: register_savevm_live doesn't need dev - -Commit 78dd48df3 removed the last caller of register_savevm_live for an -instantiable device (rather than a single system wide device); -so trim out the parameter. - -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20190822115433.12070-1-dgilbert@redhat.com> -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Cornelia Huck -Signed-off-by: Dr. David Alan Gilbert ---- - docs/devel/migration.rst | 3 +-- - hw/ppc/spapr.c | 2 +- - hw/s390x/s390-skeys.c | 2 +- - hw/s390x/s390-stattrib.c | 2 +- - hw/s390x/tod.c | 2 +- - include/migration/register.h | 3 +-- - migration/block-dirty-bitmap.c | 2 +- - migration/block.c | 2 +- - migration/ram.c | 2 +- - migration/savevm.c | 23 +---------------------- - net/slirp.c | 2 +- - 11 files changed, 11 insertions(+), 34 deletions(-) - -diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst -index 220059679a..cc6f839fce 100644 ---- a/docs/devel/migration.rst -+++ b/docs/devel/migration.rst -@@ -183,8 +183,7 @@ another to load the state back. - - .. code:: c - -- int register_savevm_live(DeviceState *dev, -- const char *idstr, -+ int register_savevm_live(const char *idstr, - int instance_id, - int version_id, - SaveVMHandlers *ops, -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index b0f37c34a4..289967c3de 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3069,7 +3069,7 @@ static void spapr_machine_init(MachineState *machine) - * interface, this is a legacy from the sPAPREnvironment structure - * which predated MachineState but had a similar function */ - vmstate_register(NULL, 0, &vmstate_spapr, spapr); -- register_savevm_live(NULL, "spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, -+ register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, - &savevm_htab_handlers, spapr); - - qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine), -diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c -index e5bd92c0c7..fb7d57865d 100644 ---- a/hw/s390x/s390-skeys.c -+++ b/hw/s390x/s390-skeys.c -@@ -388,7 +388,7 @@ static inline void s390_skeys_set_migration_enabled(Object *obj, bool value, - ss->migration_enabled = value; - - if (ss->migration_enabled) { -- register_savevm_live(NULL, TYPE_S390_SKEYS, 0, 1, -+ register_savevm_live(TYPE_S390_SKEYS, 0, 1, - &savevm_s390_storage_keys, ss); - } else { - unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss); -diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c -index 766f2015a4..5ee15d5e82 100644 ---- a/hw/s390x/s390-stattrib.c -+++ b/hw/s390x/s390-stattrib.c -@@ -382,7 +382,7 @@ static void s390_stattrib_instance_init(Object *obj) - { - S390StAttribState *sas = S390_STATTRIB(obj); - -- register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0, -+ register_savevm_live(TYPE_S390_STATTRIB, 0, 0, - &savevm_s390_stattrib_handlers, sas); - - object_property_add_bool(obj, "migration-enabled", -diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c -index a9fca8eb0b..d6b22bb966 100644 ---- a/hw/s390x/tod.c -+++ b/hw/s390x/tod.c -@@ -100,7 +100,7 @@ static void s390_tod_realize(DeviceState *dev, Error **errp) - S390TODState *td = S390_TOD(dev); - - /* Legacy migration interface */ -- register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td); -+ register_savevm_live("todclock", 0, 1, &savevm_tod, td); - } - - static void s390_tod_class_init(ObjectClass *oc, void *data) -diff --git a/include/migration/register.h b/include/migration/register.h -index 8b2bc5b129..f3ba10b6ef 100644 ---- a/include/migration/register.h -+++ b/include/migration/register.h -@@ -68,8 +68,7 @@ typedef struct SaveVMHandlers { - int (*resume_prepare)(MigrationState *s, void *opaque); - } SaveVMHandlers; - --int register_savevm_live(DeviceState *dev, -- const char *idstr, -+int register_savevm_live(const char *idstr, - uint32_t instance_id, - int version_id, - const SaveVMHandlers *ops, -diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c -index 4a896a09eb..11e8feb595 100644 ---- a/migration/block-dirty-bitmap.c -+++ b/migration/block-dirty-bitmap.c -@@ -733,7 +733,7 @@ void dirty_bitmap_mig_init(void) - { - QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list); - -- register_savevm_live(NULL, "dirty-bitmap", 0, 1, -+ register_savevm_live("dirty-bitmap", 0, 1, - &savevm_dirty_bitmap_handlers, - &dirty_bitmap_mig_state); - } -diff --git a/migration/block.c b/migration/block.c -index 91f98ef44a..ec15d1d6b3 100644 ---- a/migration/block.c -+++ b/migration/block.c -@@ -1030,6 +1030,6 @@ void blk_mig_init(void) - QSIMPLEQ_INIT(&block_mig_state.blk_list); - qemu_mutex_init(&block_mig_state.lock); - -- register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers, -+ register_savevm_live("block", 0, 1, &savevm_block_handlers, - &block_mig_state); - } -diff --git a/migration/ram.c b/migration/ram.c -index d6657a8093..2077ba5be4 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -5125,5 +5125,5 @@ static SaveVMHandlers savevm_ram_handlers = { - void ram_mig_init(void) - { - qemu_mutex_init(&XBZRLE.lock); -- register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, &ram_state); -+ register_savevm_live("ram", 0, 4, &savevm_ram_handlers, &ram_state); - } -diff --git a/migration/savevm.c b/migration/savevm.c -index f0974380e5..cdb79222a4 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -683,8 +683,7 @@ static void savevm_state_handler_insert(SaveStateEntry *nse) - of the system, so instance_id should be removed/replaced. - Meanwhile pass -1 as instance_id if you do not already have a clearly - distinguishing id for all instances of your device class. */ --int register_savevm_live(DeviceState *dev, -- const char *idstr, -+int register_savevm_live(const char *idstr, - uint32_t instance_id, - int version_id, - const SaveVMHandlers *ops, -@@ -703,26 +702,6 @@ int register_savevm_live(DeviceState *dev, - se->is_ram = 1; - } - -- if (dev) { -- char *id = qdev_get_dev_path(dev); -- if (id) { -- if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >= -- sizeof(se->idstr)) { -- error_report("Path too long for VMState (%s)", id); -- g_free(id); -- g_free(se); -- -- return -1; -- } -- g_free(id); -- -- se->compat = g_new0(CompatEntry, 1); -- pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr); -- se->compat->instance_id = instance_id == -1 ? -- calculate_compat_instance_id(idstr) : instance_id; -- instance_id = -1; -- } -- } - pstrcat(se->idstr, sizeof(se->idstr), idstr); - - if (instance_id == VMSTATE_INSTANCE_ID_ANY) { -diff --git a/net/slirp.c b/net/slirp.c -index b34cb29276..f42f496641 100644 ---- a/net/slirp.c -+++ b/net/slirp.c -@@ -576,7 +576,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, - * specific version? - */ - g_assert(slirp_state_version() == 4); -- register_savevm_live(NULL, "slirp", 0, slirp_state_version(), -+ register_savevm_live("slirp", 0, slirp_state_version(), - &savevm_slirp_state, s->slirp); - - s->poll_notifier.notify = net_slirp_poll_notify; --- -2.27.0 - diff --git a/migration-report-compress-thread-pid-to-libvirt.patch b/migration-report-compress-thread-pid-to-libvirt.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d1194734acb3e5f0b704e5eb10006f20ffd9be8 --- /dev/null +++ b/migration-report-compress-thread-pid-to-libvirt.patch @@ -0,0 +1,54 @@ +From 16c188d246f8d74f3d25098effdb836cdeb17e16 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Sat, 1 Jul 2023 13:08:53 +0800 +Subject: [PATCH] migration: report compress thread pid to libvirt + +Supports migrating compressed threads bound to physical cores,qemu need to tell libvirt the compress thread pids. + +Signed-off-by:jipengfei +--- + migration/ram.c | 3 +++ + qapi/migration.json | 13 +++++++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index c3484ee1a9..c6c59b54d9 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -755,6 +755,9 @@ static void *do_data_compress(void *opaque) + RAMBlock *block; + bool zero_page; + ++ /* report compress thread pids to libvirt */ ++ qapi_event_send_migration_compress_pid(qemu_get_thread_id()); ++ + qemu_mutex_lock(¶m->mutex); + while (!param->quit) { + if (param->block) { +diff --git a/qapi/migration.json b/qapi/migration.json +index 8e18fd30e4..e965f4329b 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -1308,6 +1308,19 @@ + { 'event': 'MIGRATION_PID', + 'data': { 'pid': 'int' } } + ++## ++# @MIGRATION_COMPRESS_PID: ++# ++# Emitted when compress thread appear ++# ++# @pid: pid of compress thread ++# ++# Since: 6.2 ++## ++{ 'event': 'MIGRATION_COMPRESS_PID', ++ 'data': { 'pid': 'int' } } ++ ++ + ## + # @COLOMessage: + # +-- +2.41.0.windows.1 + diff --git a/migration-report-migration-related-thread-pid-to-lib.patch b/migration-report-migration-related-thread-pid-to-lib.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea9a6b58f2292393d92b77d140324c34ff495c9d --- /dev/null +++ b/migration-report-migration-related-thread-pid-to-lib.patch @@ -0,0 +1,54 @@ +From f8bc91f17630ddf9272fba600f4452a3871b3fec Mon Sep 17 00:00:00 2001 +From: zhengchuan +Date: Mon, 5 Dec 2022 20:52:25 +0800 +Subject: [PATCH 4/5] migration: report migration related thread pid to libvirt + +in order to control migration thread cgroup, +we need to report migration related thread pid to libvirt + +Signed-off-by:zhengchuan +--- + migration/migration.c | 3 +++ + qapi/migration.json | 12 ++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/migration/migration.c b/migration/migration.c +index f86dd8cccd..33d5832e47 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -3823,6 +3823,9 @@ static void *migration_thread(void *opaque) + MigThrError thr_error; + bool urgent = false; + ++ /* report migration thread pid to libvirt */ ++ qapi_event_send_migration_pid(qemu_get_thread_id()); ++ + rcu_register_thread(); + + object_ref(OBJECT(s)); +diff --git a/qapi/migration.json b/qapi/migration.json +index fee266017d..48e3d36d39 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -1284,6 +1284,18 @@ + { 'event': 'MIGRATION_PASS', + 'data': { 'pass': 'int' } } + ++## ++# @MIGRATION_PID: ++# ++# Emitted when migration thread appear ++# ++# @pid: pid of migration thread ++# ++# Since: EulerOS Virtual ++## ++{ 'event': 'MIGRATION_PID', ++ 'data': { 'pid': 'int' } } ++ + ## + # @COLOMessage: + # +-- +2.27.0 + diff --git a/migration-report-multiFd-related-thread-pid-to-libvi.patch b/migration-report-multiFd-related-thread-pid-to-libvi.patch new file mode 100644 index 0000000000000000000000000000000000000000..35b451db7464768c064f4f15f58104bd2b3b1e9c --- /dev/null +++ b/migration-report-multiFd-related-thread-pid-to-libvi.patch @@ -0,0 +1,62 @@ +From 5bc58d9cecbcb56c2494ea4aee7cd8a4a988b403 Mon Sep 17 00:00:00 2001 +From: zhengchuan +Date: Mon, 5 Dec 2022 20:56:35 +0800 +Subject: [PATCH 5/5] migration: report multiFd related thread pid to libvirt + +report multiFd related thread pid to libvirt in order to +pin multiFd thread to different cpu. + +Signed-off-by:zhengchuan +--- + migration/multifd.c | 4 ++++ + qapi/migration.json | 12 ++++++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 7c9deb1921..0d3f66537c 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -17,6 +17,7 @@ + #include "exec/ramblock.h" + #include "qemu/error-report.h" + #include "qapi/error.h" ++#include "qapi/qapi-events-migration.h" + #include "ram.h" + #include "migration.h" + #include "socket.h" +@@ -629,6 +630,9 @@ static void *multifd_send_thread(void *opaque) + int ret = 0; + uint32_t flags = 0; + ++ /* report multifd thread pid to libvirt */ ++ qapi_event_send_migration_multifd_pid(qemu_get_thread_id()); ++ + trace_multifd_send_thread_start(p->id); + rcu_register_thread(); + +diff --git a/qapi/migration.json b/qapi/migration.json +index 48e3d36d39..8e18fd30e4 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -1284,6 +1284,18 @@ + { 'event': 'MIGRATION_PASS', + 'data': { 'pass': 'int' } } + ++## ++# @MIGRATION_MULTIFD_PID: ++# ++# Emitted when multifd thread appear ++# ++# @pid: pid of multifd thread ++# ++# Since: EulerOS Virtual ++## ++{ 'event': 'MIGRATION_MULTIFD_PID', ++ 'data': { 'pid': 'int' } } ++ + ## + # @MIGRATION_PID: + # +-- +2.27.0 + diff --git a/migration-savevm-release-gslist-after-dump_vmstate_j.patch b/migration-savevm-release-gslist-after-dump_vmstate_j.patch deleted file mode 100644 index d5ec9b881005dc21ec927a9f4b37f57999c89c1f..0000000000000000000000000000000000000000 --- a/migration-savevm-release-gslist-after-dump_vmstate_j.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0d8c145e986d4f500f065d2d8645e95175324e62 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Wed, 19 Feb 2020 17:47:05 +0800 -Subject: [PATCH 8/9] migration/savevm: release gslist after dump_vmstate_json - -'list' forgot to free at the end of dump_vmstate_json_to_file(), although it's called only once, but seems like a clean code. - -Fix the leak as follow: -Direct leak of 16 byte(s) in 1 object(s) allocated from: - #0 0x7fb946abd768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768) - #1 0x7fb945eca445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445) - #2 0x7fb945ee2066 in g_slice_alloc (/lib64/libglib-2.0.so.0+0x6a066) - #3 0x7fb945ee3139 in g_slist_prepend (/lib64/libglib-2.0.so.0+0x6b139) - #4 0x5585db591581 in object_class_get_list_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1084 - #5 0x5585db590f66 in object_class_foreach_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1028 - #6 0x7fb945eb35f7 in g_hash_table_foreach (/lib64/libglib-2.0.so.0+0x3b5f7) - #7 0x5585db59110c in object_class_foreach /mnt/sdb/qemu-new/qemu/qom/object.c:1038 - #8 0x5585db5916b6 in object_class_get_list /mnt/sdb/qemu-new/qemu/qom/object.c:1092 - #9 0x5585db335ca0 in dump_vmstate_json_to_file /mnt/sdb/qemu-new/qemu/migration/savevm.c:638 - #10 0x5585daa5bcbf in main /mnt/sdb/qemu-new/qemu/vl.c:4420 - #11 0x7fb941204812 in __libc_start_main ../csu/libc-start.c:308 - #12 0x5585da29420d in _start (/mnt/sdb/qemu-new/qemu/build/x86_64-softmmu/qemu-system-x86_64+0x27f020d) - -Indirect leak of 7472 byte(s) in 467 object(s) allocated from: - #0 0x7fb946abd768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768) - #1 0x7fb945eca445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445) - #2 0x7fb945ee2066 in g_slice_alloc (/lib64/libglib-2.0.so.0+0x6a066) - #3 0x7fb945ee3139 in g_slist_prepend (/lib64/libglib-2.0.so.0+0x6b139) - #4 0x5585db591581 in object_class_get_list_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1084 - #5 0x5585db590f66 in object_class_foreach_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1028 - #6 0x7fb945eb35f7 in g_hash_table_foreach (/lib64/libglib-2.0.so.0+0x3b5f7) - #7 0x5585db59110c in object_class_foreach /mnt/sdb/qemu-new/qemu/qom/object.c:1038 - #8 0x5585db5916b6 in object_class_get_list /mnt/sdb/qemu-new/qemu/qom/object.c:1092 - #9 0x5585db335ca0 in dump_vmstate_json_to_file /mnt/sdb/qemu-new/qemu/migration/savevm.c:638 - #10 0x5585daa5bcbf in main /mnt/sdb/qemu-new/qemu/vl.c:4420 - #11 0x7fb941204812 in __libc_start_main ../csu/libc-start.c:308 - #12 0x5585da29420d in _start (/mnt/sdb/qemu-new/qemu/build/x86_64-softmmu/qemu-system-x86_64+0x27f020d) - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Reviewed-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Juan Quintela -Signed-off-by: AlexChen ---- - migration/savevm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/migration/savevm.c b/migration/savevm.c -index 7d89c57..8163de7 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -614,6 +614,7 @@ void dump_vmstate_json_to_file(FILE *out_file) - } - fprintf(out_file, "\n}\n"); - fclose(out_file); -+ g_slist_free(list); - } - - static uint32_t calculate_new_instance_id(const char *idstr) --- -1.8.3.1 - diff --git a/migration-skip-cache_drop-for-bios-bootloader-and-nv.patch b/migration-skip-cache_drop-for-bios-bootloader-and-nv.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7f90b3e2cf859fecaf55cffaa886a08297ff5d4 --- /dev/null +++ b/migration-skip-cache_drop-for-bios-bootloader-and-nv.patch @@ -0,0 +1,47 @@ +From d9fef6139e17976db194d73848baff543c4a2590 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 08:49:41 +0800 +Subject: [PATCH 10/15] migration: skip cache_drop for bios bootloader and + nvram template + +Qemu enabled page cache dropping for raw device on the destionation host +during shared storage migration. +However, fsync may take 300ms to multiple seconds to return in multiple-migration +scene, because all domains in a host share bios bootloader file, skip cache_drop +for bios bootloader and nvram template to avoid downtime increase. +--- + block.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/block.c b/block.c +index 0ac5b163d2..91f123a354 100644 +--- a/block.c ++++ b/block.c +@@ -67,6 +67,9 @@ + + #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ + ++#define DEFAULT_BIOS_BOOT_LOADER_DIR "/usr/share/edk2" ++#define DEFAULT_NVRAM_TEMPLATE_DIR "/var/lib/libvirt/qemu/nvram" ++ + static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states = + QTAILQ_HEAD_INITIALIZER(graph_bdrv_states); + +@@ -6432,7 +6435,13 @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) + return ret; + } + +- if (bs->drv->bdrv_co_invalidate_cache) { ++ /* ++ * It's not necessary for bios bootloader and nvram template to drop cache ++ * when migration, skip this step for them to avoid dowtime increase. ++ */ ++ if (bs->drv->bdrv_co_invalidate_cache && ++ !strstr(bs->filename, DEFAULT_BIOS_BOOT_LOADER_DIR) && ++ !strstr(bs->filename, DEFAULT_NVRAM_TEMPLATE_DIR)) { + bs->drv->bdrv_co_invalidate_cache(bs, &local_err); + if (local_err) { + bs->open_flags |= BDRV_O_INACTIVE; +-- +2.27.0 + diff --git a/migration-tls-add-error-handling-in-multifd_tls_hand.patch b/migration-tls-add-error-handling-in-multifd_tls_hand.patch deleted file mode 100644 index de444af35d9713e092f98a89485a8a8c590a2203..0000000000000000000000000000000000000000 --- a/migration-tls-add-error-handling-in-multifd_tls_hand.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 4bf84b63bf1b2fba031fc6c3f4948785d534df3b Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Fri, 5 Mar 2021 16:10:57 +0800 -Subject: [PATCH] migration/tls: add error handling in - multifd_tls_handshake_thread - -If any error happens during multifd send thread creating (e.g. channel broke -because new domain is destroyed by the dst), multifd_tls_handshake_thread -may exit silently, leaving main migration thread hanging (ram_save_setup -> -multifd_send_sync_main -> qemu_sem_wait(&p->sem_sync)). -Fix that by adding error handling in multifd_tls_handshake_thread. - -Signed-off-by: Hao Wang ---- - migration/ram.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 3338363e9d..d4ac696899 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1516,7 +1516,16 @@ static void multifd_tls_outgoing_handshake(QIOTask *task, - } else { - trace_multifd_tls_outgoing_handshake_complete(ioc); - } -- multifd_channel_connect(p, ioc, err); -+ -+ if (!multifd_channel_connect(p, ioc, err)) { -+ /* -+ * Error happen, mark multifd_send_thread status as 'quit' although it -+ * is not created, and then tell who pay attention to me. -+ */ -+ p->quit = true; -+ qemu_sem_post(&multifd_send_state->channels_ready); -+ qemu_sem_post(&p->sem_sync); -+ } - } - - static void *multifd_tls_handshake_thread(void *opaque) --- -2.27.0 - diff --git a/migration-tls-add-support-for-multifd-tls-handshake.patch b/migration-tls-add-support-for-multifd-tls-handshake.patch deleted file mode 100644 index f81bb6194cdd98b8a83046cc6cfc831d108d5aae..0000000000000000000000000000000000000000 --- a/migration-tls-add-support-for-multifd-tls-handshake.patch +++ /dev/null @@ -1,125 +0,0 @@ -From e283c7dab15fed5af2904480230f86cf81b67aed Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 11:38:37 +0800 -Subject: [PATCH] migration/tls: add support for multifd tls-handshake -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Similar like migration main thread, we need to do handshake -for each multifd thread. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Reviewed-by: Daniel P. Berrangé -Message-Id: <1600139042-104593-6-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 75 insertions(+), 2 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 2b9d00745c..b82c0e6562 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -38,6 +38,7 @@ - #include "ram.h" - #include "migration.h" - #include "socket.h" -+#include "tls.h" - #include "migration/register.h" - #include "migration/misc.h" - #include "qemu-file.h" -@@ -1200,6 +1201,77 @@ out: - return NULL; - } - -+static bool multifd_channel_connect(MultiFDSendParams *p, -+ QIOChannel *ioc, -+ Error *error); -+ -+static void multifd_tls_outgoing_handshake(QIOTask *task, -+ gpointer opaque) -+{ -+ MultiFDSendParams *p = opaque; -+ QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); -+ Error *err = NULL; -+ -+ qio_task_propagate_error(task, &err); -+ multifd_channel_connect(p, ioc, err); -+} -+ -+static void multifd_tls_channel_connect(MultiFDSendParams *p, -+ QIOChannel *ioc, -+ Error **errp) -+{ -+ MigrationState *s = migrate_get_current(); -+ const char *hostname = p->tls_hostname; -+ QIOChannelTLS *tioc; -+ -+ tioc = migration_tls_client_create(s, ioc, hostname, errp); -+ if (!tioc) { -+ return; -+ } -+ -+ qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); -+ qio_channel_tls_handshake(tioc, -+ multifd_tls_outgoing_handshake, -+ p, -+ NULL, -+ NULL); -+ -+} -+ -+static bool multifd_channel_connect(MultiFDSendParams *p, -+ QIOChannel *ioc, -+ Error *error) -+{ -+ MigrationState *s = migrate_get_current(); -+ -+ if (!error) { -+ if (s->parameters.tls_creds && -+ *s->parameters.tls_creds && -+ !object_dynamic_cast(OBJECT(ioc), -+ TYPE_QIO_CHANNEL_TLS)) { -+ multifd_tls_channel_connect(p, ioc, &error); -+ if (!error) { -+ /* -+ * tls_channel_connect will call back to this -+ * function after the TLS handshake, -+ * so we mustn't call multifd_send_thread until then -+ */ -+ return false; -+ } else { -+ return true; -+ } -+ } else { -+ /* update for tls qio channel */ -+ p->c = ioc; -+ qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, -+ QEMU_THREAD_JOINABLE); -+ } -+ return false; -+ } -+ -+ return true; -+} -+ - static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, - QIOChannel *ioc, Error *err) - { -@@ -1229,8 +1301,9 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); - p->running = true; -- qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, -- QEMU_THREAD_JOINABLE); -+ if (multifd_channel_connect(p, sioc, local_err)) { -+ goto cleanup; -+ } - return; - } - --- -2.27.0 - diff --git a/migration-tls-add-tls_hostname-into-MultiFDSendParam.patch b/migration-tls-add-tls_hostname-into-MultiFDSendParam.patch deleted file mode 100644 index 3b06a42fad428d20035072601afbcd139b77c291..0000000000000000000000000000000000000000 --- a/migration-tls-add-tls_hostname-into-MultiFDSendParam.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0aff29297923b32e919ce944030a043e0826d9aa Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 11:25:44 +0800 -Subject: [PATCH] migration/tls: add tls_hostname into MultiFDSendParams -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since multifd creation is async with migration_channel_connect, we should -pass the hostname from MigrationState to MultiFDSendParams. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Message-Id: <1600139042-104593-4-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 1a33c7b3e2..bb8f383c3b 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -621,6 +621,8 @@ typedef struct { - uint8_t id; - /* channel thread name */ - char *name; -+ /* tls hostname */ -+ char *tls_hostname; - /* channel thread id */ - QemuThread thread; - /* communication channel */ -@@ -1041,6 +1043,8 @@ void multifd_save_cleanup(void) - qemu_sem_destroy(&p->sem_sync); - g_free(p->name); - p->name = NULL; -+ g_free(p->tls_hostname); -+ p->tls_hostname = NULL; - multifd_pages_clear(p->pages); - p->pages = NULL; - p->packet_len = 0; -@@ -1229,10 +1233,12 @@ int multifd_save_setup(void) - int thread_count; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); - uint8_t i; -+ MigrationState *s; - - if (!migrate_use_multifd()) { - return 0; - } -+ s = migrate_get_current(); - thread_count = migrate_multifd_channels(); - multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); - multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); -@@ -1253,6 +1259,7 @@ int multifd_save_setup(void) - + sizeof(ram_addr_t) * page_count; - p->packet = g_malloc0(p->packet_len); - p->name = g_strdup_printf("multifdsend_%d", i); -+ p->tls_hostname = g_strdup(s->hostname); - socket_send_channel_create(multifd_new_send_channel_async, p); - } - return 0; --- -2.27.0 - diff --git a/migration-tls-add-trace-points-for-multifd-tls.patch b/migration-tls-add-trace-points-for-multifd-tls.patch deleted file mode 100644 index a49ef1faad30e725b45c01e10812df9b7b72b7b3..0000000000000000000000000000000000000000 --- a/migration-tls-add-trace-points-for-multifd-tls.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 83cbd3a645e9376a25cd359e8f12f8db025bf071 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 13:56:11 +0800 -Subject: [PATCH] migration/tls: add trace points for multifd-tls -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -add trace points for multifd-tls for debug. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Reviewed-by: Daniel P. Berrangé -Message-Id: <1600139042-104593-7-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 10 +++++++++- - migration/trace-events | 4 ++++ - 2 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index b82c0e6562..3ded38c0be 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1212,7 +1212,11 @@ static void multifd_tls_outgoing_handshake(QIOTask *task, - QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); - Error *err = NULL; - -- qio_task_propagate_error(task, &err); -+ if (qio_task_propagate_error(task, &err)) { -+ trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err)); -+ } else { -+ trace_multifd_tls_outgoing_handshake_complete(ioc); -+ } - multifd_channel_connect(p, ioc, err); - } - -@@ -1229,6 +1233,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, - return; - } - -+ trace_multifd_tls_outgoing_handshake_start(ioc, tioc, hostname); - qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); - qio_channel_tls_handshake(tioc, - multifd_tls_outgoing_handshake, -@@ -1244,6 +1249,9 @@ static bool multifd_channel_connect(MultiFDSendParams *p, - { - MigrationState *s = migrate_get_current(); - -+ trace_multifd_set_outgoing_channel( -+ ioc, object_get_typename(OBJECT(ioc)), p->tls_hostname, error); -+ - if (!error) { - if (s->parameters.tls_creds && - *s->parameters.tls_creds && -diff --git a/migration/trace-events b/migration/trace-events -index 69620c43c2..c0640cd424 100644 ---- a/migration/trace-events -+++ b/migration/trace-events -@@ -93,6 +93,10 @@ multifd_send_sync_main_signal(uint8_t id) "channel %d" - multifd_send_sync_main_wait(uint8_t id) "channel %d" - multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 - multifd_send_thread_start(uint8_t id) "%d" -+multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s" -+multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s" -+multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p" -+multifd_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname, void *err) "ioc=%p ioctype=%s hostname=%s err=%p" - ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" - ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: 0x%" PRIx64 " flags: 0x%x host: %p" - ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x" --- -2.27.0 - diff --git a/migration-tls-extract-cleanup-function-for-common-us.patch b/migration-tls-extract-cleanup-function-for-common-us.patch deleted file mode 100644 index 5ac83e9200020300060317065bfbfeca0ebf84e2..0000000000000000000000000000000000000000 --- a/migration-tls-extract-cleanup-function-for-common-us.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 29914b97b20a6415476095c913607412a3f7572f Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 11:32:44 +0800 -Subject: [PATCH] migration/tls: extract cleanup function for common-use -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -multifd channel cleanup is need if multifd handshake failed, -let's extract it. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Reviewed-by: Daniel P. Berrangé -Message-Id: <1600139042-104593-5-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 34 ++++++++++++++++++++++------------ - 1 file changed, 22 insertions(+), 12 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index bb8f383c3b..2b9d00745c 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1200,6 +1200,23 @@ out: - return NULL; - } - -+static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, -+ QIOChannel *ioc, Error *err) -+{ -+ migrate_set_error(migrate_get_current(), err); -+ /* Error happen, we need to tell who pay attention to me */ -+ qemu_sem_post(&multifd_send_state->channels_ready); -+ qemu_sem_post(&p->sem_sync); -+ /* -+ * Although multifd_send_thread is not created, but main migration -+ * thread neet to judge whether it is running, so we need to mark -+ * its status. -+ */ -+ p->quit = true; -+ object_unref(OBJECT(ioc)); -+ error_free(err); -+} -+ - static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - { - MultiFDSendParams *p = opaque; -@@ -1207,25 +1224,18 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - Error *local_err = NULL; - - if (qio_task_propagate_error(task, &local_err)) { -- migrate_set_error(migrate_get_current(), local_err); -- /* Error happen, we need to tell who pay attention to me */ -- qemu_sem_post(&multifd_send_state->channels_ready); -- qemu_sem_post(&p->sem_sync); -- /* -- * Although multifd_send_thread is not created, but main migration -- * thread neet to judge whether it is running, so we need to mark -- * its status. -- */ -- p->quit = true; -- object_unref(OBJECT(sioc)); -- error_free(local_err); -+ goto cleanup; - } else { - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); - p->running = true; - qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, - QEMU_THREAD_JOINABLE); -+ return; - } -+ -+cleanup: -+ multifd_new_send_channel_cleanup(p, sioc, local_err); - } - - int multifd_save_setup(void) --- -2.27.0 - diff --git a/migration-tls-extract-migration_tls_client_create-fo.patch b/migration-tls-extract-migration_tls_client_create-fo.patch deleted file mode 100644 index 7f538332241d60313f87533cff62785c11e98f39..0000000000000000000000000000000000000000 --- a/migration-tls-extract-migration_tls_client_create-fo.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 4ffa2ea3749066a0444b69ef16ec4e4d6cdad0e1 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Tue, 15 Sep 2020 11:03:58 +0800 -Subject: [PATCH] migration/tls: extract migration_tls_client_create for - common-use -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -migration_tls_client_create will be used in multifd-tls, let's -extract it. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Reviewed-by: Daniel P. Berrangé -Message-Id: <1600139042-104593-3-git-send-email-zhengchuan@huawei.com> -Signed-off-by: Dr. David Alan Gilbert ---- - migration/tls.c | 26 ++++++++++++++++++-------- - migration/tls.h | 6 ++++++ - 2 files changed, 24 insertions(+), 8 deletions(-) - -diff --git a/migration/tls.c b/migration/tls.c -index a0eb553e14..1d5b571d8e 100644 ---- a/migration/tls.c -+++ b/migration/tls.c -@@ -22,7 +22,6 @@ - #include "channel.h" - #include "migration.h" - #include "tls.h" --#include "io/channel-tls.h" - #include "crypto/tlscreds.h" - #include "qemu/error-report.h" - #include "qapi/error.h" -@@ -126,11 +125,10 @@ static void migration_tls_outgoing_handshake(QIOTask *task, - object_unref(OBJECT(ioc)); - } - -- --void migration_tls_channel_connect(MigrationState *s, -- QIOChannel *ioc, -- const char *hostname, -- Error **errp) -+QIOChannelTLS *migration_tls_client_create(MigrationState *s, -+ QIOChannel *ioc, -+ const char *hostname, -+ Error **errp) - { - QCryptoTLSCreds *creds; - QIOChannelTLS *tioc; -@@ -138,7 +136,7 @@ void migration_tls_channel_connect(MigrationState *s, - creds = migration_tls_get_creds( - s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp); - if (!creds) { -- return; -+ return NULL; - } - - if (s->parameters.tls_hostname && *s->parameters.tls_hostname) { -@@ -146,11 +144,23 @@ void migration_tls_channel_connect(MigrationState *s, - } - if (!hostname) { - error_setg(errp, "No hostname available for TLS"); -- return; -+ return NULL; - } - - tioc = qio_channel_tls_new_client( - ioc, creds, hostname, errp); -+ -+ return tioc; -+} -+ -+void migration_tls_channel_connect(MigrationState *s, -+ QIOChannel *ioc, -+ const char *hostname, -+ Error **errp) -+{ -+ QIOChannelTLS *tioc; -+ -+ tioc = migration_tls_client_create(s, ioc, hostname, errp); - if (!tioc) { - return; - } -diff --git a/migration/tls.h b/migration/tls.h -index cdd70001ed..0cfbe368ba 100644 ---- a/migration/tls.h -+++ b/migration/tls.h -@@ -22,11 +22,17 @@ - #define QEMU_MIGRATION_TLS_H - - #include "io/channel.h" -+#include "io/channel-tls.h" - - void migration_tls_channel_process_incoming(MigrationState *s, - QIOChannel *ioc, - Error **errp); - -+QIOChannelTLS *migration_tls_client_create(MigrationState *s, -+ QIOChannel *ioc, -+ const char *hostname, -+ Error **errp); -+ - void migration_tls_channel_connect(MigrationState *s, - QIOChannel *ioc, - const char *hostname, --- -2.27.0 - diff --git a/migration-tls-fix-inverted-semantics-in-multifd_chan.patch b/migration-tls-fix-inverted-semantics-in-multifd_chan.patch deleted file mode 100644 index 3f5a52aa6db6d5ecd034a1fc2f98c994b84ade64..0000000000000000000000000000000000000000 --- a/migration-tls-fix-inverted-semantics-in-multifd_chan.patch +++ /dev/null @@ -1,55 +0,0 @@ -From ee0d1b508a144ab390fb7bc8b7a4fe3161aebecf Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Fri, 5 Mar 2021 16:09:29 +0800 -Subject: [PATCH] migration/tls: fix inverted semantics in - multifd_channel_connect - -Function multifd_channel_connect() return "true" to indicate failure, -which is rather confusing. Fix that. - -Signed-off-by: Hao Wang ---- - migration/ram.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index ba1e729c39..3338363e9d 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1575,9 +1575,9 @@ static bool multifd_channel_connect(MultiFDSendParams *p, - * function after the TLS handshake, - * so we mustn't call multifd_send_thread until then - */ -- return false; -- } else { - return true; -+ } else { -+ return false; - } - } else { - /* update for tls qio channel */ -@@ -1585,10 +1585,10 @@ static bool multifd_channel_connect(MultiFDSendParams *p, - qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, - QEMU_THREAD_JOINABLE); - } -- return false; -+ return true; - } - -- return true; -+ return false; - } - - static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, -@@ -1620,7 +1620,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); - p->running = true; -- if (multifd_channel_connect(p, sioc, local_err)) { -+ if (!multifd_channel_connect(p, sioc, local_err)) { - goto cleanup; - } - return; --- -2.27.0 - diff --git a/migration-tls-save-hostname-into-MigrationState.patch b/migration-tls-save-hostname-into-MigrationState.patch deleted file mode 100644 index 538a8f69179d536f2f5bc307a66d4c900c5fd790..0000000000000000000000000000000000000000 --- a/migration-tls-save-hostname-into-MigrationState.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 08ae1eda02ff08b3431b227ed702ea0fc5f8a4a2 Mon Sep 17 00:00:00 2001 -From: Chuan Zheng -Date: Tue, 15 Sep 2020 11:03:57 +0800 -Subject: [PATCH] migration/tls: save hostname into MigrationState -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -hostname is need in multifd-tls, save hostname into MigrationState. - -Signed-off-by: Chuan Zheng -Signed-off-by: Yan Jin -Message-Id: <1600139042-104593-2-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Dr. David Alan Gilbert ---- - migration/channel.c | 1 + - migration/migration.c | 1 + - migration/migration.h | 5 +++++ - migration/tls.c | 2 ++ - 4 files changed, 9 insertions(+) - -diff --git a/migration/channel.c b/migration/channel.c -index 7462181484..46ed40b89c 100644 ---- a/migration/channel.c -+++ b/migration/channel.c -@@ -99,5 +99,6 @@ void migration_channel_connect(MigrationState *s, - } - } - migrate_fd_connect(s, error); -+ g_free(s->hostname); - error_free(error); - } -diff --git a/migration/migration.c b/migration/migration.c -index 7949f2a40b..993d77b7d6 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1710,6 +1710,7 @@ void migrate_init(MigrationState *s) - s->migration_thread_running = false; - error_free(s->error); - s->error = NULL; -+ s->hostname = NULL; - - migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP); - -diff --git a/migration/migration.h b/migration/migration.h -index feb344306a..e5aaf2ef70 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -259,6 +259,11 @@ struct MigrationState - * (which is in 4M chunk). - */ - uint8_t clear_bitmap_shift; -+ -+ /* -+ * This save hostname when out-going migration starts -+ */ -+ char *hostname; - }; - - void migrate_set_state(int *state, int old_state, int new_state); -diff --git a/migration/tls.c b/migration/tls.c -index 5171afc6c4..a0eb553e14 100644 ---- a/migration/tls.c -+++ b/migration/tls.c -@@ -155,6 +155,8 @@ void migration_tls_channel_connect(MigrationState *s, - return; - } - -+ /* Save hostname into MigrationState for handshake */ -+ s->hostname = g_strdup(hostname); - trace_migration_tls_outgoing_handshake_start(hostname); - qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-outgoing"); - qio_channel_tls_handshake(tioc, --- -2.27.0 - diff --git a/migration-update-ram_counters-for-multifd-sync-packe.patch b/migration-update-ram_counters-for-multifd-sync-packe.patch deleted file mode 100644 index 838380403f1ac31df0f2befd62a14711cee71e58..0000000000000000000000000000000000000000 --- a/migration-update-ram_counters-for-multifd-sync-packe.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e93040851d683f1f7750acfa0e862b4405678f24 Mon Sep 17 00:00:00 2001 -From: Zheng Chuan -Date: Fri, 24 Apr 2020 11:50:41 +0800 -Subject: [PATCH 04/10] migration: update ram_counters for multifd sync packet - -Multifd sync will send MULTIFD_FLAG_SYNC flag info to destination, add -these bytes to ram_counters record. - -Change-Id: I885166f412f58e74de40ea6ffec1c35e82ae4619 -Signed-off-by: Ivan Ren -Suggested-by: Wei Yang -Message-Id: <1564464816-21804-4-git-send-email-ivanren@tencent.com> -Reviewed-by: Juan Quintela -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 88ddd2bb..c75716bb 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1085,6 +1085,10 @@ static void multifd_send_sync_main(RAMState *rs) - p->flags |= MULTIFD_FLAG_SYNC; - p->pending_job++; - qemu_file_update_transfer(rs->f, p->packet_len); -+ ram_counters.multifd_bytes += p->packet_len; -+ ram_counters.transferred += p->packet_len; -+ ram_counters.multifd_bytes += p->packet_len; -+ ram_counters.transferred += p->packet_len; - qemu_mutex_unlock(&p->mutex); - qemu_sem_post(&p->sem); - } --- -2.19.1 diff --git a/migration-use-migration_is_active-to-represent-activ.patch b/migration-use-migration_is_active-to-represent-activ.patch deleted file mode 100644 index c9e926ad8e16dcfe9c931fae96cc9b8ad8e0cb93..0000000000000000000000000000000000000000 --- a/migration-use-migration_is_active-to-represent-activ.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 9662d44633dd4582dc47d58f63ee63b2c8f60a4f Mon Sep 17 00:00:00 2001 -From: Wei Yang -Date: Wed, 17 Jul 2019 08:53:41 +0800 -Subject: [PATCH] migration: use migration_is_active to represent active state - -Wrap the check into a function to make it easy to read. - -Signed-off-by: Wei Yang -Message-Id: <20190717005341.14140-1-richardw.yang@linux.intel.com> -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Dr. David Alan Gilbert ---- - include/migration/misc.h | 1 + - migration/migration.c | 12 ++++++++---- - 2 files changed, 9 insertions(+), 4 deletions(-) - -diff --git a/include/migration/misc.h b/include/migration/misc.h -index 5cdbabd094..42d6abc920 100644 ---- a/include/migration/misc.h -+++ b/include/migration/misc.h -@@ -61,6 +61,7 @@ void migration_object_init(void); - void migration_shutdown(void); - void qemu_start_incoming_migration(const char *uri, Error **errp); - bool migration_is_idle(void); -+bool migration_is_active(MigrationState *); - void add_migration_state_change_notifier(Notifier *notify); - void remove_migration_state_change_notifier(Notifier *notify); - bool migration_in_setup(MigrationState *); -diff --git a/migration/migration.c b/migration/migration.c -index 9b40380d7c..fd7d81d4b6 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1578,8 +1578,7 @@ static void migrate_fd_cleanup(MigrationState *s) - qemu_fclose(tmp); - } - -- assert((s->state != MIGRATION_STATUS_ACTIVE) && -- (s->state != MIGRATION_STATUS_POSTCOPY_ACTIVE)); -+ assert(!migration_is_active(s)); - - if (s->state == MIGRATION_STATUS_CANCELLING) { - migrate_set_state(&s->state, MIGRATION_STATUS_CANCELLING, -@@ -1741,6 +1740,12 @@ bool migration_is_idle(void) - return false; - } - -+bool migration_is_active(MigrationState *s) -+{ -+ return (s->state == MIGRATION_STATUS_ACTIVE || -+ s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE); -+} -+ - void migrate_init(MigrationState *s) - { - /* -@@ -3307,8 +3312,7 @@ static void *migration_thread(void *opaque) - - trace_migration_thread_setup_complete(); - -- while (s->state == MIGRATION_STATUS_ACTIVE || -- s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { -+ while (migration_is_active(s)) { - int64_t current_time; - - if (urgent || !qemu_file_rate_limit(s->to_dst_file)) { --- -2.27.0 - diff --git a/migration-xbzrle-fix-out-of-bounds-write-with-axv512.patch b/migration-xbzrle-fix-out-of-bounds-write-with-axv512.patch new file mode 100644 index 0000000000000000000000000000000000000000..95afae2cf08463dc8d86f8a099b3e4750a3161f0 --- /dev/null +++ b/migration-xbzrle-fix-out-of-bounds-write-with-axv512.patch @@ -0,0 +1,81 @@ +From 553baa5eac50560c14ed216744062f542df17011 Mon Sep 17 00:00:00 2001 +From: Matheus Tavares Bernardino +Date: Mon, 13 Mar 2023 15:58:20 -0300 +Subject: [PATCH] migration/xbzrle: fix out-of-bounds write with axv512 + +mainline inclusion +from mainline-v8.0.0-rc1 +commit 1776b70f55c75541e9cab3423650a59b085162a9 +category: feature +feature: AVX512 support for xbzrle_encode_buffer +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Z50P + +Intel-SIG: commit 1776b70f55c7 ("migration/xbzrle: fix out-of-bounds write with axv512") + +------------------------------------- + +migration/xbzrle: fix out-of-bounds write with axv512 + +xbzrle_encode_buffer_avx512() checks for overflows too scarcely in its +outer loop, causing out-of-bounds writes: + +$ ../configure --target-list=aarch64-softmmu --enable-sanitizers --enable-avx512bw +$ make tests/unit/test-xbzrle && ./tests/unit/test-xbzrle + +==5518==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100000b100 at pc 0x561109a7714d bp 0x7ffed712a440 sp 0x7ffed712a430 +WRITE of size 1 at 0x62100000b100 thread T0 + #0 0x561109a7714c in uleb128_encode_small ../util/cutils.c:831 + #1 0x561109b67f6a in xbzrle_encode_buffer_avx512 ../migration/xbzrle.c:275 + #2 0x5611099a7428 in test_encode_decode_overflow ../tests/unit/test-xbzrle.c:153 + #3 0x7fb2fb65a58d (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7a58d) + #4 0x7fb2fb65a333 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7a333) + #5 0x7fb2fb65aa79 in g_test_run_suite (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7aa79) + #6 0x7fb2fb65aa94 in g_test_run (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7aa94) + #7 0x5611099a3a23 in main ../tests/unit/test-xbzrle.c:218 + #8 0x7fb2fa78c082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) + #9 0x5611099a608d in _start (/qemu/build/tests/unit/test-xbzrle+0x28408d) + +0x62100000b100 is located 0 bytes to the right of 4096-byte region [0x62100000a100,0x62100000b100) +allocated by thread T0 here: + #0 0x7fb2fb823a06 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:153 + #1 0x7fb2fb637ef0 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x57ef0) + +Fix that by performing the overflow check in the inner loop, instead. + +Signed-off-by: Matheus Tavares Bernardino +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Aichun Shi +--- + migration/xbzrle.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/migration/xbzrle.c b/migration/xbzrle.c +index 21b92d4eae..c6f8b20917 100644 +--- a/migration/xbzrle.c ++++ b/migration/xbzrle.c +@@ -197,10 +197,6 @@ int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + __m512i r = _mm512_set1_epi32(0); + + while (count512s) { +- if (d + 2 > dlen) { +- return -1; +- } +- + int bytes_to_check = 64; + uint64_t mask = 0xffffffffffffffff; + if (count512s == 1) { +@@ -216,6 +212,9 @@ int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + + bool is_same = (comp & 0x1); + while (bytes_to_check) { ++ if (d + 2 > dlen) { ++ return -1; ++ } + if (is_same) { + if (nzrun_len) { + d += uleb128_encode_small(dst + d, nzrun_len); +-- +2.27.0 + diff --git a/migration-xbzrle-use-ctz64-to-avoid-undefined-result.patch b/migration-xbzrle-use-ctz64-to-avoid-undefined-result.patch new file mode 100644 index 0000000000000000000000000000000000000000..a2dbddeac9ca1a2d31fddd2d9a665ed67ca21a41 --- /dev/null +++ b/migration-xbzrle-use-ctz64-to-avoid-undefined-result.patch @@ -0,0 +1,69 @@ +From d4c03c1e41043f25e21889762bceb480abb56634 Mon Sep 17 00:00:00 2001 +From: Matheus Tavares Bernardino +Date: Mon, 13 Mar 2023 15:58:19 -0300 +Subject: [PATCH] migration/xbzrle: use ctz64 to avoid undefined result + +mainline inclusion +from mainline-v8.0.0-rc1 +commit d84a78d15d3af9ff28ceec6906a4b101bd545b55 +category: feature +feature: AVX512 support for xbzrle_encode_buffer +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Z50P + +Intel-SIG: commit d84a78d15d3a ("migration/xbzrle: use ctz64 to avoid undefined result") + +------------------------------------- + +migration/xbzrle: use ctz64 to avoid undefined result + +__builtin_ctzll() produces undefined results when the argument is 0. +This can be seen through test-xbzrle, which produces the following +warning: + +../migration/xbzrle.c:265: runtime error: passing zero to ctz(), which is not a valid argument + +Replace __builtin_ctzll() with our ctz64() wrapper which properly +handles 0. + +Signed-off-by: Matheus Tavares Bernardino +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Aichun Shi +--- + migration/xbzrle.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/migration/xbzrle.c b/migration/xbzrle.c +index 05366e86c0..21b92d4eae 100644 +--- a/migration/xbzrle.c ++++ b/migration/xbzrle.c +@@ -12,6 +12,7 @@ + */ + #include "qemu/osdep.h" + #include "qemu/cutils.h" ++#include "qemu/host-utils.h" + #include "xbzrle.h" + + /* +@@ -233,7 +234,7 @@ int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + break; + } + never_same = false; +- num = __builtin_ctzll(~comp); ++ num = ctz64(~comp); + num = (num < bytes_to_check) ? num : bytes_to_check; + zrun_len += num; + bytes_to_check -= num; +@@ -262,7 +263,7 @@ int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + nzrun_len += 64; + break; + } +- num = __builtin_ctzll(comp); ++ num = ctz64(comp); + num = (num < bytes_to_check) ? num : bytes_to_check; + nzrun_len += num; + bytes_to_check -= num; +-- +2.27.0 + diff --git a/mirror-Do-not-dereference-invalid-pointers.patch b/mirror-Do-not-dereference-invalid-pointers.patch deleted file mode 100644 index b83e0695e5ff96a429e26f65b2c206eebb9b3f86..0000000000000000000000000000000000000000 --- a/mirror-Do-not-dereference-invalid-pointers.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 609aad11051c6f2053cc32b4881f5581c92435f3 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 14 Oct 2019 17:39:28 +0200 -Subject: [PATCH] mirror: Do not dereference invalid pointers - -mirror_exit_common() may be called twice (if it is called from -mirror_prepare() and fails, it will be called from mirror_abort() -again). - -In such a case, many of the pointers in the MirrorBlockJob object will -already be freed. This can be seen most reliably for s->target, which -is set to NULL (and then dereferenced by blk_bs()). - -Cc: qemu-stable@nongnu.org -Fixes: 737efc1eda23b904fbe0e66b37715fb0e5c3e58b -Signed-off-by: Max Reitz -Reviewed-by: John Snow -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-id: 20191014153931.20699-2-mreitz@redhat.com -Signed-off-by: Max Reitz -(cherry picked from commit f93c3add3a773e0e3f6277e5517583c4ad3a43c2) -Signed-off-by: Michael Roth ---- - block/mirror.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -diff --git a/block/mirror.c b/block/mirror.c -index 062dc42..408486c 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -617,11 +617,11 @@ static int mirror_exit_common(Job *job) - { - MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); - BlockJob *bjob = &s->common; -- MirrorBDSOpaque *bs_opaque = s->mirror_top_bs->opaque; -+ MirrorBDSOpaque *bs_opaque; - AioContext *replace_aio_context = NULL; -- BlockDriverState *src = s->mirror_top_bs->backing->bs; -- BlockDriverState *target_bs = blk_bs(s->target); -- BlockDriverState *mirror_top_bs = s->mirror_top_bs; -+ BlockDriverState *src; -+ BlockDriverState *target_bs; -+ BlockDriverState *mirror_top_bs; - Error *local_err = NULL; - bool abort = job->ret < 0; - int ret = 0; -@@ -631,6 +631,11 @@ static int mirror_exit_common(Job *job) - } - s->prepared = true; - -+ mirror_top_bs = s->mirror_top_bs; -+ bs_opaque = mirror_top_bs->opaque; -+ src = mirror_top_bs->backing->bs; -+ target_bs = blk_bs(s->target); -+ - if (bdrv_chain_contains(src, target_bs)) { - bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs); - } --- -1.8.3.1 - diff --git a/mirror-Fix-bdrv_has_zero_init-use.patch b/mirror-Fix-bdrv_has_zero_init-use.patch deleted file mode 100644 index 54fde6927f378bdddbe92495f8b5616dfd3f6953..0000000000000000000000000000000000000000 --- a/mirror-Fix-bdrv_has_zero_init-use.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 7fcb1c1a956a8cad5c2e8585e53878edc4fd9eca Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Wed, 24 Jul 2019 19:12:30 +0200 -Subject: [PATCH] mirror: Fix bdrv_has_zero_init() use - -bdrv_has_zero_init() only has meaning for newly created images or image -areas. If the mirror job itself did not create the image, it cannot -rely on bdrv_has_zero_init()'s result to carry any meaning. - -This is the case for drive-mirror with mode=existing and always for -blockdev-mirror. - -Note that we only have to zero-initialize the target with sync=full, -because other modes actually do not promise that the target will contain -the same data as the source after the job -- sync=top only promises to -copy anything allocated in the top layer, and sync=none will only copy -new I/O. (Which is how mirror has always handled it.) - -Signed-off-by: Max Reitz -Message-id: 20190724171239.8764-3-mreitz@redhat.com -Reviewed-by: Maxim Levitsky -Signed-off-by: Max Reitz ---- - block/mirror.c | 11 ++++++++--- - blockdev.c | 16 +++++++++++++--- - include/block/block_int.h | 2 ++ - tests/test-block-iothread.c | 2 +- - 4 files changed, 24 insertions(+), 7 deletions(-) - -diff --git a/block/mirror.c b/block/mirror.c -index ccae49a28e..89a053b265 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -51,6 +51,8 @@ typedef struct MirrorBlockJob { - Error *replace_blocker; - bool is_none_mode; - BlockMirrorBackingMode backing_mode; -+ /* Whether the target image requires explicit zero-initialization */ -+ bool zero_target; - MirrorCopyMode copy_mode; - BlockdevOnError on_source_error, on_target_error; - bool synced; -@@ -779,7 +781,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) - int ret; - int64_t count; - -- if (base == NULL && !bdrv_has_zero_init(target_bs)) { -+ if (s->zero_target) { - if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { - bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); - return 0; -@@ -1531,6 +1533,7 @@ static BlockJob *mirror_start_job( - const char *replaces, int64_t speed, - uint32_t granularity, int64_t buf_size, - BlockMirrorBackingMode backing_mode, -+ bool zero_target, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - bool unmap, -@@ -1658,6 +1661,7 @@ static BlockJob *mirror_start_job( - s->on_target_error = on_target_error; - s->is_none_mode = is_none_mode; - s->backing_mode = backing_mode; -+ s->zero_target = zero_target; - s->copy_mode = copy_mode; - s->base = base; - s->granularity = granularity; -@@ -1762,6 +1766,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, - int creation_flags, int64_t speed, - uint32_t granularity, int64_t buf_size, - MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, -+ bool zero_target, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - bool unmap, const char *filter_node_name, -@@ -1779,7 +1784,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, - is_none_mode = mode == MIRROR_SYNC_MODE_NONE; - base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; - mirror_start_job(job_id, bs, creation_flags, target, replaces, -- speed, granularity, buf_size, backing_mode, -+ speed, granularity, buf_size, backing_mode, zero_target, - on_source_error, on_target_error, unmap, NULL, NULL, - &mirror_job_driver, is_none_mode, base, false, - filter_node_name, true, copy_mode, errp); -@@ -1806,7 +1811,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, - - ret = mirror_start_job( - job_id, bs, creation_flags, base, NULL, speed, 0, 0, -- MIRROR_LEAVE_BACKING_CHAIN, -+ MIRROR_LEAVE_BACKING_CHAIN, false, - on_error, on_error, true, cb, opaque, - &commit_active_job_driver, false, base, auto_complete, - filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, -diff --git a/blockdev.c b/blockdev.c -index 94e5aee30b..4435795b6d 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3739,6 +3739,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, - bool has_replaces, const char *replaces, - enum MirrorSyncMode sync, - BlockMirrorBackingMode backing_mode, -+ bool zero_target, - bool has_speed, int64_t speed, - bool has_granularity, uint32_t granularity, - bool has_buf_size, int64_t buf_size, -@@ -3847,7 +3848,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, - */ - mirror_start(job_id, bs, target, - has_replaces ? replaces : NULL, job_flags, -- speed, granularity, buf_size, sync, backing_mode, -+ speed, granularity, buf_size, sync, backing_mode, zero_target, - on_source_error, on_target_error, unmap, filter_node_name, - copy_mode, errp); - } -@@ -3863,6 +3864,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) - int flags; - int64_t size; - const char *format = arg->format; -+ bool zero_target; - int ret; - - bs = qmp_get_root_bs(arg->device, errp); -@@ -3964,6 +3966,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) - goto out; - } - -+ zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL && -+ (arg->mode == NEW_IMAGE_MODE_EXISTING || -+ !bdrv_has_zero_init(target_bs))); -+ - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); - if (ret < 0) { - bdrv_unref(target_bs); -@@ -3972,7 +3978,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) - - blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, - arg->has_replaces, arg->replaces, arg->sync, -- backing_mode, arg->has_speed, arg->speed, -+ backing_mode, zero_target, -+ arg->has_speed, arg->speed, - arg->has_granularity, arg->granularity, - arg->has_buf_size, arg->buf_size, - arg->has_on_source_error, arg->on_source_error, -@@ -4012,6 +4019,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, - AioContext *aio_context; - BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; - Error *local_err = NULL; -+ bool zero_target; - int ret; - - bs = qmp_get_root_bs(device, errp); -@@ -4024,6 +4032,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, - return; - } - -+ zero_target = (sync == MIRROR_SYNC_MODE_FULL); -+ - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - -@@ -4034,7 +4044,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, - - blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, - has_replaces, replaces, sync, backing_mode, -- has_speed, speed, -+ zero_target, has_speed, speed, - has_granularity, granularity, - has_buf_size, buf_size, - has_on_source_error, on_source_error, -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 76117a761a..154b9b5501 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -1120,6 +1120,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, - * @buf_size: The amount of data that can be in flight at one time. - * @mode: Whether to collapse all images in the chain to the target. - * @backing_mode: How to establish the target's backing chain after completion. -+ * @zero_target: Whether the target should be explicitly zero-initialized - * @on_source_error: The action to take upon error reading from the source. - * @on_target_error: The action to take upon error writing to the target. - * @unmap: Whether to unmap target where source sectors only contain zeroes. -@@ -1139,6 +1140,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, - int creation_flags, int64_t speed, - uint32_t granularity, int64_t buf_size, - MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, -+ bool zero_target, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - bool unmap, const char *filter_node_name, -diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c -index 1949d5e61a..debfb69bfb 100644 ---- a/tests/test-block-iothread.c -+++ b/tests/test-block-iothread.c -@@ -611,7 +611,7 @@ static void test_propagate_mirror(void) - - /* Start a mirror job */ - mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, -- MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, -+ MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, - BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, - false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, - &error_abort); --- -2.27.0 - diff --git a/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch b/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch deleted file mode 100644 index 52f07f951aef929e9fe58740955f97af25e5ba85..0000000000000000000000000000000000000000 --- a/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch +++ /dev/null @@ -1,52 +0,0 @@ -From e092a17d3825a8f2c93cb429aaa5d857b579b64c Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 22 Jul 2019 17:44:27 +0200 -Subject: [PATCH] mirror: Keep mirror_top_bs drained after dropping permissions - -mirror_top_bs is currently implicitly drained through its connection to -the source or the target node. However, the drain section for target_bs -ends early after moving mirror_top_bs from src to target_bs, so that -requests can already be restarted while mirror_top_bs is still present -in the chain, but has dropped all permissions and therefore runs into an -assertion failure like this: - - qemu-system-x86_64: block/io.c:1634: bdrv_co_write_req_prepare: - Assertion `child->perm & BLK_PERM_WRITE' failed. - -Keep mirror_top_bs drained until all graph changes have completed. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Kevin Wolf -Reviewed-by: Max Reitz -(cherry picked from commit d2da5e288a2e71e82866c8fdefd41b5727300124) -Signed-off-by: Michael Roth ---- - block/mirror.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/block/mirror.c b/block/mirror.c -index 0e3f7923cf..681b305de6 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -661,7 +661,10 @@ static int mirror_exit_common(Job *job) - s->target = NULL; - - /* We don't access the source any more. Dropping any WRITE/RESIZE is -- * required before it could become a backing file of target_bs. */ -+ * required before it could become a backing file of target_bs. Not having -+ * these permissions any more means that we can't allow any new requests on -+ * mirror_top_bs from now on, so keep it drained. */ -+ bdrv_drained_begin(mirror_top_bs); - bs_opaque->stop = true; - bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, - &error_abort); -@@ -729,6 +732,7 @@ static int mirror_exit_common(Job *job) - bs_opaque->job = NULL; - - bdrv_drained_end(src); -+ bdrv_drained_end(mirror_top_bs); - s->in_drain = false; - bdrv_unref(mirror_top_bs); - bdrv_unref(src); --- -2.23.0 diff --git a/mirror-Make-sure-that-source-and-target-size-match.patch b/mirror-Make-sure-that-source-and-target-size-match.patch deleted file mode 100644 index 5e4edd26ce42f4507240fe806ed7a2ce57364a41..0000000000000000000000000000000000000000 --- a/mirror-Make-sure-that-source-and-target-size-match.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 9f57569d541acaa4a76513d09ede7d2b19aa69ea Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Wed, 3 Jun 2020 16:03:24 +0100 -Subject: [PATCH] mirror: Make sure that source and target size match - -RH-Author: Kevin Wolf -Message-id: <20200603160325.67506-11-kwolf@redhat.com> -Patchwork-id: 97110 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH v2 10/11] mirror: Make sure that source and target size match -Bugzilla: 1778593 -RH-Acked-by: Eric Blake -RH-Acked-by: Max Reitz -RH-Acked-by: Stefano Garzarella - -If the target is shorter than the source, mirror would copy data until -it reaches the end of the target and then fail with an I/O error when -trying to write past the end. - -If the target is longer than the source, the mirror job would complete -successfully, but the target wouldn't actually be an accurate copy of -the source image (it would contain some additional garbage at the end). - -Fix this by checking that both images have the same size when the job -starts. - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-Id: <20200511135825.219437-4-kwolf@redhat.com> -Reviewed-by: Max Reitz -Reviewed-by: Vladimir Sementsov-Ogievskiy -Signed-off-by: Kevin Wolf -(cherry picked from commit e83dd6808c6e0975970f37b49b27cc37bb54eea8) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - block/mirror.c | 21 ++++++++++++--------- - 1 file changed, 12 insertions(+), 9 deletions(-) - -diff --git a/block/mirror.c b/block/mirror.c -index ef6c958ff9..8f0d4544d8 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -853,6 +853,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) - BlockDriverState *target_bs = blk_bs(s->target); - bool need_drain = true; - int64_t length; -+ int64_t target_length; - BlockDriverInfo bdi; - char backing_filename[2]; /* we only need 2 characters because we are only - checking for a NULL string */ -@@ -868,24 +869,26 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) - goto immediate_exit; - } - -+ target_length = blk_getlength(s->target); -+ if (target_length < 0) { -+ ret = target_length; -+ goto immediate_exit; -+ } -+ - /* Active commit must resize the base image if its size differs from the - * active layer. */ - if (s->base == blk_bs(s->target)) { -- int64_t base_length; -- -- base_length = blk_getlength(s->target); -- if (base_length < 0) { -- ret = base_length; -- goto immediate_exit; -- } -- -- if (s->bdev_length > base_length) { -+ if (s->bdev_length > target_length) { - ret = blk_truncate(s->target, s->bdev_length, PREALLOC_MODE_OFF, - NULL); - if (ret < 0) { - goto immediate_exit; - } - } -+ } else if (s->bdev_length != target_length) { -+ error_setg(errp, "Source and target image have different sizes"); -+ ret = -EINVAL; -+ goto immediate_exit; - } - - if (s->bdev_length == 0) { --- -2.27.0 - diff --git a/mirror-Wait-only-for-in-flight-operations.patch b/mirror-Wait-only-for-in-flight-operations.patch deleted file mode 100644 index d1b00c059a7afc7d25a7ec53f18cae8dbcdad85f..0000000000000000000000000000000000000000 --- a/mirror-Wait-only-for-in-flight-operations.patch +++ /dev/null @@ -1,83 +0,0 @@ -From b4e1ea1c59e4dd8cc95b97ccc4eb1d3957fe5489 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Thu, 26 Mar 2020 16:36:28 +0100 -Subject: [PATCH] mirror: Wait only for in-flight operations - -mirror_wait_for_free_in_flight_slot() just picks a random operation to -wait for. However, a MirrorOp is already in s->ops_in_flight when -mirror_co_read() waits for free slots, so if not enough slots are -immediately available, an operation can end up waiting for itself, or -two or more operations can wait for each other to complete, which -results in a hang. - -Fix this by adding a flag to MirrorOp that tells us if the request is -already in flight (and therefore occupies slots that it will later -free), and picking only such operations for waiting. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1794692 -Signed-off-by: Kevin Wolf -Message-Id: <20200326153628.4869-3-kwolf@redhat.com> -Reviewed-by: Eric Blake -Signed-off-by: Kevin Wolf ---- - block/mirror.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/block/mirror.c b/block/mirror.c -index 8f0d4544d8..abcf60a961 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -100,6 +100,7 @@ struct MirrorOp { - - bool is_pseudo_op; - bool is_active_write; -+ bool is_in_flight; - CoQueue waiting_requests; - - QTAILQ_ENTRY(MirrorOp) next; -@@ -290,7 +291,9 @@ mirror_wait_for_any_operation(MirrorBlockJob *s, bool active) - * caller of this function. Since there is only one pseudo op - * at any given time, we will always find some real operation - * to wait on. */ -- if (!op->is_pseudo_op && op->is_active_write == active) { -+ if (!op->is_pseudo_op && op->is_in_flight && -+ op->is_active_write == active) -+ { - qemu_co_queue_wait(&op->waiting_requests, NULL); - return; - } -@@ -364,6 +367,7 @@ static void coroutine_fn mirror_co_read(void *opaque) - /* Copy the dirty cluster. */ - s->in_flight++; - s->bytes_in_flight += op->bytes; -+ op->is_in_flight = true; - trace_mirror_one_iteration(s, op->offset, op->bytes); - - ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes, -@@ -379,6 +383,7 @@ static void coroutine_fn mirror_co_zero(void *opaque) - op->s->in_flight++; - op->s->bytes_in_flight += op->bytes; - *op->bytes_handled = op->bytes; -+ op->is_in_flight = true; - - ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes, - op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0); -@@ -393,6 +398,7 @@ static void coroutine_fn mirror_co_discard(void *opaque) - op->s->in_flight++; - op->s->bytes_in_flight += op->bytes; - *op->bytes_handled = op->bytes; -+ op->is_in_flight = true; - - ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes); - mirror_write_complete(op, ret); -@@ -1305,6 +1311,7 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s, - .offset = offset, - .bytes = bytes, - .is_active_write = true, -+ .is_in_flight = true, - }; - qemu_co_queue_init(&op->waiting_requests); - QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next); --- -2.27.0 - diff --git a/monitor-Discard-BLOCK_IO_ERROR-event-when-VM-reboote.patch b/monitor-Discard-BLOCK_IO_ERROR-event-when-VM-reboote.patch new file mode 100644 index 0000000000000000000000000000000000000000..13d16d03846771b316c9a42c3e616d473c299984 --- /dev/null +++ b/monitor-Discard-BLOCK_IO_ERROR-event-when-VM-reboote.patch @@ -0,0 +1,97 @@ +From f5af9ac3c9af4602812060759f6f95da8725314b Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 11:18:13 +0800 +Subject: [PATCH] monitor: Discard BLOCK_IO_ERROR event when VM rebooted + +Throttled event like QAPI_EVENT_BLOCK_IO_ERROR may be queued +to limit event rate. Event may be delivered when VM is rebooted +if the event was queued in the *monitor_qapi_event_state* hash table. +Which may casue VM pause and other related problems. +Such as seabios blocked during virtio-scsi initialization: + vring_add_buf(vq, sg, out_num, in_num, 0, 0); + vring_kick(vp, vq, 1); + ------------> VM paused here <----------- + /* Wait for reply */ + while (!vring_more_used(vq)) usleep(5); + +Signed-off-by: Yan Wang +--- + include/monitor/monitor.h | 2 ++ + monitor/monitor.c | 30 ++++++++++++++++++++++++++++++ + softmmu/runstate.c | 1 + + 3 files changed, 33 insertions(+) + +diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h +index 12d395d62d..847445f972 100644 +--- a/include/monitor/monitor.h ++++ b/include/monitor/monitor.h +@@ -56,4 +56,6 @@ void monitor_register_hmp(const char *name, bool info, + void monitor_register_hmp_info_hrt(const char *name, + HumanReadableText *(*handler)(Error **errp)); + ++void monitor_qapi_event_discard_io_error(void); ++ + #endif /* MONITOR_H */ +diff --git a/monitor/monitor.c b/monitor/monitor.c +index 013c628695..fb4ae9531c 100644 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -34,6 +34,9 @@ + #include "qemu/option.h" + #include "sysemu/qtest.h" + #include "trace.h" ++#include "qemu/log.h" ++#include "qapi/qmp/qjson.h" ++#include "qapi/qmp/qobject.h" + + /* + * To prevent flooding clients, events can be throttled. The +@@ -767,6 +770,33 @@ int monitor_init_opts(QemuOpts *opts, Error **errp) + return ret; + } + ++void monitor_qapi_event_discard_io_error(void) ++{ ++ GHashTableIter event_iter; ++ MonitorQAPIEventState *evstate; ++ gpointer key, value; ++ GString *json; ++ ++ qemu_mutex_lock(&monitor_lock); ++ g_hash_table_iter_init(&event_iter, monitor_qapi_event_state); ++ while (g_hash_table_iter_next(&event_iter, &key, &value)) { ++ evstate = key; ++ /* Only QAPI_EVENT_BLOCK_IO_ERROR is discarded */ ++ if (evstate->event == QAPI_EVENT_BLOCK_IO_ERROR) { ++ g_hash_table_iter_remove(&event_iter); ++ json = qobject_to_json(QOBJECT(evstate->qdict)); ++ qemu_log(" %s event discarded\n", json->str); ++ timer_del(evstate->timer); ++ timer_free(evstate->timer); ++ qobject_unref(evstate->data); ++ qobject_unref(evstate->qdict); ++ g_string_free(json, true); ++ g_free(evstate); ++ } ++ } ++ qemu_mutex_unlock(&monitor_lock); ++} ++ + QemuOptsList qemu_mon_opts = { + .name = "mon", + .implied_opt_name = "chardev", +diff --git a/softmmu/runstate.c b/softmmu/runstate.c +index 10d9b7365a..5736d908db 100644 +--- a/softmmu/runstate.c ++++ b/softmmu/runstate.c +@@ -448,6 +448,7 @@ void qemu_system_reset(ShutdownCause reason) + qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); + } + cpu_synchronize_all_post_reset(); ++ monitor_qapi_event_discard_io_error(); + } + + /* +-- +2.27.0 + diff --git a/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch b/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch deleted file mode 100644 index 791449b59540fd0d66cac0c367af8436abb55741..0000000000000000000000000000000000000000 --- a/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 117082ef493e62e6e2cd972b309e0cd72682ab02 Mon Sep 17 00:00:00 2001 -From: Chen Qun -Date: Tue, 14 Apr 2020 19:50:59 +0800 -Subject: [PATCH] moniter: fix memleak in monitor_fdset_dup_fd_find_remove - -When remove dup_fd in monitor_fdset_dup_fd_find_remove function, -we need to free mon_fdset_fd_dup. ASAN shows memory leak stack: - -Direct leak of 96 byte(s) in 3 object(s) allocated from: - #0 0xfffd37b033b3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33b3) - #1 0xfffd375c71cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb) - #2 0xaaae25bf1c17 in monitor_fdset_dup_fd_add /qemu/monitor.c:2576 - #3 0xaaae265cfd8f in qemu_open /qemu/util/osdep.c:315 - #4 0xaaae264e2b2b in qmp_chardev_open_file_source /qemu/chardev/char-fd.c:122 - #5 0xaaae264e47cf in qmp_chardev_open_file /qemu/chardev/char-file.c:81 - #6 0xaaae264e118b in qemu_char_open /qemu/chardev/char.c:237 - #7 0xaaae264e118b in qemu_chardev_new /qemu/chardev/char.c:964 - #8 0xaaae264e1543 in qemu_chr_new_from_opts /qemu/chardev/char.c:680 - #9 0xaaae25e12e0f in chardev_init_func /qemu/vl.c:2083 - #10 0xaaae26603823 in qemu_opts_foreach /qemu/util/qemu-option.c:1170 - #11 0xaaae258c9787 in main /qemu/vl.c:4089 - #12 0xfffd35b80b9f in __libc_start_main (/lib64/libc.so.6+0x20b9f) - -Reported-by: Euler Robot -Signed-off-by: Chen Qun -(cherry picked from commit a661614de18c89f58cad3fc1bb8aab44e820183a) ---- - monitor/misc.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/monitor/misc.c b/monitor/misc.c -index 00338c00..0d6369ba 100644 ---- a/monitor/misc.c -+++ b/monitor/misc.c -@@ -1746,6 +1746,7 @@ static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) - if (mon_fdset_fd_dup->fd == dup_fd) { - if (remove) { - QLIST_REMOVE(mon_fdset_fd_dup, next); -+ g_free(mon_fdset_fd_dup); - if (QLIST_EMPTY(&mon_fdset->dup_fds)) { - monitor_fdset_cleanup(mon_fdset); - } --- -2.23.0 diff --git a/monitor-limit-io-error-qmp-event-to-at-most-once-per.patch b/monitor-limit-io-error-qmp-event-to-at-most-once-per.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b3b02f82514599c996d2ba05950ac2445afd773 --- /dev/null +++ b/monitor-limit-io-error-qmp-event-to-at-most-once-per.patch @@ -0,0 +1,29 @@ +From 44f45b5c163efed5387dac40e229e0a50bf5921a Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 11:35:58 +0800 +Subject: [PATCH] monitor: limit io error qmp event to at most once per 60s + +The speed of BLOCK IO ERROR event maybe very high (thousands per +second). If we report all BLOCK IO ERRORs, the log file will be flooded +with BLOCK IO ERROR event. So throttle it to at most once per 60s. + +Signed-off-by: Yan Wang +--- + monitor/monitor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/monitor/monitor.c b/monitor/monitor.c +index fb4ae9531c..621e79eb66 100644 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -300,6 +300,7 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { + [QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS }, + [QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS }, + [QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE] = { 1000 * SCALE_MS }, ++ [QAPI_EVENT_BLOCK_IO_ERROR] = { 60L * 1000 * SCALE_MS }, + }; + + /* +-- +2.27.0 + diff --git a/monitor-qmp-drop-inflight-rsp-if-qmp-client-broken.patch b/monitor-qmp-drop-inflight-rsp-if-qmp-client-broken.patch new file mode 100644 index 0000000000000000000000000000000000000000..d45cb3189c161de501ac329027b502ec60858546 --- /dev/null +++ b/monitor-qmp-drop-inflight-rsp-if-qmp-client-broken.patch @@ -0,0 +1,111 @@ +From 7eb28408efe75192a0f976a197f8f1906d9073e8 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 14:13:05 +0800 +Subject: [PATCH 14/15] monitor/qmp: drop inflight rsp if qmp client broken + +If libvirt restart while qemu is handle qmp message, libvirt will +reconnect qemu monitor socket, and query status of qemu by qmp. +But qemu may return last qmp respond to new connect socket, and libvirt +recv unexpected respond, So libvirt think qemu is abnormal, and will +kill qemu. + +This patch add qmp connect id, while reconnect id will change. While +respond to libvirt, judge if id is same, if not, drop this respond. +--- + monitor/monitor-internal.h | 1 + + monitor/qmp.c | 19 +++++++++++-------- + 2 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h +index 3da3f86c6a..5435864add 100644 +--- a/monitor/monitor-internal.h ++++ b/monitor/monitor-internal.h +@@ -144,6 +144,7 @@ typedef struct { + const QmpCommandList *commands; + bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ + bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ ++ uint64_t qmp_client_id; /*qmp client id, update if peer disconnect */ + /* + * Protects qmp request/response queue. + * Take monitor_lock first when you need both. +diff --git a/monitor/qmp.c b/monitor/qmp.c +index 092c527b6f..4d1ac66785 100644 +--- a/monitor/qmp.c ++++ b/monitor/qmp.c +@@ -125,18 +125,19 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp) + * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. + * Nothing is emitted then. + */ +-static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) ++static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp, uint64_t req_client_id) + { +- if (rsp) { +- qmp_send_response(mon, rsp); ++ if (!rsp || (mon->qmp_client_id != req_client_id)) { ++ return; + } ++ qmp_send_response(mon, rsp); + } + + /* + * Runs outside of coroutine context for OOB commands, but in + * coroutine context for everything else. + */ +-static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) ++static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req, uint64_t req_client_id) + { + QDict *rsp; + QDict *error; +@@ -156,7 +157,7 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) + } + } + +- monitor_qmp_respond(mon, rsp); ++ monitor_qmp_respond(mon, rsp, req_client_id); + qobject_unref(rsp); + } + +@@ -315,13 +316,13 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) + trace_monitor_qmp_cmd_in_band(id_json->str); + g_string_free(id_json, true); + } +- monitor_qmp_dispatch(mon, req_obj->req); ++ monitor_qmp_dispatch(mon, req_obj->req, mon->qmp_client_id); + } else { + assert(req_obj->err); + trace_monitor_qmp_err_in_band(error_get_pretty(req_obj->err)); + rsp = qmp_error_response(req_obj->err); + req_obj->err = NULL; +- monitor_qmp_respond(mon, rsp); ++ monitor_qmp_respond(mon, rsp, mon->qmp_client_id); + qobject_unref(rsp); + } + +@@ -366,7 +367,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err) + trace_monitor_qmp_cmd_out_of_band(id_json->str); + g_string_free(id_json, true); + } +- monitor_qmp_dispatch(mon, req); ++ monitor_qmp_dispatch(mon, req, mon->qmp_client_id); + qobject_unref(req); + return; + } +@@ -452,6 +453,7 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event) + mon_refcount++; + break; + case CHR_EVENT_CLOSED: ++ mon->qmp_client_id++; + /* + * Note: this is only useful when the output of the chardev + * backend is still open. For example, when the backend is +@@ -505,6 +507,7 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) + } + qemu_chr_fe_set_echo(&mon->common.chr, true); + ++ mon->qmp_client_id = 1; + /* Note: we run QMP monitor in I/O thread when @chr supports that */ + monitor_data_init(&mon->common, true, false, + qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); +-- +2.27.0 + diff --git a/msix-add-valid.accepts-methods-to-check-address.patch b/msix-add-valid.accepts-methods-to-check-address.patch deleted file mode 100644 index 67397549683ec1e44d29c1f858f4154bc3b6a024..0000000000000000000000000000000000000000 --- a/msix-add-valid.accepts-methods-to-check-address.patch +++ /dev/null @@ -1,78 +0,0 @@ -From e9cc24b1737f745b23c408b183dd34fda5abc30c Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 19 Feb 2021 16:28:00 +0800 -Subject: [PATCH] msix: add valid.accepts methods to check address - -Fix CVE-2020-13754 - -While doing msi-x mmio operations, a guest may send an address -that leads to an OOB access issue. Add valid.accepts methods to -ensure that ensuing mmio r/w operation don't go beyond regions. - -Reported-by: Ren Ding -Reported-by: Hanqing Zhao -Reported-by: Anatoly Trosinenko -Reported-by: Alexander Bulekov -Signed-off-by: Prasad J Pandit - -patch link: https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg00004.html -Signed-off-by: Jiajie Li ---- - hw/pci/msix.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/hw/pci/msix.c b/hw/pci/msix.c -index d39dcf32e8..ec43f16875 100644 ---- a/hw/pci/msix.c -+++ b/hw/pci/msix.c -@@ -192,6 +192,15 @@ static void msix_table_mmio_write(void *opaque, hwaddr addr, - msix_handle_mask_update(dev, vector, was_masked); - } - -+static bool msix_table_accepts(void *opaque, hwaddr addr, unsigned size, -+ bool is_write, MemTxAttrs attrs) -+{ -+ PCIDevice *dev = opaque; -+ uint16_t tbl_size = dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE; -+ -+ return dev->msix_table + addr + 4 <= dev->msix_table + tbl_size; -+} -+ - static const MemoryRegionOps msix_table_mmio_ops = { - .read = msix_table_mmio_read, - .write = msix_table_mmio_write, -@@ -199,6 +208,7 @@ static const MemoryRegionOps msix_table_mmio_ops = { - .valid = { - .min_access_size = 4, - .max_access_size = 4, -+ .accepts = msix_table_accepts - }, - }; - -@@ -220,6 +230,15 @@ static void msix_pba_mmio_write(void *opaque, hwaddr addr, - { - } - -+static bool msix_pba_accepts(void *opaque, hwaddr addr, unsigned size, -+ bool is_write, MemTxAttrs attrs) -+{ -+ PCIDevice *dev = opaque; -+ uint16_t pba_size = QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8; -+ -+ return dev->msix_pba + addr + 4 <= dev->msix_pba + pba_size; -+} -+ - static const MemoryRegionOps msix_pba_mmio_ops = { - .read = msix_pba_mmio_read, - .write = msix_pba_mmio_write, -@@ -227,6 +246,7 @@ static const MemoryRegionOps msix_pba_mmio_ops = { - .valid = { - .min_access_size = 4, - .max_access_size = 4, -+ .accepts = msix_pba_accepts - }, - }; - --- -2.27.0 - diff --git a/multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch b/multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch deleted file mode 100644 index ef380e66655d0faf290b1d61072165a64bc0861e..0000000000000000000000000000000000000000 --- a/multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 3db288bbddb730960430fb4907e100f19001ca0a Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:31:07 +0800 -Subject: [PATCH] multifd: Make sure that we don't do any IO after an error - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert ---- - migration/ram.c | 22 +++++++++++++--------- - 1 file changed, 13 insertions(+), 9 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 3ded38c0be..b74929542d 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -3617,7 +3617,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) - { - RAMState **temp = opaque; - RAMState *rs = *temp; -- int ret; -+ int ret = 0; - int i; - int64_t t0; - int done = 0; -@@ -3686,12 +3686,14 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) - ram_control_after_iterate(f, RAM_CONTROL_ROUND); - - out: -- multifd_send_sync_main(rs); -- qemu_put_be64(f, RAM_SAVE_FLAG_EOS); -- qemu_fflush(f); -- ram_counters.transferred += 8; -+ if (ret >= 0) { -+ multifd_send_sync_main(rs); -+ qemu_put_be64(f, RAM_SAVE_FLAG_EOS); -+ qemu_fflush(f); -+ ram_counters.transferred += 8; - -- ret = qemu_file_get_error(f); -+ ret = qemu_file_get_error(f); -+ } - if (ret < 0) { - return ret; - } -@@ -3745,9 +3747,11 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - - rcu_read_unlock(); - -- multifd_send_sync_main(rs); -- qemu_put_be64(f, RAM_SAVE_FLAG_EOS); -- qemu_fflush(f); -+ if (ret >= 0) { -+ multifd_send_sync_main(rs); -+ qemu_put_be64(f, RAM_SAVE_FLAG_EOS); -+ qemu_fflush(f); -+ } - - return ret; - } --- -2.27.0 - diff --git a/multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch b/multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch deleted file mode 100644 index a2209ef5776728ced1205b9b1ce3e50daeaa84d3..0000000000000000000000000000000000000000 --- a/multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch +++ /dev/null @@ -1,37 +0,0 @@ -From a4288f41b3af9f4f73f162b89007c6928509a43c Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:51:51 +0800 -Subject: [PATCH] multifd/tls: fix memoryleak of the QIOChannelSocket object - when cancelling migration -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When creating new tls client, the tioc->master will be referenced which results in socket -leaking after multifd_save_cleanup if we cancel migration. -Fix it by do object_unref() after tls client creation. - -Suggested-by: Daniel P. Berrangé -Signed-off-by: Chuan Zheng -Message-Id: <1605104763-118687-1-git-send-email-zhengchuan@huawei.com> -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Dr. David Alan Gilbert ---- - migration/ram.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/migration/ram.c b/migration/ram.c -index a37dbfc049..92ce1a53e7 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1246,6 +1246,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, - return; - } - -+ object_unref(OBJECT(ioc)); - trace_multifd_tls_outgoing_handshake_start(ioc, tioc, hostname); - qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); - p->c = QIO_CHANNEL(tioc); --- -2.27.0 - diff --git a/nbd-allow-reconnect-on-open-with-corresponding-new-o.patch b/nbd-allow-reconnect-on-open-with-corresponding-new-o.patch new file mode 100644 index 0000000000000000000000000000000000000000..274536ba6cb5bbe05f9fa61d7aea2fa768cd11be --- /dev/null +++ b/nbd-allow-reconnect-on-open-with-corresponding-new-o.patch @@ -0,0 +1,138 @@ +From eb42fba27842e3ebc342f15847863b5e812a7919 Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Mon, 29 Aug 2022 15:28:55 +0800 +Subject: [PATCH 1/5] nbd: allow reconnect on open, with corresponding new + options + +It is useful when start of vm and start of nbd server are not +simple to sync. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Signed-off-by: Zhang Bo +--- + block/nbd.c | 45 +++++++++++++++++++++++++++++++++++++++++++- + qapi/block-core.json | 9 ++++++++- + 2 files changed, 52 insertions(+), 2 deletions(-) + +diff --git a/block/nbd.c b/block/nbd.c +index 5ef462db1b..63dbfa807d 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -80,6 +80,7 @@ typedef struct BDRVNBDState { + NBDClientState state; + + QEMUTimer *reconnect_delay_timer; ++ QEMUTimer *open_timer; + + NBDClientRequest requests[MAX_NBD_REQUESTS]; + NBDReply reply; +@@ -87,6 +88,7 @@ typedef struct BDRVNBDState { + + /* Connection parameters */ + uint32_t reconnect_delay; ++ uint32_t open_timeout; + SocketAddress *saddr; + char *export, *tlscredsid; + QCryptoTLSCreds *tlscreds; +@@ -218,6 +220,32 @@ static void nbd_teardown_connection(BlockDriverState *bs) + s->state = NBD_CLIENT_QUIT; + } + ++static void open_timer_del(BDRVNBDState *s) ++{ ++ if (s->open_timer) { ++ timer_free(s->open_timer); ++ s->open_timer = NULL; ++ } ++} ++ ++static void open_timer_cb(void *opaque) ++{ ++ BDRVNBDState *s = opaque; ++ ++ nbd_co_establish_connection_cancel(s->conn); ++ open_timer_del(s); ++} ++ ++static void open_timer_init(BDRVNBDState *s, uint64_t expire_time_ns) ++{ ++ assert(!s->open_timer); ++ s->open_timer = aio_timer_new(bdrv_get_aio_context(s->bs), ++ QEMU_CLOCK_REALTIME, ++ SCALE_NS, ++ open_timer_cb, s); ++ timer_mod(s->open_timer, expire_time_ns); ++} ++ + static bool nbd_client_connecting(BDRVNBDState *s) + { + NBDClientState state = qatomic_load_acquire(&s->state); +@@ -1742,6 +1770,15 @@ static QemuOptsList nbd_runtime_opts = { + "future requests before a successful reconnect will " + "immediately fail. Default 0", + }, ++ { ++ .name = "open-timeout", ++ .type = QEMU_OPT_NUMBER, ++ .help = "In seconds. If zero, the nbd driver tries the connection " ++ "only once, and fails to open if the connection fails. " ++ "If non-zero, the nbd driver will repeat connection " ++ "attempts until successful or until @open-timeout seconds " ++ "have elapsed. Default 0", ++ }, + { /* end of list */ } + }, + }; +@@ -1797,6 +1834,7 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options, + } + + s->reconnect_delay = qemu_opt_get_number(opts, "reconnect-delay", 0); ++ s->open_timeout = qemu_opt_get_number(opts, "open-timeout", 0); + + ret = 0; + +@@ -1828,7 +1866,12 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + s->conn = nbd_client_connection_new(s->saddr, true, s->export, + s->x_dirty_bitmap, s->tlscreds); + +- /* TODO: Configurable retry-until-timeout behaviour. */ ++ if (s->open_timeout) { ++ nbd_client_connection_enable_retry(s->conn); ++ open_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ++ s->open_timeout * NANOSECONDS_PER_SECOND); ++ } ++ + s->state = NBD_CLIENT_CONNECTING_WAIT; + ret = nbd_do_establish_connection(bs, errp); + if (ret < 0) { +diff --git a/qapi/block-core.json b/qapi/block-core.json +index e65fabe36d..618e417135 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -4096,6 +4096,12 @@ + # future requests before a successful reconnect will + # immediately fail. Default 0 (Since 4.2) + # ++# @open-timeout: In seconds. If zero, the nbd driver tries the connection ++# only once, and fails to open if the connection fails. ++# If non-zero, the nbd driver will repeat connection attempts ++# until successful or until @open-timeout seconds have elapsed. ++# Default 0 (Since 7.0) ++# + # Features: + # @unstable: Member @x-dirty-bitmap is experimental. + # +@@ -4106,7 +4112,8 @@ + '*export': 'str', + '*tls-creds': 'str', + '*x-dirty-bitmap': { 'type': 'str', 'features': [ 'unstable' ] }, +- '*reconnect-delay': 'uint32' } } ++ '*reconnect-delay': 'uint32', ++ '*open-timeout': 'uint32' } } + + ## + # @BlockdevOptionsRaw: +-- +2.27.0 + diff --git a/nbd-fix-uninitialized-variable-warning.patch b/nbd-fix-uninitialized-variable-warning.patch deleted file mode 100644 index be69252807d1a7fbd5be7e8e6d187862527c439d..0000000000000000000000000000000000000000 --- a/nbd-fix-uninitialized-variable-warning.patch +++ /dev/null @@ -1,46 +0,0 @@ -From eb5abb631196b97879a868ec75e7f70400695f7f Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Mon, 13 Jan 2020 17:03:08 +0800 -Subject: [PATCH] nbd: fix uninitialized variable warning - -Fixes: -/mnt/sdb/qemu/nbd/server.c: In function 'nbd_handle_request': -/mnt/sdb/qemu/nbd/server.c:2313:9: error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized] - int ret; - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan ---- - nbd/server.c | 10 +--------- - 1 file changed, 1 insertion(+), 9 deletions(-) - -diff --git a/nbd/server.c b/nbd/server.c -index e21bd501..aefb07d9 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -2304,20 +2304,12 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, - !client->export_meta.bitmap, - NBD_META_ID_BASE_ALLOCATION, - errp); -- if (ret < 0) { -- return ret; -- } -- } -- -- if (client->export_meta.bitmap) { -+ } else { /* client->export_meta.bitmap */ - ret = nbd_co_send_bitmap(client, request->handle, - client->exp->export_bitmap, - request->from, request->len, - dont_fragment, - true, NBD_META_ID_DIRTY_BITMAP, errp); -- if (ret < 0) { -- return ret; -- } - } - - return ret; --- -2.18.1 - - diff --git a/nbd-server-Avoid-long-error-message-assertions-CVE-2.patch b/nbd-server-Avoid-long-error-message-assertions-CVE-2.patch deleted file mode 100644 index 71ce6cabd3a38d5af0701f579babe793b1ea7d07..0000000000000000000000000000000000000000 --- a/nbd-server-Avoid-long-error-message-assertions-CVE-2.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 719292175d391e77487f3c55f5f97a065e44d9f8 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 10 Jun 2020 18:32:01 -0400 -Subject: [PATCH] nbd/server: Avoid long error message assertions - CVE-2020-10761 - -RH-Author: Eric Blake -Message-id: <20200610183202.3780750-2-eblake@redhat.com> -Patchwork-id: 97494 -O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 1/2] nbd/server: Avoid long error message assertions CVE-2020-10761 -Bugzilla: 1845384 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Max Reitz -RH-Acked-by: Stefan Hajnoczi - -Ever since commit 36683283 (v2.8), the server code asserts that error -strings sent to the client are well-formed per the protocol by not -exceeding the maximum string length of 4096. At the time the server -first started sending error messages, the assertion could not be -triggered, because messages were completely under our control. -However, over the years, we have added latent scenarios where a client -could trigger the server to attempt an error message that would -include the client's information if it passed other checks first: - -- requesting NBD_OPT_INFO/GO on an export name that is not present - (commit 0cfae925 in v2.12 echoes the name) - -- requesting NBD_OPT_LIST/SET_META_CONTEXT on an export name that is - not present (commit e7b1948d in v2.12 echoes the name) - -At the time, those were still safe because we flagged names larger -than 256 bytes with a different message; but that changed in commit -93676c88 (v4.2) when we raised the name limit to 4096 to match the NBD -string limit. (That commit also failed to change the magic number -4096 in nbd_negotiate_send_rep_err to the just-introduced named -constant.) So with that commit, long client names appended to server -text can now trigger the assertion, and thus be used as a denial of -service attack against a server. As a mitigating factor, if the -server requires TLS, the client cannot trigger the problematic paths -unless it first supplies TLS credentials, and such trusted clients are -less likely to try to intentionally crash the server. - -We may later want to further sanitize the user-supplied strings we -place into our error messages, such as scrubbing out control -characters, but that is less important to the CVE fix, so it can be a -later patch to the new nbd_sanitize_name. - -Consideration was given to changing the assertion in -nbd_negotiate_send_rep_verr to instead merely log a server error and -truncate the message, to avoid leaving a latent path that could -trigger a future CVE DoS on any new error message. However, this -merely complicates the code for something that is already (correctly) -flagging coding errors, and now that we are aware of the long message -pitfall, we are less likely to introduce such errors in the future, -which would make such error handling dead code. - -Reported-by: Xueqiang Wei -CC: qemu-stable@nongnu.org -Fixes: https://bugzilla.redhat.com/1843684 CVE-2020-10761 -Fixes: 93676c88d7 -Signed-off-by: Eric Blake -Message-Id: <20200610163741.3745251-2-eblake@redhat.com> -Reviewed-by: Vladimir Sementsov-Ogievskiy -(cherry picked from commit 5c4fe018c025740fef4a0a4421e8162db0c3eefd) -Signed-off-by: Eric Blake -Signed-off-by: Eduardo Lima (Etrunko) ---- - nbd/server.c | 21 +++++++++++++++++++-- - tests/qemu-iotests/143 | 4 ++++ - tests/qemu-iotests/143.out | 2 ++ - 3 files changed, 25 insertions(+), 2 deletions(-) - -diff --git a/nbd/server.c b/nbd/server.c -index 2d81248967..115e8f06ed 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -229,6 +229,19 @@ out: - return ret; - } - -+/* -+ * Return a malloc'd copy of @name suitable for use in an error reply. -+ */ -+static char * -+nbd_sanitize_name(const char *name) -+{ -+ if (strnlen(name, 80) < 80) { -+ return g_strdup(name); -+ } -+ /* XXX Should we also try to sanitize any control characters? */ -+ return g_strdup_printf("%.80s...", name); -+} -+ - /* Send an error reply. - * Return -errno on error, 0 on success. */ - static int GCC_FMT_ATTR(4, 5) -@@ -584,9 +597,11 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, - - exp = nbd_export_find(name); - if (!exp) { -+ g_autofree char *sane_name = nbd_sanitize_name(name); -+ - return nbd_negotiate_send_rep_err(client, NBD_REP_ERR_UNKNOWN, - errp, "export '%s' not present", -- name); -+ sane_name); - } - - /* Don't bother sending NBD_INFO_NAME unless client requested it */ -@@ -975,8 +990,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client, - - meta->exp = nbd_export_find(export_name); - if (meta->exp == NULL) { -+ g_autofree char *sane_name = nbd_sanitize_name(export_name); -+ - return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp, -- "export '%s' not present", export_name); -+ "export '%s' not present", sane_name); - } - - ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), errp); -diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 -index f649b36195..d2349903b1 100755 ---- a/tests/qemu-iotests/143 -+++ b/tests/qemu-iotests/143 -@@ -58,6 +58,10 @@ _send_qemu_cmd $QEMU_HANDLE \ - $QEMU_IO_PROG -f raw -c quit \ - "nbd+unix:///no_such_export?socket=$SOCK_DIR/nbd" 2>&1 \ - | _filter_qemu_io | _filter_nbd -+# Likewise, with longest possible name permitted in NBD protocol -+$QEMU_IO_PROG -f raw -c quit \ -+ "nbd+unix:///$(printf %4096d 1 | tr ' ' a)?socket=$SOCK_DIR/nbd" 2>&1 \ -+ | _filter_qemu_io | _filter_nbd | sed 's/aaaa*aa/aa--aa/' - - _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'quit' }" \ -diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out -index 037d34a409..fc7bab3129 100644 ---- a/tests/qemu-iotests/143.out -+++ b/tests/qemu-iotests/143.out -@@ -3,6 +3,8 @@ QA output created by 143 - {"return": {}} - qemu-io: can't open device nbd+unix:///no_such_export?socket=SOCK_DIR/nbd: Requested export not available - server reported: export 'no_such_export' not present -+qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available -+server reported: export 'aa--aa...' not present - {"return": {}} - {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} - *** done --- -2.27.0 - diff --git a/nbd-server.c-fix-invalid-read-after-client-was-alrea.patch b/nbd-server.c-fix-invalid-read-after-client-was-alrea.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6ba4e43042cefc06fe36e3a932a1c5a764a5a1d --- /dev/null +++ b/nbd-server.c-fix-invalid-read-after-client-was-alrea.patch @@ -0,0 +1,45 @@ +From 4b156248776f734d63fe37629d56c40234fda9c0 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 10:42:33 +0800 +Subject: [PATCH] nbd/server.c: fix invalid read after client was already free + +In the process of NBD equipment pressurization, executing QEMU NBD will +lead to the failure of IO distribution and go to NBD_ Out process of trip(). +If two or more IO go to the out process, client NBD will release in nbd_request_put(). +The user after free problem that is read again in close(). +Through the NBD_ Save the value of client > closing before the out process in trip +to solve the use after free problem. + +Signed-off-by: wangjian161 +--- + nbd/server.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 4630dd7322..37515ed520 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -2606,6 +2606,7 @@ static coroutine_fn void nbd_trip(void *opaque) + NBDRequestData *req; + NBDRequest request = { 0 }; /* GCC thinks it can be used uninitialized */ + int ret; ++ bool client_closing; + Error *local_err = NULL; + + trace_nbd_trip(); +@@ -2681,8 +2682,11 @@ disconnect: + if (local_err) { + error_reportf_err(local_err, "Disconnect client, due to: "); + } ++ client_closing = client->closing; + nbd_request_put(req); +- client_close(client, true); ++ if (!client_closing) { ++ client_close(client, true); ++ } + nbd_client_put(client); + } + +-- +2.27.0 + diff --git a/net-Fix-a-misleading-error-message.patch b/net-Fix-a-misleading-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..75a49b12e60c6a8a5e20c02cc82d480e23df2d00 --- /dev/null +++ b/net-Fix-a-misleading-error-message.patch @@ -0,0 +1,50 @@ +From 1cc7783df04674ff375905cc9a8ec23f71617408 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 21 Nov 2023 20:40:24 +0800 +Subject: [PATCH] net: Fix a misleading error message + +cheery-pick from 0a4a1512e01228fc59b00d68e86f7099b6439773 + +The error message + + $ qemu-system-x86_64 -netdev user,id=net0,ipv6-net=fec0::0/ + qemu-system-x86_64: -netdev user,id=net0,ipv6-net=fec0::0/: Parameter 'ipv6-prefixlen' expects a number + +points to ipv6-prefixlen instead of ipv6-net. Fix: + + qemu-system-x86_64: -netdev user,id=net0,ipv6-net=fec0::0/: parameter 'ipv6-net' expects a number after '/' + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-6-armbru@redhat.com> +Signed-off-by: qihao_yewu +--- + net/net.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/net.c b/net/net.c +index ed4b1c1740..daad8784ec 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -1122,7 +1122,7 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) + int ret = -1; + Visitor *v = opts_visitor_new(opts); + +- /* Parse convenience option format ip6-net=fec0::0[/64] */ ++ /* Parse convenience option format ipv6-net=fec0::0[/64] */ + const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); + + if (ip6_net) { +@@ -1142,8 +1142,8 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) + if (substrings[1] && + qemu_strtoul(substrings[1], NULL, 10, &prefix_len)) + { +- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, +- "ipv6-prefixlen", "a number"); ++ error_setg(errp, ++ "parameter 'ipv6-net' expects a number after '/'"); + goto out; + } + +-- +2.27.0 + diff --git a/net-Fix-uninitialized-data-usage.patch b/net-Fix-uninitialized-data-usage.patch new file mode 100644 index 0000000000000000000000000000000000000000..d72c895855854c90ff16ce5c3908e6332d15dcbe --- /dev/null +++ b/net-Fix-uninitialized-data-usage.patch @@ -0,0 +1,92 @@ +From de8ab0c3b4e5f9aac9e7be00cfbd86d724bf036e Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 24 Mar 2023 07:42:33 +0000 +Subject: [PATCH] net: Fix uninitialized data usage mainline inclusion commit + e29919c93d19118610d64de9deb9c223024c0bc6 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +e.g. +1109 15:16:20.151506 Uninitialized bytes in ioctl_common_pre at offset 0 inside [0x7ffc516af9b8, 4) + 1109 15:16:20.151659 ==588974==WARNING: MemorySanitizer: use-of-uninitialized-value + 1109 15:16:20.312923 #0 0x5639b88acb21 in tap_probe_vnet_hdr_len third_party/qemu/net/tap-linux.c:183:9 + 1109 15:16:20.312952 #1 0x5639b88afd66 in net_tap_fd_init third_party/qemu/net/tap.c:409:9 + 1109 15:16:20.312954 #2 0x5639b88b2d1b in net_init_tap_one third_party/qemu/net/tap.c:681:19 + 1109 15:16:20.312956 #3 0x5639b88b16a8 in net_init_tap third_party/qemu/net/tap.c:912:13 + 1109 15:16:20.312957 #4 0x5639b8890175 in net_client_init1 third_party/qemu/net/net.c:1110:9 + 1109 15:16:20.312958 #5 0x5639b888f912 in net_client_init third_party/qemu/net/net.c:1208:15 + 1109 15:16:20.312960 #6 0x5639b8894aa5 in net_param_nic third_party/qemu/net/net.c:1588:11 + 1109 15:16:20.312961 #7 0x5639b900cd18 in qemu_opts_foreach third_party/qemu/util/qemu-option.c:1135:14 + 1109 15:16:20.312962 #8 0x5639b889393c in net_init_clients third_party/qemu/net/net.c:1612:9 + 1109 15:16:20.312964 #9 0x5639b717aaf3 in qemu_create_late_backends third_party/qemu/softmmu/vl.c:1962:5 + 1109 15:16:20.312965 #10 0x5639b717aaf3 in qemu_init third_party/qemu/softmmu/vl.c:3694:5 + 1109 15:16:20.312967 #11 0x5639b71083b8 in main third_party/qemu/softmmu/main.c:49:5 + 1109 15:16:20.312968 #12 0x7f464de1d8d2 in __libc_start_main (/usr/grte/v5/lib64/libc.so.6+0x628d2) + 1109 15:16:20.312969 #13 0x5639b6bbd389 in _start /usr/grte/v5/debug-src/src/csu/../sysdeps/x86_64/start.S:120 + 1109 15:16:20.312970 + 1109 15:16:20.312975 Uninitialized value was stored to memory at + 1109 15:16:20.313393 #0 0x5639b88acbee in tap_probe_vnet_hdr_len third_party/qemu/net/tap-linux.c + 1109 15:16:20.313396 #1 0x5639b88afd66 in net_tap_fd_init third_party/qemu/net/tap.c:409:9 + 1109 15:16:20.313398 #2 0x5639b88b2d1b in net_init_tap_one third_party/qemu/net/tap.c:681:19 + 1109 15:16:20.313399 #3 0x5639b88b16a8 in net_init_tap third_party/qemu/net/tap.c:912:13 + 1109 15:16:20.313400 #4 0x5639b8890175 in net_client_init1 third_party/qemu/net/net.c:1110:9 + 1109 15:16:20.313401 #5 0x5639b888f912 in net_client_init third_party/qemu/net/net.c:1208:15 + 1109 15:16:20.313403 #6 0x5639b8894aa5 in net_param_nic third_party/qemu/net/net.c:1588:11 + 1109 15:16:20.313404 #7 0x5639b900cd18 in qemu_opts_foreach third_party/qemu/util/qemu-option.c:1135:14 + 1109 15:16:20.313405 #8 0x5639b889393c in net_init_clients third_party/qemu/net/net.c:1612:9 + 1109 15:16:20.313407 #9 0x5639b717aaf3 in qemu_create_late_backends third_party/qemu/softmmu/vl.c:1962:5 + 1109 15:16:20.313408 #10 0x5639b717aaf3 in qemu_init third_party/qemu/softmmu/vl.c:3694:5 + 1109 15:16:20.313409 #11 0x5639b71083b8 in main third_party/qemu/softmmu/main.c:49:5 + 1109 15:16:20.313410 #12 0x7f464de1d8d2 in __libc_start_main (/usr/grte/v5/lib64/libc.so.6+0x628d2) + 1109 15:16:20.313412 #13 0x5639b6bbd389 in _start /usr/grte/v5/debug-src/src/csu/../sysdeps/x86_64/start.S:120 + 1109 15:16:20.313413 + 1109 15:16:20.313417 Uninitialized value was stored to memory at + 1109 15:16:20.313791 #0 0x5639b88affbd in net_tap_fd_init third_party/qemu/net/tap.c:400:26 + 1109 15:16:20.313826 #1 0x5639b88b2d1b in net_init_tap_one third_party/qemu/net/tap.c:681:19 + 1109 15:16:20.313829 #2 0x5639b88b16a8 in net_init_tap third_party/qemu/net/tap.c:912:13 + 1109 15:16:20.313831 #3 0x5639b8890175 in net_client_init1 third_party/qemu/net/net.c:1110:9 + 1109 15:16:20.313836 #4 0x5639b888f912 in net_client_init third_party/qemu/net/net.c:1208:15 + 1109 15:16:20.313838 #5 0x5639b8894aa5 in net_param_nic third_party/qemu/net/net.c:1588:11 + 1109 15:16:20.313839 #6 0x5639b900cd18 in qemu_opts_foreach third_party/qemu/util/qemu-option.c:1135:14 + 1109 15:16:20.313841 #7 0x5639b889393c in net_init_clients third_party/qemu/net/net.c:1612:9 + 1109 15:16:20.313843 #8 0x5639b717aaf3 in qemu_create_late_backends third_party/qemu/softmmu/vl.c:1962:5 + 1109 15:16:20.313844 #9 0x5639b717aaf3 in qemu_init third_party/qemu/softmmu/vl.c:3694:5 + 1109 15:16:20.313845 #10 0x5639b71083b8 in main third_party/qemu/softmmu/main.c:49:5 + 1109 15:16:20.313846 #11 0x7f464de1d8d2 in __libc_start_main (/usr/grte/v5/lib64/libc.so.6+0x628d2) + 1109 15:16:20.313847 #12 0x5639b6bbd389 in _start /usr/grte/v5/debug-src/src/csu/../sysdeps/x86_64/start.S:120 + 1109 15:16:20.313849 + 1109 15:16:20.313851 Uninitialized value was created by an allocation of 'ifr' in the stack frame of function 'tap_probe_vnet_hdr' + 1109 15:16:20.313855 #0 0x5639b88ac680 in tap_probe_vnet_hdr third_party/qemu/net/tap-linux.c:151 + 1109 15:16:20.313856 + 1109 15:16:20.313878 SUMMARY: MemorySanitizer: use-of-uninitialized-value third_party/qemu/net/tap-linux.c:183:9 in tap_probe_vnet_hdr_len + +Fixes: dc69004c7d8 ("net: move tap_probe_vnet_hdr() to tap-linux.c") +Reviewed-by: Hao Wu +Reviewed-by: Patrick Venture +Reviewed-by: Philippe Mathieu-Daud茅 +Signed-off-by: Peter Foley +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + net/tap-linux.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/tap-linux.c b/net/tap-linux.c +index 9584769740..5e70b93037 100644 +--- a/net/tap-linux.c ++++ b/net/tap-linux.c +@@ -150,6 +150,7 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) + int tap_probe_vnet_hdr(int fd, Error **errp) + { + struct ifreq ifr; ++ memset(&ifr, 0, sizeof(ifr)); + + if (ioctl(fd, TUNGETIFF, &ifr) != 0) { + /* TUNGETIFF is available since kernel v2.6.27 */ +-- +2.27.0 + diff --git a/net-Provide-MemReentrancyGuard-to-qemu_new_nic.patch b/net-Provide-MemReentrancyGuard-to-qemu_new_nic.patch new file mode 100644 index 0000000000000000000000000000000000000000..d913ff6dc403192ad53ad494724b608dba2c2c71 --- /dev/null +++ b/net-Provide-MemReentrancyGuard-to-qemu_new_nic.patch @@ -0,0 +1,604 @@ +From cfb14ba8c266935afd660bcada152a36cafce521 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Thu, 1 Jun 2023 12:18:58 +0900 +Subject: [PATCH] net: Provide MemReentrancyGuard * to qemu_new_nic() + +Recently MemReentrancyGuard was added to DeviceState to record that the +device is engaging in I/O. The network device backend needs to update it +when delivering a packet to a device. + +In preparation for such a change, add MemReentrancyGuard * as a +parameter of qemu_new_nic(). + +Signed-off-by: Akihiko Odaki +Reviewed-by: Alexander Bulekov +Signed-off-by: Jason Wang +Signed-off-by: liuxiangdong +--- + hw/arm/musicpal.c | 3 ++- + hw/net/allwinner-sun8i-emac.c | 3 ++- + hw/net/allwinner_emac.c | 3 ++- + hw/net/cadence_gem.c | 3 ++- + hw/net/dp8393x.c | 3 ++- + hw/net/e1000.c | 3 ++- + hw/net/e1000e.c | 2 +- + hw/net/eepro100.c | 4 +++- + hw/net/etraxfs_eth.c | 3 ++- + hw/net/fsl_etsec/etsec.c | 3 ++- + hw/net/ftgmac100.c | 3 ++- + hw/net/i82596.c | 2 +- + hw/net/imx_fec.c | 2 +- + hw/net/lan9118.c | 3 ++- + hw/net/mcf_fec.c | 3 ++- + hw/net/mipsnet.c | 3 ++- + hw/net/msf2-emac.c | 3 ++- + hw/net/ne2000-isa.c | 3 ++- + hw/net/ne2000-pci.c | 3 ++- + hw/net/npcm7xx_emc.c | 3 ++- + hw/net/opencores_eth.c | 3 ++- + hw/net/pcnet.c | 3 ++- + hw/net/rocker/rocker_fp.c | 4 ++-- + hw/net/rtl8139.c | 3 ++- + hw/net/smc91c111.c | 3 ++- + hw/net/spapr_llan.c | 3 ++- + hw/net/stellaris_enet.c | 3 ++- + hw/net/sungem.c | 2 +- + hw/net/sunhme.c | 3 ++- + hw/net/tulip.c | 3 ++- + hw/net/virtio-net.c | 6 ++++-- + hw/net/vmxnet3.c | 2 +- + hw/net/xen_nic.c | 2 +- + hw/net/xgmac.c | 3 ++- + hw/net/xilinx_axienet.c | 3 ++- + hw/net/xilinx_ethlite.c | 3 ++- + hw/usb/dev-network.c | 3 ++- + include/net/net.h | 1 + + net/net.c | 1 + + 39 files changed, 73 insertions(+), 39 deletions(-) + +diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c +index 2680ec55b5..15fc7fee41 100644 +--- a/hw/arm/musicpal.c ++++ b/hw/arm/musicpal.c +@@ -418,7 +418,8 @@ static void mv88w8618_eth_realize(DeviceState *dev, Error **errp) + + address_space_init(&s->dma_as, s->dma_mr, "emac-dma"); + s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + } + + static const VMStateDescription mv88w8618_eth_vmsd = { +diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c +index ecc0245fe8..cf93b2fdac 100644 +--- a/hw/net/allwinner-sun8i-emac.c ++++ b/hw/net/allwinner-sun8i-emac.c +@@ -816,7 +816,8 @@ static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_allwinner_sun8i_emac_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c +index ddddf35c45..b3d73143bf 100644 +--- a/hw/net/allwinner_emac.c ++++ b/hw/net/allwinner_emac.c +@@ -453,7 +453,8 @@ static void aw_emac_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_aw_emac_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + fifo8_create(&s->rx_fifo, RX_FIFO_SIZE); +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index 21e1bd091f..bd7585c018 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -1633,7 +1633,8 @@ static void gem_realize(DeviceState *dev, Error **errp) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_gem_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + + if (s->jumbo_max_len > MAX_FRAME_SIZE) { + error_setg(errp, "jumbo-max-len is greater than %d", +diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c +index 45b954e46c..abfcc6f69f 100644 +--- a/hw/net/dp8393x.c ++++ b/hw/net/dp8393x.c +@@ -943,7 +943,8 @@ static void dp8393x_realize(DeviceState *dev, Error **errp) + "dp8393x-regs", SONIC_REG_COUNT << s->it_shift); + + s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index e26e0a64c1..33cd33a8ff 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -1736,7 +1736,8 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) + macaddr); + + d->nic = qemu_new_nic(&net_e1000_info, &d->conf, +- object_get_typename(OBJECT(d)), dev->id, d); ++ object_get_typename(OBJECT(d)), dev->id, ++ &dev->mem_reentrancy_guard, d); + + qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr); + +diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c +index ac96f7665a..b6e9b0e178 100644 +--- a/hw/net/e1000e.c ++++ b/hw/net/e1000e.c +@@ -328,7 +328,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr) + int i; + + s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, +- object_get_typename(OBJECT(s)), dev->id, s); ++ object_get_typename(OBJECT(s)), dev->id, &dev->mem_reentrancy_guard, s); + + s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0; + +diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c +index 9c178c1448..074d54ec97 100644 +--- a/hw/net/eepro100.c ++++ b/hw/net/eepro100.c +@@ -1886,7 +1886,9 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp) + nic_reset(s); + + s->nic = qemu_new_nic(&net_eepro100_info, &s->conf, +- object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); ++ object_get_typename(OBJECT(pci_dev)), ++ pci_dev->qdev.id, ++ &pci_dev->qdev.mem_reentrancy_guard, s); + + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str)); +diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c +index 1b82aec794..ba57a978d1 100644 +--- a/hw/net/etraxfs_eth.c ++++ b/hw/net/etraxfs_eth.c +@@ -618,7 +618,8 @@ static void etraxfs_eth_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, +- object_get_typename(OBJECT(s)), dev->id, s); ++ object_get_typename(OBJECT(s)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + s->phy.read = tdk_read; +diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c +index bd9d62b559..f790613b52 100644 +--- a/hw/net/fsl_etsec/etsec.c ++++ b/hw/net/fsl_etsec/etsec.c +@@ -391,7 +391,8 @@ static void etsec_realize(DeviceState *dev, Error **errp) + eTSEC *etsec = ETSEC_COMMON(dev); + + etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf, +- object_get_typename(OBJECT(dev)), dev->id, etsec); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, etsec); + qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a); + + etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT); +diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c +index d3bf14be53..be2cf63c08 100644 +--- a/hw/net/ftgmac100.c ++++ b/hw/net/ftgmac100.c +@@ -1118,7 +1118,8 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/i82596.c b/hw/net/i82596.c +index ec21e2699a..dc64246f75 100644 +--- a/hw/net/i82596.c ++++ b/hw/net/i82596.c +@@ -743,7 +743,7 @@ void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + } + s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), +- dev->id, s); ++ dev->id, &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + if (USE_TIMER) { +diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c +index 0db9aaf76a..74e7e0d122 100644 +--- a/hw/net/imx_fec.c ++++ b/hw/net/imx_fec.c +@@ -1318,7 +1318,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) + + s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, + object_get_typename(OBJECT(dev)), +- dev->id, s); ++ dev->id, &dev->mem_reentrancy_guard, s); + + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } +diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c +index 6aff424cbe..942bce9ae6 100644 +--- a/hw/net/lan9118.c ++++ b/hw/net/lan9118.c +@@ -1354,7 +1354,8 @@ static void lan9118_realize(DeviceState *dev, Error **errp) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_lan9118_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + s->eeprom[0] = 0xa5; + for (i = 0; i < 6; i++) { +diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c +index 25e3e453ab..a6be7bf413 100644 +--- a/hw/net/mcf_fec.c ++++ b/hw/net/mcf_fec.c +@@ -643,7 +643,8 @@ static void mcf_fec_realize(DeviceState *dev, Error **errp) + mcf_fec_state *s = MCF_FEC_NET(dev); + + s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c +index 2ade72dea0..8e925de867 100644 +--- a/hw/net/mipsnet.c ++++ b/hw/net/mipsnet.c +@@ -255,7 +255,8 @@ static void mipsnet_realize(DeviceState *dev, Error **errp) + sysbus_init_irq(sbd, &s->irq); + + s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c +index 9278fdce0b..1efa3dbf01 100644 +--- a/hw/net/msf2-emac.c ++++ b/hw/net/msf2-emac.c +@@ -527,7 +527,8 @@ static void msf2_emac_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_msf2_emac_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c +index dd6f6e34d3..30bd20c293 100644 +--- a/hw/net/ne2000-isa.c ++++ b/hw/net/ne2000-isa.c +@@ -74,7 +74,8 @@ static void isa_ne2000_realizefn(DeviceState *dev, Error **errp) + ne2000_reset(s); + + s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); + } + +diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c +index 9e5d10859a..4f8a699081 100644 +--- a/hw/net/ne2000-pci.c ++++ b/hw/net/ne2000-pci.c +@@ -71,7 +71,8 @@ static void pci_ne2000_realize(PCIDevice *pci_dev, Error **errp) + + s->nic = qemu_new_nic(&net_ne2000_info, &s->c, + object_get_typename(OBJECT(pci_dev)), +- pci_dev->qdev.id, s); ++ pci_dev->qdev.id, ++ &pci_dev->qdev.mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); + } + +diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c +index 9a2328935c..cafda78772 100644 +--- a/hw/net/npcm7xx_emc.c ++++ b/hw/net/npcm7xx_emc.c +@@ -804,7 +804,8 @@ static void npcm7xx_emc_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&emc->conf.macaddr); + emc->nic = qemu_new_nic(&net_npcm7xx_emc_info, &emc->conf, +- object_get_typename(OBJECT(dev)), dev->id, emc); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, emc); + qemu_format_nic_info_str(qemu_get_queue(emc->nic), emc->conf.macaddr.a); + } + +diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c +index 0b3dc3146e..f96d6ea2cc 100644 +--- a/hw/net/opencores_eth.c ++++ b/hw/net/opencores_eth.c +@@ -732,7 +732,8 @@ static void sysbus_open_eth_realize(DeviceState *dev, Error **errp) + sysbus_init_irq(sbd, &s->irq); + + s->nic = qemu_new_nic(&net_open_eth_info, &s->conf, +- object_get_typename(OBJECT(s)), dev->id, s); ++ object_get_typename(OBJECT(s)), dev->id, ++ &dev->mem_reentrancy_guard, s); + } + + static void qdev_open_eth_reset(DeviceState *dev) +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index dcd3fc4948..da910a70bf 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1718,7 +1718,8 @@ void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) + s->poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pcnet_poll_timer, s); + + qemu_macaddr_default_if_unset(&s->conf.macaddr); +- s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); ++ s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), ++ dev->id, &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + /* Initialize the PROM */ +diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c +index cbeed65bd5..0d21948ada 100644 +--- a/hw/net/rocker/rocker_fp.c ++++ b/hw/net/rocker/rocker_fp.c +@@ -241,8 +241,8 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name, + port->conf.bootindex = -1; + port->conf.peers = *peers; + +- port->nic = qemu_new_nic(&fp_port_info, &port->conf, +- sw_name, NULL, port); ++ port->nic = qemu_new_nic(&fp_port_info, &port->conf, sw_name, NULL, ++ &DEVICE(r)->mem_reentrancy_guard, port); + qemu_format_nic_info_str(qemu_get_queue(port->nic), + port->conf.macaddr.a); + +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index 90b4fc63ce..43d65d7252 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -3398,7 +3398,8 @@ static void pci_rtl8139_realize(PCIDevice *dev, Error **errp) + s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8; + + s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf, +- object_get_typename(OBJECT(dev)), d->id, s); ++ object_get_typename(OBJECT(dev)), d->id, ++ &d->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + s->cplus_txbuffer = NULL; +diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c +index ad778cd8fc..4eda971ef3 100644 +--- a/hw/net/smc91c111.c ++++ b/hw/net/smc91c111.c +@@ -783,7 +783,8 @@ static void smc91c111_realize(DeviceState *dev, Error **errp) + sysbus_init_irq(sbd, &s->irq); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + /* ??? Save/restore. */ + } +diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c +index a6876a936d..475d5f3a34 100644 +--- a/hw/net/spapr_llan.c ++++ b/hw/net/spapr_llan.c +@@ -325,7 +325,8 @@ static void spapr_vlan_realize(SpaprVioDevice *sdev, Error **errp) + memcpy(&dev->perm_mac.a, &dev->nicconf.macaddr.a, sizeof(dev->perm_mac.a)); + + dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, +- object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); ++ object_get_typename(OBJECT(sdev)), sdev->qdev.id, ++ &sdev->qdev.mem_reentrancy_guard, dev); + qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); + + dev->rxp_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, spapr_vlan_flush_rx_queue, +diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c +index 8dd60783d8..6768a6912f 100644 +--- a/hw/net/stellaris_enet.c ++++ b/hw/net/stellaris_enet.c +@@ -492,7 +492,8 @@ static void stellaris_enet_realize(DeviceState *dev, Error **errp) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/sungem.c b/hw/net/sungem.c +index 3684a4d733..c12d44e9dc 100644 +--- a/hw/net/sungem.c ++++ b/hw/net/sungem.c +@@ -1361,7 +1361,7 @@ static void sungem_realize(PCIDevice *pci_dev, Error **errp) + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_sungem_info, &s->conf, + object_get_typename(OBJECT(dev)), +- dev->id, s); ++ dev->id, &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), + s->conf.macaddr.a); + } +diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c +index fc34905f87..fa98528d71 100644 +--- a/hw/net/sunhme.c ++++ b/hw/net/sunhme.c +@@ -892,7 +892,8 @@ static void sunhme_realize(PCIDevice *pci_dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_sunhme_info, &s->conf, +- object_get_typename(OBJECT(d)), d->id, s); ++ object_get_typename(OBJECT(d)), d->id, ++ &d->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index b9e42c322a..d319f9fb80 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -985,7 +985,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) + + s->nic = qemu_new_nic(&net_tulip_info, &s->c, + object_get_typename(OBJECT(pci_dev)), +- pci_dev->qdev.id, s); ++ pci_dev->qdev.id, ++ &pci_dev->qdev.mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 3e1fa6adf3..d7405c3bf1 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3585,10 +3585,12 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) + * Happen when virtio_net_set_netclient_name has been called. + */ + n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, +- n->netclient_type, n->netclient_name, n); ++ n->netclient_type, n->netclient_name, ++ &dev->mem_reentrancy_guard, n); + } else { + n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, +- object_get_typename(OBJECT(dev)), dev->id, n); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, n); + } + + for (i = 0; i < n->max_queue_pairs; i++) { +diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c +index a2037583bf..2a32ab32ea 100644 +--- a/hw/net/vmxnet3.c ++++ b/hw/net/vmxnet3.c +@@ -2080,7 +2080,7 @@ static void vmxnet3_net_init(VMXNET3State *s) + + s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf, + object_get_typename(OBJECT(s)), +- d->id, s); ++ d->id, &d->mem_reentrancy_guard, s); + + s->peer_has_vhdr = vmxnet3_peer_has_vnet_hdr(s); + s->tx_sop = true; +diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c +index 5c815b4f0c..712fe6706d 100644 +--- a/hw/net/xen_nic.c ++++ b/hw/net/xen_nic.c +@@ -294,7 +294,7 @@ static int net_init(struct XenLegacyDevice *xendev) + } + + netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, +- "xen", NULL, netdev); ++ "xen", NULL, &xendev->qdev.mem_reentrancy_guard, netdev); + + snprintf(qemu_get_queue(netdev->nic)->info_str, + sizeof(qemu_get_queue(netdev->nic)->info_str), +diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c +index 0ab6ae91aa..1f4f277d84 100644 +--- a/hw/net/xgmac.c ++++ b/hw/net/xgmac.c +@@ -402,7 +402,8 @@ static void xgmac_enet_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | +diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c +index 990ff3a1c2..8a34243803 100644 +--- a/hw/net/xilinx_axienet.c ++++ b/hw/net/xilinx_axienet.c +@@ -968,7 +968,8 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + + tdk_init(&s->TEMAC.phy); +diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c +index 6e09f7e422..80cb869e22 100644 +--- a/hw/net/xilinx_ethlite.c ++++ b/hw/net/xilinx_ethlite.c +@@ -235,7 +235,8 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, +- object_get_typename(OBJECT(dev)), dev->id, s); ++ object_get_typename(OBJECT(dev)), dev->id, ++ &dev->mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + } + +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index 6c49c16015..ae447a8bc3 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -1362,7 +1362,8 @@ static void usb_net_realize(USBDevice *dev, Error **errp) + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, +- object_get_typename(OBJECT(s)), s->dev.qdev.id, s); ++ object_get_typename(OBJECT(s)), s->dev.qdev.id, ++ &s->dev.qdev.mem_reentrancy_guard, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), + "%02x%02x%02x%02x%02x%02x", +diff --git a/include/net/net.h b/include/net/net.h +index 81d0b21def..f5313b7e4e 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -151,6 +151,7 @@ NICState *qemu_new_nic(NetClientInfo *info, + NICConf *conf, + const char *model, + const char *name, ++ MemReentrancyGuard *reentrancy_guard, + void *opaque); + void qemu_del_nic(NICState *nic); + NetClientState *qemu_get_subqueue(NICState *nic, int queue_index); +diff --git a/net/net.c b/net/net.c +index daad8784ec..e4e4cf45a2 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -299,6 +299,7 @@ NICState *qemu_new_nic(NetClientInfo *info, + NICConf *conf, + const char *model, + const char *name, ++ MemReentrancyGuard *reentrancy_guard, + void *opaque) + { + NetClientState **peers = conf->peers.ncs; +-- +2.27.0 + diff --git a/net-Update-MemReentrancyGuard-for-NIC-CVE-2023-3019.patch b/net-Update-MemReentrancyGuard-for-NIC-CVE-2023-3019.patch new file mode 100644 index 0000000000000000000000000000000000000000..88ce75f3bedabb8699dc4cef017efc345c437079 --- /dev/null +++ b/net-Update-MemReentrancyGuard-for-NIC-CVE-2023-3019.patch @@ -0,0 +1,85 @@ +From e69961a3c833e79dbcaca3f651b6f0ebfc86c93b Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Thu, 1 Jun 2023 12:18:59 +0900 +Subject: [PATCH] net: Update MemReentrancyGuard for NIC (CVE-2023-3019) + +Recently MemReentrancyGuard was added to DeviceState to record that the +device is engaging in I/O. The network device backend needs to update it +when delivering a packet to a device. + +This implementation follows what bottom half does, but it does not add +a tracepoint for the case that the network device backend started +delivering a packet to a device which is already engaging in I/O. This +is because such reentrancy frequently happens for +qemu_flush_queued_packets() and is insignificant. + +Fixes: CVE-2023-3019 +Reported-by: Alexander Bulekov +Signed-off-by: Akihiko Odaki +Acked-by: Alexander Bulekov +Signed-off-by: Jason Wang +--- + include/net/net.h | 1 + + net/net.c | 14 ++++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/include/net/net.h b/include/net/net.h +index f5313b7e4e..b55f6cf698 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -118,6 +118,7 @@ struct NetClientState { + typedef struct NICState { + NetClientState *ncs; + NICConf *conf; ++ MemReentrancyGuard *reentrancy_guard; + void *opaque; + bool peer_deleted; + } NICState; +diff --git a/net/net.c b/net/net.c +index e4e4cf45a2..abdb9dfdc5 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -312,6 +312,7 @@ NICState *qemu_new_nic(NetClientInfo *info, + nic = g_malloc0(info->size + sizeof(NetClientState) * queues); + nic->ncs = (void *)nic + info->size; + nic->conf = conf; ++ nic->reentrancy_guard = reentrancy_guard, + nic->opaque = opaque; + + for (i = 0; i < queues; i++) { +@@ -767,6 +768,7 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender, + int iovcnt, + void *opaque) + { ++ MemReentrancyGuard *owned_reentrancy_guard; + NetClientState *nc = opaque; + int ret; + +@@ -779,12 +781,24 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender, + return 0; + } + ++ if (nc->info->type != NET_CLIENT_DRIVER_NIC || ++ qemu_get_nic(nc)->reentrancy_guard->engaged_in_io) { ++ owned_reentrancy_guard = NULL; ++ } else { ++ owned_reentrancy_guard = qemu_get_nic(nc)->reentrancy_guard; ++ owned_reentrancy_guard->engaged_in_io = true; ++ } ++ + if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { + ret = nc->info->receive_iov(nc, iov, iovcnt); + } else { + ret = nc_sendv_compat(nc, iov, iovcnt, flags); + } + ++ if (owned_reentrancy_guard) { ++ owned_reentrancy_guard->engaged_in_io = false; ++ } ++ + if (ret == 0) { + nc->receive_disabled = 1; + } +-- +2.27.0 + diff --git a/net-dump.c-Suppress-spurious-compiler-warning.patch b/net-dump.c-Suppress-spurious-compiler-warning.patch new file mode 100644 index 0000000000000000000000000000000000000000..5db07d345719ea6895740fc529358d52c6eb4b0d --- /dev/null +++ b/net-dump.c-Suppress-spurious-compiler-warning.patch @@ -0,0 +1,51 @@ +From 08801d190afd21f7d3db9a2cdce2b1528903ac2c Mon Sep 17 00:00:00 2001 +From: liuxiangdong +Date: Tue, 8 Feb 2022 15:10:25 +0800 +Subject: [PATCH] net/dump.c: Suppress spurious compiler warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Compiling with gcc version 11.2.0 (Ubuntu 11.2.0-13ubuntu1) results in +a (spurious) warning: + + In function ‘dump_receive_iov’, + inlined from ‘filter_dump_receive_iov’ at ../net/dump.c:157:5: + ../net/dump.c:89:9: error: ‘writev’ specified size 18446744073709551600 +exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=] + 89 | if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + In file included from /home/ptomsich/qemu/include/qemu/osdep.h:108, + from ../net/dump.c:25: + ../net/dump.c: In function ‘filter_dump_receive_iov’: + /usr/include/x86_64-linux-gnu/sys/uio.h:52:16: note: in a call to function +‘writev’ declared with attribute ‘read_only (2, 3)’ + 52 | extern ssize_t writev (int __fd, const struct iovec *__iovec, int +__count) + | ^~~~~~ + cc1: all warnings being treated as errors + +This change helps that version of GCC to understand what is going on +and suppresses this warning. + +Signed-off-by: Philipp Tomsich +--- + net/dump.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/dump.c b/net/dump.c +index a07ba62401..c32d3bf4e6 100644 +--- a/net/dump.c ++++ b/net/dump.c +@@ -86,7 +86,7 @@ static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt) + dumpiov[0].iov_len = sizeof(hdr); + cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen); + +- if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { ++ if (writev(s->fd, &dumpiov[0], cnt + 1) != sizeof(hdr) + caplen) { + error_report("network dump write error - stopping dump"); + close(s->fd); + s->fd = -1; +-- +2.27.0 + diff --git a/net-eepro100-validate-various-address-valuesi-CVE-20.patch b/net-eepro100-validate-various-address-valuesi-CVE-20.patch new file mode 100644 index 0000000000000000000000000000000000000000..47095713aabaf1232ac04d75dc97f189c67df4aa --- /dev/null +++ b/net-eepro100-validate-various-address-valuesi-CVE-20.patch @@ -0,0 +1,58 @@ +From 5db012b1116d21c64da88ad206b3589ddf5f219b Mon Sep 17 00:00:00 2001 +From: zhouli57 +Date: Sat, 18 Dec 2021 09:39:57 +0800 +Subject: [PATCH] net: eepro100: validate various address + valuesi(CVE-2021-20255) + +fix CVE-2021-20255 + +patch link: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg06098.html + +fix CVE-2021-20255, sync patch from ostms platform. + +Signed-off-by: zhouli57 +Signed-off-by: Yan Wang +--- + hw/net/eepro100.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c +index 16e95ef9cc..2474cf3dc2 100644 +--- a/hw/net/eepro100.c ++++ b/hw/net/eepro100.c +@@ -279,6 +279,9 @@ typedef struct { + /* Quasi static device properties (no need to save them). */ + uint16_t stats_size; + bool has_extended_tcb_support; ++ ++ /* Flag to avoid recursions. */ ++ bool busy; + } EEPRO100State; + + /* Word indices in EEPROM. */ +@@ -837,6 +840,14 @@ static void action_command(EEPRO100State *s) + Therefore we limit the number of iterations. */ + unsigned max_loop_count = 16; + ++ if (s->busy) { ++ /* Prevent recursions. */ ++ logout("recursion in %s:%u\n", __FILE__, __LINE__); ++ return; ++ } ++ ++ s->busy = true; ++ + for (;;) { + bool bit_el; + bool bit_s; +@@ -933,6 +944,7 @@ static void action_command(EEPRO100State *s) + } + TRACE(OTHER, logout("CU list empty\n")); + /* List is empty. Now CU is idle or suspended. */ ++ s->busy = false; + } + + static void eepro100_cu_command(EEPRO100State * s, uint8_t val) +-- +2.27.0 + diff --git a/net-eth-Don-t-consider-ESP-to-be-an-IPv6-option-head.patch b/net-eth-Don-t-consider-ESP-to-be-an-IPv6-option-head.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff3a759f015ee40bfdc7ea0cbff242b8bba8e49 --- /dev/null +++ b/net-eth-Don-t-consider-ESP-to-be-an-IPv6-option-head.patch @@ -0,0 +1,60 @@ +From 4e18cc43f7e83714da041d69d13265605c22c50c Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 24 Mar 2023 07:28:57 +0000 +Subject: [PATCH] net/eth: Don't consider ESP to be an IPv6 option header + mainline inclusion commit 9d6267b240c114d1a3cd314a08fd6e1339d34b83 category: + bugfix + +--------------------------------------------------------------- + +The IPv6 option headers all have in common that they start with some +common fields, in particular the type of the next header followed by the +extention header length. This is used to traverse the list of the +options. The ESP header does not follow that format, which can break the +IPv6 option header traversal code in eth_parse_ipv6_hdr(). + +The effect of that is that network interfaces such as vmxnet3 that use +the following call chain + eth_is_ip6_extension_header_type + eth_parse_ipv6_hdr + net_tx_pkt_parse_headers + net_tx_pkt_parse + vmxnet3_process_tx_queue +to send packets from the VM out to the host will drop packets of the +following structure: + Ethernet-Header(IPv6-Header(ESP(encrypted data))) + +Note that not all types of network interfaces use the net_tx_pkt_parse +function though, leading to inconsistent behavior regarding sending +those packets. The e1000 network interface for example does not suffer +from this limitation. + +By not considering ESP to be an IPv6 header we can allow sending those +packets out to the host on all types of network interfaces. + +Fixes: 75020a702151 ("Common definitions for VMWARE devices") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/149 +Buglink: https://bugs.launchpad.net/qemu/+bug/1758091 +Signed-off-by: Thomas Jansen +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + net/eth.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/eth.c b/net/eth.c +index fe876d1a55..f074b2f9f3 100644 +--- a/net/eth.c ++++ b/net/eth.c +@@ -389,7 +389,6 @@ eth_is_ip6_extension_header_type(uint8_t hdr_type) + case IP6_HOP_BY_HOP: + case IP6_ROUTING: + case IP6_FRAGMENT: +- case IP6_ESP: + case IP6_AUTHENTICATION: + case IP6_DESTINATON: + case IP6_MOBILITY: +-- +2.27.0 + diff --git a/net-l2tpv3-Remove-redundant-check-in-net_init_l2tpv3.patch b/net-l2tpv3-Remove-redundant-check-in-net_init_l2tpv3.patch deleted file mode 100644 index a96c178294ea7c2afe5a860f4021efe361a6a18f..0000000000000000000000000000000000000000 --- a/net-l2tpv3-Remove-redundant-check-in-net_init_l2tpv3.patch +++ /dev/null @@ -1,46 +0,0 @@ -From cb6048ace290e770b0ec1a6011209192541d3e8a Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Fri, 30 Oct 2020 10:46:55 +0800 -Subject: [PATCH] net/l2tpv3: Remove redundant check in net_init_l2tpv3() - -The result has been checked to be NULL before, it cannot be NULL here, -so the check is redundant. Remove it. - -Reported-by: Euler Robot -Signed-off-by: AlexChen -Signed-off-by: Jason Wang -(cherry-picked from commit d949fe64b0) ---- - net/l2tpv3.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/net/l2tpv3.c b/net/l2tpv3.c -index 55fea17c0f..e4d4218db6 100644 ---- a/net/l2tpv3.c -+++ b/net/l2tpv3.c -@@ -655,9 +655,8 @@ int net_init_l2tpv3(const Netdev *netdev, - error_setg(errp, "could not bind socket err=%i", errno); - goto outerr; - } -- if (result) { -- freeaddrinfo(result); -- } -+ -+ freeaddrinfo(result); - - memset(&hints, 0, sizeof(hints)); - -@@ -686,9 +685,7 @@ int net_init_l2tpv3(const Netdev *netdev, - memcpy(s->dgram_dst, result->ai_addr, result->ai_addrlen); - s->dst_size = result->ai_addrlen; - -- if (result) { -- freeaddrinfo(result); -- } -+ freeaddrinfo(result); - - if (l2tpv3->has_counter && l2tpv3->counter) { - s->has_counter = true; --- -2.27.0 - diff --git a/net-remove-an-assert-call-in-eth_get_gso_type.patch b/net-remove-an-assert-call-in-eth_get_gso_type.patch deleted file mode 100644 index 79d740922a2c2fd766b19c89d68df49a6d0a96f1..0000000000000000000000000000000000000000 --- a/net-remove-an-assert-call-in-eth_get_gso_type.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 9b210ed120ac82e647ed99be3679bab2bc55932b Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Wed, 21 Oct 2020 11:35:50 +0530 -Subject: [PATCH] net: remove an assert call in eth_get_gso_type - -fix CVE-2020-27617 - -eth_get_gso_type() routine returns segmentation offload type based on -L3 protocol type. It calls g_assert_not_reached if L3 protocol is -unknown, making the following return statement unreachable. Remove the -g_assert call, it maybe triggered by a guest user. - -Reported-by: Gaoning Pan -Signed-off-by: Prasad J Pandit -Signed-off-by: Jason Wang - -cherry-pick from commit 7564bf7701f00214cdc8a678a9f7df765244def1 -Signed-off-by: Jiajie Li ---- - net/eth.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/net/eth.c b/net/eth.c -index 0c1d413ee2..1e0821c5f8 100644 ---- a/net/eth.c -+++ b/net/eth.c -@@ -16,6 +16,7 @@ - */ - - #include "qemu/osdep.h" -+#include "qemu/log.h" - #include "net/eth.h" - #include "net/checksum.h" - #include "net/tap.h" -@@ -71,9 +72,8 @@ eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto) - return VIRTIO_NET_HDR_GSO_TCPV6 | ecn_state; - } - } -- -- /* Unsupported offload */ -- g_assert_not_reached(); -+ qemu_log_mask(LOG_UNIMP, "%s: probably not GSO frame, " -+ "unknown L3 protocol: 0x%04"PRIx16"\n", __func__, l3_proto); - - return VIRTIO_NET_HDR_GSO_NONE | ecn_state; - } --- -2.27.0 - diff --git a/net-tulip-Restrict-DMA-engine-to-memories.patch b/net-tulip-Restrict-DMA-engine-to-memories.patch new file mode 100644 index 0000000000000000000000000000000000000000..5be976d55f72857085c77faa81accdd9ef24d88e --- /dev/null +++ b/net-tulip-Restrict-DMA-engine-to-memories.patch @@ -0,0 +1,62 @@ +From 828774ed550d33e1cf8bf4bbc2a0fcf6fdf22094 Mon Sep 17 00:00:00 2001 +From: Zhang Bo +Date: Fri, 30 Sep 2022 12:24:58 +0800 +Subject: [PATCH] net: tulip: Restrict DMA engine to memories + +fix CVE-2022-2962. +The DMA engine is started by I/O access and then itself accesses the +I/O registers, triggering a reentrancy bug. + +The following log can reveal it: +==5637==ERROR: AddressSanitizer: stack-overflow + #0 0x5595435f6078 in tulip_xmit_list_update qemu/hw/net/tulip.c:673 + #1 0x5595435f204a in tulip_write qemu/hw/net/tulip.c:805:13 + #2 0x559544637f86 in memory_region_write_accessor qemu/softmmu/memory.c:492:5 + #3 0x5595446379fa in access_with_adjusted_size qemu/softmmu/memory.c:554:18 + #4 0x5595446372fa in memory_region_dispatch_write qemu/softmmu/memory.c + #5 0x55954468b74c in flatview_write_continue qemu/softmmu/physmem.c:2825:23 + #6 0x559544683662 in flatview_write qemu/softmmu/physmem.c:2867:12 + #7 0x5595446833f3 in address_space_write qemu/softmmu/physmem.c:2963:18 + #8 0x5595435fb082 in dma_memory_rw_relaxed qemu/include/sysemu/dma.h:87:12 + #9 0x5595435fb082 in dma_memory_rw qemu/include/sysemu/dma.h:130:12 + #10 0x5595435fb082 in dma_memory_write qemu/include/sysemu/dma.h:171:12 + #11 0x5595435fb082 in stl_le_dma qemu/include/sysemu/dma.h:272:1 + #12 0x5595435fb082 in stl_le_pci_dma qemu/include/hw/pci/pci.h:910:1 + #13 0x5595435fb082 in tulip_desc_write qemu/hw/net/tulip.c:101:9 + #14 0x5595435f7e3d in tulip_xmit_list_update qemu/hw/net/tulip.c:706:9 + #15 0x5595435f204a in tulip_write qemu/hw/net/tulip.c:805:13 + +Fix this bug by restricting the DMA engine to memories regions. + +Signed-off-by: Zheyu Ma +Signed-off-by: Jason Wang +Signed-off-by: Zhang Bo +--- + hw/net/tulip.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index d5b6cc5ee6..5f8badefca 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -70,7 +70,7 @@ static const VMStateDescription vmstate_pci_tulip = { + static void tulip_desc_read(TULIPState *s, hwaddr p, + struct tulip_descriptor *desc) + { +- const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ const MemTxAttrs attrs = { .memory = true }; + + if (s->csr[0] & CSR0_DBO) { + ldl_be_pci_dma(&s->dev, p, &desc->status, attrs); +@@ -88,7 +88,7 @@ static void tulip_desc_read(TULIPState *s, hwaddr p, + static void tulip_desc_write(TULIPState *s, hwaddr p, + struct tulip_descriptor *desc) + { +- const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ const MemTxAttrs attrs = { .memory = true }; + + if (s->csr[0] & CSR0_DBO) { + stl_be_pci_dma(&s->dev, p, desc->status, attrs); +-- +2.27.0 + diff --git a/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch b/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch new file mode 100644 index 0000000000000000000000000000000000000000..47ea2c8c7089fe46d337892afdd7bd71ca7791e4 --- /dev/null +++ b/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch @@ -0,0 +1,62 @@ +From 02c67ab8c1f1e29bf8274d9b460dc2f07b8e195b Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Mon, 31 Oct 2022 13:29:01 +0000 +Subject: [PATCH] net/vhost-vdpa.c: Fix clang compilation failure + +Commit 8801ccd0500437 introduced a compilation failure with clang +version 10.0.0-4ubuntu1: + +../../net/vhost-vdpa.c:654:16: error: variable 'vdpa_device_fd' is +used uninitialized whenever 'if' condition is false +[-Werror,-Wsometimes-uninitialized] + } else if (opts->has_vhostfd) { + ^~~~~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:662:33: note: uninitialized use occurs here + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); + ^~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:654:12: note: remove the 'if' if its condition +is always true + } else if (opts->has_vhostfd) { + ^~~~~~~~~~~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:629:23: note: initialize the variable +'vdpa_device_fd' to silence this warning + int vdpa_device_fd; + ^ + = 0 +1 error generated. + +It's a false positive -- the compiler doesn't manage to figure out +that the error checks further up mean that there's no code path where +vdpa_device_fd isn't initialized. Put another way, the problem is +that we check "if (opts->has_vhostfd)" when in fact that condition +must always be true. A cleverer static analyser would probably warn +that we were checking an always-true condition. + +Fix the compilation failure by removing the unnecessary if(). + +Fixes: 8801ccd0500437 ("vhost-vdpa: allow passing opened vhostfd to vhost-vdpa") +Signed-off-by: Peter Maydell +Message-Id: <20221031132901.1277150-1-peter.maydell@linaro.org> +Signed-off-by: Stefan Hajnoczi +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 58225649f9..c89f9d1243 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -659,7 +659,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (vdpa_device_fd == -1) { + return -errno; + } +- } else if (opts->has_vhostfd) { ++ } else { ++ /* has_vhostfd */ + vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp); + if (vdpa_device_fd == -1) { + error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: "); +-- +2.27.0 + diff --git a/net-vmxnet3-validate-configuration-values-during-act.patch b/net-vmxnet3-validate-configuration-values-during-act.patch deleted file mode 100644 index a4ed4bccc5534b5b6f04d61ea7c4bccfc72e3fa8..0000000000000000000000000000000000000000 --- a/net-vmxnet3-validate-configuration-values-during-act.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 18d22b1f2b2f89bbdd77bd4d62e0fe42f19b3962 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 9 Mar 2021 17:37:20 +0800 -Subject: [PATCH] net: vmxnet3: validate configuration values during activate - (CVE-2021-20203) - -fix CVE-2021-20203 #I3A34O - -While activating device in vmxnet3_acticate_device(), it does not -validate guest supplied configuration values against predefined -minimum - maximum limits. This may lead to integer overflow or -OOB access issues. Add checks to avoid it. - -Fixes: CVE-2021-20203 -Buglink: https://bugs.launchpad.net/qemu/+bug/1913873 -Reported-by: Gaoning Pan -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/net/vmxnet3.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c -index 10d01d0058..ecc4f5bcf0 100644 ---- a/hw/net/vmxnet3.c -+++ b/hw/net/vmxnet3.c -@@ -1418,6 +1418,7 @@ static void vmxnet3_activate_device(VMXNET3State *s) - vmxnet3_setup_rx_filtering(s); - /* Cache fields from shared memory */ - s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); -+ assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU); - VMW_CFPRN("MTU is %u", s->mtu); - - s->max_rx_frags = -@@ -1471,7 +1472,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) - /* Read rings memory locations for TX queues */ - pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA); - size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize); -- -+ if (size > VMXNET3_TX_RING_MAX_SIZE) { -+ size = VMXNET3_TX_RING_MAX_SIZE; -+ } - vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size, - sizeof(struct Vmxnet3_TxDesc), false); - VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring); -@@ -1481,6 +1484,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) - /* TXC ring */ - pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA); - size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize); -+ if (size > VMXNET3_TC_RING_MAX_SIZE) { -+ size = VMXNET3_TC_RING_MAX_SIZE; -+ } - vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size, - sizeof(struct Vmxnet3_TxCompDesc), true); - VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring); -@@ -1522,6 +1528,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) - /* RX rings */ - pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]); - size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]); -+ if (size > VMXNET3_RX_RING_MAX_SIZE) { -+ size = VMXNET3_RX_RING_MAX_SIZE; -+ } - vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size, - sizeof(struct Vmxnet3_RxDesc), false); - VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d", -@@ -1531,6 +1540,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) - /* RXC ring */ - pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA); - size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize); -+ if (size > VMXNET3_RC_RING_MAX_SIZE) { -+ size = VMXNET3_RC_RING_MAX_SIZE; -+ } - vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size, - sizeof(struct Vmxnet3_RxCompDesc), true); - VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size); --- -2.27.0 - diff --git a/numa-Enable-numa-for-SGX-EPC-sections.patch b/numa-Enable-numa-for-SGX-EPC-sections.patch new file mode 100644 index 0000000000000000000000000000000000000000..0eec4721ccb321406bc9ab74352ef3dc9102f5e1 --- /dev/null +++ b/numa-Enable-numa-for-SGX-EPC-sections.patch @@ -0,0 +1,291 @@ +From c9071221ea67c7ee72fab5956e4c2c9da3fd39ef Mon Sep 17 00:00:00 2001 +From: Yang Zhong +Date: Mon, 1 Nov 2021 12:20:05 -0400 +Subject: [PATCH 1/9] numa: Enable numa for SGX EPC sections + +mainline inclusion +from mainline-v7.0.0-rc0 +commit 1105812382e1126d86dddc16b3700f8c79dc93d1 +category: feature +feature: NUMA support for SGX EPC sections +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5K27A + +Intel-SIG: commit 1105812382e1 ("numa: Enable numa for SGX EPC sections") + +------------------------------------- + +numa: Enable numa for SGX EPC sections + +The basic SGX did not enable numa for SGX EPC sections, which +result in all EPC sections located in numa node 0. This patch +enable SGX numa function in the guest and the EPC section can +work with RAM as one numa node. + +The Guest kernel related log: +[ 0.009981] ACPI: SRAT: Node 0 PXM 0 [mem 0x180000000-0x183ffffff] +[ 0.009982] ACPI: SRAT: Node 1 PXM 1 [mem 0x184000000-0x185bfffff] +The SRAT table can normally show SGX EPC sections menory info in different +numa nodes. + +The SGX EPC numa related command: + ...... + -m 4G,maxmem=20G \ + -smp sockets=2,cores=2 \ + -cpu host,+sgx-provisionkey \ + -object memory-backend-ram,size=2G,host-nodes=0,policy=bind,id=node0 \ + -object memory-backend-epc,id=mem0,size=64M,prealloc=on,host-nodes=0,policy=bind \ + -numa node,nodeid=0,cpus=0-1,memdev=node0 \ + -object memory-backend-ram,size=2G,host-nodes=1,policy=bind,id=node1 \ + -object memory-backend-epc,id=mem1,size=28M,prealloc=on,host-nodes=1,policy=bind \ + -numa node,nodeid=1,cpus=2-3,memdev=node1 \ + -M sgx-epc.0.memdev=mem0,sgx-epc.0.node=0,sgx-epc.1.memdev=mem1,sgx-epc.1.node=1 \ + ...... + +Signed-off-by: Yang Zhong +Message-Id: <20211101162009.62161-2-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + hw/core/numa.c | 5 ++--- + hw/i386/acpi-build.c | 2 ++ + hw/i386/sgx-epc.c | 3 +++ + hw/i386/sgx-stub.c | 4 ++++ + hw/i386/sgx.c | 44 +++++++++++++++++++++++++++++++++++++++ + include/hw/i386/sgx-epc.h | 3 +++ + monitor/hmp-cmds.c | 1 + + qapi/machine.json | 10 ++++++++- + qemu-options.hx | 4 ++-- + 9 files changed, 70 insertions(+), 6 deletions(-) + +diff --git a/hw/core/numa.c b/hw/core/numa.c +index e6050b2273..1aa05dcf42 100644 +--- a/hw/core/numa.c ++++ b/hw/core/numa.c +@@ -784,9 +784,8 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[]) + break; + case MEMORY_DEVICE_INFO_KIND_SGX_EPC: + se = value->u.sgx_epc.data; +- /* TODO: once we support numa, assign to right node */ +- node_mem[0].node_mem += se->size; +- node_mem[0].node_plugged_mem += se->size; ++ node_mem[se->node].node_mem += se->size; ++ node_mem[se->node].node_plugged_mem = 0; + break; + default: + g_assert_not_reached(); +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 0ec2932ec2..1e33e1f3d0 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2068,6 +2068,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + nvdimm_build_srat(table_data); + } + ++ sgx_epc_build_srat(table_data); ++ + /* + * TODO: this part is not in ACPI spec and current linux kernel boots fine + * without these entries. But I recall there were issues the last time I +diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c +index e508827e78..96b2940d75 100644 +--- a/hw/i386/sgx-epc.c ++++ b/hw/i386/sgx-epc.c +@@ -21,6 +21,7 @@ + + static Property sgx_epc_properties[] = { + DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), ++ DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0), + DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, + TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), + DEFINE_PROP_END_OF_LIST(), +@@ -139,6 +140,8 @@ static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, + se->memaddr = epc->addr; + se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, + NULL); ++ se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP, ++ NULL); + se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); + + info->u.sgx_epc.data = se; +diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c +index c9b379e665..26833eb233 100644 +--- a/hw/i386/sgx-stub.c ++++ b/hw/i386/sgx-stub.c +@@ -6,6 +6,10 @@ + #include "qapi/error.h" + #include "qapi/qapi-commands-misc-target.h" + ++void sgx_epc_build_srat(GArray *table_data) ++{ ++} ++ + SGXInfo *qmp_query_sgx(Error **errp) + { + error_setg(errp, "SGX support is not compiled in"); +diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c +index 8fef3dd8fa..d04299904a 100644 +--- a/hw/i386/sgx.c ++++ b/hw/i386/sgx.c +@@ -23,6 +23,7 @@ + #include "sysemu/hw_accel.h" + #include "sysemu/reset.h" + #include ++#include "hw/acpi/aml-build.h" + + #define SGX_MAX_EPC_SECTIONS 8 + #define SGX_CPUID_EPC_INVALID 0x0 +@@ -36,6 +37,46 @@ + + #define RETRY_NUM 2 + ++static int sgx_epc_device_list(Object *obj, void *opaque) ++{ ++ GSList **list = opaque; ++ ++ if (object_dynamic_cast(obj, TYPE_SGX_EPC)) { ++ *list = g_slist_append(*list, DEVICE(obj)); ++ } ++ ++ object_child_foreach(obj, sgx_epc_device_list, opaque); ++ return 0; ++} ++ ++static GSList *sgx_epc_get_device_list(void) ++{ ++ GSList *list = NULL; ++ ++ object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list); ++ return list; ++} ++ ++void sgx_epc_build_srat(GArray *table_data) ++{ ++ GSList *device_list = sgx_epc_get_device_list(); ++ ++ for (; device_list; device_list = device_list->next) { ++ DeviceState *dev = device_list->data; ++ Object *obj = OBJECT(dev); ++ uint64_t addr, size; ++ int node; ++ ++ node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP, ++ &error_abort); ++ addr = object_property_get_uint(obj, SGX_EPC_ADDR_PROP, &error_abort); ++ size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, &error_abort); ++ ++ build_srat_memory(table_data, addr, size, node, MEM_AFFINITY_ENABLED); ++ } ++ g_slist_free(device_list); ++} ++ + static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) + { + return (low & MAKE_64BIT_MASK(12, 20)) + +@@ -226,6 +267,9 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms) + /* set the memdev link with memory backend */ + object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev, + &error_fatal); ++ /* set the numa node property for sgx epc object */ ++ object_property_set_uint(obj, SGX_EPC_NUMA_NODE_PROP, list->value->node, ++ &error_fatal); + object_property_set_bool(obj, "realized", true, &error_fatal); + object_unref(obj); + } +diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h +index a6a65be854..581fac389a 100644 +--- a/include/hw/i386/sgx-epc.h ++++ b/include/hw/i386/sgx-epc.h +@@ -25,6 +25,7 @@ + #define SGX_EPC_ADDR_PROP "addr" + #define SGX_EPC_SIZE_PROP "size" + #define SGX_EPC_MEMDEV_PROP "memdev" ++#define SGX_EPC_NUMA_NODE_PROP "node" + + /** + * SGXEPCDevice: +@@ -38,6 +39,7 @@ typedef struct SGXEPCDevice { + + /* public */ + uint64_t addr; ++ uint32_t node; + HostMemoryBackendEpc *hostmem; + } SGXEPCDevice; + +@@ -56,6 +58,7 @@ typedef struct SGXEPCState { + } SGXEPCState; + + bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size); ++void sgx_epc_build_srat(GArray *table_data); + + static inline uint64_t sgx_epc_above_4g_end(SGXEPCState *sgx_epc) + { +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 294652034e..9570011232 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -1823,6 +1823,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) + se->id ? se->id : ""); + monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", se->memaddr); + monitor_printf(mon, " size: %" PRIu64 "\n", se->size); ++ monitor_printf(mon, " node: %" PRId64 "\n", se->node); + monitor_printf(mon, " memdev: %s\n", se->memdev); + break; + default: +diff --git a/qapi/machine.json b/qapi/machine.json +index 6ed8488255..85c35e7fc5 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -1209,12 +1209,15 @@ + # + # @memdev: memory backend linked with device + # ++# @node: the numa node ++# + # Since: 6.2 + ## + { 'struct': 'SgxEPCDeviceInfo', + 'data': { '*id': 'str', + 'memaddr': 'size', + 'size': 'size', ++ 'node': 'int', + 'memdev': 'str' + } + } +@@ -1287,10 +1290,15 @@ + # + # @memdev: memory backend linked with device + # ++# @node: the numa node ++# + # Since: 6.2 + ## + { 'struct': 'SgxEPC', +- 'data': { 'memdev': 'str' } } ++ 'data': { 'memdev': 'str', ++ 'node': 'int' ++ } ++} + + ## + # @SgxEPCProperties: +diff --git a/qemu-options.hx b/qemu-options.hx +index 74d335e4c3..1aaf38c613 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -127,11 +127,11 @@ SRST + ERST + + DEF("M", HAS_ARG, QEMU_OPTION_M, +- " sgx-epc.0.memdev=memid\n", ++ " sgx-epc.0.memdev=memid,sgx-epc.0.node=numaid\n", + QEMU_ARCH_ALL) + + SRST +-``sgx-epc.0.memdev=@var{memid}`` ++``sgx-epc.0.memdev=@var{memid},sgx-epc.0.node=@var{numaid}`` + Define an SGX EPC section. + ERST + +-- +2.27.0 + diff --git a/numa-Support-SGX-numa-in-the-monitor-and-Libvirt-int.patch b/numa-Support-SGX-numa-in-the-monitor-and-Libvirt-int.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef45f00ba17d0b0066e443225058addc0e53c2d9 --- /dev/null +++ b/numa-Support-SGX-numa-in-the-monitor-and-Libvirt-int.patch @@ -0,0 +1,213 @@ +From 86648f137c72241005327b55208eeeed8b3cfd5e Mon Sep 17 00:00:00 2001 +From: Yang Zhong +Date: Mon, 1 Nov 2021 12:20:07 -0400 +Subject: [PATCH 2/9] numa: Support SGX numa in the monitor and Libvirt + interfaces + +from mainline-v7.0.0-rc0 +commit 4755927ae12547c2e7cb22c5fa1b39038c6c11b1 +category: feature +feature: NUMA support for SGX EPC sections +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5K27A + +Intel-SIG: commit 4755927ae125 ("numa: Support SGX numa in the monitor and +Libvirt interfaces") + ------------------------------------- + +numa: Support SGX numa in the monitor and Libvirt interfaces + +Add the SGXEPCSection list into SGXInfo to show the multiple +SGX EPC sections detailed info, not the total size like before. +This patch can enable numa support for 'info sgx' command and +QMP interfaces. The new interfaces show each EPC section info +in one numa node. Libvirt can use QMP interface to get the +detailed host SGX EPC capabilities to decide how to allocate +host EPC sections to guest. + +(qemu) info sgx + SGX support: enabled + SGX1 support: enabled + SGX2 support: enabled + FLC support: enabled + NUMA node #0: size=67108864 + NUMA node #1: size=29360128 + +The QMP interface show: +(QEMU) query-sgx +{"return": {"sgx": true, "sgx2": true, "sgx1": true, "sections": \ +[{"node": 0, "size": 67108864}, {"node": 1, "size": 29360128}], "flc": true}} + +(QEMU) query-sgx-capabilities +{"return": {"sgx": true, "sgx2": true, "sgx1": true, "sections": \ +[{"node": 0, "size": 17070817280}, {"node": 1, "size": 17079205888}], "flc": true}} + +Signed-off-by: Yang Zhong +Message-Id: <20211101162009.62161-4-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + hw/i386/sgx.c | 51 +++++++++++++++++++++++++++++++++++-------- + qapi/misc-target.json | 19 ++++++++++++++-- + 2 files changed, 59 insertions(+), 11 deletions(-) + +diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c +index d04299904a..5de5dd0893 100644 +--- a/hw/i386/sgx.c ++++ b/hw/i386/sgx.c +@@ -83,11 +83,13 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) + ((high & MAKE_64BIT_MASK(0, 20)) << 32); + } + +-static uint64_t sgx_calc_host_epc_section_size(void) ++static SGXEPCSectionList *sgx_calc_host_epc_sections(void) + { ++ SGXEPCSectionList *head = NULL, **tail = &head; ++ SGXEPCSection *section; + uint32_t i, type; + uint32_t eax, ebx, ecx, edx; +- uint64_t size = 0; ++ uint32_t j = 0; + + for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) { + host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx); +@@ -101,10 +103,13 @@ static uint64_t sgx_calc_host_epc_section_size(void) + break; + } + +- size += sgx_calc_section_metric(ecx, edx); ++ section = g_new0(SGXEPCSection, 1); ++ section->node = j++; ++ section->size = sgx_calc_section_metric(ecx, edx); ++ QAPI_LIST_APPEND(tail, section); + } + +- return size; ++ return head; + } + + static void sgx_epc_reset(void *opaque) +@@ -168,13 +173,35 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) + info->sgx1 = eax & (1U << 0) ? true : false; + info->sgx2 = eax & (1U << 1) ? true : false; + +- info->section_size = sgx_calc_host_epc_section_size(); ++ info->sections = sgx_calc_host_epc_sections(); + + close(fd); + + return info; + } + ++static SGXEPCSectionList *sgx_get_epc_sections_list(void) ++{ ++ GSList *device_list = sgx_epc_get_device_list(); ++ SGXEPCSectionList *head = NULL, **tail = &head; ++ SGXEPCSection *section; ++ ++ for (; device_list; device_list = device_list->next) { ++ DeviceState *dev = device_list->data; ++ Object *obj = OBJECT(dev); ++ ++ section = g_new0(SGXEPCSection, 1); ++ section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP, ++ &error_abort); ++ section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, ++ &error_abort); ++ QAPI_LIST_APPEND(tail, section); ++ } ++ g_slist_free(device_list); ++ ++ return head; ++} ++ + SGXInfo *qmp_query_sgx(Error **errp) + { + SGXInfo *info = NULL; +@@ -193,14 +220,13 @@ SGXInfo *qmp_query_sgx(Error **errp) + return NULL; + } + +- SGXEPCState *sgx_epc = &pcms->sgx_epc; + info = g_new0(SGXInfo, 1); + + info->sgx = true; + info->sgx1 = true; + info->sgx2 = true; + info->flc = true; +- info->section_size = sgx_epc->size; ++ info->sections = sgx_get_epc_sections_list(); + + return info; + } +@@ -208,6 +234,7 @@ SGXInfo *qmp_query_sgx(Error **errp) + void hmp_info_sgx(Monitor *mon, const QDict *qdict) + { + Error *err = NULL; ++ SGXEPCSectionList *section_list, *section; + g_autoptr(SGXInfo) info = qmp_query_sgx(&err); + + if (err) { +@@ -222,8 +249,14 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) + info->sgx2 ? "enabled" : "disabled"); + monitor_printf(mon, "FLC support: %s\n", + info->flc ? "enabled" : "disabled"); +- monitor_printf(mon, "size: %" PRIu64 "\n", +- info->section_size); ++ ++ section_list = info->sections; ++ for (section = section_list; section; section = section->next) { ++ monitor_printf(mon, "NUMA node #%" PRId64 ": ", ++ section->value->node); ++ monitor_printf(mon, "size=%" PRIu64 "\n", ++ section->value->size); ++ } + } + + bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) +diff --git a/qapi/misc-target.json b/qapi/misc-target.json +index 5aa2b95b7d..1022aa0184 100644 +--- a/qapi/misc-target.json ++++ b/qapi/misc-target.json +@@ -337,6 +337,21 @@ + 'if': 'TARGET_ARM' } + + ++## ++# @SGXEPCSection: ++# ++# Information about intel SGX EPC section info ++# ++# @node: the numa node ++# ++# @size: the size of epc section ++# ++# Since: 6.2 ++## ++{ 'struct': 'SGXEPCSection', ++ 'data': { 'node': 'int', ++ 'size': 'uint64'}} ++ + ## + # @SGXInfo: + # +@@ -350,7 +365,7 @@ + # + # @flc: true if FLC is supported + # +-# @section-size: The EPC section size for guest ++# @sections: The EPC sections info for guest + # + # Since: 6.2 + ## +@@ -359,7 +374,7 @@ + 'sgx1': 'bool', + 'sgx2': 'bool', + 'flc': 'bool', +- 'section-size': 'uint64'}, ++ 'sections': ['SGXEPCSection']}, + 'if': 'TARGET_I386' } + + ## +-- +2.27.0 + diff --git a/nvram-add-nrf51_soc-flash-read-method.patch b/nvram-add-nrf51_soc-flash-read-method.patch deleted file mode 100644 index 915bbf8a1e6eecaa0974f14db93847cedded7d85..0000000000000000000000000000000000000000 --- a/nvram-add-nrf51_soc-flash-read-method.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 6f88633406e546eb6a01786b910a2ab12373abf8 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:19:15 +0800 -Subject: [PATCH] nvram: add nrf51_soc flash read method - -fix CVE-2020-15469 - -Add nrf51_soc mmio read method to avoid NULL pointer dereference -issue. - -Reported-by: Lei Sun -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/nvram/nrf51_nvm.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c -index eca0cb35b5..7b2b1351f4 100644 ---- a/hw/nvram/nrf51_nvm.c -+++ b/hw/nvram/nrf51_nvm.c -@@ -271,6 +271,10 @@ static const MemoryRegionOps io_ops = { - .endianness = DEVICE_LITTLE_ENDIAN, - }; - -+static uint64_t flash_read(void *opaque, hwaddr offset, unsigned size) -+{ -+ g_assert_not_reached(); -+} - - static void flash_write(void *opaque, hwaddr offset, uint64_t value, - unsigned int size) -@@ -298,6 +302,7 @@ static void flash_write(void *opaque, hwaddr offset, uint64_t value, - - - static const MemoryRegionOps flash_ops = { -+ .read = flash_read, - .write = flash_write, - .valid.min_access_size = 4, - .valid.max_access_size = 4, --- -2.27.0 - diff --git a/object-return-self-in-object_ref.patch b/object-return-self-in-object_ref.patch deleted file mode 100644 index e851fb30d20a4c56b65bb7ce1c6ddb9109c643aa..0000000000000000000000000000000000000000 --- a/object-return-self-in-object_ref.patch +++ /dev/null @@ -1,58 +0,0 @@ -From b77ade9bb37b2e9813a42008cb21d0c743aa50a1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Fri, 10 Jan 2020 19:30:31 +0400 -Subject: [PATCH] object: return self in object_ref() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This allow for simpler assignment with ref: foo = object_ref(bar) - -Signed-off-by: Marc-André Lureau -Reviewed-by: Philippe Mathieu-Daudé -Message-Id: <20200110153039.1379601-19-marcandre.lureau@redhat.com> -Signed-off-by: Paolo Bonzini -Signed-off-by: Zhenyu Ye ---- - include/qom/object.h | 3 ++- - qom/object.c | 5 +++-- - 2 files changed, 5 insertions(+), 3 deletions(-) - -diff --git a/include/qom/object.h b/include/qom/object.h -index 5e2f60d4b0..18660fde1c 100644 ---- a/include/qom/object.h -+++ b/include/qom/object.h -@@ -1005,8 +1005,9 @@ GSList *object_class_get_list_sorted(const char *implements_type, - * - * Increase the reference count of a object. A object cannot be freed as long - * as its reference count is greater than zero. -+ * Returns: @obj - */ --void object_ref(Object *obj); -+Object *object_ref(Object *obj); - - /** - * object_unref: -diff --git a/qom/object.c b/qom/object.c -index 66c4a5f1cb..555c8b9d07 100644 ---- a/qom/object.c -+++ b/qom/object.c -@@ -1107,12 +1107,13 @@ GSList *object_class_get_list_sorted(const char *implements_type, - object_class_cmp); - } - --void object_ref(Object *obj) -+Object *object_ref(Object *obj) - { - if (!obj) { -- return; -+ return NULL; - } - atomic_inc(&obj->ref); -+ return obj; - } - - void object_unref(Object *obj) --- -2.22.0.windows.1 - diff --git a/oslib-posix-optimise-vm-startup-time-for-1G-hugepage.patch b/oslib-posix-optimise-vm-startup-time-for-1G-hugepage.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e87543dfe4485d6799039e6783c165d87452a39 --- /dev/null +++ b/oslib-posix-optimise-vm-startup-time-for-1G-hugepage.patch @@ -0,0 +1,56 @@ +From e5fc3a755c9ba9f18bc0416c60f745912cb5b104 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 14:21:39 +0800 +Subject: [PATCH 15/15] oslib-posix: optimise vm startup time for 1G hugepage + +It takes quit a long time to clear 1G-hugepage, which makes glibc +pthread_create quit slow. +Create touch_pages threads in advance, and then handle the touch_pages +callback. Only read lock is held here. +--- + util/oslib-posix.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/util/oslib-posix.c b/util/oslib-posix.c +index e8bdb02e1d..18a38b9464 100644 +--- a/util/oslib-posix.c ++++ b/util/oslib-posix.c +@@ -84,6 +84,7 @@ typedef struct MemsetThread MemsetThread; + + static MemsetThread *memset_thread; + static int memset_num_threads; ++static int started_num_threads; + static bool memset_thread_failed; + + static QemuMutex page_mutex; +@@ -464,6 +465,10 @@ static void *do_touch_pages(void *arg) + } + qemu_mutex_unlock(&page_mutex); + ++ while (started_num_threads != memset_num_threads) { ++ smp_mb(); ++ } ++ + /* unblock SIGBUS */ + sigemptyset(&set); + sigaddset(&set, SIGBUS); +@@ -529,7 +534,7 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, + memset_thread = g_new0(MemsetThread, memset_num_threads); + numpages_per_thread = numpages / memset_num_threads; + leftover = numpages % memset_num_threads; +- for (i = 0; i < memset_num_threads; i++) { ++ for (i = 0, started_num_threads = 0; i < memset_num_threads; i++) { + memset_thread[i].addr = addr; + memset_thread[i].numpages = numpages_per_thread + (i < leftover); + memset_thread[i].hpagesize = hpagesize; +@@ -537,6 +542,7 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, + do_touch_pages, &memset_thread[i], + QEMU_THREAD_JOINABLE); + addr += memset_thread[i].numpages * hpagesize; ++ started_num_threads++; + } + + qemu_mutex_lock(&page_mutex); +-- +2.27.0 + diff --git a/pc-Don-t-make-die-id-mandatory-unless-necessary.patch b/pc-Don-t-make-die-id-mandatory-unless-necessary.patch deleted file mode 100644 index c51b40f33020e36547f44b895b040acc07bf741c..0000000000000000000000000000000000000000 --- a/pc-Don-t-make-die-id-mandatory-unless-necessary.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 7ebcd375ade505358c1c45542de22f188c599bdd Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 16 Aug 2019 14:07:50 -0300 -Subject: [PATCH] pc: Don't make die-id mandatory unless necessary - -We have this issue reported when using libvirt to hotplug CPUs: -https://bugzilla.redhat.com/show_bug.cgi?id=1741451 - -Basically, libvirt is not copying die-id from -query-hotpluggable-cpus, but die-id is now mandatory. - -We could blame libvirt and say it is not following the documented -interface, because we have this buried in the QAPI schema -documentation: - -> Note: currently there are 5 properties that could be present -> but management should be prepared to pass through other -> properties with device_add command to allow for future -> interface extension. This also requires the filed names to be kept in -> sync with the properties passed to -device/device_add. - -But I don't think this would be reasonable from us. We can just -make QEMU more flexible and let die-id to be omitted when there's -no ambiguity. This will allow us to keep compatibility with -existing libvirt versions. - -Test case included to ensure we don't break this again. - -Fixes: commit 176d2cda0dee ("i386/cpu: Consolidate die-id validity in smp context") -Signed-off-by: Eduardo Habkost -Message-Id: <20190816170750.23910-1-ehabkost@redhat.com> -Signed-off-by: Eduardo Habkost -(cherry picked from commit fea374e7c8079563bca7c8fac895c6a880f76adc) -Signed-off-by: Michael Roth ---- - hw/i386/pc.c | 8 ++++++ - tests/acceptance/pc_cpu_hotplug_props.py | 35 ++++++++++++++++++++++++ - 2 files changed, 43 insertions(+) - create mode 100644 tests/acceptance/pc_cpu_hotplug_props.py - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 549c437050..947f81070f 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -2403,6 +2403,14 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, - int max_socket = (ms->smp.max_cpus - 1) / - smp_threads / smp_cores / pcms->smp_dies; - -+ /* -+ * die-id was optional in QEMU 4.0 and older, so keep it optional -+ * if there's only one die per socket. -+ */ -+ if (cpu->die_id < 0 && pcms->smp_dies == 1) { -+ cpu->die_id = 0; -+ } -+ - if (cpu->socket_id < 0) { - error_setg(errp, "CPU socket-id is not set"); - return; -diff --git a/tests/acceptance/pc_cpu_hotplug_props.py b/tests/acceptance/pc_cpu_hotplug_props.py -new file mode 100644 -index 0000000000..08b7e632c6 ---- /dev/null -+++ b/tests/acceptance/pc_cpu_hotplug_props.py -@@ -0,0 +1,35 @@ -+# -+# Ensure CPU die-id can be omitted on -device -+# -+# Copyright (c) 2019 Red Hat Inc -+# -+# Author: -+# Eduardo Habkost -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2 of the License, or (at your option) any later version. -+# -+# This library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, see . -+# -+ -+from avocado_qemu import Test -+ -+class OmittedCPUProps(Test): -+ """ -+ :avocado: tags=arch:x86_64 -+ """ -+ def test_no_die_id(self): -+ self.vm.add_args('-nodefaults', '-S') -+ self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8') -+ self.vm.add_args('-cpu', 'qemu64') -+ self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0') -+ self.vm.launch() -+ self.assertEquals(len(self.vm.command('query-cpus')), 2) --- -2.23.0 diff --git a/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch b/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch deleted file mode 100644 index 6e29f08d69c56a2907892008c9c4ce177778c097..0000000000000000000000000000000000000000 --- a/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d2bb5b4c4ed3b1dbc0096deb195b6df33f813f23 Mon Sep 17 00:00:00 2001 -From: Yifan Luo -Date: Wed, 14 Aug 2019 14:14:26 +0800 -Subject: [PATCH 5/5] pc-bios/s390-ccw/net: fix a possible memory leak in - get_uuid() - -There is a possible memory leak in get_uuid(). Should free allocated mem -before -return NULL. - -Signed-off-by: Yifan Luo -Message-Id: <02cf01d55267$86cf2850$946d78f0$@cmss.chinamobile.com> -Reviewed-by: Thomas Huth -Reviewed-by: Cornelia Huck -Signed-off-by: Thomas Huth ---- - pc-bios/s390-ccw/netmain.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c -index f3542cb2..f2dcc01e 100644 ---- a/pc-bios/s390-ccw/netmain.c -+++ b/pc-bios/s390-ccw/netmain.c -@@ -269,6 +269,7 @@ static const char *get_uuid(void) - : "d" (r0), "d" (r1), [addr] "a" (buf) - : "cc", "memory"); - if (cc) { -+ free(mem); - return NULL; - } - --- -2.23.0 - diff --git a/pci-Add-return_page_response-pci-ops.patch b/pci-Add-return_page_response-pci-ops.patch index 133762085ba7a4a01fd5e909a3c17cd45a975978..25e665f8bb14c8004760a11f67e8d7b572fc1b17 100644 --- a/pci-Add-return_page_response-pci-ops.patch +++ b/pci-Add-return_page_response-pci-ops.patch @@ -1,4 +1,4 @@ -From e3b498a1afec138693251bf1bd1fa9b322a880fb Mon Sep 17 00:00:00 2001 +From 228345cfa59c764e725e2d3680a4bc3ecb237609 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 6 Nov 2020 14:34:35 +0100 Subject: [PATCH] pci: Add return_page_response pci ops @@ -15,10 +15,10 @@ Signed-off-by: Kunkun Jiang 3 files changed, 28 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index f11ca7964e..a8b3d1c071 100644 +index 4a9374c025..64db325d6b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c -@@ -2660,6 +2660,22 @@ int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, +@@ -2793,6 +2793,22 @@ int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, return -ENOENT; } @@ -60,10 +60,10 @@ index 12092bda7b..5890f095b1 100644 #endif /* QEMU_HW_IOMMU_IOMMU_H */ diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h -index bb14ed61b0..5e7e0e4e6f 100644 +index abffa12a99..809eb32f4a 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h -@@ -266,6 +266,8 @@ typedef struct PCIReqIDCache PCIReqIDCache; +@@ -268,6 +268,8 @@ typedef struct PCIReqIDCache PCIReqIDCache; struct PCIPASIDOps { int (*set_pasid_table)(PCIBus *bus, int32_t devfn, IOMMUConfig *config); @@ -72,7 +72,7 @@ index bb14ed61b0..5e7e0e4e6f 100644 }; typedef struct PCIPASIDOps PCIPASIDOps; -@@ -495,6 +497,8 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); +@@ -508,6 +510,8 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); void pci_setup_pasid_ops(PCIDevice *dev, PCIPASIDOps *ops); bool pci_device_is_pasid_ops_set(PCIBus *bus, int32_t devfn); int pci_device_set_pasid_table(PCIBus *bus, int32_t devfn, IOMMUConfig *config); diff --git a/pci-Export-the-pci_intx-function.patch b/pci-Export-the-pci_intx-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..732b6717538c970b9326ca1107176100b7e88a4c --- /dev/null +++ b/pci-Export-the-pci_intx-function.patch @@ -0,0 +1,59 @@ +From 0d74ea5e0426c6ebf8666e8b88469b838d03ea01 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 16:55:35 +0800 +Subject: [PATCH] pci: Export the pci_intx() function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 2fedf46e34d2377760b2d26cf85487b772bca6fa + +Move the pci_intx() definition to the PCI header file, so that it can +be called from other PCI files. It is used by the next patch. + +Signed-off-by: Frederic Barrat +Message-Id: <20211116170133.724751-3-fbarrat@linux.ibm.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Cédric Le Goater +Signed-off-by: boringandboring +--- + hw/pci/pci.c | 5 ----- + include/hw/pci/pci.h | 5 +++++ + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 7a62f0e1fc..9ea67dba31 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -1504,11 +1504,6 @@ static void pci_irq_handler(void *opaque, int irq_num, int level) + pci_change_irq_level(pci_dev, irq_num, change); + } + +-static inline int pci_intx(PCIDevice *pci_dev) +-{ +- return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; +-} +- + qemu_irq pci_allocate_irq(PCIDevice *pci_dev) + { + int intx = pci_intx(pci_dev); +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index 5b36334a28..483d5c7c72 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -735,6 +735,11 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); + qemu_irq pci_allocate_irq(PCIDevice *pci_dev); + void pci_set_irq(PCIDevice *pci_dev, int level); + ++static inline int pci_intx(PCIDevice *pci_dev) ++{ ++ return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; ++} ++ + static inline void pci_irq_assert(PCIDevice *pci_dev) + { + pci_set_irq(pci_dev, 1); +-- +2.27.0 + diff --git a/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch b/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2b162c06e787adcbdb6aff78ca98027f27297e5 --- /dev/null +++ b/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch @@ -0,0 +1,53 @@ +From d81bf8c86e2b024f85d90e199181ae048134d4ee Mon Sep 17 00:00:00 2001 +From: Guoyi Tu +Date: Fri, 11 Aug 2023 22:46:51 +0800 +Subject: [PATCH] pci: Fix the update of interrupt disable bit in PCI_COMMAND + register + +The PCI_COMMAND register is located at offset 4 within +the PCI configuration space and occupies 2 bytes. The +interrupt disable bit is at the 10th bit, which corresponds +to the byte at offset 5 in the PCI configuration space. + +In our testing environment, the guest driver may directly +updates the byte at offset 5 in the PCI configuration space. +The backtrace looks like as following: + at hw/pci/pci.c:1442 + at hw/virtio/virtio-pci.c:605 + val=5, len=1) at hw/pci/pci_host.c:81 + +In this situation, the range_covers_byte function called +by the pci_default_write_config function will return false, +resulting in the inability to handle the interrupt disable +update event. + +To fix this issue, we can use the ranges_overlap function +instead of range_covers_byte to determine whether the interrupt +bit has been updated. + +Signed-off-by: Guoyi Tu +Signed-off-by: yuanminghao +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Fixes: b6981cb57be5 ("pci: interrupt disable bit support") +--- + hw/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 3e6805d54a..3a4619e2a5 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -1471,7 +1471,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int + range_covers_byte(addr, l, PCI_COMMAND)) + pci_update_mappings(d); + +- if (range_covers_byte(addr, l, PCI_COMMAND)) { ++ if (ranges_overlap(addr, l, PCI_COMMAND, 2)) { + pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + (pci_get_word(d->config + PCI_COMMAND) +-- +2.27.0 + diff --git a/pci-Let-ld-_pci_dma-propagate-MemTxResult.patch b/pci-Let-ld-_pci_dma-propagate-MemTxResult.patch new file mode 100644 index 0000000000000000000000000000000000000000..91406d122841c2f8f9e06bcfccc3f7ac8a99ac31 --- /dev/null +++ b/pci-Let-ld-_pci_dma-propagate-MemTxResult.patch @@ -0,0 +1,292 @@ +From d7e2bb6bba0b5b77b296ca99b26c0d0a4db0d9f0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 23:49:30 +0100 +Subject: [PATCH 22/25] pci: Let ld*_pci_dma() propagate MemTxResult +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ld*_dma() returns a MemTxResult type. Do not discard +it, return it to the caller. + +Update the few callers. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-24-philmd@redhat.com> +--- + hw/audio/intel-hda.c | 2 +- + hw/net/eepro100.c | 25 ++++++++++--------------- + hw/net/tulip.c | 16 ++++++++-------- + hw/scsi/megasas.c | 21 ++++++++++++--------- + hw/scsi/mptsas.c | 16 +++++++++++----- + hw/scsi/vmw_pvscsi.c | 16 ++++++++++------ + include/hw/pci/pci.h | 17 ++++++++--------- + 7 files changed, 60 insertions(+), 53 deletions(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index e34b7ab0e9..2b55d52150 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -335,7 +335,7 @@ static void intel_hda_corb_run(IntelHDAState *d) + + rp = (d->corb_rp + 1) & 0xff; + addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); +- verb = ldl_le_pci_dma(&d->pci, addr + 4 * rp, MEMTXATTRS_UNSPECIFIED); ++ ldl_le_pci_dma(&d->pci, addr + 4 * rp, &verb, MEMTXATTRS_UNSPECIFIED); + d->corb_rp = rp; + + dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __func__, rp, verb); +diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c +index 36dc1e22d7..9c178c1448 100644 +--- a/hw/net/eepro100.c ++++ b/hw/net/eepro100.c +@@ -772,18 +772,16 @@ static void tx_command(EEPRO100State *s) + } else { + /* Flexible mode. */ + uint8_t tbd_count = 0; ++ uint32_t tx_buffer_address; ++ uint16_t tx_buffer_size; ++ uint16_t tx_buffer_el; ++ + if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) { + /* Extended Flexible TCB. */ + for (; tbd_count < 2; tbd_count++) { +- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, +- tbd_address, +- attrs); +- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, +- tbd_address + 4, +- attrs); +- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, +- tbd_address + 6, +- attrs); ++ ldl_le_pci_dma(&s->dev, tbd_address, &tx_buffer_address, attrs); ++ lduw_le_pci_dma(&s->dev, tbd_address + 4, &tx_buffer_size, attrs); ++ lduw_le_pci_dma(&s->dev, tbd_address + 6, &tx_buffer_el, attrs); + tbd_address += 8; + TRACE(RXTX, logout + ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n", +@@ -799,12 +797,9 @@ static void tx_command(EEPRO100State *s) + } + tbd_address = tbd_array; + for (; tbd_count < s->tx.tbd_count; tbd_count++) { +- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address, +- attrs); +- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4, +- attrs); +- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6, +- attrs); ++ ldl_le_pci_dma(&s->dev, tbd_address, &tx_buffer_address, attrs); ++ lduw_le_pci_dma(&s->dev, tbd_address + 4, &tx_buffer_size, attrs); ++ lduw_le_pci_dma(&s->dev, tbd_address + 6, &tx_buffer_el, attrs); + tbd_address += 8; + TRACE(RXTX, logout + ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n", +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index c76e4868f7..d5b6cc5ee6 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -73,15 +73,15 @@ static void tulip_desc_read(TULIPState *s, hwaddr p, + const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + + if (s->csr[0] & CSR0_DBO) { +- desc->status = ldl_be_pci_dma(&s->dev, p, attrs); +- desc->control = ldl_be_pci_dma(&s->dev, p + 4, attrs); +- desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8, attrs); +- desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12, attrs); ++ ldl_be_pci_dma(&s->dev, p, &desc->status, attrs); ++ ldl_be_pci_dma(&s->dev, p + 4, &desc->control, attrs); ++ ldl_be_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs); ++ ldl_be_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs); + } else { +- desc->status = ldl_le_pci_dma(&s->dev, p, attrs); +- desc->control = ldl_le_pci_dma(&s->dev, p + 4, attrs); +- desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8, attrs); +- desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12, attrs); ++ ldl_le_pci_dma(&s->dev, p, &desc->status, attrs); ++ ldl_le_pci_dma(&s->dev, p + 4, &desc->control, attrs); ++ ldl_le_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs); ++ ldl_le_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs); + } + } + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 23380008e1..946050bf83 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -202,9 +202,12 @@ static uint64_t megasas_frame_get_context(MegasasState *s, + unsigned long frame) + { + PCIDevice *pci = &s->parent_obj; +- return ldq_le_pci_dma(pci, +- frame + offsetof(struct mfi_frame_header, context), +- MEMTXATTRS_UNSPECIFIED); ++ uint64_t val; ++ ++ ldq_le_pci_dma(pci, frame + offsetof(struct mfi_frame_header, context), ++ &val, MEMTXATTRS_UNSPECIFIED); ++ ++ return val; + } + + static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd) +@@ -535,8 +538,8 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, + s->busy++; + + if (s->consumer_pa) { +- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa, +- MEMTXATTRS_UNSPECIFIED); ++ ldl_le_pci_dma(pcid, s->consumer_pa, &s->reply_queue_tail, ++ MEMTXATTRS_UNSPECIFIED); + } + trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context, + s->reply_queue_head, s->reply_queue_tail, s->busy); +@@ -567,14 +570,14 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) + stl_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, + context, attrs); + } +- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa, attrs); ++ ldl_le_pci_dma(pci_dev, s->consumer_pa, &s->reply_queue_tail, attrs); + trace_megasas_qf_complete(context, s->reply_queue_head, + s->reply_queue_tail, s->busy); + } + + if (megasas_intr_enabled(s)) { + /* Update reply queue pointer */ +- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa, attrs); ++ ldl_le_pci_dma(pci_dev, s->consumer_pa, &s->reply_queue_tail, attrs); + tail = s->reply_queue_head; + s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); + trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, +@@ -678,9 +681,9 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) + pa_lo = le32_to_cpu(initq->pi_addr_lo); + pa_hi = le32_to_cpu(initq->pi_addr_hi); + s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo; +- s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa, attrs); ++ ldl_le_pci_dma(pcid, s->producer_pa, &s->reply_queue_head, attrs); + s->reply_queue_head %= MEGASAS_MAX_FRAMES; +- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa, attrs); ++ ldl_le_pci_dma(pcid, s->consumer_pa, &s->reply_queue_tail, attrs); + s->reply_queue_tail %= MEGASAS_MAX_FRAMES; + flags = le32_to_cpu(initq->flags); + if (flags & MFI_QUEUE_FLAG_CONTEXT64) { +diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c +index ac9f4dfcd2..5181b0c0b0 100644 +--- a/hw/scsi/mptsas.c ++++ b/hw/scsi/mptsas.c +@@ -177,10 +177,16 @@ static dma_addr_t mptsas_ld_sg_base(MPTSASState *s, uint32_t flags_and_length, + dma_addr_t addr; + + if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { +- addr = ldq_le_pci_dma(pci, *sgaddr + 4, attrs); ++ uint64_t addr64; ++ ++ ldq_le_pci_dma(pci, *sgaddr + 4, &addr64, attrs); ++ addr = addr64; + *sgaddr += 12; + } else { +- addr = ldl_le_pci_dma(pci, *sgaddr + 4, attrs); ++ uint32_t addr32; ++ ++ ldl_le_pci_dma(pci, *sgaddr + 4, &addr32, attrs); ++ addr = addr32; + *sgaddr += 8; + } + return addr; +@@ -204,7 +210,7 @@ static int mptsas_build_sgl(MPTSASState *s, MPTSASRequest *req, hwaddr addr) + dma_addr_t addr, len; + uint32_t flags_and_length; + +- flags_and_length = ldl_le_pci_dma(pci, sgaddr, MEMTXATTRS_UNSPECIFIED); ++ ldl_le_pci_dma(pci, sgaddr, &flags_and_length, MEMTXATTRS_UNSPECIFIED); + len = flags_and_length & MPI_SGE_LENGTH_MASK; + if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK) + != MPI_SGE_FLAGS_SIMPLE_ELEMENT || +@@ -235,8 +241,8 @@ static int mptsas_build_sgl(MPTSASState *s, MPTSASRequest *req, hwaddr addr) + break; + } + +- flags_and_length = ldl_le_pci_dma(pci, next_chain_addr, +- MEMTXATTRS_UNSPECIFIED); ++ ldl_le_pci_dma(pci, next_chain_addr, &flags_and_length, ++ MEMTXATTRS_UNSPECIFIED); + if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK) + != MPI_SGE_FLAGS_CHAIN_ELEMENT) { + return MPI_IOCSTATUS_INVALID_SGL; +diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c +index 33e16f9111..4d9969f3b1 100644 +--- a/hw/scsi/vmw_pvscsi.c ++++ b/hw/scsi/vmw_pvscsi.c +@@ -50,10 +50,10 @@ + #define PVSCSI_MAX_CMD_DATA_WORDS \ + (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t)) + +-#define RS_GET_FIELD(m, field) \ +- (ldl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ ++#define RS_GET_FIELD(pval, m, field) \ ++ ldl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ + (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), \ +- MEMTXATTRS_UNSPECIFIED)) ++ pval, MEMTXATTRS_UNSPECIFIED) + #define RS_SET_FIELD(m, field, val) \ + (stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ + (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val, \ +@@ -249,10 +249,11 @@ pvscsi_ring_cleanup(PVSCSIRingInfo *mgr) + static hwaddr + pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr) + { +- uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx); ++ uint32_t ready_ptr; + uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING + * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; + ++ RS_GET_FIELD(&ready_ptr, mgr, reqProdIdx); + if (ready_ptr != mgr->consumed_ptr + && ready_ptr - mgr->consumed_ptr < ring_size) { + uint32_t next_ready_ptr = +@@ -323,8 +324,11 @@ pvscsi_ring_flush_cmp(PVSCSIRingInfo *mgr) + static bool + pvscsi_ring_msg_has_room(PVSCSIRingInfo *mgr) + { +- uint32_t prodIdx = RS_GET_FIELD(mgr, msgProdIdx); +- uint32_t consIdx = RS_GET_FIELD(mgr, msgConsIdx); ++ uint32_t prodIdx; ++ uint32_t consIdx; ++ ++ RS_GET_FIELD(&prodIdx, mgr, msgProdIdx); ++ RS_GET_FIELD(&consIdx, mgr, msgConsIdx); + + return (prodIdx - consIdx) < (mgr->msg_len_mask + 1); + } +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index a9834e17e2..bfe3a6bca7 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -865,15 +865,14 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); + } + +-#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ +- static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ +- dma_addr_t addr, \ +- MemTxAttrs attrs) \ +- { \ +- uint##_bits##_t val; \ +- ld##_l##_dma(pci_get_address_space(dev), addr, &val, attrs); \ +- return val; \ +- } \ ++#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ ++ static inline MemTxResult ld##_l##_pci_dma(PCIDevice *dev, \ ++ dma_addr_t addr, \ ++ uint##_bits##_t *val, \ ++ MemTxAttrs attrs) \ ++ { \ ++ return ld##_l##_dma(pci_get_address_space(dev), addr, val, attrs); \ ++ } \ + static inline MemTxResult st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, \ + uint##_bits##_t val, \ +-- +2.27.0 + diff --git a/pci-Let-ld-_pci_dma-take-MemTxAttrs-argument.patch b/pci-Let-ld-_pci_dma-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..cbe94d91e2ab0a1ed53f897affab8445bcceca65 --- /dev/null +++ b/pci-Let-ld-_pci_dma-take-MemTxAttrs-argument.patch @@ -0,0 +1,267 @@ +From 0317671b81ebbff7187a1b836a2adde4fe16b762 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 23:45:06 +0100 +Subject: [PATCH 20/25] pci: Let ld*_pci_dma() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling ld*_pci_dma(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-22-philmd@redhat.com> +--- + hw/audio/intel-hda.c | 2 +- + hw/net/eepro100.c | 19 +++++++++++++------ + hw/net/tulip.c | 18 ++++++++++-------- + hw/scsi/megasas.c | 16 ++++++++++------ + hw/scsi/mptsas.c | 10 ++++++---- + hw/scsi/vmw_pvscsi.c | 3 ++- + hw/usb/hcd-xhci.c | 1 + + include/hw/pci/pci.h | 6 +++--- + 8 files changed, 46 insertions(+), 29 deletions(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index 3309ae0ea1..e34b7ab0e9 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -335,7 +335,7 @@ static void intel_hda_corb_run(IntelHDAState *d) + + rp = (d->corb_rp + 1) & 0xff; + addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); +- verb = ldl_le_pci_dma(&d->pci, addr + 4*rp); ++ verb = ldl_le_pci_dma(&d->pci, addr + 4 * rp, MEMTXATTRS_UNSPECIFIED); + d->corb_rp = rp; + + dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __func__, rp, verb); +diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c +index 160b9b0b4c..36dc1e22d7 100644 +--- a/hw/net/eepro100.c ++++ b/hw/net/eepro100.c +@@ -740,6 +740,7 @@ static void read_cb(EEPRO100State *s) + + static void tx_command(EEPRO100State *s) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + uint32_t tbd_array = s->tx.tbd_array_addr; + uint16_t tcb_bytes = s->tx.tcb_bytes & 0x3fff; + /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */ +@@ -775,11 +776,14 @@ static void tx_command(EEPRO100State *s) + /* Extended Flexible TCB. */ + for (; tbd_count < 2; tbd_count++) { + uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, +- tbd_address); ++ tbd_address, ++ attrs); + uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, +- tbd_address + 4); ++ tbd_address + 4, ++ attrs); + uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, +- tbd_address + 6); ++ tbd_address + 6, ++ attrs); + tbd_address += 8; + TRACE(RXTX, logout + ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n", +@@ -795,9 +799,12 @@ static void tx_command(EEPRO100State *s) + } + tbd_address = tbd_array; + for (; tbd_count < s->tx.tbd_count; tbd_count++) { +- uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address); +- uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4); +- uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6); ++ uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address, ++ attrs); ++ uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4, ++ attrs); ++ uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6, ++ attrs); + tbd_address += 8; + TRACE(RXTX, logout + ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n", +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index 1f2c79dd58..c76e4868f7 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -70,16 +70,18 @@ static const VMStateDescription vmstate_pci_tulip = { + static void tulip_desc_read(TULIPState *s, hwaddr p, + struct tulip_descriptor *desc) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ + if (s->csr[0] & CSR0_DBO) { +- desc->status = ldl_be_pci_dma(&s->dev, p); +- desc->control = ldl_be_pci_dma(&s->dev, p + 4); +- desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8); +- desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12); ++ desc->status = ldl_be_pci_dma(&s->dev, p, attrs); ++ desc->control = ldl_be_pci_dma(&s->dev, p + 4, attrs); ++ desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8, attrs); ++ desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12, attrs); + } else { +- desc->status = ldl_le_pci_dma(&s->dev, p); +- desc->control = ldl_le_pci_dma(&s->dev, p + 4); +- desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8); +- desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12); ++ desc->status = ldl_le_pci_dma(&s->dev, p, attrs); ++ desc->control = ldl_le_pci_dma(&s->dev, p + 4, attrs); ++ desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8, attrs); ++ desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12, attrs); + } + } + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index b4d448370f..23380008e1 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -202,7 +202,9 @@ static uint64_t megasas_frame_get_context(MegasasState *s, + unsigned long frame) + { + PCIDevice *pci = &s->parent_obj; +- return ldq_le_pci_dma(pci, frame + offsetof(struct mfi_frame_header, context)); ++ return ldq_le_pci_dma(pci, ++ frame + offsetof(struct mfi_frame_header, context), ++ MEMTXATTRS_UNSPECIFIED); + } + + static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd) +@@ -533,7 +535,8 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, + s->busy++; + + if (s->consumer_pa) { +- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa); ++ s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa, ++ MEMTXATTRS_UNSPECIFIED); + } + trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context, + s->reply_queue_head, s->reply_queue_tail, s->busy); +@@ -564,14 +567,14 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) + stl_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, + context, attrs); + } +- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa); ++ s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa, attrs); + trace_megasas_qf_complete(context, s->reply_queue_head, + s->reply_queue_tail, s->busy); + } + + if (megasas_intr_enabled(s)) { + /* Update reply queue pointer */ +- s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa); ++ s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa, attrs); + tail = s->reply_queue_head; + s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); + trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, +@@ -636,6 +639,7 @@ static void megasas_abort_command(MegasasCmd *cmd) + + static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + PCIDevice *pcid = PCI_DEVICE(s); + uint32_t pa_hi, pa_lo; + hwaddr iq_pa, initq_size = sizeof(struct mfi_init_qinfo); +@@ -674,9 +678,9 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) + pa_lo = le32_to_cpu(initq->pi_addr_lo); + pa_hi = le32_to_cpu(initq->pi_addr_hi); + s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo; +- s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa); ++ s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa, attrs); + s->reply_queue_head %= MEGASAS_MAX_FRAMES; +- s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa); ++ s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa, attrs); + s->reply_queue_tail %= MEGASAS_MAX_FRAMES; + flags = le32_to_cpu(initq->flags); + if (flags & MFI_QUEUE_FLAG_CONTEXT64) { +diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c +index f6c7765544..ac9f4dfcd2 100644 +--- a/hw/scsi/mptsas.c ++++ b/hw/scsi/mptsas.c +@@ -172,14 +172,15 @@ static const int mpi_request_sizes[] = { + static dma_addr_t mptsas_ld_sg_base(MPTSASState *s, uint32_t flags_and_length, + dma_addr_t *sgaddr) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + PCIDevice *pci = (PCIDevice *) s; + dma_addr_t addr; + + if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { +- addr = ldq_le_pci_dma(pci, *sgaddr + 4); ++ addr = ldq_le_pci_dma(pci, *sgaddr + 4, attrs); + *sgaddr += 12; + } else { +- addr = ldl_le_pci_dma(pci, *sgaddr + 4); ++ addr = ldl_le_pci_dma(pci, *sgaddr + 4, attrs); + *sgaddr += 8; + } + return addr; +@@ -203,7 +204,7 @@ static int mptsas_build_sgl(MPTSASState *s, MPTSASRequest *req, hwaddr addr) + dma_addr_t addr, len; + uint32_t flags_and_length; + +- flags_and_length = ldl_le_pci_dma(pci, sgaddr); ++ flags_and_length = ldl_le_pci_dma(pci, sgaddr, MEMTXATTRS_UNSPECIFIED); + len = flags_and_length & MPI_SGE_LENGTH_MASK; + if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK) + != MPI_SGE_FLAGS_SIMPLE_ELEMENT || +@@ -234,7 +235,8 @@ static int mptsas_build_sgl(MPTSASState *s, MPTSASRequest *req, hwaddr addr) + break; + } + +- flags_and_length = ldl_le_pci_dma(pci, next_chain_addr); ++ flags_and_length = ldl_le_pci_dma(pci, next_chain_addr, ++ MEMTXATTRS_UNSPECIFIED); + if ((flags_and_length & MPI_SGE_FLAGS_ELEMENT_TYPE_MASK) + != MPI_SGE_FLAGS_CHAIN_ELEMENT) { + return MPI_IOCSTATUS_INVALID_SGL; +diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c +index 59c3e8ba04..33e16f9111 100644 +--- a/hw/scsi/vmw_pvscsi.c ++++ b/hw/scsi/vmw_pvscsi.c +@@ -52,7 +52,8 @@ + + #define RS_GET_FIELD(m, field) \ + (ldl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ +- (m)->rs_pa + offsetof(struct PVSCSIRingsState, field))) ++ (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), \ ++ MEMTXATTRS_UNSPECIFIED)) + #define RS_SET_FIELD(m, field, val) \ + (stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ + (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val, \ +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 30c477f36e..47fb79aa4d 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3444,6 +3444,7 @@ static int usb_xhci_post_load(void *opaque, int version_id) + } + ldq_le_dma(xhci->as, dcbaap + 8 * slotid, &addr, MEMTXATTRS_UNSPECIFIED); + slot->ctx = xhci_mask64(addr); ++ + xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx)); + slot->uport = xhci_lookup_uport(xhci, slot_ctx); + if (!slot->uport) { +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index f6b0e843c1..d0f0d9bd50 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -867,11 +867,11 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + + #define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \ +- dma_addr_t addr) \ ++ dma_addr_t addr, \ ++ MemTxAttrs attrs) \ + { \ + uint##_bits##_t val; \ +- ld##_l##_dma(pci_get_address_space(dev), addr, &val, \ +- MEMTXATTRS_UNSPECIFIED); \ ++ ld##_l##_dma(pci_get_address_space(dev), addr, &val, attrs); \ + return val; \ + } \ + static inline void st##_s##_pci_dma(PCIDevice *dev, \ +-- +2.27.0 + diff --git a/pci-Let-pci_dma_rw-take-MemTxAttrs-argument.patch b/pci-Let-pci_dma_rw-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..58511afd9869fcba23deb729d16bfcc6363f09f6 --- /dev/null +++ b/pci-Let-pci_dma_rw-take-MemTxAttrs-argument.patch @@ -0,0 +1,88 @@ +From de60977c6a41b6de65e74918024c150e44311940 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 22:18:19 +0100 +Subject: [PATCH 10/25] pci: Let pci_dma_rw() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling pci_dma_rw(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Klaus Jensen +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-10-philmd@redhat.com> +--- + hw/audio/intel-hda.c | 3 ++- + hw/scsi/esp-pci.c | 2 +- + include/hw/pci/pci.h | 10 ++++++---- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index 8ce9df64e3..fb3d34a4a0 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -427,7 +427,8 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n", + st->be, st->bp, st->bpl[st->be].len, copy); + +- pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output); ++ pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output, ++ MEMTXATTRS_UNSPECIFIED); + st->lpib += copy; + st->bp += copy; + buf += copy; +diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c +index dac054aeed..1792f84cea 100644 +--- a/hw/scsi/esp-pci.c ++++ b/hw/scsi/esp-pci.c +@@ -280,7 +280,7 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len, + len = pci->dma_regs[DMA_WBC]; + } + +- pci_dma_rw(PCI_DEVICE(pci), addr, buf, len, dir); ++ pci_dma_rw(PCI_DEVICE(pci), addr, buf, len, dir, MEMTXATTRS_UNSPECIFIED); + + /* update status registers */ + pci->dma_regs[DMA_WBC] -= len; +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index c3d5e06364..c7177646a4 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -821,10 +821,10 @@ static inline AddressSpace *pci_get_address_space(PCIDevice *dev) + */ + static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len, +- DMADirection dir) ++ DMADirection dir, MemTxAttrs attrs) + { + return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, +- dir, MEMTXATTRS_UNSPECIFIED); ++ dir, attrs); + } + + /** +@@ -842,7 +842,8 @@ static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + static inline MemTxResult pci_dma_read(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len) + { +- return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE); ++ return pci_dma_rw(dev, addr, buf, len, ++ DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); + } + + /** +@@ -860,7 +861,8 @@ static inline MemTxResult pci_dma_read(PCIDevice *dev, dma_addr_t addr, + static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + const void *buf, dma_addr_t len) + { +- return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE); ++ return pci_dma_rw(dev, addr, (void *) buf, len, ++ DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); + } + + #define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ +-- +2.27.0 + diff --git a/pci-Let-st-_pci_dma-propagate-MemTxResult.patch b/pci-Let-st-_pci_dma-propagate-MemTxResult.patch new file mode 100644 index 0000000000000000000000000000000000000000..6dc64011a2ea27cb9f4069f9f70cd6f782881086 --- /dev/null +++ b/pci-Let-st-_pci_dma-propagate-MemTxResult.patch @@ -0,0 +1,43 @@ +From b498014d3214e053cfc97d0d48bcaae3176764ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 23:47:30 +0100 +Subject: [PATCH 21/25] pci: Let st*_pci_dma() propagate MemTxResult +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +st*_dma() returns a MemTxResult type. Do not discard +it, return it to the caller. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-23-philmd@redhat.com> +--- + include/hw/pci/pci.h | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index d0f0d9bd50..a9834e17e2 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -874,12 +874,12 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + ld##_l##_dma(pci_get_address_space(dev), addr, &val, attrs); \ + return val; \ + } \ +- static inline void st##_s##_pci_dma(PCIDevice *dev, \ +- dma_addr_t addr, \ +- uint##_bits##_t val, \ +- MemTxAttrs attrs) \ ++ static inline MemTxResult st##_s##_pci_dma(PCIDevice *dev, \ ++ dma_addr_t addr, \ ++ uint##_bits##_t val, \ ++ MemTxAttrs attrs) \ + { \ +- st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \ ++ return st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \ + } + + PCI_DMA_DEFINE_LDST(ub, b, 8); +-- +2.27.0 + diff --git a/pci-Let-st-_pci_dma-take-MemTxAttrs-argument.patch b/pci-Let-st-_pci_dma-take-MemTxAttrs-argument.patch new file mode 100644 index 0000000000000000000000000000000000000000..a99cd45746110861ac637eb09feadd22306e3df5 --- /dev/null +++ b/pci-Let-st-_pci_dma-take-MemTxAttrs-argument.patch @@ -0,0 +1,299 @@ +From b823af328bc872734b0a2e4b0db3c5d2ec27a83f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 17 Dec 2021 22:39:42 +0100 +Subject: [PATCH 19/25] pci: Let st*_pci_dma() take MemTxAttrs argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let devices specify transaction attributes when calling st*_pci_dma(). + +Keep the default MEMTXATTRS_UNSPECIFIED in the few callers. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211223115554.3155328-21-philmd@redhat.com> +--- + hw/audio/intel-hda.c | 10 ++++++---- + hw/net/eepro100.c | 29 ++++++++++++++++++----------- + hw/net/tulip.c | 18 ++++++++++-------- + hw/scsi/megasas.c | 15 ++++++++++----- + hw/scsi/vmw_pvscsi.c | 3 ++- + include/hw/pci/pci.h | 11 ++++++----- + 6 files changed, 52 insertions(+), 34 deletions(-) + +diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c +index fb3d34a4a0..3309ae0ea1 100644 +--- a/hw/audio/intel-hda.c ++++ b/hw/audio/intel-hda.c +@@ -345,6 +345,7 @@ static void intel_hda_corb_run(IntelHDAState *d) + + static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + hwaddr addr; +@@ -367,8 +368,8 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res + ex = (solicited ? 0 : (1 << 4)) | dev->cad; + wp = (d->rirb_wp + 1) & 0xff; + addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); +- stl_le_pci_dma(&d->pci, addr + 8*wp, response); +- stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex); ++ stl_le_pci_dma(&d->pci, addr + 8 * wp, response, attrs); ++ stl_le_pci_dma(&d->pci, addr + 8 * wp + 4, ex, attrs); + d->rirb_wp = wp; + + dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", +@@ -394,6 +395,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res + static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + uint8_t *buf, uint32_t len) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + hwaddr addr; +@@ -428,7 +430,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + st->be, st->bp, st->bpl[st->be].len, copy); + + pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output, +- MEMTXATTRS_UNSPECIFIED); ++ attrs); + st->lpib += copy; + st->bp += copy; + buf += copy; +@@ -451,7 +453,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + if (d->dp_lbase & 0x01) { + s = st - d->st; + addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); +- stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib); ++ stl_le_pci_dma(&d->pci, addr + 8 * s, st->lpib, attrs); + } + dprint(d, 3, "dma: --\n"); + +diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c +index 2474cf3dc2..160b9b0b4c 100644 +--- a/hw/net/eepro100.c ++++ b/hw/net/eepro100.c +@@ -703,6 +703,8 @@ static void set_ru_state(EEPRO100State * s, ru_state_t state) + + static void dump_statistics(EEPRO100State * s) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ + /* Dump statistical data. Most data is never changed by the emulation + * and always 0, so we first just copy the whole block and then those + * values which really matter. +@@ -710,16 +712,18 @@ static void dump_statistics(EEPRO100State * s) + */ + pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size); + stl_le_pci_dma(&s->dev, s->statsaddr + 0, +- s->statistics.tx_good_frames); ++ s->statistics.tx_good_frames, attrs); + stl_le_pci_dma(&s->dev, s->statsaddr + 36, +- s->statistics.rx_good_frames); ++ s->statistics.rx_good_frames, attrs); + stl_le_pci_dma(&s->dev, s->statsaddr + 48, +- s->statistics.rx_resource_errors); ++ s->statistics.rx_resource_errors, attrs); + stl_le_pci_dma(&s->dev, s->statsaddr + 60, +- s->statistics.rx_short_frame_errors); ++ s->statistics.rx_short_frame_errors, attrs); + #if 0 +- stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames); +- stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames); ++ stw_le_pci_dma(&s->dev, s->statsaddr + 76, ++ s->statistics.xmt_tco_frames, attrs); ++ stw_le_pci_dma(&s->dev, s->statsaddr + 78, ++ s->statistics.rcv_tco_frames, attrs); + missing("CU dump statistical counters"); + #endif + } +@@ -836,6 +840,7 @@ static void set_multicast_list(EEPRO100State *s) + + static void action_command(EEPRO100State *s) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + /* The loop below won't stop if it gets special handcrafted data. + Therefore we limit the number of iterations. */ + unsigned max_loop_count = 16; +@@ -922,7 +927,7 @@ static void action_command(EEPRO100State *s) + } + /* Write new status. */ + stw_le_pci_dma(&s->dev, s->cb_address, +- s->tx.status | ok_status | STATUS_C); ++ s->tx.status | ok_status | STATUS_C, attrs); + if (bit_i) { + /* CU completed action. */ + eepro100_cx_interrupt(s); +@@ -949,6 +954,7 @@ static void action_command(EEPRO100State *s) + + static void eepro100_cu_command(EEPRO100State * s, uint8_t val) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + cu_state_t cu_state; + switch (val) { + case CU_NOP: +@@ -998,7 +1004,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) + /* Dump statistical counters. */ + TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val)); + dump_statistics(s); +- stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005); ++ stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005, attrs); + break; + case CU_CMD_BASE: + /* Load CU base. */ +@@ -1009,7 +1015,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) + /* Dump and reset statistical counters. */ + TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val)); + dump_statistics(s); +- stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007); ++ stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007, attrs); + memset(&s->statistics, 0, sizeof(s->statistics)); + break; + case CU_SRESUME: +@@ -1624,6 +1630,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) + * - Magic packets should set bit 30 in power management driver register. + * - Interesting packets should set bit 29 in power management driver register. + */ ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + EEPRO100State *s = qemu_get_nic_opaque(nc); + uint16_t rfd_status = 0xa000; + #if defined(CONFIG_PAD_RECEIVED_FRAMES) +@@ -1738,9 +1745,9 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) + TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", + rfd_command, rx.link, rx.rx_buf_addr, rfd_size)); + stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset + +- offsetof(eepro100_rx_t, status), rfd_status); ++ offsetof(eepro100_rx_t, status), rfd_status, attrs); + stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset + +- offsetof(eepro100_rx_t, count), size); ++ offsetof(eepro100_rx_t, count), size, attrs); + /* Early receive interrupt not supported. */ + #if 0 + eepro100_er_interrupt(s); +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index ca69f7ea5e..1f2c79dd58 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -86,16 +86,18 @@ static void tulip_desc_read(TULIPState *s, hwaddr p, + static void tulip_desc_write(TULIPState *s, hwaddr p, + struct tulip_descriptor *desc) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; ++ + if (s->csr[0] & CSR0_DBO) { +- stl_be_pci_dma(&s->dev, p, desc->status); +- stl_be_pci_dma(&s->dev, p + 4, desc->control); +- stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1); +- stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2); ++ stl_be_pci_dma(&s->dev, p, desc->status, attrs); ++ stl_be_pci_dma(&s->dev, p + 4, desc->control, attrs); ++ stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); ++ stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); + } else { +- stl_le_pci_dma(&s->dev, p, desc->status); +- stl_le_pci_dma(&s->dev, p + 4, desc->control); +- stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1); +- stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2); ++ stl_le_pci_dma(&s->dev, p, desc->status, attrs); ++ stl_le_pci_dma(&s->dev, p + 4, desc->control, attrs); ++ stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); ++ stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); + } + } + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index f1c4d5782b..b4d448370f 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -168,14 +168,16 @@ static void megasas_frame_set_cmd_status(MegasasState *s, + unsigned long frame, uint8_t v) + { + PCIDevice *pci = &s->parent_obj; +- stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, cmd_status), v); ++ stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, cmd_status), ++ v, MEMTXATTRS_UNSPECIFIED); + } + + static void megasas_frame_set_scsi_status(MegasasState *s, + unsigned long frame, uint8_t v) + { + PCIDevice *pci = &s->parent_obj; +- stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), v); ++ stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), ++ v, MEMTXATTRS_UNSPECIFIED); + } + + static inline const char *mfi_frame_desc(unsigned int cmd) +@@ -541,6 +543,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, + + static void megasas_complete_frame(MegasasState *s, uint64_t context) + { ++ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + PCIDevice *pci_dev = PCI_DEVICE(s); + int tail, queue_offset; + +@@ -554,10 +557,12 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) + */ + if (megasas_use_queue64(s)) { + queue_offset = s->reply_queue_head * sizeof(uint64_t); +- stq_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, context); ++ stq_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, ++ context, attrs); + } else { + queue_offset = s->reply_queue_head * sizeof(uint32_t); +- stl_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, context); ++ stl_le_pci_dma(pci_dev, s->reply_queue_pa + queue_offset, ++ context, attrs); + } + s->reply_queue_tail = ldl_le_pci_dma(pci_dev, s->consumer_pa); + trace_megasas_qf_complete(context, s->reply_queue_head, +@@ -571,7 +576,7 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) + s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); + trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, + s->busy); +- stl_le_pci_dma(pci_dev, s->producer_pa, s->reply_queue_head); ++ stl_le_pci_dma(pci_dev, s->producer_pa, s->reply_queue_head, attrs); + /* Notify HBA */ + if (msix_enabled(pci_dev)) { + trace_megasas_msix_raise(0); +diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c +index cd76bd67ab..59c3e8ba04 100644 +--- a/hw/scsi/vmw_pvscsi.c ++++ b/hw/scsi/vmw_pvscsi.c +@@ -55,7 +55,8 @@ + (m)->rs_pa + offsetof(struct PVSCSIRingsState, field))) + #define RS_SET_FIELD(m, field, val) \ + (stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \ +- (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val)) ++ (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val, \ ++ MEMTXATTRS_UNSPECIFIED)) + + struct PVSCSIClass { + PCIDeviceClass parent_class; +diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h +index 71c6513641..f6b0e843c1 100644 +--- a/include/hw/pci/pci.h ++++ b/include/hw/pci/pci.h +@@ -874,11 +874,12 @@ static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + MEMTXATTRS_UNSPECIFIED); \ + return val; \ + } \ +- static inline void st##_s##_pci_dma(PCIDevice *dev, \ +- dma_addr_t addr, uint##_bits##_t val) \ +- { \ +- st##_s##_dma(pci_get_address_space(dev), addr, val, \ +- MEMTXATTRS_UNSPECIFIED); \ ++ static inline void st##_s##_pci_dma(PCIDevice *dev, \ ++ dma_addr_t addr, \ ++ uint##_bits##_t val, \ ++ MemTxAttrs attrs) \ ++ { \ ++ st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \ + } + + PCI_DMA_DEFINE_LDST(ub, b, 8); +-- +2.27.0 + diff --git a/pci-check-bus-pointer-before-dereference.patch b/pci-check-bus-pointer-before-dereference.patch index 540caaf945f28b4e13e53a299495528cb0703b5d..fbd30a32937a53dede688323163c8d229e93a054 100644 --- a/pci-check-bus-pointer-before-dereference.patch +++ b/pci-check-bus-pointer-before-dereference.patch @@ -1,4 +1,4 @@ -From e393095e6d1456e2fb22f3cde3a9f0a307152562 Mon Sep 17 00:00:00 2001 +From 92da19fb18c234bb8872b9d8f7dedcc73e5fcafb Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Wed, 14 Oct 2020 15:00:20 +0800 Subject: [PATCH] pci: check bus pointer before dereference @@ -27,15 +27,16 @@ avoid it. Reported-by: Ruhr-University Signed-off-by: Prasad J Pandit +Signed-off-by: Yan Wang --- hw/pci/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index de0fae10ab..df5a2c3294 100644 +index e5993c1ef5..6d1c39a9de 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c -@@ -253,6 +253,9 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) +@@ -270,6 +270,9 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) PCIBus *bus; for (;;) { bus = pci_get_bus(pci_dev); @@ -46,5 +47,5 @@ index de0fae10ab..df5a2c3294 100644 if (bus->set_irq) break; -- -2.23.0 +2.27.0 diff --git a/pci-expose-TYPE_XIO3130_DOWNSTREAM-name.patch b/pci-expose-TYPE_XIO3130_DOWNSTREAM-name.patch new file mode 100644 index 0000000000000000000000000000000000000000..30d9615bca97e2c4585db878946965b8de7e6a9b --- /dev/null +++ b/pci-expose-TYPE_XIO3130_DOWNSTREAM-name.patch @@ -0,0 +1,64 @@ +From e88d2f15443811e40c4e1ba8299c12b35b75cb1e Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Tue, 1 Mar 2022 10:11:58 -0500 +Subject: [PATCH 4/6] pci: expose TYPE_XIO3130_DOWNSTREAM name + +Type name will be used in followup patch for cast check +in pcihp code. + +Signed-off-by: Igor Mammedov +Message-Id: <20220301151200.3507298-2-imammedo@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: wanbo +--- + hw/pci-bridge/xio3130_downstream.c | 3 ++- + include/hw/pci-bridge/xio3130_downstream.h | 15 +++++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + create mode 100644 include/hw/pci-bridge/xio3130_downstream.h + +diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c +index 04aae72cd6..b17cafd359 100644 +--- a/hw/pci-bridge/xio3130_downstream.c ++++ b/hw/pci-bridge/xio3130_downstream.c +@@ -28,6 +28,7 @@ + #include "migration/vmstate.h" + #include "qapi/error.h" + #include "qemu/module.h" ++#include "hw/pci-bridge/xio3130_downstream.h" + + #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ + #define XIO3130_REVISION 0x1 +@@ -173,7 +174,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) + } + + static const TypeInfo xio3130_downstream_info = { +- .name = "xio3130-downstream", ++ .name = TYPE_XIO3130_DOWNSTREAM, + .parent = TYPE_PCIE_SLOT, + .class_init = xio3130_downstream_class_init, + .interfaces = (InterfaceInfo[]) { +diff --git a/include/hw/pci-bridge/xio3130_downstream.h b/include/hw/pci-bridge/xio3130_downstream.h +new file mode 100644 +index 0000000000..1d10139aea +--- /dev/null ++++ b/include/hw/pci-bridge/xio3130_downstream.h +@@ -0,0 +1,15 @@ ++/* ++ * TI X3130 pci express downstream port switch ++ * ++ * Copyright (C) 2022 Igor Mammedov ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H ++#define HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H ++ ++#define TYPE_XIO3130_DOWNSTREAM "xio3130-downstream" ++ ++#endif ++ +-- +2.27.0 + diff --git a/pci-fix-overflow-in-snprintf-string-formatting.patch b/pci-fix-overflow-in-snprintf-string-formatting.patch new file mode 100644 index 0000000000000000000000000000000000000000..e1e2e1b6cd2a2d5da17bbe351a363631018e50cf --- /dev/null +++ b/pci-fix-overflow-in-snprintf-string-formatting.patch @@ -0,0 +1,106 @@ +From b2d665abb4dbd3c91c0ceceebe537cf411f6c650 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:35:28 +0000 +Subject: [PATCH] pci: fix overflow in snprintf string formatting mainline + inclusion commit 36f18c6989a3d1ff1d7a0e50b0868ef3958299b4 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +the code in pcibus_get_fw_dev_path contained the potential for a +stack buffer overflow of 1 byte, potentially writing to the stack an +extra NUL byte. + +This overflow could happen if the PCI slot is >= 0x10000000, +and the PCI function is >= 0x10000000, due to the size parameter +of snprintf being incorrectly calculated in the call: + + if (PCI_FUNC(d->devfn)) + snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); + +since the off obtained from a previous call to snprintf is added +instead of subtracted from the total available size of the buffer. + +Without the accurate size guard from snprintf, we end up writing in the +worst case: + +name (32) + "@" (1) + SLOT (8) + "," (1) + FUNC (8) + term NUL (1) = 51 bytes + +In order to provide something more robust, replace all of the code in +pcibus_get_fw_dev_path with a single call to g_strdup_printf, +so there is no need to rely on manual calculations. + +Found by compiling QEMU with FORTIFY_SOURCE=3 as the error: + +*** buffer overflow detected ***: terminated + +Thread 1 "qemu-system-x86" received signal SIGABRT, Aborted. +[Switching to Thread 0x7ffff642c380 (LWP 121307)] +0x00007ffff71ff55c in __pthread_kill_implementation () from /lib64/libc.so.6 +(gdb) bt + #0 0x00007ffff71ff55c in __pthread_kill_implementation () at /lib64/libc.so.6 + #1 0x00007ffff71ac6f6 in raise () at /lib64/libc.so.6 + #2 0x00007ffff7195814 in abort () at /lib64/libc.so.6 + #3 0x00007ffff71f279e in __libc_message () at /lib64/libc.so.6 + #4 0x00007ffff729767a in __fortify_fail () at /lib64/libc.so.6 + #5 0x00007ffff7295c36 in () at /lib64/libc.so.6 + #6 0x00007ffff72957f5 in __snprintf_chk () at /lib64/libc.so.6 + #7 0x0000555555b1c1fd in pcibus_get_fw_dev_path () + #8 0x0000555555f2bde4 in qdev_get_fw_dev_path_helper.constprop () + #9 0x0000555555f2bd86 in qdev_get_fw_dev_path_helper.constprop () + #10 0x00005555559a6e5d in get_boot_device_path () + #11 0x00005555559a712c in get_boot_devices_list () + #12 0x0000555555b1a3d0 in fw_cfg_machine_reset () + #13 0x0000555555bf4c2d in pc_machine_reset () + #14 0x0000555555c66988 in qemu_system_reset () + #15 0x0000555555a6dff6 in qdev_machine_creation_done () + #16 0x0000555555c79186 in qmp_x_exit_preconfig.part () + #17 0x0000555555c7b459 in qemu_init () + #18 0x0000555555960a29 in main () + +Found-by: Dario Faggioli +Found-by: Martin Liška +Cc: qemu-stable@nongnu.org +Signed-off-by: Claudio Fontana +Message-Id: <20220531114707.18830-1-cfontana@suse.de> +Reviewed-by: Ani Sinha + +Signed-off-by: tangbinzy +--- + hw/pci/pci.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 3e6805d54a..6a5e8a3654 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -2588,15 +2588,15 @@ static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) + static char *pcibus_get_fw_dev_path(DeviceState *dev) + { + PCIDevice *d = (PCIDevice *)dev; +- char path[50], name[33]; +- int off; +- +- off = snprintf(path, sizeof(path), "%s@%x", +- pci_dev_fw_name(dev, name, sizeof name), +- PCI_SLOT(d->devfn)); +- if (PCI_FUNC(d->devfn)) +- snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); +- return g_strdup(path); ++ char name[33]; ++ int has_func = !!PCI_FUNC(d->devfn); ++ ++ return g_strdup_printf("%s@%x%s%.*x", ++ pci_dev_fw_name(dev, name, sizeof(name)), ++ PCI_SLOT(d->devfn), ++ has_func ? "," : "", ++ has_func, ++ PCI_FUNC(d->devfn)); + } + + static char *pcibus_get_dev_path(DeviceState *dev) +-- +2.27.0 + diff --git a/pci-host-add-pcie-msi-read-method.patch b/pci-host-add-pcie-msi-read-method.patch deleted file mode 100644 index 7433fb0c3ce55f68593f3d612663c4db3a9960cd..0000000000000000000000000000000000000000 --- a/pci-host-add-pcie-msi-read-method.patch +++ /dev/null @@ -1,56 +0,0 @@ -From dd86dc83fcccc0d1773bd93c509e3a03e7ef9b38 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:08:24 +0800 -Subject: [PATCH] pci-host: add pcie-msi read method - -fix CVE-2020-15469 - -Add pcie-msi mmio read method to avoid NULL pointer dereference -issue. - -Reported-by: Lei Sun -Reviewed-by: Li Qiang -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/pci-host/designware.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c -index 9ae8c0deb7..23e3de3cad 100644 ---- a/hw/pci-host/designware.c -+++ b/hw/pci-host/designware.c -@@ -21,6 +21,7 @@ - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "qemu/module.h" -+#include "qemu/log.h" - #include "hw/pci/msi.h" - #include "hw/pci/pci_bridge.h" - #include "hw/pci/pci_host.h" -@@ -60,6 +61,13 @@ designware_pcie_root_to_host(DesignwarePCIERoot *root) - return DESIGNWARE_PCIE_HOST(bus->parent); - } - -+static uint64_t designware_pcie_root_msi_read(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); -+ return 0; -+} -+ - static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) - { -@@ -74,6 +82,7 @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, - } - - static const MemoryRegionOps designware_pci_host_msi_ops = { -+ .read = designware_pcie_root_msi_read, - .write = designware_pcie_root_msi_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { --- -2.27.0 - diff --git a/pci-introduce-PCIPASIDOps-to-PCIDevice.patch b/pci-introduce-PCIPASIDOps-to-PCIDevice.patch index e89cdc8df7130e348c916988d8b85f39ec4b6d19..f4cb611607899f89956b788e615d2d964b3a71ec 100644 --- a/pci-introduce-PCIPASIDOps-to-PCIDevice.patch +++ b/pci-introduce-PCIPASIDOps-to-PCIDevice.patch @@ -1,4 +1,4 @@ -From 26adddfe4645b69c16ed8d6601f373d40bddd0e3 Mon Sep 17 00:00:00 2001 +From c71485494970e7aa986be2b05bf7e2847017e264 Mon Sep 17 00:00:00 2001 From: Liu Yi L Date: Fri, 5 Jul 2019 19:01:36 +0800 Subject: [PATCH] pci: introduce PCIPASIDOps to PCIDevice @@ -35,10 +35,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 45 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index e74143ccc3..f11ca7964e 100644 +index e5993c1ef5..4a9374c025 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c -@@ -2626,6 +2626,40 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) +@@ -2759,6 +2759,40 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) bus->iommu_opaque = opaque; } @@ -80,18 +80,18 @@ index e74143ccc3..f11ca7964e 100644 { Range *range = opaque; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h -index aaf1b9f70d..bb14ed61b0 100644 +index e7cdf2d5ec..abffa12a99 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -9,6 +9,7 @@ - #include "hw/isa/isa.h" #include "hw/pci/pcie.h" + #include "qom/object.h" +#include "hw/iommu/iommu.h" extern bool pci_available; -@@ -263,6 +264,11 @@ struct PCIReqIDCache { +@@ -265,6 +266,11 @@ struct PCIReqIDCache { }; typedef struct PCIReqIDCache PCIReqIDCache; @@ -102,16 +102,16 @@ index aaf1b9f70d..bb14ed61b0 100644 + struct PCIDevice { DeviceState qdev; - -@@ -352,6 +358,7 @@ struct PCIDevice { - MSIVectorUseNotifier msix_vector_use_notifier; - MSIVectorReleaseNotifier msix_vector_release_notifier; - MSIVectorPollNotifier msix_vector_poll_notifier; + bool partially_hotplugged; +@@ -361,6 +367,7 @@ struct PCIDevice { + /* ID of standby device in net_failover pair */ + char *failover_pair_id; + uint32_t acpi_index; + PCIPASIDOps *pasid_ops; }; void pci_register_bar(PCIDevice *pci_dev, int region_num, -@@ -485,6 +492,10 @@ typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); +@@ -498,6 +505,10 @@ typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); diff --git a/pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch b/pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch index bf5b144d12407aacbd859ebd813b8f303126f789..7822fb936d6cedc0169e8abe2370ac030db7188a 100644 --- a/pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch +++ b/pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch @@ -1,7 +1,7 @@ -From 55c4f093b3a527c52cc8ed7138c330512973c9e6 Mon Sep 17 00:00:00 2001 -From: fangying -Date: Wed, 18 Mar 2020 12:49:33 +0800 -Subject: [PATCH 1/2] pcie: Add pcie-root-port fast plug/unplug feature +From 2412c1968777a0fe77cb24dda935e3414e00ebb1 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Tue, 8 Feb 2022 16:10:31 +0800 +Subject: [PATCH 5/6] pcie: Add pcie-root-port fast plug/unplug feature If a device is plugged in the pcie-root-port when VM kernel is booting, the kernel may wrongly disable the device. @@ -15,108 +15,85 @@ so we must fix it up. We hack into the pcie native hotplug patch so that hotplug/unplug will work under this circumstance. Signed-off-by: Ying Fang +Signed-off-by: Yan Wang --- - hw/core/machine.c | 1 + - hw/pci-bridge/gen_pcie_root_port.c | 3 ++- - hw/pci/pcie.c | 23 +++++++++++++++++++---- - include/hw/pci/pcie_port.h | 3 ++- - 4 files changed, 24 insertions(+), 6 deletions(-) + hw/core/machine.c | 2 ++ + hw/pci-bridge/gen_pcie_root_port.c | 2 ++ + hw/pci/pcie.c | 13 ++++++++++++- + include/hw/pci/pcie_port.h | 3 +++ + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/core/machine.c b/hw/core/machine.c -index 2baf9ec3..3138f97b 100644 +index 53a99ab..126e3e2 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c -@@ -33,6 +33,7 @@ GlobalProperty hw_compat_3_1[] = { +@@ -121,6 +121,8 @@ const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0); + GlobalProperty hw_compat_3_1[] = { { "pcie-root-port", "x-speed", "2_5" }, { "pcie-root-port", "x-width", "1" }, - { "pcie-root-port", "fast-plug", "0" }, ++ { "pcie-root-port", "fast-plug", "0" }, + { "pcie-root-port", "fast-unplug", "0" }, { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, { "tpm-crb", "ppi", "false" }, diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index 3179c4ea..2fbb11d0 100644 +index 20099a8..0bf9df9 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -131,7 +131,8 @@ static Property gen_rp_props[] = { +@@ -140,6 +140,8 @@ static Property gen_rp_props[] = { speed, PCIE_LINK_SPEED_16), DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, width, PCIE_LINK_WIDTH_32), -- DEFINE_PROP_UINT8("fast-plug", PCIESlot, disable_lnksta_dllla, 0), + DEFINE_PROP_UINT8("fast-plug", PCIESlot, fast_plug, 0), + DEFINE_PROP_UINT8("fast-unplug", PCIESlot, fast_unplug, 0), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c -index c0d6ff13..2a8ff86d 100644 +index d7d73a3..d7d1504 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c -@@ -85,7 +85,7 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) - * To fix this up, let's enable the PCI_EXP_LNKSTA_DLLLA - * only if it is a PCIESlot device. - */ -- if (s == NULL || s->disable_lnksta_dllla == 0) { -+ if (s == NULL || s->fast_plug == 0) { - if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_DLLLA); -@@ -136,8 +136,11 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) - */ - pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, - PCI_EXP_LNKCAP_DLLLARC); -- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -- PCI_EXP_LNKSTA_DLLLA); -+ -+ if(s->fast_plug == 0) { -+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -+ PCI_EXP_LNKSTA_DLLLA); -+ } - - /* - * Target Link Speed defaults to the highest link speed supported by -@@ -477,6 +480,8 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, - Error *local_err = NULL; - PCIDevice *pci_dev = PCI_DEVICE(dev); - PCIBus *bus = pci_get_bus(pci_dev); -+ PCIESlot *s = PCIE_SLOT(PCI_DEVICE(hotplug_dev)); -+ uint8_t *exp_cap = pci_dev->config + pci_dev->exp.exp_cap; +@@ -526,6 +526,7 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, + uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; + uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); + uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); ++ PCIESlot *s = PCIE_SLOT(hotplug_pdev); - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); - if (local_err) { -@@ -495,7 +500,17 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, + /* Check if hot-unplug is disabled on the slot */ + if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) { +@@ -572,7 +573,17 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, return; } -- pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev)); +- pcie_cap_slot_push_attention_button(hotplug_pdev); + if ((pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) && s->fast_plug) { -+ pci_word_test_and_clear_mask(exp_cap+ PCI_EXP_LNKSTA, ++ pci_word_test_and_clear_mask(pci_dev->config + pci_dev->exp.exp_cap + PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_DLLLA); + } + + if (s->fast_unplug) { -+ pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), ++ pcie_cap_slot_event(hotplug_pdev, + PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP); + } else { -+ pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev)); ++ pcie_cap_slot_push_attention_button(hotplug_pdev); + } } /* pci express slot for pci express root/downstream port diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h -index c3969921..b57af4ee 100644 +index e25b289..5b80a13 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h -@@ -50,7 +50,8 @@ struct PCIESlot { +@@ -51,6 +51,9 @@ struct PCIESlot { uint8_t chassis; uint16_t slot; -- uint8_t disable_lnksta_dllla; + uint8_t fast_plug; + uint8_t fast_unplug; - ++ PCIExpLinkSpeed speed; PCIExpLinkWidth width; + -- -2.19.1 +1.9.1 diff --git a/pcie-Compat-with-devices-which-do-not-support-Link-W.patch b/pcie-Compat-with-devices-which-do-not-support-Link-W.patch index f5c261916fb66e0a54844ddea65ab70fe2bfdee8..aeb31bbf66402b4db3fb510e53f9cc2f7e29abf3 100644 --- a/pcie-Compat-with-devices-which-do-not-support-Link-W.patch +++ b/pcie-Compat-with-devices-which-do-not-support-Link-W.patch @@ -1,7 +1,7 @@ -From 5e1ad9f0f3c344b9fe20fc01ea2f1dfb8ac7fd67 Mon Sep 17 00:00:00 2001 +From 14d1ad1309a1bd035250512368221088c2f83f32 Mon Sep 17 00:00:00 2001 From: fangying Date: Wed, 18 Mar 2020 12:51:33 +0800 -Subject: [PATCH 2/2] pcie: Compat with devices which do not support Link +Subject: [PATCH 6/6] pcie: Compat with devices which do not support Link Width, such as ioh3420 We hack into PCI_EXP_LNKCAP to support device fast plug/unplug @@ -9,15 +9,16 @@ for pcie-root-port. However some devices like ioh3420 does not suport it, so PCI_EXP_LNKCAP is not set for such devices. Signed-off-by: Ying Fang +Signed-off-by: Yan Wang --- hw/pci/pcie.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c -index 2a8ff86d..5044bff4 100644 +index d7d1504..30c09ed 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c -@@ -108,13 +108,6 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) +@@ -92,13 +92,6 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) return; } @@ -31,7 +32,7 @@ index 2a8ff86d..5044bff4 100644 /* * Link bandwidth notification is required for all root ports and * downstream ports supporting links wider than x1 or multiple link -@@ -122,6 +115,12 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) +@@ -106,6 +99,12 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) */ if (s->width > QEMU_PCI_EXP_LNK_X1 || s->speed > QEMU_PCI_EXP_LNK_2_5GT) { @@ -45,5 +46,5 @@ index 2a8ff86d..5044bff4 100644 PCI_EXP_LNKCAP_LBNC); } -- -2.19.1 +1.9.1 diff --git a/pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch b/pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch deleted file mode 100644 index dc31a503345e1599abe5cf879b8edfeff4ee22e9..0000000000000000000000000000000000000000 --- a/pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 7381599d4222f9b5cff6935a66e8b311af77f620 Mon Sep 17 00:00:00 2001 -From: Li Mingwang -Date: Thu, 17 Oct 2019 16:57:52 +0800 -Subject: [PATCH] Subject: [PATCH] pcie: disable the PCI_EXP_LINKSTA_DLLA cap - for pcie-root-port by default - -If the PCI_EXP_LNKSTA_DLLLA capability is set by default, linux -kernel will send PDC event to detect whether there is a device in -pcie slot. If a device is pluged in the pcie-root-port at the same -time, hot-plug device will send ABP + PDC events to the kernel. The -VM kernel will wrongly unplug the device if two PDC events get too -close. Thus we'd better set the PCI_EXP_LNKSTA_DLLLA capability only -in hotplug scenario - -Signed-off-by: Li Mingwang ---- - hw/core/machine.c | 1 + - hw/pci-bridge/gen_pcie_root_port.c | 1 + - hw/pci/pcie.c | 18 ++++++++++++++---- - include/hw/pci/pcie_port.h | 2 ++ - 4 files changed, 18 insertions(+), 4 deletions(-) - -diff --git a/hw/core/machine.c b/hw/core/machine.c -index 5d046a43..29a708da 100644 ---- a/hw/core/machine.c -+++ b/hw/core/machine.c -@@ -30,6 +30,7 @@ const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0); - GlobalProperty hw_compat_3_1[] = { - { "pcie-root-port", "x-speed", "2_5" }, - { "pcie-root-port", "x-width", "1" }, -+ { "pcie-root-port", "fast-plug", "0" }, - { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, - { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, - { "tpm-crb", "ppi", "false" }, -diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index 26bda73e..3179c4ea 100644 ---- a/hw/pci-bridge/gen_pcie_root_port.c -+++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -131,6 +131,7 @@ static Property gen_rp_props[] = { - speed, PCIE_LINK_SPEED_16), - DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, - width, PCIE_LINK_WIDTH_32), -+ DEFINE_PROP_UINT8("fast-plug", PCIESlot, disable_lnksta_dllla, 0), - DEFINE_PROP_END_OF_LIST() - }; - -diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c -index cf1ca30f..c0d6ff13 100644 ---- a/hw/pci/pcie.c -+++ b/hw/pci/pcie.c -@@ -50,6 +50,7 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) - { - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - uint8_t *cmask = dev->cmask + dev->exp.exp_cap; -+ PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT); - - /* capability register - interrupt message number defaults to 0 */ -@@ -76,11 +77,20 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) - QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) | - QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT)); - -- if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -- PCI_EXP_LNKSTA_DLLLA); -+ /* If a device is plugged in the pcie-root-port when VM kernel -+ * is just booting, the kernel will wrongly disable the device. -+ * This bug was brought in two patches of the linux kernel, i.e. -+ * https://patchwork.kernel.org/patch/10575355/ and -+ * https://patchwork.kernel.org/patch/10766219/. -+ * To fix this up, let's enable the PCI_EXP_LNKSTA_DLLLA -+ * only if it is a PCIESlot device. -+ */ -+ if (s == NULL || s->disable_lnksta_dllla == 0) { -+ if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -+ PCI_EXP_LNKSTA_DLLLA); -+ } - } -- - /* We changed link status bits over time, and changing them across - * migrations is generally fine as hardware changes them too. - * Let's not bother checking. -diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h -index 09586f46..c3969921 100644 ---- a/include/hw/pci/pcie_port.h -+++ b/include/hw/pci/pcie_port.h -@@ -50,6 +50,8 @@ struct PCIESlot { - uint8_t chassis; - uint16_t slot; - -+ uint8_t disable_lnksta_dllla; -+ - PCIExpLinkSpeed speed; - PCIExpLinkWidth width; - --- -2.19.1 - diff --git a/pcie_aer-Don-t-trigger-a-LSI-if-none-are-defined.patch b/pcie_aer-Don-t-trigger-a-LSI-if-none-are-defined.patch new file mode 100644 index 0000000000000000000000000000000000000000..c4462b724006ede86401d7e38c385db71052aab2 --- /dev/null +++ b/pcie_aer-Don-t-trigger-a-LSI-if-none-are-defined.patch @@ -0,0 +1,42 @@ +From 77633ce67c1cff764fe4951a6837462f51ace8aa Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 17:00:28 +0800 +Subject: [PATCH] pcie_aer: Don't trigger a LSI if none are defined +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 20766514d602c50b870ae943aaa8e5b9e2e8a161 + +Skip triggering an LSI when the AER root error status is updated if no +LSI is defined for the device. We can have a root bridge with no LSI, +MSI and MSI-X defined, for example on POWER systems. + +Signed-off-by: Frederic Barrat +Message-Id: <20211116170133.724751-4-fbarrat@linux.ibm.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Cédric Le Goater +Signed-off-by: boringandboring +--- + hw/pci/pcie_aer.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c +index 27f9cc56af..e1a8a88c8c 100644 +--- a/hw/pci/pcie_aer.c ++++ b/hw/pci/pcie_aer.c +@@ -774,7 +774,9 @@ void pcie_aer_root_write_config(PCIDevice *dev, + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); + /* 6.2.4.1.2 Interrupt Generation */ + if (!msix_enabled(dev) && !msi_enabled(dev)) { +- pci_set_irq(dev, !!(root_cmd & enabled_cmd)); ++ if (pci_intx(dev) != -1) { ++ pci_set_irq(dev, !!(root_cmd & enabled_cmd)); ++ } + return; + } + +-- +2.27.0 + diff --git a/pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch b/pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch index b375c20f10426f4328d288d1be037609c06842de..a917143fd0d18befb2c11f0bf6bb0a11b758d218 100644 --- a/pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch +++ b/pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch @@ -1,7 +1,7 @@ -From f995e8b5e5c14f83a16433f192440ec5c82c87fa Mon Sep 17 00:00:00 2001 +From 696abba190a0daad488d709d733f0d1f10df6f89 Mon Sep 17 00:00:00 2001 From: Ying Fang Date: Mon, 29 Jul 2019 16:16:35 +0800 -Subject: [PATCH] pl011: reset read FIFO when UARTTIMSC=0 & UARTICR=0xffff +Subject: [PATCH 1/6] pl011: reset read FIFO when UARTTIMSC=0 & UARTICR=0xffff We can enable ACPI when AArch64 Linux is booted with QEMU and UEFI (AAVMF). When VM is booting and the SBSA driver has not initialized, writting data @@ -17,15 +17,16 @@ https://www.spinics.net/lists/linux-serial/msg23163.html Signed-off-by: Haibin Wang Reviewed-by: Shannon Zhao Reviewed-by: Ying Fang +Signed-off-by: Yan Wang --- hw/char/pl011.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/char/pl011.c b/hw/char/pl011.c -index e5dd448f..899745ef 100644 +index 6e2d7f7..8ca2a4e 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c -@@ -223,6 +223,10 @@ static void pl011_write(void *opaque, hwaddr offset, +@@ -255,6 +255,10 @@ static void pl011_write(void *opaque, hwaddr offset, case 17: /* UARTICR */ s->int_level &= ~value; pl011_update(s); @@ -37,5 +38,5 @@ index e5dd448f..899745ef 100644 case 18: /* UARTDMACR */ s->dmacr = value; -- -2.19.1 +1.9.1 diff --git a/pl031-support-rtc-timer-property-for-pl031.patch b/pl031-support-rtc-timer-property-for-pl031.patch index 7bd977af364da6871f7b0b7f8cb62af2f23ab26c..b57f0e75965a62e7f929b740babe184546efa0c5 100644 --- a/pl031-support-rtc-timer-property-for-pl031.patch +++ b/pl031-support-rtc-timer-property-for-pl031.patch @@ -1,23 +1,25 @@ -From 68d4653b5ffde629e9b05d5de13b6adcde9d153b Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Mon, 29 Jul 2019 16:20:51 +0800 +From f8e5f099c5b6665e3ed9f397ddca9283148938a4 Mon Sep 17 00:00:00 2001 +From: Jinhao Gao +Date: Tue, 15 Feb 2022 17:02:08 +0800 Subject: [PATCH] pl031: support rtc-timer property for pl031 This patch adds the rtc-timer property for pl031, we can get the rtc time (UTC) through qmp command "qom-get date" with this property. Signed-off-by: Haibin Wang -Reviewed-by: Shannon Zhao +Reviewed-by: Shannon Zhao Reviewed-by: Ying Fang +Signed-off-by: Keqian Zhu +Signed-off-by: Jinhao Gao --- - hw/timer/pl031.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) + hw/rtc/pl031.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) -diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c -index 274ad47a..04331472 100644 ---- a/hw/timer/pl031.c -+++ b/hw/timer/pl031.c -@@ -57,6 +57,15 @@ static uint32_t pl031_get_count(PL031State *s) +diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c +index da8b061e91..61a2948f77 100644 +--- a/hw/rtc/pl031.c ++++ b/hw/rtc/pl031.c +@@ -63,6 +63,15 @@ static uint32_t pl031_get_count(PL031State *s) return s->tick_offset + now / NANOSECONDS_PER_SECOND; } @@ -33,17 +35,36 @@ index 274ad47a..04331472 100644 static void pl031_set_alarm(PL031State *s) { uint32_t ticks; -@@ -191,6 +200,10 @@ static void pl031_init(Object *obj) +@@ -201,6 +210,20 @@ static void pl031_init(Object *obj) qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND; s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s); ++ object_property_add_tm(OBJECT(s), "date", pl031_get_date); ++} + -+ object_property_add_tm(OBJECT(s), "date", pl031_get_date, NULL); ++static void pl031_realize(DeviceState *d, Error **errp) ++{ + object_property_add_alias(qdev_get_machine(), "rtc-time", -+ OBJECT(s), "date", NULL); ++ OBJECT(d), "date"); ++} ++ ++static void pl031_unrealize(DeviceState *d) ++{ ++ if (object_property_find(qdev_get_machine(), "rtc-time")) { ++ object_property_del(qdev_get_machine(), "rtc-time"); ++ } + } + + static void pl031_finalize(Object *obj) +@@ -337,6 +360,8 @@ static void pl031_class_init(ObjectClass *klass, void *data) + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_pl031; ++ dc->realize = pl031_realize; ++ dc->unrealize = pl031_unrealize; + device_class_set_props(dc, pl031_properties); } - static int pl031_pre_save(void *opaque) -- -2.19.1 +2.27.0 diff --git a/plugins-make-qemu_plugin_user_exit-s-locking-order-c.patch b/plugins-make-qemu_plugin_user_exit-s-locking-order-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..6655be53f517249b9f6050596b06b24ef9c670b5 --- /dev/null +++ b/plugins-make-qemu_plugin_user_exit-s-locking-order-c.patch @@ -0,0 +1,66 @@ +From a729d2730d9d30f6610e43f070cedd1d60ba022f Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 30 Mar 2023 17:58:32 +0800 +Subject: [PATCH] plugins: make qemu_plugin_user_exit's locking order + consistent with fork_start's +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 2bbbc1be8d9a21b25d0c80b9a7345074d54abd51 + +To fix potential deadlocks as reported by tsan. + +Signed-off-by: qihao_yewu +Reviewed-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Emilio Cota +Message-Id: <20230111151628.320011-6-cota@braap.org> +Signed-off-by: Alex Bennée +Message-Id: <20230124180127.1881110-31-alex.bennee@linaro.org> +--- + plugins/core.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/plugins/core.c b/plugins/core.c +index 792262da08..e935e3c0c9 100644 +--- a/plugins/core.c ++++ b/plugins/core.c +@@ -500,10 +500,18 @@ void qemu_plugin_user_exit(void) + enum qemu_plugin_event ev; + CPUState *cpu; + +- QEMU_LOCK_GUARD(&plugin.lock); ++ /* ++ * Locking order: we must acquire locks in an order that is consistent ++ * with the one in fork_start(). That is: ++ * - start_exclusive(), which acquires qemu_cpu_list_lock, ++ * must be called before acquiring plugin.lock. ++ * - tb_flush(), which acquires mmap_lock(), must be called ++ * while plugin.lock is not held. ++ */ + + start_exclusive(); + ++ qemu_rec_mutex_lock(&plugin.lock); + /* un-register all callbacks except the final AT_EXIT one */ + for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) { + if (ev != QEMU_PLUGIN_EV_ATEXIT) { +@@ -514,12 +522,12 @@ void qemu_plugin_user_exit(void) + } + } + +- tb_flush(current_cpu); +- + CPU_FOREACH(cpu) { + qemu_plugin_disable_mem_helpers(cpu); + } ++ qemu_rec_mutex_unlock(&plugin.lock); + ++ tb_flush(current_cpu); + end_exclusive(); + + /* now it's safe to handle the exit case */ +-- +2.27.0 + diff --git a/ppc-spelling-fixes.patch b/ppc-spelling-fixes.patch new file mode 100644 index 0000000000000000000000000000000000000000..127101b5e1852db4de3f9acb95856addece1b1dc --- /dev/null +++ b/ppc-spelling-fixes.patch @@ -0,0 +1,271 @@ +From 0adb55804594e60380450c7644a05f9cfc4ebb8a Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Sun, 26 Nov 2023 18:34:45 -0800 +Subject: [PATCH] ppc: spelling fixes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit e6a19a6477407e57b4deb61aaa497a14d7db9626 +category: bugfix + +Signed-off-by: Michael Tokarev +Reviewed-by: Cédric Le Goater +Signed-off-by: zhujun2 +--- + hw/ppc/ppc.c | 2 +- + hw/ppc/prep_systemio.c | 2 +- + hw/ppc/spapr.c | 8 ++++---- + hw/ppc/spapr_hcall.c | 2 +- + hw/ppc/spapr_nvdimm.c | 2 +- + hw/ppc/spapr_pci_vfio.c | 2 +- + include/hw/ppc/openpic.h | 2 +- + include/hw/ppc/spapr.h | 2 +- + target/ppc/cpu-models.h | 4 ++-- + target/ppc/cpu.h | 2 +- + target/ppc/cpu_init.c | 2 +- + target/ppc/excp_helper.c | 2 +- + target/ppc/power8-pmu-regs.c.inc | 4 ++-- + target/ppc/translate/vmx-impl.c.inc | 4 ++-- + 14 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c +index cf90ab7805..6396bbe523 100644 +--- a/hw/ppc/ppc.c ++++ b/hw/ppc/ppc.c +@@ -745,7 +745,7 @@ target_ulong cpu_ppc_load_decr(CPUPPCState *env) + decr = _cpu_ppc_load_decr(env, tb_env->decr_next); + + /* +- * If large decrementer is enabled then the decrementer is signed extened ++ * If large decrementer is enabled then the decrementer is signed extended + * to 64 bits, otherwise it is a 32 bit value. + */ + if (env->spr[SPR_LPCR] & LPCR_LD) { +diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c +index b2bd783248..e51da91de5 100644 +--- a/hw/ppc/prep_systemio.c ++++ b/hw/ppc/prep_systemio.c +@@ -39,7 +39,7 @@ + #define TYPE_PREP_SYSTEMIO "prep-systemio" + OBJECT_DECLARE_SIMPLE_TYPE(PrepSystemIoState, PREP_SYSTEMIO) + +-/* Bit as defined in PowerPC Reference Plaform v1.1, sect. 6.1.5, p. 132 */ ++/* Bit as defined in PowerPC Reference Platform v1.1, sect. 6.1.5, p. 132 */ + #define PREP_BIT(n) (1 << (7 - (n))) + + struct PrepSystemIoState { +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 3b5fd749be..7f352ceaaa 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -2488,7 +2488,7 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) + return; + } + +- /* Detemine the VSMT mode to use: */ ++ /* Determine the VSMT mode to use: */ + if (vsmt_user) { + if (spapr->vsmt < smp_threads) { + error_setg(errp, "Cannot support VSMT mode %d" +@@ -3016,7 +3016,7 @@ static int spapr_kvm_type(MachineState *machine, const char *vm_type) + { + /* + * The use of g_ascii_strcasecmp() for 'hv' and 'pr' is to +- * accomodate the 'HV' and 'PV' formats that exists in the ++ * accommodate the 'HV' and 'PV' formats that exists in the + * wild. The 'auto' mode is being introduced already as + * lower-case, thus we don't need to bother checking for + * "AUTO". +@@ -4250,7 +4250,7 @@ spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index) + CPUArchId *core_slot; + MachineClass *mc = MACHINE_GET_CLASS(machine); + +- /* make sure possible_cpu are intialized */ ++ /* make sure possible_cpu are initialized */ + mc->possible_cpu_arch_ids(machine); + /* get CPU core slot containing thread that matches cpu_index */ + core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL); +@@ -4870,7 +4870,7 @@ static void spapr_machine_2_12_class_options(MachineClass *mc) + + /* We depend on kvm_enabled() to choose a default value for the + * hpt-max-page-size capability. Of course we can't do it here +- * because this is too early and the HW accelerator isn't initialzed ++ * because this is too early and the HW accelerator isn't initialized + * yet. Postpone this to machine init (see default_caps_with_cpu()). + */ + smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0; +diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c +index 222c1b6bbd..5364bbcffa 100644 +--- a/hw/ppc/spapr_hcall.c ++++ b/hw/ppc/spapr_hcall.c +@@ -1532,7 +1532,7 @@ static void hypercall_register_types(void) + spapr_register_hypercall(H_GET_CPU_CHARACTERISTICS, + h_get_cpu_characteristics); + +- /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate ++ /* "debugger" hcalls (also used by SLOF). Note: We do -not- differentiate + * here between the "CI" and the "CACHE" variants, they will use whatever + * mapping attributes qemu is using. When using KVM, the kernel will + * enforce the attributes more strongly +diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c +index 91de1052f2..b111380a45 100644 +--- a/hw/ppc/spapr_nvdimm.c ++++ b/hw/ppc/spapr_nvdimm.c +@@ -336,7 +336,7 @@ static target_ulong h_scm_bind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr, + + /* + * Currently continue token should be zero qemu has already bound +- * everything and this hcall doesnt return H_BUSY. ++ * everything and this hcall doesn't return H_BUSY. + */ + if (continue_token > 0) { + return H_P5; +diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c +index 2a76b4e0b5..6326948143 100644 +--- a/hw/ppc/spapr_pci_vfio.c ++++ b/hw/ppc/spapr_pci_vfio.c +@@ -77,7 +77,7 @@ int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb, + * call. Now we just need to check the validity of the PCI + * pass-through devices (vfio-pci) under this sphb bus. + * We have already validated that all the devices under this sphb +- * are from same iommu group (within same PE) before comming here. ++ * are from same iommu group (within same PE) before coming here. + * + * Prior to linux commit 98ba956f6a389 ("powerpc/pseries/eeh: + * Rework device EEH PE determination") kernel would call +diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h +index ebdaf8a493..44976e6b07 100644 +--- a/include/hw/ppc/openpic.h ++++ b/include/hw/ppc/openpic.h +@@ -14,7 +14,7 @@ enum { + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ +- OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ ++ OPENPIC_OUTPUT_DEBUG, /* Unconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, + }; +diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h +index ee7504b976..316b80318e 100644 +--- a/include/hw/ppc/spapr.h ++++ b/include/hw/ppc/spapr.h +@@ -179,7 +179,7 @@ struct SpaprMachineState { + SpaprResizeHpt resize_hpt; + void *htab; + uint32_t htab_shift; +- uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROC_TBL */ ++ uint64_t patb_entry; /* Process tbl registered in H_REGISTER_PROC_TBL */ + SpaprPendingHpt *pending_hpt; /* in-progress resize */ + + hwaddr rma_size; +diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h +index 0952592759..75ea085bd5 100644 +--- a/target/ppc/cpu-models.h ++++ b/target/ppc/cpu-models.h +@@ -63,7 +63,7 @@ enum { + /* PowerPC 405 cores */ + CPU_POWERPC_405D2 = 0x20010000, + CPU_POWERPC_405D4 = 0x41810000, +- /* PowerPC 405 microcontrolers */ ++ /* PowerPC 405 microcontrollers */ + /* XXX: missing 0x200108a0 */ + CPU_POWERPC_405CRa = 0x40110041, + CPU_POWERPC_405CRb = 0x401100C5, +@@ -93,7 +93,7 @@ enum { + #define CPU_POWERPC_440 CPU_POWERPC_440GXf + /* PowerPC 440 cores */ + CPU_POWERPC_440_XILINX = 0x7ff21910, +- /* PowerPC 440 microcontrolers */ ++ /* PowerPC 440 microcontrollers */ + CPU_POWERPC_440EPa = 0x42221850, + CPU_POWERPC_440EPb = 0x422218D3, + CPU_POWERPC_440GPb = 0x40120440, +diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h +index e946da5f3a..26312f9d5f 100644 +--- a/target/ppc/cpu.h ++++ b/target/ppc/cpu.h +@@ -345,7 +345,7 @@ typedef struct ppc_v3_pate_t { + + /* PMU bits */ + #define MMCR0_FC PPC_BIT(32) /* Freeze Counters */ +-#define MMCR0_PMAO PPC_BIT(56) /* Perf Monitor Alert Ocurred */ ++#define MMCR0_PMAO PPC_BIT(56) /* Perf Monitor Alert Occurred */ + #define MMCR0_PMAE PPC_BIT(37) /* Perf Monitor Alert Enable */ + #define MMCR0_EBE PPC_BIT(43) /* Perf Monitor EBB Enable */ + #define MMCR0_FCECE PPC_BIT(38) /* FC on Enabled Cond or Event */ +diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c +index 6695985e9b..986d16a24d 100644 +--- a/target/ppc/cpu_init.c ++++ b/target/ppc/cpu_init.c +@@ -7023,7 +7023,7 @@ static void register_970_lpar_sprs(CPUPPCState *env) + static void register_power5p_lpar_sprs(CPUPPCState *env) + { + #if !defined(CONFIG_USER_ONLY) +- /* Logical partitionning */ ++ /* Logical partitioning */ + spr_register_kvm_hv(env, SPR_LPCR, "LPCR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, +diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c +index 17607adbe4..f66063d55c 100644 +--- a/target/ppc/excp_helper.c ++++ b/target/ppc/excp_helper.c +@@ -312,7 +312,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) + + /* + * new interrupt handler msr preserves existing HV and ME unless +- * explicitly overriden ++ * explicitly overridden + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); + +diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc +index 7391851238..c58874752b 100644 +--- a/target/ppc/power8-pmu-regs.c.inc ++++ b/target/ppc/power8-pmu-regs.c.inc +@@ -16,7 +16,7 @@ + * Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the + * PMCs) has problem state read access. + * +- * Read acccess is granted for all PMCC values but 0b01, where a ++ * Read access is granted for all PMCC values but 0b01, where a + * Facility Unavailable Interrupt will occur. + */ + static bool spr_groupA_read_allowed(DisasContext *ctx) +@@ -33,7 +33,7 @@ static bool spr_groupA_read_allowed(DisasContext *ctx) + * Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the + * PMCs) has problem state write access. + * +- * Write acccess is granted for PMCC values 0b10 and 0b11. Userspace ++ * Write access is granted for PMCC values 0b10 and 0b11. Userspace + * writing with PMCC 0b00 will generate a Hypervisor Emulation + * Assistance Interrupt. Userspace writing with PMCC 0b01 will + * generate a Facility Unavailable Interrupt. +diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc +index 8eb8d3a067..f56f061d18 100644 +--- a/target/ppc/translate/vmx-impl.c.inc ++++ b/target/ppc/translate/vmx-impl.c.inc +@@ -127,7 +127,7 @@ static void gen_stve##name(DisasContext *ctx) \ + } + + GEN_VR_LDX(lvx, 0x07, 0x03); +-/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ ++/* As we don't emulate the cache, lvxl is strictly equivalent to lvx */ + GEN_VR_LDX(lvxl, 0x07, 0x0B); + + GEN_VR_LVE(bx, 0x07, 0x00, 1); +@@ -135,7 +135,7 @@ GEN_VR_LVE(hx, 0x07, 0x01, 2); + GEN_VR_LVE(wx, 0x07, 0x02, 4); + + GEN_VR_STX(svx, 0x07, 0x07); +-/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ ++/* As we don't emulate the cache, stvxl is strictly equivalent to stvx */ + GEN_VR_STX(svxl, 0x07, 0x0F); + + GEN_VR_STVE(bx, 0x07, 0x04, 1); +-- +2.27.0 + diff --git a/ppc-vof-Fix-missed-fields-in-VOF-cleanup.patch b/ppc-vof-Fix-missed-fields-in-VOF-cleanup.patch new file mode 100644 index 0000000000000000000000000000000000000000..93498aea9948c72aec58513ab36246283896ce44 --- /dev/null +++ b/ppc-vof-Fix-missed-fields-in-VOF-cleanup.patch @@ -0,0 +1,43 @@ +From 62083d43f24d801f74b8e0aee7693811c19a366d Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 18 Sep 2023 15:26:28 +0800 +Subject: [PATCH] ppc/vof: Fix missed fields in VOF cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 7b8589d7ce7e23f26ff53338d575a5cbd7818e28 + +Failing to reset the of_instance_last makes ihandle allocation continue +to increase, which causes record-replay replay fail to match the +recorded trace. + +Not resetting claimed_base makes VOF eventually run out of memory after +some resets. + +Cc: Alexey Kardashevskiy +Fixes: fc8c745d501 ("spapr: Implement Open Firmware client interface") +Signed-off-by: Nicholas Piggin +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Cédric Le Goater +Signed-off-by: qihao_yewu +--- + hw/ppc/vof.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c +index 73adc44ec2..b1aa0ceb8b 100644 +--- a/hw/ppc/vof.c ++++ b/hw/ppc/vof.c +@@ -1026,6 +1026,8 @@ void vof_cleanup(Vof *vof) + } + vof->claimed = NULL; + vof->of_instances = NULL; ++ vof->of_instance_last = 0; ++ vof->claimed_base = 0; + } + + void vof_build_dt(void *fdt, Vof *vof) +-- +2.41.0.windows.1 + diff --git a/pr-manager-Fix-invalid-g_free-crash-bug.patch b/pr-manager-Fix-invalid-g_free-crash-bug.patch deleted file mode 100644 index b171cdb5ae34dab7135926c2250541814d543a02..0000000000000000000000000000000000000000 --- a/pr-manager-Fix-invalid-g_free-crash-bug.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 57fdf4a13ff16d9d48a43f02a5e7b42e3d264f83 Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Thu, 22 Aug 2019 15:38:46 +0200 -Subject: [PATCH] pr-manager: Fix invalid g_free() crash bug -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -pr_manager_worker() passes its @opaque argument to g_free(). Wrong; -it points to pr_manager_worker()'s automatic @data. Broken when -commit 2f3a7ab39be converted @data from heap- to stack-allocated. Fix -by deleting the g_free(). - -Fixes: 2f3a7ab39bec4ba8022dc4d42ea641165b004e3e -Cc: qemu-stable@nongnu.org -Signed-off-by: Markus Armbruster -Reviewed-by: Philippe Mathieu-Daudé -Acked-by: Paolo Bonzini -Signed-off-by: Kevin Wolf -(cherry picked from commit 6b9d62c2a9e83bbad73fb61406f0ff69b46ff6f3) -Signed-off-by: Michael Roth ---- - scsi/pr-manager.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c -index ee43663576..0c866e8698 100644 ---- a/scsi/pr-manager.c -+++ b/scsi/pr-manager.c -@@ -39,7 +39,6 @@ static int pr_manager_worker(void *opaque) - int fd = data->fd; - int r; - -- g_free(data); - trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); - - /* The reference was taken in pr_manager_execute. */ --- -2.23.0 diff --git a/prep-add-ppc-parity-write-method.patch b/prep-add-ppc-parity-write-method.patch deleted file mode 100644 index fbc3dcc8cf024a5f26ce66f73ff653b5c74837dd..0000000000000000000000000000000000000000 --- a/prep-add-ppc-parity-write-method.patch +++ /dev/null @@ -1,50 +0,0 @@ -From f4eed258b1b8b434927fbc9a18bbcb52d3f55ce6 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:16:14 +0800 -Subject: [PATCH] prep: add ppc-parity write method - -fix CVE-2020-15469 - -Add ppc-parity mmio write method to avoid NULL pointer dereference -issue. - -Reported-by: Lei Sun -Acked-by: David Gibson -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/ppc/prep_systemio.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c -index df7603b986..67244ed48c 100644 ---- a/hw/ppc/prep_systemio.c -+++ b/hw/ppc/prep_systemio.c -@@ -23,6 +23,7 @@ - */ - - #include "qemu/osdep.h" -+#include "qemu/log.h" - #include "hw/isa/isa.h" - #include "exec/address-spaces.h" - #include "qemu/error-report.h" /* for error_report() */ -@@ -232,8 +233,15 @@ static uint64_t ppc_parity_error_readl(void *opaque, hwaddr addr, - return val; - } - -+static void ppc_parity_error_writel(void *opaque, hwaddr addr, -+ uint64_t data, unsigned size) -+{ -+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write access\n", __func__); -+} -+ - static const MemoryRegionOps ppc_parity_error_ops = { - .read = ppc_parity_error_readl, -+ .write = ppc_parity_error_writel, - .valid = { - .min_access_size = 4, - .max_access_size = 4, --- -2.27.0 - diff --git a/ps2-fix-oob-in-ps2-kbd.patch b/ps2-fix-oob-in-ps2-kbd.patch new file mode 100644 index 0000000000000000000000000000000000000000..a385968fd30566264e234cc57ef60a7ad03097a3 --- /dev/null +++ b/ps2-fix-oob-in-ps2-kbd.patch @@ -0,0 +1,35 @@ +From 19523565181bb6efb1b9f819d45a7ca8ea6eca19 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 9 Feb 2022 11:21:28 +0800 +Subject: [PATCH 11/15] ps2: fix oob in ps2 kbd + +fix oob in ps2 kbd +--- + hw/input/ps2.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/input/ps2.c b/hw/input/ps2.c +index 9376a8f4ce..5d82ee3cdf 100644 +--- a/hw/input/ps2.c ++++ b/hw/input/ps2.c +@@ -205,7 +205,7 @@ void ps2_queue_noirq(PS2State *s, int b) + } + + q->data[q->wptr] = b; +- if (++q->wptr == PS2_BUFFER_SIZE) { ++ if (++q->wptr >= PS2_BUFFER_SIZE) { + q->wptr = 0; + } + q->count++; +@@ -578,7 +578,7 @@ uint32_t ps2_read_data(PS2State *s) + val = q->data[index]; + } else { + val = q->data[q->rptr]; +- if (++q->rptr == PS2_BUFFER_SIZE) { ++ if (++q->rptr >= PS2_BUFFER_SIZE) { + q->rptr = 0; + } + q->count--; +-- +2.27.0 + diff --git a/qapi-Add-VFIO-devices-migration-stats-in-Migration-s.patch b/qapi-Add-VFIO-devices-migration-stats-in-Migration-s.patch deleted file mode 100644 index 3ee078c19f392be5b53214f0f03dcea3ecc216fa..0000000000000000000000000000000000000000 --- a/qapi-Add-VFIO-devices-migration-stats-in-Migration-s.patch +++ /dev/null @@ -1,214 +0,0 @@ -From f97eaa27e2fb6b985f090af9acaa780bb6a2ee5b Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:27 +0530 -Subject: [PATCH] qapi: Add VFIO devices migration stats in Migration stats - -Added amount of bytes transferred to the VM at destination by all VFIO -devices - -Signed-off-by: Kirti Wankhede -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 19 +++++++++++++++++++ - hw/vfio/migration.c | 9 +++++++++ - include/hw/vfio/vfio-common.h | 3 +++ - migration/migration.c | 17 +++++++++++++++++ - monitor/hmp-cmds.c | 6 ++++++ - qapi/migration.json | 17 +++++++++++++++++ - 6 files changed, 71 insertions(+) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 4ce1c10734..a86a4c4506 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -291,6 +291,25 @@ const MemoryRegionOps vfio_region_ops = { - * Device state interfaces - */ - -+bool vfio_mig_active(void) -+{ -+ VFIOGroup *group; -+ VFIODevice *vbasedev; -+ -+ if (QLIST_EMPTY(&vfio_group_list)) { -+ return false; -+ } -+ -+ QLIST_FOREACH(group, &vfio_group_list, next) { -+ QLIST_FOREACH(vbasedev, &group->device_list, next) { -+ if (vbasedev->migration_blocker) { -+ return false; -+ } -+ } -+ } -+ return true; -+} -+ - static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) - { - VFIOGroup *group; -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 0bdf6a1820..b77c66557e 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -45,6 +45,8 @@ - #define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) - #define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) - -+static int64_t bytes_transferred; -+ - static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, - off_t off, bool iswrite) - { -@@ -255,6 +257,7 @@ static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) - *size = data_size; - } - -+ bytes_transferred += data_size; - return ret; - } - -@@ -785,6 +788,7 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) - case MIGRATION_STATUS_CANCELLING: - case MIGRATION_STATUS_CANCELLED: - case MIGRATION_STATUS_FAILED: -+ bytes_transferred = 0; - ret = vfio_migration_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_SAVING | VFIO_DEVICE_STATE_RESUMING), - VFIO_DEVICE_STATE_RUNNING); -@@ -866,6 +870,11 @@ err: - - /* ---------------------------------------------------------------------- */ - -+int64_t vfio_mig_bytes_transferred(void) -+{ -+ return bytes_transferred; -+} -+ - int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) - { - VFIOContainer *container = vbasedev->group->container; -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 8fd0212264..048731e81f 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -203,6 +203,9 @@ extern const MemoryRegionOps vfio_region_ops; - typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; - extern VFIOGroupList vfio_group_list; - -+bool vfio_mig_active(void); -+int64_t vfio_mig_bytes_transferred(void); -+ - #ifdef CONFIG_LINUX - int vfio_get_region_info(VFIODevice *vbasedev, int index, - struct vfio_region_info **info); -diff --git a/migration/migration.c b/migration/migration.c -index b0b9430822..9faf5f63a6 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -49,6 +49,10 @@ - #include "monitor/monitor.h" - #include "net/announce.h" - -+#ifdef CONFIG_VFIO -+#include "hw/vfio/vfio-common.h" -+#endif -+ - #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ - - /* Amount of time to allocate to each "chunk" of bandwidth-throttled -@@ -908,6 +912,17 @@ static void populate_disk_info(MigrationInfo *info) - } - } - -+static void populate_vfio_info(MigrationInfo *info) -+{ -+#ifdef CONFIG_VFIO -+ if (vfio_mig_active()) { -+ info->has_vfio = true; -+ info->vfio = g_malloc0(sizeof(*info->vfio)); -+ info->vfio->transferred = vfio_mig_bytes_transferred(); -+ } -+#endif -+} -+ - static void fill_source_migration_info(MigrationInfo *info) - { - MigrationState *s = migrate_get_current(); -@@ -941,6 +956,7 @@ static void fill_source_migration_info(MigrationInfo *info) - - populate_ram_info(info, s); - populate_disk_info(info); -+ populate_vfio_info(info); - break; - case MIGRATION_STATUS_COLO: - info->has_status = true; -@@ -956,6 +972,7 @@ static void fill_source_migration_info(MigrationInfo *info) - info->setup_time = s->setup_time; - - populate_ram_info(info, s); -+ populate_vfio_info(info); - break; - case MIGRATION_STATUS_FAILED: - info->has_status = true; -diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c -index e5a7a88ba2..cecaae0a47 100644 ---- a/monitor/hmp-cmds.c -+++ b/monitor/hmp-cmds.c -@@ -370,6 +370,12 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) - } - monitor_printf(mon, "]\n"); - } -+ -+ if (info->has_vfio) { -+ monitor_printf(mon, "vfio device transferred: %" PRIu64 " kbytes\n", -+ info->vfio->transferred >> 10); -+ } -+ - qapi_free_MigrationInfo(info); - qapi_free_MigrationCapabilityStatusList(caps); - } -diff --git a/qapi/migration.json b/qapi/migration.json -index 587ef65872..1f0eb19ac6 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -141,6 +141,18 @@ - 'active', 'postcopy-active', 'postcopy-paused', - 'postcopy-recover', 'completed', 'failed', 'colo', - 'pre-switchover', 'device' ] } -+## -+# @VfioStats: -+# -+# Detailed VFIO devices migration statistics -+# -+# @transferred: amount of bytes transferred to the target VM by VFIO devices -+# -+# Since: 5.2 -+# -+## -+{ 'struct': 'VfioStats', -+ 'data': {'transferred': 'int' } } - - ## - # @MigrationInfo: -@@ -202,11 +214,16 @@ - # - # @socket-address: Only used for tcp, to know what the real port is (Since 4.0) - # -+# @vfio: @VfioStats containing detailed VFIO devices migration statistics, -+# only returned if VFIO device is present, migration is supported by all -+# VFIO devices and status is 'active' or 'completed' (since 5.2) -+# - # Since: 0.14.0 - ## - { 'struct': 'MigrationInfo', - 'data': {'*status': 'MigrationStatus', '*ram': 'MigrationStats', - '*disk': 'MigrationStats', -+ '*vfio': 'VfioStats', - '*xbzrle-cache': 'XBZRLECacheStats', - '*total-time': 'int', - '*expected-downtime': 'int', --- -2.27.0 - diff --git a/qapi-Cleanup-SGX-related-comments-and-restore-sectio.patch b/qapi-Cleanup-SGX-related-comments-and-restore-sectio.patch new file mode 100644 index 0000000000000000000000000000000000000000..0834e79ca19a45eed4a70dcea0e620413dcd77d9 --- /dev/null +++ b/qapi-Cleanup-SGX-related-comments-and-restore-sectio.patch @@ -0,0 +1,219 @@ +From 646cfa4209dde2258891668576d32759e1479dfa Mon Sep 17 00:00:00 2001 +From: Yang Zhong +Date: Thu, 20 Jan 2022 17:31:04 -0500 +Subject: [PATCH 4/9] qapi: Cleanup SGX related comments and restore + @section-size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +from mainline-v7.0.0-rc0 +commit a66bd91f030827742778a9e0da19fe55716b4a60 +category: feature +feature: NUMA support for SGX EPC sections +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5K27A + +Intel-SIG: commit a66bd91f0308 ("qapi: Cleanup SGX related comments +and restore @section-size") + +------------------------------------- + +qapi: Cleanup SGX related comments and restore @section-size + +The SGX NUMA patches were merged into Qemu 7.0 release, we need +clarify detailed version history information and also change +some related comments, which make SGX related comments clearer. + +The QMP command schema promises backwards compatibility as standard. +We temporarily restore "@section-size", which can avoid incompatible +API breakage. The "@section-size" will be deprecated in 7.2 version. + +Suggested-by: Daniel P. Berrangé +Signed-off-by: Yang Zhong +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220120223104.437161-1-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + docs/about/deprecated.rst | 13 +++++++++++++ + hw/i386/sgx.c | 11 +++++++++-- + qapi/machine.json | 4 ++-- + qapi/misc-target.json | 22 +++++++++++++++++----- + 4 files changed, 41 insertions(+), 9 deletions(-) + +diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst +index ff7488cb63..33925edf45 100644 +--- a/docs/about/deprecated.rst ++++ b/docs/about/deprecated.rst +@@ -270,6 +270,19 @@ accepted incorrect commands will return an error. Users should make sure that + all arguments passed to ``device_add`` are consistent with the documented + property types. + ++``query-sgx`` return value member ``section-size`` (since 7.0) ++'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ++ ++Member ``section-size`` in return value elements with meta-type ``uint64`` is ++deprecated. Use ``sections`` instead. ++ ++ ++``query-sgx-capabilities`` return value member ``section-size`` (since 7.0) ++''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ++ ++Member ``section-size`` in return value elements with meta-type ``uint64`` is ++deprecated. Use ``sections`` instead. ++ + System accelerators + ------------------- + +diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c +index 5de5dd0893..a2b318dd93 100644 +--- a/hw/i386/sgx.c ++++ b/hw/i386/sgx.c +@@ -83,7 +83,7 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) + ((high & MAKE_64BIT_MASK(0, 20)) << 32); + } + +-static SGXEPCSectionList *sgx_calc_host_epc_sections(void) ++static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size) + { + SGXEPCSectionList *head = NULL, **tail = &head; + SGXEPCSection *section; +@@ -106,6 +106,7 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(void) + section = g_new0(SGXEPCSection, 1); + section->node = j++; + section->size = sgx_calc_section_metric(ecx, edx); ++ *size += section->size; + QAPI_LIST_APPEND(tail, section); + } + +@@ -156,6 +157,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) + { + SGXInfo *info = NULL; + uint32_t eax, ebx, ecx, edx; ++ uint64_t size = 0; + + int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR); + if (fd < 0) { +@@ -173,7 +175,8 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) + info->sgx1 = eax & (1U << 0) ? true : false; + info->sgx2 = eax & (1U << 1) ? true : false; + +- info->sections = sgx_calc_host_epc_sections(); ++ info->sections = sgx_calc_host_epc_sections(&size); ++ info->section_size = size; + + close(fd); + +@@ -220,12 +223,14 @@ SGXInfo *qmp_query_sgx(Error **errp) + return NULL; + } + ++ SGXEPCState *sgx_epc = &pcms->sgx_epc; + info = g_new0(SGXInfo, 1); + + info->sgx = true; + info->sgx1 = true; + info->sgx2 = true; + info->flc = true; ++ info->section_size = sgx_epc->size; + info->sections = sgx_get_epc_sections_list(); + + return info; +@@ -249,6 +254,8 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) + info->sgx2 ? "enabled" : "disabled"); + monitor_printf(mon, "FLC support: %s\n", + info->flc ? "enabled" : "disabled"); ++ monitor_printf(mon, "size: %" PRIu64 "\n", ++ info->section_size); + + section_list = info->sections; + for (section = section_list; section; section = section->next) { +diff --git a/qapi/machine.json b/qapi/machine.json +index 85c35e7fc5..03cfb268a4 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -1209,7 +1209,7 @@ + # + # @memdev: memory backend linked with device + # +-# @node: the numa node ++# @node: the numa node (Since: 7.0) + # + # Since: 6.2 + ## +@@ -1290,7 +1290,7 @@ + # + # @memdev: memory backend linked with device + # +-# @node: the numa node ++# @node: the numa node (Since: 7.0) + # + # Since: 6.2 + ## +diff --git a/qapi/misc-target.json b/qapi/misc-target.json +index 1022aa0184..4bc45d2474 100644 +--- a/qapi/misc-target.json ++++ b/qapi/misc-target.json +@@ -344,9 +344,9 @@ + # + # @node: the numa node + # +-# @size: the size of epc section ++# @size: the size of EPC section + # +-# Since: 6.2 ++# Since: 7.0 + ## + { 'struct': 'SGXEPCSection', + 'data': { 'node': 'int', +@@ -365,7 +365,13 @@ + # + # @flc: true if FLC is supported + # +-# @sections: The EPC sections info for guest ++# @section-size: The EPC section size for guest ++# Redundant with @sections. Just for backward compatibility. ++# ++# @sections: The EPC sections info for guest (Since: 7.0) ++# ++# Features: ++# @deprecated: Member @section-size is deprecated. Use @sections instead. + # + # Since: 6.2 + ## +@@ -374,6 +380,8 @@ + 'sgx1': 'bool', + 'sgx2': 'bool', + 'flc': 'bool', ++ 'section-size': { 'type': 'uint64', ++ 'features': [ 'deprecated' ] }, + 'sections': ['SGXEPCSection']}, + 'if': 'TARGET_I386' } + +@@ -390,7 +398,9 @@ + # + # -> { "execute": "query-sgx" } + # <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, +-# "flc": true, "section-size" : 0 } } ++# "flc": true, "section-size" : 96468992, ++# "sections": [{"node": 0, "size": 67108864}, ++# {"node": 1, "size": 29360128}]} } + # + ## + { 'command': 'query-sgx', 'returns': 'SGXInfo', 'if': 'TARGET_I386' } +@@ -408,7 +418,9 @@ + # + # -> { "execute": "query-sgx-capabilities" } + # <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, +-# "flc": true, "section-size" : 0 } } ++# "flc": true, "section-size" : 96468992, ++# "section" : [{"node": 0, "size": 67108864}, ++# {"node": 1, "size": 29360128}]} } + # + ## + { 'command': 'query-sgx-capabilities', 'returns': 'SGXInfo', 'if': 'TARGET_I386' } +-- +2.27.0 + diff --git a/qapi-add-BitmapSyncMode-enum.patch b/qapi-add-BitmapSyncMode-enum.patch deleted file mode 100644 index 778faeee0dc98c233e2415190a8941ed6bd137db..0000000000000000000000000000000000000000 --- a/qapi-add-BitmapSyncMode-enum.patch +++ /dev/null @@ -1,54 +0,0 @@ -From bd1d5d79f4629520d0753676cea8129c60fc6bbc Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:52 -0400 -Subject: [PATCH] qapi: add BitmapSyncMode enum - -Depending on what a user is trying to accomplish, there might be a few -bitmap cleanup actions that occur when an operation is finished that -could be useful. - -I am proposing three: -- NEVER: The bitmap is never synchronized against what was copied. -- ALWAYS: The bitmap is always synchronized, even on failures. -- ON-SUCCESS: The bitmap is synchronized only on success. - -The existing incremental backup modes use 'on-success' semantics, -so add just that one for right now. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -Reviewed-by: Markus Armbruster -Message-id: 20190709232550.10724-5-jsnow@redhat.com -Signed-off-by: John Snow ---- - qapi/block-core.json | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/qapi/block-core.json b/qapi/block-core.json -index 37aa1b7b9a..b8d12a4951 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -1134,6 +1134,20 @@ - { 'enum': 'MirrorSyncMode', - 'data': ['top', 'full', 'none', 'incremental'] } - -+## -+# @BitmapSyncMode: -+# -+# An enumeration of possible behaviors for the synchronization of a bitmap -+# when used for data copy operations. -+# -+# @on-success: The bitmap is only synced when the operation is successful. -+# This is the behavior always used for 'INCREMENTAL' backups. -+# -+# Since: 4.2 -+## -+{ 'enum': 'BitmapSyncMode', -+ 'data': ['on-success'] } -+ - ## - # @MirrorCopyMode: - # --- -2.27.0 - diff --git a/qapi-block-Tidy-up-block-latency-histogram-set-docum.patch b/qapi-block-Tidy-up-block-latency-histogram-set-docum.patch new file mode 100644 index 0000000000000000000000000000000000000000..73fc5b3c412668e83d1b7981a107c334840f20fd --- /dev/null +++ b/qapi-block-Tidy-up-block-latency-histogram-set-docum.patch @@ -0,0 +1,77 @@ +From 880364a83e4c7a7e379136056d63346cbdd7c2f0 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Sun, 30 Jul 2023 18:58:08 -0700 +Subject: [PATCH] qapi/block: Tidy up block-latency-histogram-set documentation + mainline inclusion commit e893b9e3b3a6029384253f768cdc06969732e517 category: + bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +Examples come out like + +Example + +set new histograms for all io types with intervals [0, 10), [10, + 50), [50, 100), [100, +inf): + +The sentence "set new histograms ..." starts with a lower case letter. +Capitalize it. Same for the other examples. + +Signed-off-by: Markus Armbruster +Message-ID: <20230720071610.1096458-3-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: zhujun2 +--- + qapi/block.json | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/qapi/block.json b/qapi/block.json +index 82fcf2c914..71136db777 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -529,7 +529,8 @@ + # Since: 4.0 + # + # Example: +-# set new histograms for all io types with intervals ++ ++# Set new histograms for all io types with intervals + # [0, 10), [10, 50), [50, 100), [100, +inf): + # + # -> { "execute": "block-latency-histogram-set", +@@ -538,7 +539,8 @@ + # <- { "return": {} } + # + # Example: +-# set new histogram only for write, other histograms will remain ++ ++# Set new histogram only for write, other histograms will remain + # not changed (or not created): + # + # -> { "execute": "block-latency-histogram-set", +@@ -547,7 +549,8 @@ + # <- { "return": {} } + # + # Example: +-# set new histograms with the following intervals: ++ ++# Set new histograms with the following intervals: + # read, flush: [0, 10), [10, 50), [50, 100), [100, +inf) + # write: [0, 1000), [1000, 5000), [5000, +inf) + # +@@ -558,7 +561,8 @@ + # <- { "return": {} } + # + # Example: +-# remove all latency histograms: ++ ++# Remove all latency histograms: + # + # -> { "execute": "block-latency-histogram-set", + # "arguments": { "id": "drive0" } } +-- +2.41.0.windows.1 + diff --git a/qapi-block-core-Add-retry-option-for-error-action.patch b/qapi-block-core-Add-retry-option-for-error-action.patch index 817ff7051db6ab8b9a36d8d53427495c628a2a89..f1536884698c15c4470c3c049093d24ffcc8b4c9 100644 --- a/qapi-block-core-Add-retry-option-for-error-action.patch +++ b/qapi-block-core-Add-retry-option-for-error-action.patch @@ -1,22 +1,23 @@ -From 9a95d75bdd469c9c7d44c7c72bc16d57ef2f65cc Mon Sep 17 00:00:00 2001 +From 4c3d47e04886e072acc0e4fefdc49e9d1f6b4ad1 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:45 +0800 -Subject: [PATCH] qapi/block-core: Add retry option for error action +Subject: [PATCH 1/7] qapi/block-core: Add retry option for error action Add a new error action 'retry' to support retry on errors. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- blockdev.c | 2 ++ qapi/block-core.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/blockdev.c b/blockdev.c -index 4d141e9a1f..0f49fd290e 100644 +index b35072644e..6f1981635b 100644 --- a/blockdev.c +++ b/blockdev.c -@@ -319,6 +319,8 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp) +@@ -333,6 +333,8 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp) return BLOCKDEV_ON_ERROR_STOP; } else if (!strcmp(buf, "report")) { return BLOCKDEV_ON_ERROR_REPORT; @@ -26,10 +27,10 @@ index 4d141e9a1f..0f49fd290e 100644 error_setg(errp, "'%s' invalid %s error action", buf, is_read ? "read" : "write"); diff --git a/qapi/block-core.json b/qapi/block-core.json -index 0d43d4f37c..db24f0dfe5 100644 +index 1d3dd9cb48..804beabfb0 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json -@@ -1113,7 +1113,7 @@ +@@ -1146,7 +1146,7 @@ # Since: 1.3 ## { 'enum': 'BlockdevOnError', @@ -38,7 +39,7 @@ index 0d43d4f37c..db24f0dfe5 100644 ## # @MirrorSyncMode: -@@ -4894,7 +4894,7 @@ +@@ -4952,7 +4952,7 @@ # Since: 2.1 ## { 'enum': 'BlockErrorAction', diff --git a/qapi-block-core-Introduce-BackupCommon.patch b/qapi-block-core-Introduce-BackupCommon.patch deleted file mode 100644 index 2d160748c79371b993fd4f0c82a48b535d7b29cd..0000000000000000000000000000000000000000 --- a/qapi-block-core-Introduce-BackupCommon.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 2204b4839fb90658e13ddc608df7b35ed1ea9fd0 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Mon, 29 Jul 2019 16:35:52 -0400 -Subject: [PATCH] qapi/block-core: Introduce BackupCommon - -drive-backup and blockdev-backup have an awful lot of things in common -that are the same. Let's fix that. - -I don't deduplicate 'target', because the semantics actually did change -between each structure. Leave that one alone so it can be documented -separately. - -Where documentation was not identical, use the most up-to-date version. -For "speed", use Blockdev-Backup's version. For "sync", use -Drive-Backup's version. - -Signed-off-by: John Snow -Reviewed-by: Max Reitz -[Maintainer edit: modified commit message. --js] -Reviewed-by: Markus Armbruster -Message-id: 20190709232550.10724-2-jsnow@redhat.com -Signed-off-by: John Snow ---- - qapi/block-core.json | 95 ++++++++++++++------------------------------ - 1 file changed, 29 insertions(+), 66 deletions(-) - -diff --git a/qapi/block-core.json b/qapi/block-core.json -index db24f0dfe5..37aa1b7b9a 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -1315,32 +1315,23 @@ - 'data': { 'node': 'str', 'overlay': 'str' } } - - ## --# @DriveBackup: -+# @BackupCommon: - # - # @job-id: identifier for the newly-created block job. If - # omitted, the device name will be used. (Since 2.7) - # - # @device: the device name or node-name of a root node which should be copied. - # --# @target: the target of the new image. If the file exists, or if it --# is a device, the existing file/device will be used as the new --# destination. If it does not exist, a new file will be created. --# --# @format: the format of the new destination, default is to --# probe if @mode is 'existing', else the format of the source --# - # @sync: what parts of the disk image should be copied to the destination - # (all the disk, only the sectors allocated in the topmost image, from a - # dirty bitmap, or only new I/O). - # --# @mode: whether and how QEMU should create a new image, default is --# 'absolute-paths'. --# --# @speed: the maximum speed, in bytes per second -+# @speed: the maximum speed, in bytes per second. The default is 0, -+# for unlimited. - # - # @bitmap: the name of dirty bitmap if sync is "incremental". - # Must be present if sync is "incremental", must NOT be present --# otherwise. (Since 2.4) -+# otherwise. (Since 2.4 (drive-backup), 3.1 (blockdev-backup)) - # - # @compress: true to compress data, if the target format supports it. - # (default: false) (since 2.8) -@@ -1370,75 +1361,47 @@ - # I/O. If an error occurs during a guest write request, the device's - # rerror/werror actions will be used. - # --# Since: 1.6 -+# Since: 4.2 - ## --{ 'struct': 'DriveBackup', -- 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', -- '*format': 'str', 'sync': 'MirrorSyncMode', -- '*mode': 'NewImageMode', '*speed': 'int', -+{ 'struct': 'BackupCommon', -+ 'data': { '*job-id': 'str', 'device': 'str', -+ 'sync': 'MirrorSyncMode', '*speed': 'int', - '*bitmap': 'str', '*compress': 'bool', - '*on-source-error': 'BlockdevOnError', - '*on-target-error': 'BlockdevOnError', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } - - ## --# @BlockdevBackup: --# --# @job-id: identifier for the newly-created block job. If --# omitted, the device name will be used. (Since 2.7) --# --# @device: the device name or node-name of a root node which should be copied. --# --# @target: the device name or node-name of the backup target node. --# --# @sync: what parts of the disk image should be copied to the destination --# (all the disk, only the sectors allocated in the topmost image, or --# only new I/O). --# --# @speed: the maximum speed, in bytes per second. The default is 0, --# for unlimited. --# --# @bitmap: the name of dirty bitmap if sync is "incremental". --# Must be present if sync is "incremental", must NOT be present --# otherwise. (Since 3.1) --# --# @compress: true to compress data, if the target format supports it. --# (default: false) (since 2.8) -+# @DriveBackup: - # --# @on-source-error: the action to take on an error on the source, --# default 'report'. 'stop' and 'enospc' can only be used --# if the block device supports io-status (see BlockInfo). -+# @target: the target of the new image. If the file exists, or if it -+# is a device, the existing file/device will be used as the new -+# destination. If it does not exist, a new file will be created. - # --# @on-target-error: the action to take on an error on the target, --# default 'report' (no limitations, since this applies to --# a different block device than @device). -+# @format: the format of the new destination, default is to -+# probe if @mode is 'existing', else the format of the source - # --# @auto-finalize: When false, this job will wait in a PENDING state after it has --# finished its work, waiting for @block-job-finalize before --# making any block graph changes. --# When true, this job will automatically --# perform its abort or commit actions. --# Defaults to true. (Since 2.12) -+# @mode: whether and how QEMU should create a new image, default is -+# 'absolute-paths'. - # --# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it --# has completely ceased all work, and awaits @block-job-dismiss. --# When true, this job will automatically disappear from the query --# list without user intervention. --# Defaults to true. (Since 2.12) -+# Since: 1.6 -+## -+{ 'struct': 'DriveBackup', -+ 'base': 'BackupCommon', -+ 'data': { 'target': 'str', -+ '*format': 'str', -+ '*mode': 'NewImageMode' } } -+ -+## -+# @BlockdevBackup: - # --# Note: @on-source-error and @on-target-error only affect background --# I/O. If an error occurs during a guest write request, the device's --# rerror/werror actions will be used. -+# @target: the device name or node-name of the backup target node. - # - # Since: 2.3 - ## - { 'struct': 'BlockdevBackup', -- 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', -- 'sync': 'MirrorSyncMode', '*speed': 'int', -- '*bitmap': 'str', '*compress': 'bool', -- '*on-source-error': 'BlockdevOnError', -- '*on-target-error': 'BlockdevOnError', -- '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } -+ 'base': 'BackupCommon', -+ 'data': { 'target': 'str' } } - - ## - # @blockdev-snapshot-sync: --- -2.27.0 - diff --git a/qapi-machine.json-Fix-incorrect-description-for-die-.patch b/qapi-machine.json-Fix-incorrect-description-for-die-.patch new file mode 100644 index 0000000000000000000000000000000000000000..a5e605aca092a558d266b46771b4020a81c4a33c --- /dev/null +++ b/qapi-machine.json-Fix-incorrect-description-for-die-.patch @@ -0,0 +1,35 @@ +From b04e92ed13e49f666f62c8f3daa5746109caf17b Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Mon, 22 Nov 2021 11:26:51 +0800 +Subject: [PATCH 01/24] qapi/machine.json: Fix incorrect description for die-id + +In terms of scope, die-id should mean "the die number within +socket the CPU belongs to" instead of "the die number within +node/board the CPU belongs to". Fix it to avoid confusing +the Doc reader. + +Fixes: 176d2cda0d ("i386/cpu: Consolidate die-id validity in smp context") +Signed-off-by: Yanan Wang +Reviewed-by: Eric Blake +Message-Id: <20211122032651.16064-1-wangyanan55@huawei.com> +Signed-off-by: Paolo Bonzini +--- + qapi/machine.json | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qapi/machine.json b/qapi/machine.json +index 067e3f5378..f1839acf20 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -867,7 +867,7 @@ + # + # @node-id: NUMA node ID the CPU belongs to + # @socket-id: socket number within node/board the CPU belongs to +-# @die-id: die number within node/board the CPU belongs to (Since 4.1) ++# @die-id: die number within socket the CPU belongs to (since 4.1) + # @core-id: core number within die the CPU belongs to + # @thread-id: thread number within core the CPU belongs to + # +-- +2.27.0 + diff --git a/qapi-qdev-Tidy-up-device_add-documentation.patch b/qapi-qdev-Tidy-up-device_add-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..877a89541d6a385970a0dd4738a5bc91b29c2832 --- /dev/null +++ b/qapi-qdev-Tidy-up-device_add-documentation.patch @@ -0,0 +1,66 @@ +From 32b601ed22d154e9423911b27541b35aa12d18bb Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Thu, 20 Jul 2023 09:16:06 +0200 +Subject: [PATCH] qapi/qdev: Tidy up device_add documentation mainline + inclusion commit a9c72efd6d6d62ac84ae57ca55606747e04e8ba7 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +------------------------------------------------------------------- + +The notes section comes out like this: + + Notes + + Additional arguments depend on the type. + + 1. For detailed information about this command, please refer to the + ‘docs/qdev-device-use.txt’ file. + + 2. It’s possible to list device properties by running QEMU with the + “-device DEVICE,help” command-line argument, where DEVICE is the + device’s name + +The first item isn't numbered. Fix that: + + 1. Additional arguments depend on the type. + + 2. For detailed information about this command, please refer to the + ‘docs/qdev-device-use.txt’ file. + + 3. It’s possible to list device properties by running QEMU with the + “-device DEVICE,help” command-line argument, where DEVICE is the + device’s name + +Signed-off-by: Markus Armbruster +Message-ID: <20230720071610.1096458-4-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: zhujun2 +--- + qapi/qdev.json | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/qapi/qdev.json b/qapi/qdev.json +index 69656b14df..ca96a0c6eb 100644 +--- a/qapi/qdev.json ++++ b/qapi/qdev.json +@@ -47,12 +47,12 @@ + # + # Notes: + # +-# Additional arguments depend on the type. ++# 1. Additional arguments depend on the type. + # +-# 1. For detailed information about this command, please refer to the ++# 2. For detailed information about this command, please refer to the + # 'docs/qdev-device-use.txt' file. + # +-# 2. It's possible to list device properties by running QEMU with the ++# 3. It's possible to list device properties by running QEMU with the + # "-device DEVICE,help" command-line argument, where DEVICE is the + # device's name + # +-- +2.41.0.windows.1 + diff --git a/qapi-support-updating-expected-test-output-via-make.patch b/qapi-support-updating-expected-test-output-via-make.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c30d71d34b51ed478141da9b5de4a5fc7a5ca91 --- /dev/null +++ b/qapi-support-updating-expected-test-output-via-make.patch @@ -0,0 +1,43 @@ +From fb63e3343eaaf1d5aaf0a28e2f3ed2248a11e86a Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Mon, 7 Aug 2023 00:28:14 -0700 +Subject: [PATCH] qapi: support updating expected test output via make +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 7ce54db23048bfcc3ea6821525bf333b715c7655 + +It is possible to pass --update to tests/qapi-schema/test-qapi.py +to make it update the output files on error. This is inconvenient +to achieve though when test-qapi.py is run indirectly by make/meson. + +Instead simply allow for an env variable to be set: + + $ QAPI_TEST_UPDATE= make check-qapi-schema + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20230420102619.348173-2-berrange@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster + +Signed-off-by: Wanghe Xiao +--- + tests/qapi-schema/test-qapi.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py +index 2160cef082..d58c31f539 100755 +--- a/tests/qapi-schema/test-qapi.py ++++ b/tests/qapi-schema/test-qapi.py +@@ -206,6 +206,7 @@ def main(argv): + parser.add_argument('-d', '--dir', action='store', default='', + help="directory containing tests") + parser.add_argument('-u', '--update', action='store_true', ++ default='QAPI_TEST_UPDATE' in os.environ, + help="update expected test results") + parser.add_argument('tests', nargs='*', metavar='TEST', action='store') + args = parser.parse_args() +-- +2.41.0.windows.1 + diff --git a/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch b/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch deleted file mode 100644 index f2a4e5c26f50c820eb9122e8a8449b76713a8db7..0000000000000000000000000000000000000000 --- a/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 405deba14f6b61b9c557484b46e863308c8cf373 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 28 Oct 2019 17:18:40 +0100 -Subject: [PATCH] qcow2: Fix QCOW2_COMPRESSED_SECTOR_MASK - -Masks for L2 table entries should have 64 bit. - -Fixes: b6c246942b14d3e0dec46a6c5868ed84e7dbea19 -Buglink: https://bugs.launchpad.net/qemu/+bug/1850000 -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Message-id: 20191028161841.1198-2-mreitz@redhat.com -Reviewed-by: Alberto Garcia -Signed-off-by: Max Reitz -(cherry picked from commit 24552feb6ae2f615b76c2b95394af43901f75046) -Signed-off-by: Michael Roth ---- - block/qcow2.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block/qcow2.h b/block/qcow2.h -index fc1b0d3c1e..359197f89f 100644 ---- a/block/qcow2.h -+++ b/block/qcow2.h -@@ -77,7 +77,7 @@ - - /* Defined in the qcow2 spec (compressed cluster descriptor) */ - #define QCOW2_COMPRESSED_SECTOR_SIZE 512U --#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1)) -+#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL)) - - /* Must be at least 2 to cover COW */ - #define MIN_L2_CACHE_SIZE 2 /* cache entries */ --- -2.23.0 diff --git a/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch b/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch deleted file mode 100644 index b4c25806d7f7b99408a0419987c22c2175f4fee3..0000000000000000000000000000000000000000 --- a/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 416a692e51b8b582407e30046ddcffbbe52ecf77 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Thu, 24 Oct 2019 16:26:58 +0200 -Subject: [PATCH] qcow2: Fix corruption bug in - qcow2_detect_metadata_preallocation() - -qcow2_detect_metadata_preallocation() calls qcow2_get_refcount() which -requires s->lock to be taken to protect its accesses to the refcount -table and refcount blocks. However, nothing in this code path actually -took the lock. This could cause the same cache entry to be used by two -requests at the same time, for different tables at different offsets, -resulting in image corruption. - -As it would be preferable to base the detection on consistent data (even -though it's just heuristics), let's take the lock not only around the -qcow2_get_refcount() calls, but around the whole function. - -This patch takes the lock in qcow2_co_block_status() earlier and asserts -in qcow2_detect_metadata_preallocation() that we hold the lock. - -Fixes: 69f47505ee66afaa513305de0c1895a224e52c45 -Cc: qemu-stable@nongnu.org -Reported-by: Michael Weiser -Signed-off-by: Kevin Wolf -Tested-by: Michael Weiser -Reviewed-by: Michael Weiser -Reviewed-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Max Reitz -(cherry picked from commit 5e9785505210e2477e590e61b1ab100d0ec22b01) -Signed-off-by: Michael Roth ---- - block/qcow2-refcount.c | 2 ++ - block/qcow2.c | 3 ++- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c -index ef965d7895..0d64bf5a5e 100644 ---- a/block/qcow2-refcount.c -+++ b/block/qcow2-refcount.c -@@ -3455,6 +3455,8 @@ int qcow2_detect_metadata_preallocation(BlockDriverState *bs) - int64_t i, end_cluster, cluster_count = 0, threshold; - int64_t file_length, real_allocation, real_clusters; - -+ qemu_co_mutex_assert_locked(&s->lock); -+ - file_length = bdrv_getlength(bs->file->bs); - if (file_length < 0) { - return file_length; -diff --git a/block/qcow2.c b/block/qcow2.c -index 865839682c..c0f5439dc8 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -1899,6 +1899,8 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, - unsigned int bytes; - int status = 0; - -+ qemu_co_mutex_lock(&s->lock); -+ - if (!s->metadata_preallocation_checked) { - ret = qcow2_detect_metadata_preallocation(bs); - s->metadata_preallocation = (ret == 1); -@@ -1906,7 +1908,6 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, - } - - bytes = MIN(INT_MAX, count); -- qemu_co_mutex_lock(&s->lock); - ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset); - qemu_co_mutex_unlock(&s->lock); - if (ret < 0) { --- -2.23.0 diff --git a/qcow2-Fix-qcow2_alloc_cluster_abort-for-external-dat.patch b/qcow2-Fix-qcow2_alloc_cluster_abort-for-external-dat.patch deleted file mode 100644 index 8d9b71c70ea503d0bc2480439d5826357e5ab931..0000000000000000000000000000000000000000 --- a/qcow2-Fix-qcow2_alloc_cluster_abort-for-external-dat.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fad649b88c93d0567be4e426f23063b439037095 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 11 Feb 2020 10:48:59 +0100 -Subject: [PATCH] qcow2: Fix qcow2_alloc_cluster_abort() for external data file - -For external data file, cluster allocations return an offset in the data -file and are not refcounted. In this case, there is nothing to do for -qcow2_alloc_cluster_abort(). Freeing the same offset in the qcow2 file -is wrong and causes crashes in the better case or image corruption in -the worse case. - -Signed-off-by: Kevin Wolf -Message-Id: <20200211094900.17315-3-kwolf@redhat.com> -Signed-off-by: Kevin Wolf ---- - block/qcow2-cluster.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c -index f8576031b6..7e7e051437 100644 ---- a/block/qcow2-cluster.c -+++ b/block/qcow2-cluster.c -@@ -1026,8 +1026,11 @@ err: - void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) - { - BDRVQcow2State *s = bs->opaque; -- qcow2_free_clusters(bs, m->alloc_offset, m->nb_clusters << s->cluster_bits, -- QCOW2_DISCARD_NEVER); -+ if (!has_data_file(bs)) { -+ qcow2_free_clusters(bs, m->alloc_offset, -+ m->nb_clusters << s->cluster_bits, -+ QCOW2_DISCARD_NEVER); -+ } - } - - /* --- -2.27.0 - diff --git a/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch b/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch deleted file mode 100644 index be2c3c72ced8b33f569fabef0c1f01dd382993ef..0000000000000000000000000000000000000000 --- a/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch +++ /dev/null @@ -1,58 +0,0 @@ -From c9ffb12754b1575babfef45168b6e1b1af80a95f Mon Sep 17 00:00:00 2001 -From: Alberto Garcia -Date: Fri, 16 Aug 2019 15:17:42 +0300 -Subject: [PATCH] qcow2: Fix the calculation of the maximum L2 cache size - -The size of the qcow2 L2 cache defaults to 32 MB, which can be easily -larger than the maximum amount of L2 metadata that the image can have. -For example: with 64 KB clusters the user would need a qcow2 image -with a virtual size of 256 GB in order to have 32 MB of L2 metadata. - -Because of that, since commit b749562d9822d14ef69c9eaa5f85903010b86c30 -we forbid the L2 cache to become larger than the maximum amount of L2 -metadata for the image, calculated using this formula: - - uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); - -The problem with this formula is that the result should be rounded up -to the cluster size because an L2 table on disk always takes one full -cluster. - -For example, a 1280 MB qcow2 image with 64 KB clusters needs exactly -160 KB of L2 metadata, but we need 192 KB on disk (3 clusters) even if -the last 32 KB of those are not going to be used. - -However QEMU rounds the numbers down and only creates 2 cache tables -(128 KB), which is not enough for the image. - -A quick test doing 4KB random writes on a 1280 MB image gives me -around 500 IOPS, while with the correct cache size I get 16K IOPS. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Alberto Garcia -Signed-off-by: Kevin Wolf -(cherry picked from commit b70d08205b2e4044c529eefc21df2c8ab61b473b) -Signed-off-by: Michael Roth ---- - block/qcow2.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/block/qcow2.c b/block/qcow2.c -index 039bdc2f7e..865839682c 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -826,7 +826,11 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, - bool l2_cache_entry_size_set; - int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; - uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; -- uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); -+ uint64_t max_l2_entries = DIV_ROUND_UP(virtual_disk_size, s->cluster_size); -+ /* An L2 table is always one cluster in size so the max cache size -+ * should be a multiple of the cluster size. */ -+ uint64_t max_l2_cache = ROUND_UP(max_l2_entries * sizeof(uint64_t), -+ s->cluster_size); - - combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); - l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); --- -2.23.0 diff --git a/qcow2-Limit-total-allocation-range-to-INT_MAX.patch b/qcow2-Limit-total-allocation-range-to-INT_MAX.patch deleted file mode 100644 index 3f915adcf6c57f828466e8ea0feff735a2a27937..0000000000000000000000000000000000000000 --- a/qcow2-Limit-total-allocation-range-to-INT_MAX.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3d83643fb8d69f1c38df3e90634f9b82d4a62a1c Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Thu, 10 Oct 2019 12:08:57 +0200 -Subject: [PATCH] qcow2: Limit total allocation range to INT_MAX -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When the COW areas are included, the size of an allocation can exceed -INT_MAX. This is kind of limited by handle_alloc() in that it already -caps avail_bytes at INT_MAX, but the number of clusters still reflects -the original length. - -This can have all sorts of effects, ranging from the storage layer write -call failing to image corruption. (If there were no image corruption, -then I suppose there would be data loss because the .cow_end area is -forced to be empty, even though there might be something we need to -COW.) - -Fix all of it by limiting nb_clusters so the equivalent number of bytes -will not exceed INT_MAX. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Reviewed-by: Eric Blake -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Kevin Wolf -(cherry picked from commit d1b9d19f99586b33795e20a79f645186ccbc070f) -Signed-off-by: Michael Roth ---- - block/qcow2-cluster.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c -index 974a4e8..c4a99c1 100644 ---- a/block/qcow2-cluster.c -+++ b/block/qcow2-cluster.c -@@ -1342,6 +1342,9 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, - nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index); - assert(nb_clusters <= INT_MAX); - -+ /* Limit total allocation byte count to INT_MAX */ -+ nb_clusters = MIN(nb_clusters, INT_MAX >> s->cluster_bits); -+ - /* Find L2 entry for the first involved cluster */ - ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index); - if (ret < 0) { -@@ -1430,7 +1433,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, - * request actually writes to (excluding COW at the end) - */ - uint64_t requested_bytes = *bytes + offset_into_cluster(s, guest_offset); -- int avail_bytes = MIN(INT_MAX, nb_clusters << s->cluster_bits); -+ int avail_bytes = nb_clusters << s->cluster_bits; - int nb_bytes = MIN(requested_bytes, avail_bytes); - QCowL2Meta *old_m = *m; - --- -1.8.3.1 - diff --git a/qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch b/qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch deleted file mode 100644 index 358fc61764ab3a8170a4d625af0ee4136531b7c0..0000000000000000000000000000000000000000 --- a/qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 66ad3c6ecce098d8f01545859c5ebf7a9e505e2c Mon Sep 17 00:00:00 2001 -From: Tuguoyi -Date: Fri, 1 Nov 2019 07:37:35 +0000 -Subject: [PATCH] qcow2-bitmap: Fix uint64_t left-shift overflow - -There are two issues in In check_constraints_on_bitmap(), -1) The sanity check on the granularity will cause uint64_t -integer left-shift overflow when cluster_size is 2M and the -granularity is BIGGER than 32K. -2) The way to calculate image size that the maximum bitmap -supported can map to is a bit incorrect. -This patch fix it by add a helper function to calculate the -number of bytes needed by a normal bitmap in image and compare -it to the maximum bitmap bytes supported by qemu. - -Fixes: 5f72826e7fc62167cf3a -Signed-off-by: Guoyi Tu -Message-id: 4ba40cd1e7ee4a708b40899952e49f22@h3c.com -Reviewed-by: Vladimir Sementsov-Ogievskiy -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -(cherry picked from commit 570542ecb11e04b61ef4b3f4d0965a6915232a88) -Signed-off-by: Michael Roth ---- - block/qcow2-bitmap.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c -index e53a160..997923f 100644 ---- a/block/qcow2-bitmap.c -+++ b/block/qcow2-bitmap.c -@@ -143,6 +143,13 @@ static int check_table_entry(uint64_t entry, int cluster_size) - return 0; - } - -+static int64_t get_bitmap_bytes_needed(int64_t len, uint32_t granularity) -+{ -+ int64_t num_bits = DIV_ROUND_UP(len, granularity); -+ -+ return DIV_ROUND_UP(num_bits, 8); -+} -+ - static int check_constraints_on_bitmap(BlockDriverState *bs, - const char *name, - uint32_t granularity, -@@ -151,6 +158,7 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, - BDRVQcow2State *s = bs->opaque; - int granularity_bits = ctz32(granularity); - int64_t len = bdrv_getlength(bs); -+ int64_t bitmap_bytes; - - assert(granularity > 0); - assert((granularity & (granularity - 1)) == 0); -@@ -172,9 +180,9 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, - return -EINVAL; - } - -- if ((len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) || -- (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size << -- granularity_bits)) -+ bitmap_bytes = get_bitmap_bytes_needed(len, granularity); -+ if ((bitmap_bytes > (uint64_t)BME_MAX_PHYS_SIZE) || -+ (bitmap_bytes > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size)) - { - error_setg(errp, "Too much space will be occupied by the bitmap. " - "Use larger granularity"); --- -1.8.3.1 - diff --git a/qcow2-fix-memory-leak-in-qcow2_read_extensions.patch b/qcow2-fix-memory-leak-in-qcow2_read_extensions.patch index 2837a02342a4d6fde0e7f0370d64557089450870..ae629423b0389acc4594c930a3360c82898a843b 100644 --- a/qcow2-fix-memory-leak-in-qcow2_read_extensions.patch +++ b/qcow2-fix-memory-leak-in-qcow2_read_extensions.patch @@ -1,21 +1,22 @@ -From 76ab77108279f9d328e4a7fe1684141084698d97 Mon Sep 17 00:00:00 2001 +From a999e010c6af90f0fc1ad9b998e2a9b760c40f1a Mon Sep 17 00:00:00 2001 From: zhanghailiang Date: Thu, 25 Jul 2019 16:05:11 +0800 -Subject: [PATCH] qcow2: fix memory leak in qcow2_read_extensions +Subject: [PATCH 2/6] qcow2: fix memory leak in qcow2_read_extensions Free feature_table if it is failed in bdrv_pread. Signed-off-by: fangyi +Signed-off-by: Yan Wang --- block/qcow2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/qcow2.c b/block/qcow2.c -index 3ace3b22..5e85cf4b 100644 +index d509016..be90a89 100644 --- a/block/qcow2.c +++ b/block/qcow2.c -@@ -258,6 +258,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, - void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); +@@ -272,6 +272,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, + void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); ret = bdrv_pread(bs->file, offset , feature_table, ext.len); if (ret < 0) { + g_free(feature_table); @@ -23,5 +24,5 @@ index 3ace3b22..5e85cf4b 100644 "Could not read table"); return ret; -- -2.19.1 +1.9.1 diff --git a/qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch b/qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch index 85467e8412ec264d6034f59ae3704a3042d1e5e0..e02dbf6f365184c098159a72f29b7e256d235dac 100644 --- a/qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch +++ b/qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch @@ -1,4 +1,4 @@ -From 4f1396f9e173a24f78204b8849c209100499d639 Mon Sep 17 00:00:00 2001 +From ada323e932c83271184a6ddba1cfd74a29378963 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Thu, 29 Jul 2021 15:24:48 +0800 Subject: [PATCH] qdev/monitors: Fix reundant error_setg of qdev_add_device @@ -9,15 +9,16 @@ will trigger an asseration "assert(*errp == NULL)". Fixes: 515a7970490 (log: Add some logs on VM runtime path) Signed-off-by: Kunkun Jiang +Signed-off-by: Yan Wang --- - qdev-monitor.c | 1 - + softmmu/qdev-monitor.c | 1 - 1 file changed, 1 deletion(-) -diff --git a/qdev-monitor.c b/qdev-monitor.c -index c6c1d3f06a..ab2bdef105 100644 ---- a/qdev-monitor.c -+++ b/qdev-monitor.c -@@ -587,7 +587,6 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index dfd6429bf3..4a20f5dbd7 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -636,7 +636,6 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, if (path != NULL) { bus = qbus_find(path, errp); if (!bus) { diff --git a/qemu-4.1.0.tar.xz b/qemu-6.2.0.tar.xz similarity index 46% rename from qemu-4.1.0.tar.xz rename to qemu-6.2.0.tar.xz index 79ad0661eda38092de13a677ef70eeaece3ad848..da2f1cd0f62dc3048369fa1b4c459d005b104a79 100644 Binary files a/qemu-4.1.0.tar.xz and b/qemu-6.2.0.tar.xz differ diff --git a/qemu-binfmt-conf.sh-fix-F-option.patch b/qemu-binfmt-conf.sh-fix-F-option.patch new file mode 100644 index 0000000000000000000000000000000000000000..ae61bef12259ae723eb403a49d8e4a456efbf08b --- /dev/null +++ b/qemu-binfmt-conf.sh-fix-F-option.patch @@ -0,0 +1,40 @@ +From f87df2b0761b55b24a9317f7694e2225a29c981d Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 06:33:44 +0000 +Subject: [PATCH 09/29] qemu-binfmt-conf.sh: fix -F option mainline inclusion + commit 719fab3afad22f34f0c812a8956adc88ab3242ce category: bugfix + +------------------------------------------------------------ + +qemu-binfmt-conf.sh should use "-F" as short option for "--qemu-suffix". +Fix the getopt call to make this work. + +Fixes: 7155be7cda5c ("qemu-binfmt-conf.sh: allow to provide a suffix to the interpreter name") +Signed-off-by: Martin Wilck +Reviewed-by: Laurent Vivier +Message-Id: <20211129135100.3934-1-mwilck@suse.com> +Signed-off-by: Laurent Vivier + +Signed-off-by: tangbinzy +--- + scripts/qemu-binfmt-conf.sh | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh +index 7de996d536..e9bfeb94d3 100755 +--- a/scripts/qemu-binfmt-conf.sh ++++ b/scripts/qemu-binfmt-conf.sh +@@ -340,7 +340,9 @@ PERSISTENT=no + PRESERVE_ARG0=no + QEMU_SUFFIX="" + +-options=$(getopt -o ds:Q:S:e:hc:p:g: -l debian,systemd:,qemu-path:,qemu-suffix:,exportdir:,help,credential:,persistent:,preserve-argv0: -- "$@") ++_longopts="debian,systemd:,qemu-path:,qemu-suffix:,exportdir:,help,credential:,\ ++persistent:,preserve-argv0:" ++options=$(getopt -o ds:Q:S:e:hc:p:g:F: -l ${_longopts} -- "$@") + eval set -- "$options" + + while true ; do +-- +2.27.0 + diff --git a/qemu-file-Don-t-do-IO-after-shutdown.patch b/qemu-file-Don-t-do-IO-after-shutdown.patch deleted file mode 100644 index 72cfc4d7c97cc130be5ffb5556852790c17b2afa..0000000000000000000000000000000000000000 --- a/qemu-file-Don-t-do-IO-after-shutdown.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 1f8bc46e8af4ffe6d062f378bd11e0ad70d30ac8 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 2 Dec 2020 14:25:13 +0800 -Subject: [PATCH] qemu-file: Don't do IO after shutdown - -Be sure that we are not doing neither read/write after shutdown of the -QEMUFile. - -Signed-off-by: Juan Quintela -Reviewed-by: Dr. David Alan Gilbert ---- - migration/qemu-file.c | 22 +++++++++++++++++++++- - 1 file changed, 21 insertions(+), 1 deletion(-) - -diff --git a/migration/qemu-file.c b/migration/qemu-file.c -index 18f480529a..cd96d04e9a 100644 ---- a/migration/qemu-file.c -+++ b/migration/qemu-file.c -@@ -51,6 +51,8 @@ struct QEMUFile { - unsigned int iovcnt; - - int last_error; -+ /* has the file has been shutdown */ -+ bool shutdown; - }; - - /* -@@ -59,10 +61,18 @@ struct QEMUFile { - */ - int qemu_file_shutdown(QEMUFile *f) - { -+ int ret; -+ -+ f->shutdown = true; - if (!f->ops->shut_down) { - return -ENOSYS; - } -- return f->ops->shut_down(f->opaque, true, true); -+ -+ ret = f->ops->shut_down(f->opaque, true, true); -+ if (!f->last_error) { -+ qemu_file_set_error(f, -EIO); -+ } -+ return ret; - } - - /* -@@ -181,6 +191,10 @@ void qemu_fflush(QEMUFile *f) - return; - } - -+ if (f->shutdown) { -+ return; -+ } -+ - if (f->iovcnt > 0) { - expect = iov_size(f->iov, f->iovcnt); - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); -@@ -293,6 +307,9 @@ static ssize_t qemu_fill_buffer(QEMUFile *f) - f->buf_index = 0; - f->buf_size = pending; - -+ if (f->shutdown) { -+ return 0; -+ } - len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, - IO_BUF_SIZE - pending); - if (len > 0) { -@@ -591,6 +608,9 @@ int64_t qemu_ftell(QEMUFile *f) - - int qemu_file_rate_limit(QEMUFile *f) - { -+ if (f->shutdown) { -+ return 1; -+ } - if (qemu_file_get_error(f)) { - return 1; - } --- -2.27.0 - diff --git a/qemu-img-add-qemu-img-direct-create.patch b/qemu-img-add-qemu-img-direct-create.patch new file mode 100644 index 0000000000000000000000000000000000000000..082c110f1e2f83c06724a17b51e2b9c5f2d0b1a2 --- /dev/null +++ b/qemu-img-add-qemu-img-direct-create.patch @@ -0,0 +1,534 @@ +From 8832a7dcad4e09229537781ff8db98496aa6f533 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 21:27:53 +0800 +Subject: [PATCH] qemu-img: add qemu-img direct create + +Introdue buffer_size while creating raw file, then we +can controll the speed of direct write by: + qemu-img create -t 'cache' -o buffer_size='num' + +Signed-off-by: Jinhua Cao +--- + block/file-posix.c | 65 +++++++++++++++++++++-- + include/block/block_int.h | 2 + + qapi/block-core.json | 6 ++- + qemu-img-cmds.hx | 4 +- + qemu-img.c | 14 ++++- + tests/qemu-iotests/049.out | 102 ++++++++++++++++++------------------- + tests/qemu-iotests/099.out | 2 +- + 7 files changed, 134 insertions(+), 61 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index aed7529f44..5180fd1d0b 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -128,6 +128,10 @@ + #define FTYPE_CD 1 + + #define MAX_BLOCKSIZE 4096 ++#define DEFAULT_BUFFER_SIZE 65536 ++#define BUFFER_ALIGN_SIZE 65536 ++#define MIN_BUFFER_SIZE 65536 ++#define MAX_BUFFER_SIZE 16777216 + + /* Posix file locking bytes. Libvirt takes byte 0, we start from higher bytes, + * leaving a few more bytes for its future use. */ +@@ -206,6 +210,8 @@ typedef struct RawPosixAIOData { + off_t aio_offset; + uint64_t aio_nbytes; + ++ size_t buffer_size; ++ + union { + struct { + struct iovec *iov; +@@ -2218,7 +2224,8 @@ static void raw_close(BlockDriverState *bs) + */ + static int coroutine_fn + raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, +- PreallocMode prealloc, Error **errp) ++ PreallocMode prealloc, size_t buffer_size, ++ Error **errp) + { + RawPosixAIOData acb; + +@@ -2227,6 +2234,7 @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, + .aio_fildes = fd, + .aio_type = QEMU_AIO_TRUNCATE, + .aio_offset = offset, ++ .buffer_size = buffer_size, + .truncate = { + .prealloc = prealloc, + .errp = errp, +@@ -2252,7 +2260,8 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, + + if (S_ISREG(st.st_mode)) { + /* Always resizes to the exact @offset */ +- return raw_regular_truncate(bs, s->fd, offset, prealloc, errp); ++ return raw_regular_truncate(bs, s->fd, offset, prealloc, ++ DEFAULT_BUFFER_SIZE, errp); + } + + if (prealloc != PREALLOC_MODE_OFF) { +@@ -2465,6 +2474,8 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + int fd; + uint64_t perm, shared; + int result = 0; ++ int flags = O_RDWR | O_BINARY; ++ size_t buffer_size = DEFAULT_BUFFER_SIZE; + + /* Validate options and set default values */ + assert(options->driver == BLOCKDEV_DRIVER_FILE); +@@ -2484,9 +2495,19 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + error_setg(errp, "Extent size hint is too large"); + goto out; + } ++ if (!file_opts->has_cache) { ++ file_opts->cache = g_strdup("writeback"); ++ } ++ if (file_opts->preallocation == PREALLOC_MODE_FULL && ++ !strcmp(file_opts->cache, "none")) { ++ flags |= O_DIRECT; ++ } ++ if (file_opts->has_buffersize) { ++ buffer_size = file_opts->buffersize; ++ } + + /* Create file */ +- fd = qemu_create(file_opts->filename, O_RDWR | O_BINARY, 0644, errp); ++ fd = qemu_create(file_opts->filename, flags, 0644, errp); + if (fd < 0) { + result = -errno; + goto out; +@@ -2521,7 +2542,8 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + } + + /* Clear the file by truncating it to 0 */ +- result = raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, errp); ++ result = raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, ++ buffer_size, errp); + if (result < 0) { + goto out_unlock; + } +@@ -2565,7 +2587,8 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + /* Resize and potentially preallocate the file to the desired + * final size */ + result = raw_regular_truncate(NULL, fd, file_opts->size, +- file_opts->preallocation, errp); ++ file_opts->preallocation, ++ buffer_size, errp); + if (result < 0) { + goto out_unlock; + } +@@ -2586,6 +2609,7 @@ out_close: + error_setg_errno(errp, -result, "Could not close the new file"); + } + out: ++ g_free(file_opts->cache); + return result; + } + +@@ -2602,6 +2626,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, + PreallocMode prealloc; + char *buf = NULL; + Error *local_err = NULL; ++ size_t buffersize = DEFAULT_BUFFER_SIZE; ++ char *cache = NULL; + + /* Skip file: protocol prefix */ + strstart(filename, "file:", &filename); +@@ -2624,6 +2650,21 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, + return -EINVAL; + } + ++ buffersize = qemu_opt_get_size_del(opts, BLOCK_OPT_BUFFER_SIZE, ++ DEFAULT_BUFFER_SIZE); ++ if (buffersize < MIN_BUFFER_SIZE || buffersize > MAX_BUFFER_SIZE) { ++ error_setg_errno(errp, EINVAL, "Buffer size must be between %d " ++ "and %d", MIN_BUFFER_SIZE, MAX_BUFFER_SIZE); ++ return -EINVAL; ++ } ++ ++ cache = qemu_opt_get_del(opts, BLOCK_OPT_CACHE); ++ if (!cache) { ++ cache = g_strdup("writeback"); ++ } ++ ++ buffersize = ROUND_UP(buffersize, BUFFER_ALIGN_SIZE); ++ + options = (BlockdevCreateOptions) { + .driver = BLOCKDEV_DRIVER_FILE, + .u.file = { +@@ -2635,6 +2676,10 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, + .nocow = nocow, + .has_extent_size_hint = has_extent_size_hint, + .extent_size_hint = extent_size_hint, ++ .has_buffersize = true, ++ .buffersize = buffersize, ++ .has_cache = true, ++ .cache = cache, + }, + }; + return raw_co_create(&options, errp); +@@ -3133,6 +3178,16 @@ static QemuOptsList raw_create_opts = { + .type = QEMU_OPT_SIZE, + .help = "Extent size hint for the image file, 0 to disable" + }, ++ { ++ .name = BLOCK_OPT_CACHE, ++ .type = QEMU_OPT_STRING, ++ .help = "Cache mode (allowed values: writeback, none)" ++ }, ++ { ++ .name = BLOCK_OPT_BUFFER_SIZE, ++ .type = QEMU_OPT_SIZE, ++ .help = "write buffer size" ++ }, + { /* end of list */ } + } + }; +diff --git a/include/block/block_int.h b/include/block/block_int.h +index f4c75e8ba9..701f031102 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -61,6 +61,8 @@ + #define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" + #define BLOCK_OPT_COMPRESSION_TYPE "compression_type" + #define BLOCK_OPT_EXTL2 "extended_l2" ++#define BLOCK_OPT_CACHE "cache" ++#define BLOCK_OPT_BUFFER_SIZE "buffer_size" + + #define BLOCK_PROBE_BUF_SIZE 512 + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 804beabfb0..e65fabe36d 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -4437,6 +4437,8 @@ + # @nocow: Turn off copy-on-write (valid only on btrfs; default: off) + # @extent-size-hint: Extent size hint to add to the image file; 0 for not + # adding an extent size hint (default: 1 MB, since 5.1) ++# @cache: Cache mode used to write the output disk image ++# @buffersize: Buffer size for creating image + # + # Since: 2.12 + ## +@@ -4445,7 +4447,9 @@ + 'size': 'size', + '*preallocation': 'PreallocMode', + '*nocow': 'bool', +- '*extent-size-hint': 'size'} } ++ '*extent-size-hint': 'size', ++ '*cache': 'str', ++ '*buffersize': 'size'} } + + ## + # @BlockdevCreateOptionsGluster: +diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx +index 72bcdcfbfa..ec6aa2886a 100644 +--- a/qemu-img-cmds.hx ++++ b/qemu-img-cmds.hx +@@ -52,9 +52,9 @@ SRST + ERST + + DEF("create", img_create, +- "create [--object objectdef] [-q] [-f fmt] [-b backing_file] [-F backing_fmt] [-u] [-o options] filename [size]") ++ "create [--object objectdef] [-q] [-f fmt] [-b backing_file] [-F backing_fmt] [-u] [-t cache] [-o options] filename [size]") + SRST +-.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE] ++.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-t CACHE] [-o OPTIONS] FILENAME [SIZE] + ERST + + DEF("dd", img_dd, +diff --git a/qemu-img.c b/qemu-img.c +index f036a1d428..9409558772 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -504,6 +504,7 @@ static int img_create(int argc, char **argv) + const char *base_fmt = NULL; + const char *filename; + const char *base_filename = NULL; ++ const char *cache = BDRV_DEFAULT_CACHE; + char *options = NULL; + Error *local_err = NULL; + bool quiet = false; +@@ -515,7 +516,7 @@ static int img_create(int argc, char **argv) + {"object", required_argument, 0, OPTION_OBJECT}, + {0, 0, 0, 0} + }; +- c = getopt_long(argc, argv, ":F:b:f:ho:qu", ++ c = getopt_long(argc, argv, ":F:b:f:t:ho:qu", + long_options, NULL); + if (c == -1) { + break; +@@ -539,6 +540,9 @@ static int img_create(int argc, char **argv) + case 'f': + fmt = optarg; + break; ++ case 't': ++ cache = optarg; ++ break; + case 'o': + if (accumulate_options(&options, optarg) < 0) { + goto fail; +@@ -582,6 +586,14 @@ static int img_create(int argc, char **argv) + error_exit("Unexpected argument: %s", argv[optind]); + } + ++ if (!options) { ++ options = g_strdup_printf(BLOCK_OPT_CACHE"=%s", cache); ++ } else { ++ char *old_options = options; ++ options = g_strdup_printf("%s,"BLOCK_OPT_CACHE"=%s", options, cache); ++ g_free(old_options); ++ } ++ + bdrv_img_create(filename, fmt, base_filename, base_fmt, + options, img_size, flags, quiet, &local_err); + if (local_err) { +diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out +index 8719c91b48..6aca1a7797 100644 +--- a/tests/qemu-iotests/049.out ++++ b/tests/qemu-iotests/049.out +@@ -4,90 +4,90 @@ QA output created by 049 + == 1. Traditional size parameter == + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 cache=writeback + + == 2. Specifying size via -o == + + qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2 +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 cache=writeback + + == 3. Invalid sizes == + +@@ -135,84 +135,84 @@ qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once + == Check correct interpretation of suffixes for cluster size == + + qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + == Check compat level option == + + qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16 cache=writeback + qemu-img: TEST_DIR/t.qcow2: Parameter 'version' does not accept value '0.42' + + qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16 cache=writeback + qemu-img: TEST_DIR/t.qcow2: Parameter 'version' does not accept value 'foobar' + + == Check preallocation option == + + qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + qemu-img: TEST_DIR/t.qcow2: Parameter 'preallocation' does not accept value '1234' + + == Check encryption option == + + qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 cache=writeback + + == Check lazy_refcounts option (only with v3) == + + qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 cache=writeback + + qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M +-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16 ++Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16 cache=writeback + qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) + + == Expect error when backing file name is empty string == +diff --git a/tests/qemu-iotests/099.out b/tests/qemu-iotests/099.out +index 8cce627529..f6f8f25957 100644 +--- a/tests/qemu-iotests/099.out ++++ b/tests/qemu-iotests/099.out +@@ -1,6 +1,6 @@ + QA output created by 099 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 +-Formatting 'TEST_DIR/t.IMGFMT.compare', fmt=raw size=131072 ++Formatting 'TEST_DIR/t.IMGFMT.compare', fmt=raw size=131072 cache=writeback + + === Testing simple filename for blkverify === + +-- +2.27.0 + diff --git a/qemu-img-block-dont-blk_make_zero-if-discard_zeroes-.patch b/qemu-img-block-dont-blk_make_zero-if-discard_zeroes-.patch new file mode 100644 index 0000000000000000000000000000000000000000..c96e5b429f72f4830bd7361891dbda78ac217cf6 --- /dev/null +++ b/qemu-img-block-dont-blk_make_zero-if-discard_zeroes-.patch @@ -0,0 +1,26 @@ +From 724134432ef21f1fb2b18bbe55b891d31181ccca Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 14:25:39 +0800 +Subject: [PATCH] qemu-img: block: dont blk_make_zero if discard_zeroes false + +Signed-off-by: Jinhua Cao +--- + block/file-posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index b283093e5b..aed7529f44 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -804,7 +804,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + } + #endif + +- bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; ++ bs->supported_zero_flags = s->discard_zeroes ? (BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) : 0; + if (S_ISREG(st.st_mode)) { + /* When extending regular files, we get zeros from the OS */ + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; +-- +2.27.0 + diff --git a/qemu-img-convert-Don-t-pre-zero-images.patch b/qemu-img-convert-Don-t-pre-zero-images.patch deleted file mode 100644 index 925590c34903cd73307b3f806a0b407c6c744fb5..0000000000000000000000000000000000000000 --- a/qemu-img-convert-Don-t-pre-zero-images.patch +++ /dev/null @@ -1,73 +0,0 @@ -From a2fcbe2b82c42f890a857ad8d4edcfdb273106ea Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Fri, 31 Jul 2020 08:18:31 -0400 -Subject: [PATCH] qemu-img convert: Don't pre-zero images - -RH-Author: Kevin Wolf -Message-id: <20200731081831.13781-2-kwolf@redhat.com> -Patchwork-id: 98117 -O-Subject: [RHEL-AV-8.2.1.z qemu-kvm PATCH 1/1] qemu-img convert: Don't pre-zero images -Bugzilla: 1861682 -RH-Acked-by: Stefano Garzarella -RH-Acked-by: Max Reitz -RH-Acked-by: Eric Blake - -Since commit 5a37b60a61c, qemu-img create will pre-zero the target image -if it isn't already zero-initialised (most importantly, for host block -devices, but also iscsi etc.), so that writing explicit zeros wouldn't -be necessary later. - -This could speed up the operation significantly, in particular when the -source image file was only sparsely populated. However, it also means -that some block are written twice: Once when pre-zeroing them, and then -when they are overwritten with actual data. On a full image, the -pre-zeroing is wasted work because everything will be overwritten. - -In practice, write_zeroes typically turns out faster than writing -explicit zero buffers, but slow enough that first zeroing everything and -then overwriting parts can be a significant net loss. - -Meanwhile, qemu-img convert was rewritten in 690c7301600 and zero blocks -are now written to the target using bdrv_co_pwrite_zeroes() if the -target could be pre-zeroed. This way we already make use of the faster -write_zeroes operation, but avoid writing any blocks twice. - -Remove the pre-zeroing because these days this former optimisation has -actually turned into a pessimisation in the common case. - -Reported-by: Nir Soffer -Signed-off-by: Kevin Wolf -Message-Id: <20200622151203.35624-1-kwolf@redhat.com> -Tested-by: Nir Soffer -Reviewed-by: Eric Blake -Signed-off-by: Kevin Wolf -(cherry picked from commit edafc70c0c8510862f2f213a3acf7067113bcd08) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - qemu-img.c | 9 --------- - 1 file changed, 9 deletions(-) - -diff --git a/qemu-img.c b/qemu-img.c -index 2e9cc5db7c..e4abd4978a 100644 ---- a/qemu-img.c -+++ b/qemu-img.c -@@ -1981,15 +1981,6 @@ static int convert_do_copy(ImgConvertState *s) - ? bdrv_has_zero_init(blk_bs(s->target)) - : false; - -- if (!s->has_zero_init && !s->target_has_backing && -- bdrv_can_write_zeroes_with_unmap(blk_bs(s->target))) -- { -- ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK); -- if (ret == 0) { -- s->has_zero_init = true; -- } -- } -- - /* Allocate buffer for copied data. For compressed images, only one cluster - * can be copied at a time. */ - if (s->compressed) { --- -2.27.0 - diff --git a/qemu-img-create-cache-paramter-only-use-for-reg-file.patch b/qemu-img-create-cache-paramter-only-use-for-reg-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..c4664e1bc4da6edd525606b11f334f4fea4bc851 --- /dev/null +++ b/qemu-img-create-cache-paramter-only-use-for-reg-file.patch @@ -0,0 +1,66 @@ +From 85a876e0d28eac4c71350baede38ca755fdf6df0 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 24 Mar 2022 17:12:49 +0800 +Subject: [PATCH] qemu-img create: 'cache' paramter only use for reg file image + +The paramter 'cache' is invalid for host device(/dev/xxx). If +'qemu-img create' operator performed on host device, the host +device not support 'cache' would result 'qemu-img create' execute +failed. + +Signed-off-by: Jinhua Cao +--- + qemu-img.c | 30 ++++++++++++++++++++++++------ + 1 file changed, 24 insertions(+), 6 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 9409558772..059bf42fc1 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -496,6 +496,22 @@ static int64_t cvtnum(const char *name, const char *value) + return cvtnum_full(name, value, 0, INT64_MAX); + } + ++static bool is_reg_file(const char *filename) ++{ ++ struct stat st; ++ ++ /* file not exist, file will be create later, so it's a reg file */ ++ if (access(filename, F_OK) == -1) { ++ return true; ++ } ++ ++ /* file exist, check file type */ ++ if (stat(filename, &st) >= 0 && S_ISREG(st.st_mode)) { ++ return true; ++ } ++ return false; ++} ++ + static int img_create(int argc, char **argv) + { + int c; +@@ -586,12 +602,14 @@ static int img_create(int argc, char **argv) + error_exit("Unexpected argument: %s", argv[optind]); + } + +- if (!options) { +- options = g_strdup_printf(BLOCK_OPT_CACHE"=%s", cache); +- } else { +- char *old_options = options; +- options = g_strdup_printf("%s,"BLOCK_OPT_CACHE"=%s", options, cache); +- g_free(old_options); ++ if (is_reg_file(filename)) { ++ if (!options) { ++ options = g_strdup_printf(BLOCK_OPT_CACHE"=%s", cache); ++ } else { ++ char *old_options = options; ++ options = g_strdup_printf("%s,"BLOCK_OPT_CACHE"=%s", options, cache); ++ g_free(old_options); ++ } + } + + bdrv_img_create(filename, fmt, base_filename, base_fmt, +-- +2.27.0 + diff --git a/qemu-img-free-memory-before-re-assign.patch b/qemu-img-free-memory-before-re-assign.patch deleted file mode 100644 index 2d46d64b1b9664b66efc76ea6490a1bc22663137..0000000000000000000000000000000000000000 --- a/qemu-img-free-memory-before-re-assign.patch +++ /dev/null @@ -1,33 +0,0 @@ -From d22af5cb41c16829dbf3ed3c611ef56ceeb840ff Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Thu, 27 Feb 2020 09:29:50 +0800 -Subject: [PATCH 02/14] qemu-img: free memory before re-assign - -collect_image_check() is called twice in img_check(), the filename/format will be alloced without free the original memory. -It is not a big deal since the process will exit anyway, but seems like a clean code and it will remove the warning spotted by asan. - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Message-Id: <20200227012950.12256-3-pannengyuan@huawei.com> -Signed-off-by: Max Reitz -Signed-off-by: Peng Liang ---- - qemu-img.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/qemu-img.c b/qemu-img.c -index 79983772de39..2e9cc5db7c4c 100644 ---- a/qemu-img.c -+++ b/qemu-img.c -@@ -808,6 +808,8 @@ static int img_check(int argc, char **argv) - check->corruptions_fixed); - } - -+ qapi_free_ImageCheck(check); -+ check = g_new0(ImageCheck, 1); - ret = collect_image_check(bs, check, filename, fmt, 0); - - check->leaks_fixed = leaks_fixed; --- -2.26.2 - diff --git a/qemu-nbd-make-native-as-the-default-aio-mode.patch b/qemu-nbd-make-native-as-the-default-aio-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..c53f50a27d3d96cb9a970e73b381124c207b43ed --- /dev/null +++ b/qemu-nbd-make-native-as-the-default-aio-mode.patch @@ -0,0 +1,35 @@ +From de6f3fb0cf92e04c0989a9065910158eecbe4304 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 10:48:58 +0800 +Subject: [PATCH] qemu-nbd: make native as the default aio mode + +When the file system is dealing with multithreading concurrent writing to a file, +the performance will be degraded because of the lock. +At present, the default AIO mode of QEMU NBD is threads. In the case of large blocks, +because IO is divided into small pieces and multiple queues, it will become multithreading +concurrent writing the same file. Due to the file system, the performance will be greatly reduced. +If you change to native mode, this problem will not exist. + +Signed-off-by: wangjian161 +--- + qemu-nbd.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index c6c20df68a..15a4bc4018 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -800,6 +800,10 @@ int main(int argc, char **argv) + trace_init_file(); + qemu_set_log(LOG_TRACE); + ++ if (!seen_aio && (flags & BDRV_O_NOCACHE)) { ++ flags |= BDRV_O_NATIVE_AIO; ++ } ++ + socket_activation = check_socket_activation(); + if (socket_activation == 0) { + setup_address_and_port(&bindto, &port); +-- +2.27.0 + diff --git a/qemu-nbd-set-timeout-to-qemu-nbd-socket.patch b/qemu-nbd-set-timeout-to-qemu-nbd-socket.patch new file mode 100644 index 0000000000000000000000000000000000000000..3ef9b6ae61755fa3f9289a91b14a0e4fa559304e --- /dev/null +++ b/qemu-nbd-set-timeout-to-qemu-nbd-socket.patch @@ -0,0 +1,42 @@ +From f665f7836a019cc8bb8d46d076508afc761923f0 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 10:55:08 +0800 +Subject: [PATCH] qemu-nbd: set timeout to qemu-nbd socket + +In case of insufficient memory and kill-9, +the NBD socket cannot be processed and stuck all the time. + +Signed-off-by: wangjian161 +--- + nbd/client.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/nbd/client.c b/nbd/client.c +index 30d5383cb1..8ed50140f2 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -24,6 +24,8 @@ + #include "nbd-internal.h" + #include "qemu/cutils.h" + ++#define NBD_TIMEOUT_SECONDS 30 ++ + /* Definitions for opaque data types */ + + static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); +@@ -1301,6 +1303,12 @@ int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, + } + } + ++ if (ioctl(fd, NBD_SET_TIMEOUT, NBD_TIMEOUT_SECONDS) < 0) { ++ int serrno = errno; ++ error_setg(errp, "Failed setting timeout"); ++ return -serrno; ++ } ++ + trace_nbd_init_finish(); + + return 0; +-- +2.27.0 + diff --git a/qemu-options-Improve-readability-of-SMP-related-Docs.patch b/qemu-options-Improve-readability-of-SMP-related-Docs.patch new file mode 100644 index 0000000000000000000000000000000000000000..63dc895ac31d7be9be0de1a0390a039a7f66b6f3 --- /dev/null +++ b/qemu-options-Improve-readability-of-SMP-related-Docs.patch @@ -0,0 +1,146 @@ +From 07991b049fc9ebdb62c311eda1535ad4831625e5 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:08 +0800 +Subject: [PATCH 10/24] qemu-options: Improve readability of SMP related Docs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We have a description in qemu-options.hx for each CPU topology +parameter to explain what it exactly means, and also an extra +declaration for the target-specific one, e.g. "for PC only" +when describing "dies", and "for PC, it's on one die" when +describing "cores". + +Now we are going to introduce one more non-generic parameter +"clusters", it will make the Doc less readable and if we still +continue to use the legacy way to describe it. + +So let's at first make two tweaks of the Docs to improve the +readability and also scalability: +1) In the -help text: Delete the extra specific declaration and + describe each topology parameter level by level. Then add a + note to declare that different machines may support different + subsets and the actual meaning of the supported parameters + will vary accordingly. +2) In the rST text: List all the sub-hierarchies currently + supported in QEMU, and correspondingly give an example of + -smp configuration for each of them. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-2-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + qemu-options.hx | 76 ++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 59 insertions(+), 17 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index ae2c6dbbfc..7a59db7764 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -207,14 +207,26 @@ ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, + "-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n" +- " set the number of CPUs to 'n' [default=1]\n" ++ " set the number of initial CPUs to 'n' [default=1]\n" + " maxcpus= maximum number of total CPUs, including\n" + " offline CPUs for hotplug, etc\n" +- " sockets= number of discrete sockets in the system\n" +- " dies= number of CPU dies on one socket (for PC only)\n" +- " cores= number of CPU cores on one socket (for PC, it's on one die)\n" +- " threads= number of threads on one CPU core\n", +- QEMU_ARCH_ALL) ++ " sockets= number of sockets on the machine board\n" ++ " dies= number of dies in one socket\n" ++ " cores= number of cores in one die\n" ++ " threads= number of threads in one core\n" ++ "Note: Different machines may have different subsets of the CPU topology\n" ++ " parameters supported, so the actual meaning of the supported parameters\n" ++ " will vary accordingly. For example, for a machine type that supports a\n" ++ " three-level CPU hierarchy of sockets/cores/threads, the parameters will\n" ++ " sequentially mean as below:\n" ++ " sockets means the number of sockets on the machine board\n" ++ " cores means the number of cores in one socket\n" ++ " threads means the number of threads in one core\n" ++ " For a particular machine type board, an expected CPU topology hierarchy\n" ++ " can be defined through the supported sub-option. Unsupported parameters\n" ++ " can also be provided in addition to the sub-option, but their values\n" ++ " must be set as 1 in the purpose of correct parsing.\n", ++ QEMU_ARCH_ALL) + SRST + ``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]`` + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on +@@ -225,27 +237,57 @@ SRST + initial CPU count will match the maximum number. When only one of them + is given then the omitted one will be set to its counterpart's value. + Both parameters may be specified, but the maximum number of CPUs must +- be equal to or greater than the initial CPU count. Both parameters are +- subject to an upper limit that is determined by the specific machine +- type chosen. +- +- To control reporting of CPU topology information, the number of sockets, +- dies per socket, cores per die, and threads per core can be specified. +- The sum `` sockets * cores * dies * threads `` must be equal to the +- maximum CPU count. CPU targets may only support a subset of the topology +- parameters. Where a CPU target does not support use of a particular +- topology parameter, its value should be assumed to be 1 for the purpose +- of computing the CPU maximum count. ++ be equal to or greater than the initial CPU count. Product of the ++ CPU topology hierarchy must be equal to the maximum number of CPUs. ++ Both parameters are subject to an upper limit that is determined by ++ the specific machine type chosen. ++ ++ To control reporting of CPU topology information, values of the topology ++ parameters can be specified. Machines may only support a subset of the ++ parameters and different machines may have different subsets supported ++ which vary depending on capacity of the corresponding CPU targets. So ++ for a particular machine type board, an expected topology hierarchy can ++ be defined through the supported sub-option. Unsupported parameters can ++ also be provided in addition to the sub-option, but their values must be ++ set as 1 in the purpose of correct parsing. + + Either the initial CPU count, or at least one of the topology parameters + must be specified. The specified parameters must be greater than zero, + explicit configuration like "cpus=0" is not allowed. Values for any + omitted parameters will be computed from those which are given. ++ ++ For example, the following sub-option defines a CPU topology hierarchy ++ (2 sockets totally on the machine, 2 cores per socket, 2 threads per ++ core) for a machine that only supports sockets/cores/threads. ++ Some members of the option can be omitted but their values will be ++ automatically computed: ++ ++ :: ++ ++ -smp 8,sockets=2,cores=2,threads=2,maxcpus=8 ++ ++ The following sub-option defines a CPU topology hierarchy (2 sockets ++ totally on the machine, 2 dies per socket, 2 cores per die, 2 threads ++ per core) for PC machines which support sockets/dies/cores/threads. ++ Some members of the option can be omitted but their values will be ++ automatically computed: ++ ++ :: ++ ++ -smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16 ++ + Historically preference was given to the coarsest topology parameters + when computing missing values (ie sockets preferred over cores, which + were preferred over threads), however, this behaviour is considered + liable to change. Prior to 6.2 the preference was sockets over cores + over threads. Since 6.2 the preference is cores over sockets over threads. ++ ++ For example, the following option defines a machine board with 2 sockets ++ of 1 core before 6.2 and 1 socket of 2 cores after 6.2: ++ ++ :: ++ ++ -smp 2 + ERST + + DEF("numa", HAS_ARG, QEMU_OPTION_numa, +-- +2.27.0 + diff --git a/qemu-pr-fixed-ioctl-failed-for-multipath-disk.patch b/qemu-pr-fixed-ioctl-failed-for-multipath-disk.patch new file mode 100644 index 0000000000000000000000000000000000000000..7985a92790e80f44d2aaef55a0603bb8eb86b998 --- /dev/null +++ b/qemu-pr-fixed-ioctl-failed-for-multipath-disk.patch @@ -0,0 +1,36 @@ +From 56f59125707c0222bbb5d7f820792aba17c3db08 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 11:10:42 +0800 +Subject: [PATCH] qemu-pr: fixed ioctl failed for multipath disk + +We use ioctl to detect multipath devices. However, we only set flags in +struct dm_ioctl (the argument to ioctl) and left other fields in random, +which may cause the failure of calling ioctl. Hence, we set other +fields to 0 to avoid the failure. + +Signed-off-by: wangjian161 +--- + scsi/qemu-pr-helper.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index f281daeced..bbb9b57741 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -288,9 +288,12 @@ static void multipath_pr_init(void) + + static int is_mpath(int fd) + { +- struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG }; ++ struct dm_ioctl dm; + struct dm_target_spec *tgt; + ++ memset(&dm, 0, sizeof(struct dm_ioctl)); ++ dm.flags = DM_NOFLUSH_FLAG; ++ + tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm); + if (!tgt) { + if (errno == ENXIO) { +-- +2.27.0 + diff --git a/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch b/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2578891b45520ce59eb60b5f303c4d7fd4bfa9bb --- /dev/null +++ b/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch @@ -0,0 +1,39 @@ +From 274dd10230eef97714a2a283ecd8a8ce2ecbf687 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 07:28:31 +0000 +Subject: [PATCH] qemu-timer: Skip empty timer lists before locking in + qemu_clock_deadline_ns_all mainline inclusion commit + 3f42906c9ab2c777a895b48b87b8107167e4a275 category: bugfix + +--------------------------------------------------------------- + +This decreases qemu_clock_deadline_ns_all's share from 23.2% to 13% in a +profile of icount-enabled aarch64-softmmu. + +Signed-off-by: Idan Horowitz +Reviewed-by: Richard Henderson +Message-Id: <20220114004358.299534-2-idan.horowitz@gmail.com> +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + util/qemu-timer.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/util/qemu-timer.c b/util/qemu-timer.c +index 40e8c83722..c5b6dc987c 100644 +--- a/util/qemu-timer.c ++++ b/util/qemu-timer.c +@@ -330,6 +330,9 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) + } + + QLIST_FOREACH(timer_list, &clock->timerlists, list) { ++ if (!qatomic_read(&timer_list->active_timers)) { ++ continue; ++ } + qemu_mutex_lock(&timer_list->active_timers_lock); + ts = timer_list->active_timers; + /* Skip all external timers */ +-- +2.27.0 + diff --git a/qemu.spec b/qemu.spec index 981d9e122bb15216d1d717f42c62cd6ace4810fd..9faf51e8855ef8ac9f26296f5fa28ba157b4fe95 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,570 +1,891 @@ +# Whether to support Ceph rbd storage backend +%bcond_without rbd + Name: qemu -Version: 4.1.0 -Release: 76 -Epoch: 2 +Version: 6.2.0 +Release: 89 +Epoch: 10 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 URL: http://www.qemu.org -Source0: https://www.qemu.org/download/%{name}-%{version}%{?rcstr}.tar.xz +Source0: https://download.qemu.org/%{name}-%{version}%{?rcstr}.tar.xz Source1: 80-kvm.rules Source2: 99-qemu-guest-agent.rules Source3: bridge.conf - -Patch0001: pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch -Patch0002: pl031-support-rtc-timer-property-for-pl031.patch -Patch0003: vhost-cancel-migration-when-vhost-user-restarted.patch -Patch0004: qcow2-fix-memory-leak-in-qcow2_read_extensions.patch -Patch0005: bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch -Patch0006: hw-arm-expose-host-CPU-frequency-info-to-guest.patch -Patch0007: smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch -Patch0008: tests-bios-tables-test-disable-this-testcase.patch -Patch0009: hw-arm-virt-Introduce-cpu-topology-support.patch -Patch0010: hw-arm64-add-vcpu-cache-info-support.patch -Patch0011: xhci-Fix-memory-leak-in-xhci_address_slot.patch -Patch0012: xhci-Fix-memory-leak-in-xhci_kick_epctx.patch -Patch0013: ehci-fix-queue-dev-null-ptr-dereference.patch -Patch0014: util-async-hold-AioContext-ref-to-prevent-use-after-free.patch -Patch0015: vhost-user-scsi-prevent-using-uninitialized-vqs.patch -Patch0016: cpu-add-Kunpeng-920-cpu-support.patch -Patch0017: cpu-parse-feature-to-avoid-failure.patch -Patch0018: cpu-add-Cortex-A72-processor-kvm-target-support.patch -Patch0019: pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch -Patch0020: vnc-fix-memory-leak-when-vnc-disconnect.patch -Patch0021: linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch -Patch0022: intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch -Patch0023: ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch -Patch0024: 9pfs-local-Fix-possible-memory-leak-in-local_link.patch -Patch0025: scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch -Patch0026: arm-translate-a64-fix-uninitialized-variable-warning.patch -Patch0027: nbd-fix-uninitialized-variable-warning.patch -Patch0028: xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch -Patch0029: block-fix-memleaks-in-bdrv_refresh_filename.patch -Patch0030: iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch -Patch0031: tcp_emu-Fix-oob-access.patch -Patch0032: slirp-use-correct-size-while-emulating-IRC-commands.patch -Patch0033: slirp-use-correct-size-while-emulating-commands.patch -Patch0034: util-add-slirp_fmt-helpers.patch -Patch0035: tcp_emu-fix-unsafe-snprintf-usages.patch -Patch0036: block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch -Patch0037: monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch -Patch0038: memory-Align-MemoryRegionSections-fields.patch -Patch0039: memory-Provide-an-equality-function-for-MemoryRegion.patch -Patch0040: vhost-Fix-memory-region-section-comparison.patch -Patch0041: file-posix-Handle-undetectable-alignment.patch -Patch0042: block-backup-fix-max_transfer-handling-for-copy_rang.patch -Patch0043: block-backup-fix-backup_cow_with_offload-for-last-cl.patch -Patch0044: qcow2-Limit-total-allocation-range-to-INT_MAX.patch -Patch0045: mirror-Do-not-dereference-invalid-pointers.patch -Patch0046: COLO-compare-Fix-incorrect-if-logic.patch -Patch0047: qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch -Patch0048: pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch -Patch0049: pcie-Compat-with-devices-which-do-not-support-Link-W.patch -Patch0050: aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch -Patch0051: async-use-explicit-memory-barriers.patch -Patch0052: dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch -Patch0053: Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch -Patch0054: pc-Don-t-make-die-id-mandatory-unless-necessary.patch -Patch0055: block-file-posix-Reduce-xfsctl-use.patch -Patch0056: pr-manager-Fix-invalid-g_free-crash-bug.patch -Patch0057: x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch -Patch0058: vpc-Return-0-from-vpc_co_create-on-success.patch -Patch0059: target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch -Patch0060: target-arm-Don-t-abort-on-M-profile-exception-return.patch -Patch0061: libvhost-user-fix-SLAVE_SEND_FD-handling.patch -Patch0062: qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch -Patch0063: block-nfs-tear-down-aio-before-nfs_close.patch -Patch0064: blockjob-update-nodes-head-while-removing-all-bdrv.patch -Patch0065: block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch -Patch0066: coroutine-Add-qemu_co_mutex_assert_locked.patch -Patch0067: qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch -Patch0068: hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch -Patch0069: make-release-pull-in-edk2-submodules-so-we-can-build.patch -Patch0070: roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch -Patch0071: block-snapshot-Restrict-set-of-snapshot-nodes.patch -Patch0072: vhost-user-save-features-if-the-char-dev-is-closed.patch -Patch0073: hw-core-loader-Fix-possible-crash-in-rom_copy.patch -Patch0074: ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch -Patch0075: virtio-new-post_load-hook.patch -Patch0076: virtio-net-prevent-offloads-reset-on-migration.patch -Patch0077: util-hbitmap-strict-hbitmap_reset.patch -Patch0078: hbitmap-handle-set-reset-with-zero-length.patch -Patch0079: target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch -Patch0080: scsi-lsi-exit-infinite-loop-while-executing-script-C.patch -Patch0081: virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch -Patch0082: qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch -Patch0083: util-iov-introduce-qemu_iovec_init_extended.patch -Patch0084: util-iov-improve-qemu_iovec_is_zero.patch -Patch0085: block-io-refactor-padding.patch -Patch0086: block-Make-wait-mark-serialising-requests-public.patch -Patch0087: block-Add-bdrv_co_get_self_request.patch -Patch0088: block-file-posix-Let-post-EOF-fallocate-serialize.patch -Patch0089: block-posix-Always-allocate-the-first-block.patch -Patch0090: block-create-Do-not-abort-if-a-block-driver-is-not-a.patch -Patch0091: mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch -Patch0092: target-arm-kvm-trivial-Clean-up-header-documentation.patch -Patch0093: target-arm-kvm64-kvm64-cpus-have-timer-registers.patch -Patch0094: target-arm-kvm-Implement-virtual-time-adjustment.patch -Patch0095: target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch -Patch0096: hw-acpi-Make-ACPI-IO-address-space-configurable.patch -Patch0097: hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch -Patch0098: hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch -Patch0099: hw-arm-virt-Add-memory-hotplug-framework.patch -Patch0100: hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch -Patch0101: hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch -Patch0102: hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch -Patch0103: hw-arm-Use-GED-for-system_powerdown-event.patch -Patch0104: docs-specs-Add-ACPI-GED-documentation.patch -Patch0105: tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch -Patch0106: tests-acpi-add-empty-files.patch -Patch0107: tests-allow-empty-expected-files.patch -Patch0108: tests-Add-bios-tests-to-arm-virt.patch -Patch0109: tests-document-how-to-update-acpi-tables.patch -Patch0110: hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch -Patch0111: bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch -Patch0112: Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch -Patch0113: acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch -Patch0114: acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch -Patch0115: arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch -Patch0116: acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch -Patch0117: acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch -Patch0118: arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch -Patch0119: arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch -Patch0120: arm-virt-Add-CPU-hotplug-framework.patch -Patch0121: arm-virt-Add-CPU-topology-support.patch -Patch0122: test-numa-Adjust-aarch64-numa-test.patch -Patch0123: hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch -Patch0124: hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch -Patch0125: arm-virt-gic-Construct-irqs-connection-from-create_g.patch -Patch0126: intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch -Patch0127: intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch -Patch0128: intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch -Patch0129: hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch -Patch0130: accel-kvm-Add-pre-park-vCPU-support.patch -Patch0131: intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch -Patch0132: acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch -Patch0133: arm-virt-Add-cpu_hotplug_enabled-field.patch -Patch0134: arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch -Patch0135: arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch -Patch0136: arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch -Patch0137: arm-virt-Start-up-CPU-hot-plug.patch -Patch0138: migration-always-initialise-ram_counters-for-a-new-m.patch -Patch0139: migration-add-qemu_file_update_transfer-interface.patch -Patch0140: migration-add-speed-limit-for-multifd-migration.patch -Patch0141: migration-update-ram_counters-for-multifd-sync-packe.patch -Patch0142: migration-Make-global-sem_sync-semaphore-by-channel.patch -Patch0143: migration-multifd-fix-nullptr-access-in-terminating-m.patch -Patch0144: migration-Maybe-VM-is-paused-when-migration-is-cance.patch -Patch0145: migration-multifd-fix-potential-wrong-acception-orde.patch -Patch0146: migration-multifd-fix-destroyed-mutex-access-in-term.patch -Patch0147: migration-multifd-fix-nullptr-access-in-multifd_send.patch -Patch0148: vtimer-compat-cross-version-migration-from-v4.0.1.patch -Patch0149: migration-ram-Do-error_free-after-migrate_set_error-.patch -Patch0150: migration-ram-fix-memleaks-in-multifd_new_send_chann.patch -Patch0151: migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch -Patch0152: arm-virt-Support-CPU-cold-plug.patch -Patch0153: ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch -Patch0154: ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch -Patch0155: slirp-tftp-restrict-relative-path-access.patch -Patch0156: ip_reass-Fix-use-after-free.patch -Patch0157: bt-use-size_t-type-for-length-parameters-instead-of-.patch -Patch0158: log-Add-some-logs-on-VM-runtime-path.patch -Patch0159: Revert-vtimer-compat-cross-version-migration-from-v4.patch -Patch0160: ARM64-record-vtimer-tick-when-cpu-is-stopped.patch -Patch0161: hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch -Patch0162: migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch -Patch0163: vtimer-Drop-vtimer-virtual-timer-adjust.patch -Patch0164: target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch -Patch0165: target-arm-Fix-PAuth-sbox-functions.patch -Patch0166: tests-Disalbe-filemonitor-testcase.patch -Patch0167: es1370-check-total-frame-count-against-current-frame.patch -Patch0168: exec-set-map-length-to-zero-when-returning-NULL.patch -Patch0169: ati-vga-check-mm_index-before-recursive-call-CVE-202.patch -Patch0170: megasas-use-unsigned-type-for-reply_queue_head-and-c.patch -Patch0171: megasas-avoid-NULL-pointer-dereference.patch -Patch0172: megasas-use-unsigned-type-for-positive-numeric-field.patch -Patch0173: hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch -Patch0174: hw-arm-acpi-enable-SHPC-native-hot-plug.patch -Patch0175: hw-tpm-rename-Error-parameter-to-more-common-errp.patch -Patch0176: tpm-ppi-page-align-PPI-RAM.patch -Patch0177: tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch -Patch0178: spapr-Implement-get_dt_compatible-callback.patch -Patch0179: delete-the-in-tpm.txt.patch -Patch0180: tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch -Patch0181: tpm_spapr-Support-suspend-and-resume.patch -Patch0182: hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch -Patch0183: docs-specs-tpm-reST-ify-TPM-documentation.patch -Patch0184: tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch -Patch0185: tpm-Use-TPMState-as-a-common-struct.patch -Patch0186: tpm-Separate-tpm_tis-common-functions-from-isa-code.patch -Patch0187: tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch -Patch0188: tpm-Add-the-SysBus-TPM-TIS-device.patch -Patch0189: hw-arm-virt-vTPM-support.patch -Patch0190: docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch -Patch0191: test-tpm-pass-optional-machine-options-to-swtpm-test.patch -Patch0192: test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch -Patch0193: test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch -Patch0194: build-smt-processor-structure-to-support-smt-topolog.patch -Patch0195: target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch -Patch0196: target-arm-Add-ID_AA64MMFR2_EL1.patch -Patch0197: target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch -Patch0198: target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch -Patch0199: target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch -Patch0200: target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch -Patch0201: target-arm-Stop-assuming-DBGDIDR-always-exists.patch -Patch0202: target-arm-Move-DBGDIDR-into-ARMISARegisters.patch -Patch0203: target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch -Patch0204: target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch -Patch0205: target-arm-Read-debug-related-ID-registers-from-KVM.patch -Patch0206: target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch -Patch0207: target-arm-monitor-query-cpu-model-expansion-crashed.patch -Patch0208: target-arm-convert-isar-regs-to-array.patch -Patch0209: target-arm-parse-cpu-feature-related-options.patch -Patch0210: target-arm-register-CPU-features-for-property.patch -Patch0211: target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch -Patch0212: target-arm-introduce-CPU-feature-dependency-mechanis.patch -Patch0213: target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch -Patch0214: target-arm-Add-CPU-features-to-query-cpu-model-expan.patch -Patch0215: target-arm-Update-ID-fields.patch -Patch0216: target-arm-Add-more-CPU-features.patch -Patch0217: hw-usb-core-fix-buffer-overflow.patch -Patch0218: target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch -Patch0219: Drop-bogus-IPv6-messages.patch -Patch0220: hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch -Patch0221: hw-xhci-check-return-value-of-usb_packet_map.patch -Patch0222: hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch -Patch0223: hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch -Patch0224: sm501-Convert-printf-abort-to-qemu_log_mask.patch -Patch0225: sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch -Patch0226: sm501-Use-BIT-x-macro-to-shorten-constant.patch -Patch0227: sm501-Clean-up-local-variables-in-sm501_2d_operation.patch -Patch0228: sm501-Replace-hand-written-implementation-with-pixma.patch -Patch0229: pci-check-bus-pointer-before-dereference.patch -Patch0230: hw-ide-check-null-block-before-_cancel_dma_sync.patch -Patch0231: elf2dmp-Fix-memory-leak-on-main-error-paths.patch -Patch0232: io-Don-t-use-flag-of-printf-format.patch -Patch0233: hw-display-omap_lcdc-Fix-potential-NULL-pointer-dere.patch -Patch0234: hw-display-exynos4210_fimd-Fix-potential-NULL-pointe.patch -Patch0235: block-vvfat-Fix-bad-printf-format-specifiers.patch -Patch0236: block-Remove-unused-include.patch -Patch0237: ssi-Fix-bad-printf-format-specifiers.patch -Patch0238: net-l2tpv3-Remove-redundant-check-in-net_init_l2tpv3.patch -Patch0239: ati-check-x-y-display-parameter-values.patch -Patch0240: migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch -Patch0241: migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch -Patch0242: migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch -Patch0243: migration-dirtyrate-Add-dirtyrate-statistics-series-.patch -Patch0244: migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch -Patch0245: migration-dirtyrate-Record-hash-results-for-each-sam.patch -Patch0246: migration-dirtyrate-Compare-page-hash-results-for-re.patch -Patch0247: migration-dirtyrate-skip-sampling-ramblock-with-size.patch -Patch0248: migration-dirtyrate-Implement-set_sample_page_period.patch -Patch0249: migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch -Patch0250: migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch -Patch0251: migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch -Patch0252: migration-dirtyrate-record-start_time-and-calc_time-.patch -Patch0253: migration-dirtyrate-present-dirty-rate-only-when-que.patch -Patch0254: migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch -Patch0255: migration-tls-save-hostname-into-MigrationState.patch -Patch0256: migration-tls-extract-migration_tls_client_create-fo.patch -Patch0257: migration-tls-add-tls_hostname-into-MultiFDSendParam.patch -Patch0258: migration-tls-extract-cleanup-function-for-common-us.patch -Patch0259: migration-tls-add-support-for-multifd-tls-handshake.patch -Patch0260: migration-tls-add-trace-points-for-multifd-tls.patch -Patch0261: qemu-file-Don-t-do-IO-after-shutdown.patch -Patch0262: multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch -Patch0263: migration-Don-t-send-data-if-we-have-stopped.patch -Patch0264: migration-Create-migration_is_running.patch -Patch0265: migration-fix-COLO-broken-caused-by-a-previous-commi.patch -Patch0266: migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch -Patch0267: multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch -Patch0268: net-remove-an-assert-call-in-eth_get_gso_type.patch -Patch0269: json-Fix-a-memleak-in-parse_pair.patch -Patch0270: Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch -Patch0271: slirp-check-pkt_len-before-reading-protocol-header.patch -Patch0272: hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch -Patch0273: hw-ehci-check-return-value-of-usb_packet_map.patch -Patch0274: hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch -Patch0275: hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch -Patch0276: hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch -Patch0277: target-arm-Fix-write-redundant-values-to-kvm.patch -Patch0278: memory-clamp-cached-translation-in-case-it-points-to.patch -Patch0279: scsi-bus-Refactor-the-code-that-retries-requests.patch -Patch0280: scsi-disk-Add-support-for-retry-on-errors.patch -Patch0281: qapi-block-core-Add-retry-option-for-error-action.patch -Patch0282: block-backend-Introduce-retry-timer.patch -Patch0283: block-backend-Add-device-specific-retry-callback.patch -Patch0284: block-backend-Enable-retry-action-on-errors.patch -Patch0285: block-backend-Add-timeout-support-for-retry.patch -Patch0286: block-Add-error-retry-param-setting.patch -Patch0287: virtio-blk-Refactor-the-code-that-processes-queued-r.patch -Patch0288: virtio-blk-On-restart-process-queued-requests-in-the.patch -Patch0289: virtio_blk-Add-support-for-retry-on-errors.patch -Patch0290: migration-Add-multi-thread-compress-method.patch -Patch0291: migration-Refactoring-multi-thread-compress-migratio.patch -Patch0292: migration-Add-multi-thread-compress-ops.patch -Patch0293: migration-Add-zstd-support-in-multi-thread-compressi.patch -Patch0294: migration-Add-compress_level-sanity-check.patch -Patch0295: doc-Update-multi-thread-compression-doc.patch -Patch0296: configure-Enable-test-and-libs-for-zstd.patch -Patch0297: ati-use-vga_read_byte-in-ati_cursor_define.patch -Patch0298: sd-sdhci-assert-data_count-is-within-fifo_buffer.patch -Patch0299: msix-add-valid.accepts-methods-to-check-address.patch -Patch0300: ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch -Patch0301: block-backend-Stop-retrying-when-draining.patch -Patch0302: migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch -Patch0303: migration-tls-fix-inverted-semantics-in-multifd_chan.patch -Patch0304: migration-tls-add-error-handling-in-multifd_tls_hand.patch -Patch0305: net-vmxnet3-validate-configuration-values-during-act.patch -Patch0306: block-Add-sanity-check-when-setting-retry-parameters.patch -Patch0307: hw-pci-host-add-pci-intack-write-method.patch -Patch0308: pci-host-add-pcie-msi-read-method.patch -Patch0309: vfio-add-quirk-device-write-method.patch -Patch0310: prep-add-ppc-parity-write-method.patch -Patch0311: nvram-add-nrf51_soc-flash-read-method.patch -Patch0312: spapr_pci-add-spapr-msi-read-method.patch -Patch0313: tz-ppc-add-dummy-read-write-methods.patch -Patch0314: imx7-ccm-add-digprog-mmio-write-method.patch -Patch0315: util-cacheinfo-fix-crash-when-compiling-with-uClibc.patch -Patch0316: arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch -Patch0317: blockjob-Fix-crash-with-IOthread-when-block-commit-a.patch -Patch0318: vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch -Patch0319: vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch -Patch0320: vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch -Patch0321: vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch -Patch0322: vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch -Patch0323: vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch -Patch0324: vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch -Patch0325: ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch -Patch0326: hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch -Patch0327: usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch -Patch0328: hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch -Patch0329: x86-Intel-AVX512_BF16-feature-enabling.patch -Patch0330: i386-Add-MSR-feature-bit-for-MDS-NO.patch -Patch0331: i386-Add-macro-for-stibp.patch -Patch0332: i386-Add-new-CPU-model-Cooperlake.patch -Patch0333: target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch -Patch0334: target-i386-Add-missed-security-features-to-Cooperla.patch -Patch0335: target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch -Patch0336: target-i386-Export-TAA_NO-bit-to-guests.patch -Patch0337: target-i386-Introduce-Denverton-CPU-model.patch -Patch0338: target-i386-Add-Snowridge-v2-no-MPX-CPU-model.patch -Patch0339: i386-Add-CPUID-bit-for-CLZERO-and-XSAVEERPTR.patch -Patch0340: crypto-add-support-for-nettle-s-native-XTS-impl.patch -Patch0341: crypto-add-support-for-gcrypt-s-native-XTS-impl.patch -Patch0342: tests-benchmark-crypto-with-fixed-data-size-not-time.patch -Patch0343: tests-allow-filtering-crypto-cipher-benchmark-tests.patch -Patch0344: target-i386-handle-filtered_features-in-a-new-functi.patch -Patch0345: target-i386-introduce-generic-feature-dependency-mec.patch -Patch0346: target-i386-expand-feature-words-to-64-bits.patch -Patch0347: target-i386-add-VMX-definitions.patch -Patch0348: vmxcap-correct-the-name-of-the-variables.patch -Patch0349: target-i386-add-VMX-features.patch -Patch0350: target-i386-work-around-KVM_GET_MSRS-bug-for-seconda.patch -Patch0351: target-i386-add-VMX-features-to-named-CPU-models.patch -Patch0352: target-i386-add-two-missing-VMX-features-for-Skylake.patch -Patch0353: target-i386-disable-VMX-features-if-nested-0.patch -Patch0354: i386-cpu-Don-t-add-unavailable_features-to-env-user_.patch -Patch0355: target-i386-do-not-set-unsupported-VMX-secondary-exe.patch -Patch0356: migration-fix-multifd_send_pages-next-channel.patch -Patch0357: migration-Make-sure-that-we-don-t-call-write-in-case.patch -Patch0358: virtio-don-t-enable-notifications-during-polling.patch -Patch0359: usbredir-Prevent-recursion-in-usbredir_write.patch -Patch0360: xhci-recheck-slot-status.patch -Patch0361: vhost-Add-names-to-section-rounded-warning.patch -Patch0362: vhost-user-Print-unexpected-slave-message-types.patch -Patch0363: contrib-libvhost-user-Protect-slave-fd-with-mutex.patch -Patch0364: libvhost-user-Fix-some-memtable-remap-cases.patch -Patch0365: xics-Don-t-deassert-outputs.patch -Patch0366: i386-Resolve-CPU-models-to-v1-by-default.patch -Patch0367: block-curl-HTTP-header-fields-allow-whitespace-aroun.patch -Patch0368: block-curl-HTTP-header-field-names-are-case-insensit.patch -Patch0369: backup-Improve-error-for-bdrv_getlength-failure.patch -Patch0370: mirror-Make-sure-that-source-and-target-size-match.patch -Patch0371: iotests-143-Create-socket-in-SOCK_DIR.patch -Patch0372: nbd-server-Avoid-long-error-message-assertions-CVE-2.patch -Patch0373: block-Call-attention-to-truncation-of-long-NBD-expor.patch -Patch0374: qemu-img-convert-Don-t-pre-zero-images.patch -Patch0375: qcow2-Fix-qcow2_alloc_cluster_abort-for-external-dat.patch -Patch0376: mirror-Wait-only-for-in-flight-operations.patch -Patch0377: virtio-net-delete-also-control-queue-when-TX-RX-dele.patch -Patch0378: target-i386-enable-monitor-and-ucode-revision-with-c.patch -Patch0379: target-i386-set-the-CPUID-level-to-0x14-on-old-machi.patch -Patch0380: target-i386-kvm-initialize-feature-MSRs-very-early.patch -Patch0381: target-i386-add-a-ucode-rev-property.patch -Patch0382: migration-use-migration_is_active-to-represent-activ.patch -Patch0383: migration-Rate-limit-inside-host-pages.patch -Patch0384: hw-pci-pcie-Move-hot-plug-capability-check-to-pre_pl.patch -Patch0385: qapi-block-core-Introduce-BackupCommon.patch -Patch0386: drive-backup-create-do_backup_common.patch -Patch0387: blockdev-backup-utilize-do_backup_common.patch -Patch0388: qapi-add-BitmapSyncMode-enum.patch -Patch0389: block-backup-Add-mirror-sync-mode-bitmap.patch -Patch0390: block-backup-add-never-policy-to-bitmap-sync-mode.patch -Patch0391: block-backup-loosen-restriction-on-readonly-bitmaps.patch -Patch0392: block-backup-hoist-bitmap-check-into-QMP-interface.patch -Patch0393: block-backup-deal-with-zero-detection.patch -Patch0394: mirror-Fix-bdrv_has_zero_init-use.patch -Patch0395: blockdev-fix-coding-style-issues-in-drive_backup_pre.patch -Patch0396: blockdev-unify-qmp_drive_backup-and-drive-backup-tra.patch -Patch0397: blockdev-unify-qmp_blockdev_backup-and-blockdev-back.patch -Patch0398: blockdev-honor-bdrv_try_set_aio_context-context-requ.patch -Patch0399: blockdev-Return-bs-to-the-proper-context-on-snapshot.patch -Patch0400: block-Fix-cross-AioContext-blockdev-snapshot.patch -Patch0401: vl-Don-t-mismatch-g_strsplit-g_free.patch -Patch0402: seqlock-fix-seqlock_write_unlock_impl-function.patch -Patch0403: target-i386-kvm-initialize-microcode-revision-from-K.patch -Patch0404: target-i386-check-for-availability-of-MSR_IA32_UCODE.patch -Patch0405: hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch -Patch0406: Fixed-integer-overflow-in-e1000e.patch -Patch0407: migration-fix-cleanup_bh-leak-on-resume.patch -Patch0408: qmp-fix-leak-on-callbacks-that-return-both-value-and.patch -Patch0409: qga-commands-posix-fix-use-after-free-of-local_err.patch -Patch0410: file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch -Patch0411: object-return-self-in-object_ref.patch -Patch0412: lm32-do-not-leak-memory-on-object_new-object_unref.patch -Patch0413: cris-do-not-leak-struct-cris_disasm_data.patch -Patch0414: hppa-fix-leak-from-g_strdup_printf.patch -Patch0415: mcf5208-fix-leak-from-qemu_allocate_irqs.patch -Patch0416: microblaze-fix-leak-of-fdevice-tree-blob.patch -Patch0417: ide-fix-leak-from-qemu_allocate_irqs.patch -Patch0418: make-check-unit-use-after-free-in-test-opts-visitor.patch -Patch0419: xhci-fix-valid.max_access_size-to-access-address-reg.patch -Patch0420: qga-fix-assert-regression-on-guest-shutdown.patch -Patch0421: char-fix-use-after-free-with-dup-chardev-reconnect.patch -Patch0422: migration-Count-new_dirty-instead-of-real_dirty.patch -Patch0423: qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch -Patch0424: chardev-tcp-Fix-error-message-double-free-error.patch -Patch0425: colo-compare-Fix-memory-leak-in-packet_enqueue.patch -Patch0426: hw-block-nvme-fix-pin-based-interrupt-behavior.patch -Patch0427: hw-block-nvme-fix-pci-doorbell-size-calculation.patch -Patch0428: virtio-pci-fix-queue_enable-write.patch -Patch0429: hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch -Patch0430: linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch -Patch0431: migration-rdma-cleanup-rdma-context-before-g_free-to.patch -Patch0432: pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch -Patch0433: block-qcow2-do-free-crypto_opts-in-qcow2_close.patch -Patch0434: qemu-img-free-memory-before-re-assign.patch -Patch0435: block-qcow2-threads-fix-qcow2_decompress.patch -Patch0436: block-Avoid-memleak-on-qcow2-image-info-failure.patch -Patch0437: block-bdrv_set_backing_bs-fix-use-after-free.patch -Patch0438: hmp-vnc-Fix-info-vnc-list-leak.patch -Patch0439: migration-colo-fix-use-after-free-of-local_err.patch -Patch0440: migration-ram-fix-use-after-free-of-local_err.patch -Patch0441: block-mirror-fix-use-after-free-of-local_err.patch -Patch0442: block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch -Patch0443: virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch -Patch0444: virtio-blk-delete-vqs-on-the-error-path-in-realize.patch -Patch0445: fix-vhost_user_blk_watch-crash.patch -Patch0446: vhost-user-blk-delay-vhost_user_blk_disconnect.patch -Patch0447: usbredir-fix-buffer-overflow-on-vmload.patch -Patch0448: display-bochs-display-fix-memory-leak.patch -Patch0449: audio-fix-integer-overflow.patch -Patch0450: migration-multifd-clean-pages-after-filling-packet.patch -Patch0451: migration-multifd-not-use-multifd-during-postcopy.patch -Patch0452: migration-Define-VMSTATE_INSTANCE_ID_ANY.patch -Patch0453: migration-Change-SaveStateEntry.instance_id-into-uin.patch -Patch0454: apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch -Patch0455: virtio-add-ability-to-delete-vq-through-a-pointer.patch -Patch0456: virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch -Patch0457: virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch -Patch0458: vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch -Patch0459: vhost-user-blk-convert-to-new-virtio_delete_queue.patch -Patch0460: block-nbd-extract-the-common-cleanup-code.patch -Patch0461: virtio-gracefully-handle-invalid-region-caches.patch -Patch0462: migration-savevm-release-gslist-after-dump_vmstate_j.patch -Patch0463: virtio-input-fix-memory-leak-on-unrealize.patch -Patch0464: target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch -Patch0465: target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch -Patch0466: target-arm-Update-the-ID-registers-of-Kunpeng-920.patch -Patch0467: hw-net-fix-vmxnet3-live-migration.patch -Patch0468: include-Make-headers-more-self-contained.patch -Patch0469: migration-register_savevm_live-doesn-t-need-dev.patch -Patch0470: vmstate-add-qom-interface-to-get-id.patch -Patch0471: linux-headers-Update-against-Add-migration-support-f.patch -Patch0472: vfio-Add-function-to-unmap-VFIO-region.patch -Patch0473: vfio-Add-vfio_get_object-callback-to-VFIODeviceOps.patch -Patch0474: vfio-Add-save-and-load-functions-for-VFIO-PCI-device.patch -Patch0475: vfio-Add-migration-region-initialization-and-finaliz.patch -Patch0476: vfio-Add-VM-state-change-handler-to-know-state-of-VM.patch -Patch0477: vfio-Add-migration-state-change-notifier.patch -Patch0478: vfio-Register-SaveVMHandlers-for-VFIO-device.patch -Patch0479: vfio-Add-save-state-functions-to-SaveVMHandlers.patch -Patch0480: vfio-Add-load-state-functions-to-SaveVMHandlers.patch -Patch0481: memory-Set-DIRTY_MEMORY_MIGRATION-when-IOMMU-is-enab.patch -Patch0482: vfio-Get-migration-capability-flags-for-container.patch -Patch0483: vfio-Add-function-to-start-and-stop-dirty-pages-trac.patch -Patch0484: vfio-Add-vfio_listener_log_sync-to-mark-dirty-pages.patch -Patch0485: vfio-Dirty-page-tracking-when-vIOMMU-is-enabled.patch -Patch0486: vfio-Add-ioctl-to-get-dirty-pages-bitmap-during-dma-.patch -Patch0487: vfio-Make-vfio-pci-device-migration-capable.patch -Patch0488: qapi-Add-VFIO-devices-migration-stats-in-Migration-s.patch -Patch0489: vfio-Move-the-saving-of-the-config-space-to-the-righ.patch -Patch0490: vfio-Set-the-priority-of-the-VFIO-VM-state-change-ha.patch -Patch0491: vfio-Avoid-disabling-and-enabling-vectors-repeatedly.patch -Patch0492: kvm-split-too-big-memory-section-on-several-memslots.patch -Patch0493: kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch -Patch0494: accel-kvm-Fix-memory-waste-under-mismatch-page-size.patch -Patch0495: memory-Skip-dirty-tracking-for-un-migratable-memory-.patch -Patch0496: Fix-use-after-free-in-vfio_migration_probe.patch -Patch0497: vfio-Make-migration-support-experimental.patch -Patch0498: vfio-Change-default-dirty-pages-tracking-behavior-du.patch -Patch0499: vfio-Fix-vfio_listener_log_sync-function-name-typo.patch -Patch0500: vfio-Support-host-translation-granule-size.patch -Patch0501: vfio-migrate-Move-switch-of-dirty-tracking-into-vfio.patch -Patch0502: vfio-Fix-unregister-SaveVMHandler-in-vfio_migration_.patch -Patch0503: migration-ram-Reduce-unnecessary-rate-limiting.patch -Patch0504: migration-ram-Optimize-ram_save_host_page.patch -Patch0505: qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch -Patch0506: linux-headers-update-against-5.10-and-manual-clear-v.patch -Patch0507: vfio-Maintain-DMA-mapping-range-for-the-container.patch -Patch0508: vfio-migration-Add-support-for-manual-clear-vfio-dir.patch -Patch0509: hw-arm-smmuv3-Support-16K-translation-granule.patch -Patch0510: hw-arm-smmuv3-Set-the-restoration-priority-of-the-vS.patch -Patch0511: hw-vfio-common-trace-vfio_connect_container-operatio.patch -Patch0512: update-linux-headers-Import-iommu.h.patch -Patch0513: vfio.h-and-iommu.h-header-update-against-5.10.patch -Patch0514: memory-Add-new-fields-in-IOTLBEntry.patch -Patch0515: hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch -Patch0516: hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch -Patch0517: memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch -Patch0518: memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch -Patch0519: memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch -Patch0520: iommu-Introduce-generic-header.patch -Patch0521: pci-introduce-PCIPASIDOps-to-PCIDevice.patch -Patch0522: vfio-Force-nested-if-iommu-requires-it.patch -Patch0523: vfio-Introduce-hostwin_from_range-helper.patch -Patch0524: vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch -Patch0525: vfio-Set-up-nested-stage-mappings.patch -Patch0526: vfio-Pass-stage-1-MSI-bindings-to-the-host.patch -Patch0527: vfio-Helper-to-get-IRQ-info-including-capabilities.patch -Patch0528: vfio-pci-Register-handler-for-iommu-fault.patch -Patch0529: vfio-pci-Set-up-the-DMA-FAULT-region.patch -Patch0530: vfio-pci-Implement-the-DMA-fault-handler.patch -Patch0531: hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch -Patch0532: hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch -Patch0533: hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch -Patch0534: hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch -Patch0535: hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch -Patch0536: hw-arm-smmuv3-Implement-fault-injection.patch -Patch0537: hw-arm-smmuv3-Allow-MAP-notifiers.patch -Patch0538: pci-Add-return_page_response-pci-ops.patch -Patch0539: vfio-pci-Implement-return_page_response-page-respons.patch -Patch0540: vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch -Patch0541: vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch -Patch0542: vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch -Patch0543: vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch -Patch0544: vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch -Patch0545: hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch +Source4: BinDir.tar.gz + +Patch0001: net-dump.c-Suppress-spurious-compiler-warning.patch +Patch0002: cpu-parse-feature-to-avoid-failure.patch +Patch0003: cpu-add-Kunpeng-920-cpu-support.patch +Patch0004: cpu-add-Cortex-A72-processor-kvm-target-support.patch +Patch0005: add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch +Patch0006: qapi-block-core-Add-retry-option-for-error-action.patch +Patch0007: block-backend-Introduce-retry-timer.patch +Patch0008: block-backend-Add-device-specific-retry-callback.patch +Patch0009: block-backend-Enable-retry-action-on-errors.patch +Patch0010: block-backend-Add-timeout-support-for-retry.patch +Patch0011: block-Add-error-retry-param-setting.patch +Patch0012: virtio_blk-Add-support-for-retry-on-errors.patch +Patch0013: vhost-cancel-migration-when-vhost-user-restarted-dur.patch +Patch0014: migration-Add-multi-thread-compress-method.patch +Patch0015: migration-Refactoring-multi-thread-compress-migratio.patch +Patch0016: migration-Add-multi-thread-compress-ops.patch +Patch0017: migration-Add-zstd-support-in-multi-thread-compressi.patch +Patch0018: migration-Add-compress_level-sanity-check.patch +Patch0019: doc-Update-multi-thread-compression-doc.patch +Patch0020: Revert-cpu-parse-feature-to-avoid-failure.patch +Patch0021: Revert-cpu-add-Cortex-A72-processor-kvm-target-suppo.patch +Patch0022: cpu-add-Cortex-A72-processor-kvm-target-support-v2.patch +Patch0023: hugepages-hugepages-files-maybe-leftover.patch +Patch0024: target-i386-Modify-the-VM-s-physical-bits-value-set-.patch +Patch0025: vfio-pci-Ascend310-need-4Bytes-quirk-in-bar4.patch +Patch0026: vfio-pci-Ascend710-need-4Bytes-quirk-in-bar0.patch +Patch0027: vfio-pci-Ascend910-need-4Bytes-quirk-in-bar0.patch +Patch0028: scsi-bus-Refactor-the-code-that-retries-requests.patch +Patch0029: scsi-disk-Add-support-for-retry-on-errors.patch +Patch0030: block-backend-Stop-retrying-when-draining.patch +Patch0031: block-Add-sanity-check-when-setting-retry-parameters.patch +Patch0032: migration-skip-cache_drop-for-bios-bootloader-and-nv.patch +Patch0033: ps2-fix-oob-in-ps2-kbd.patch +Patch0034: Currently-while-kvm-and-qemu-can-not-handle-some-kvm.patch +Patch0035: cpu-features-fix-bug-for-memory-leakage.patch +Patch0036: monitor-qmp-drop-inflight-rsp-if-qmp-client-broken.patch +Patch0037: oslib-posix-optimise-vm-startup-time-for-1G-hugepage.patch +Patch0038: nbd-server.c-fix-invalid-read-after-client-was-alrea.patch +Patch0039: qemu-nbd-make-native-as-the-default-aio-mode.patch +Patch0040: qemu-nbd-set-timeout-to-qemu-nbd-socket.patch +Patch0041: qemu-pr-fixed-ioctl-failed-for-multipath-disk.patch +Patch0042: block-enable-cache-mode-of-empty-cdrom.patch +Patch0043: block-disallow-block-jobs-when-there-is-a-BDRV_O_INA.patch +Patch0044: scsi-cdrom-Fix-crash-after-remote-cdrom-detached.patch +Patch0045: block-bugfix-disable-process-AIO-when-attach-scsi-di.patch +Patch0046: block-bugfix-Don-t-pause-vm-when-NOSPACE-EIO-happene.patch +Patch0047: scsi-bugfix-fix-division-by-zero.patch +Patch0048: i386-cache-passthrough-Update-Intel-CPUID4.EAX-25-14.patch +Patch0049: i386-cache-passthrough-Update-AMD-8000_001D.EAX-25-1.patch +Patch0050: target-arm-convert-isar-regs-to-array.patch +Patch0051: target-arm-parse-cpu-feature-related-options.patch +Patch0052: target-arm-register-CPU-features-for-property.patch +Patch0053: target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch +Patch0054: target-arm-introduce-CPU-feature-dependency-mechanis.patch +Patch0055: target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch +Patch0056: target-arm-Add-CPU-features-to-query-cpu-model-expan.patch +Patch0057: target-arm-Add-more-CPU-features.patch +Patch0058: target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch +Patch0059: target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch +Patch0060: target-arm-Fix-write-redundant-values-to-kvm.patch +Patch0061: target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch +Patch0062: target-arm-Update-the-ID-registers-of-Kunpeng-920.patch +Patch0063: freeclock-add-qmp-command-to-get-time-offset-of-vm-i.patch +Patch0064: freeclock-set-rtc_date_diff-for-arm.patch +Patch0065: freeclock-set-rtc_date_diff-for-X86.patch +Patch0066: hw-usb-reduce-the-vpcu-cost-of-UHCI-when-VNC-disconn.patch +Patch0067: hw-net-rocker-fix-security-vulnerability.patch +Patch0068: tests-Disable-filemonitor-testcase.patch +Patch0069: seabios-convert-value-of-be16_to_cpu-to-u64-before-s.patch +Patch0070: seabios-do-not-give-back-high-ram.patch +Patch0071: seabios-drop-yield-in-smp_setup.patch +Patch0072: seabios-fix-memory-leak-when-pci-check.patch +Patch0073: seabios-increase-the-seabios-high-mem-zone-size.patch +Patch0074: seabios-increase-the-seabios-minibiostable.patch +Patch0075: IPv6-add-support-for-IPv6-protocol.patch +Patch0076: Use-post-increment-only-in-inffast.c.patch +Patch0077: util-log-add-CONFIG_DISABLE_QEMU_LOG-macro.patch +Patch0078: log-Add-some-logs-on-VM-runtime-path.patch +Patch0079: qdev-monitors-Fix-reundant-error_setg-of-qdev_add_de.patch +Patch0080: bios-tables-test-Allow-changes-to-q35-SSDT.dimmpxm-f.patch +Patch0081: smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch +Patch0082: net-eepro100-validate-various-address-valuesi-CVE-20.patch +Patch0083: pci-check-bus-pointer-before-dereference.patch +Patch0084: ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch +Patch0085: tap-return-err-when-tap-TUNGETIFF-fail.patch +Patch0086: xhci-check-reg-to-avoid-OOB-read.patch +Patch0087: monitor-Discard-BLOCK_IO_ERROR-event-when-VM-reboote.patch +Patch0088: monitor-limit-io-error-qmp-event-to-at-most-once-per.patch +Patch0089: linux-headers-update-against-5.10-and-manual-clear-v.patch +Patch0090: vfio-Maintain-DMA-mapping-range-for-the-container.patch +Patch0091: vfio-migration-Add-support-for-manual-clear-vfio-dir.patch +Patch0092: update-linux-headers-Import-iommu.h.patch +Patch0093: vfio.h-and-iommu.h-header-update-against-5.10.patch +Patch0094: memory-Add-new-fields-in-IOTLBEntry.patch +Patch0095: hw-arm-smmuv3-Improve-stage1-ASID-invalidation.patch +Patch0096: hw-arm-smmu-common-Allow-domain-invalidation-for-NH_.patch +Patch0097: memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memory-regio.patch +Patch0098: memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-memory-reg.patch +Patch0099: memory-Introduce-IOMMU-Memory-Region-inject_faults-A.patch +Patch0100: iommu-Introduce-generic-header.patch +Patch0101: pci-introduce-PCIPASIDOps-to-PCIDevice.patch +Patch0102: vfio-Force-nested-if-iommu-requires-it.patch +Patch0103: vfio-Introduce-hostwin_from_range-helper.patch +Patch0104: vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch +Patch0105: vfio-Set-up-nested-stage-mappings.patch +Patch0106: vfio-Pass-stage-1-MSI-bindings-to-the-host.patch +Patch0107: vfio-Helper-to-get-IRQ-info-including-capabilities.patch +Patch0108: vfio-pci-Register-handler-for-iommu-fault.patch +Patch0109: vfio-pci-Set-up-the-DMA-FAULT-region.patch +Patch0110: vfio-pci-Implement-the-DMA-fault-handler.patch +Patch0111: hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribute.patch +Patch0112: hw-arm-smmuv3-Store-the-PASID-table-GPA-in-the-trans.patch +Patch0113: hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-NH_VA-i.patch +Patch0114: hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-on-NH_V.patch +Patch0115: hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch +Patch0116: hw-arm-smmuv3-Implement-fault-injection.patch +Patch0117: hw-arm-smmuv3-Allow-MAP-notifiers.patch +Patch0118: pci-Add-return_page_response-pci-ops.patch +Patch0119: vfio-pci-Implement-return_page_response-page-respons.patch +Patch0120: vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch +Patch0121: vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch +Patch0122: vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch +Patch0123: vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch +Patch0124: vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch +Patch0125: hw-arm-smmuv3-Post-load-stage-1-configurations-to-th.patch +Patch0126: vfio-common-Fix-incorrect-address-alignment-in-vfio_.patch +Patch0127: vfio-common-Add-address-alignment-check-in-vfio_list.patch +Patch0128: log-Add-log-at-boot-cpu-init-for-aarch64.patch +Patch0129: feature-Add-log-for-each-modules.patch +Patch0130: feature-Add-logs-for-vm-start-and-destroy.patch +Patch0131: bugfix-fix-some-illegal-memory-access-and-memory-lea.patch +Patch0132: bugfix-fix-possible-memory-leak.patch +Patch0133: bugfix-fix-eventfds-may-double-free-when-vm_id-reuse.patch +Patch0134: block-mirror-fix-file-system-went-to-read-only-after.patch +Patch0135: bugfix-fix-mmio-information-leak-and-ehci-vm-escape-.patch +Patch0136: target-i386-Fix-the-RES-memory-inc-which-caused-by-t.patch +Patch0137: virtio-scsi-bugfix-fix-qemu-crash-for-hotplug-scsi-d.patch +Patch0138: virtio-net-tap-bugfix-del-net-client-if-net_init_tap.patch +Patch0139: virtio-bugfix-clean-up-callback-when-del-virtqueue.patch +Patch0140: virtio-net-bugfix-do-not-delete-netdev-before-virtio.patch +Patch0141: virtio-net-fix-max-vring-buf-size-when-set-ring-num.patch +Patch0142: virtio-check-descriptor-numbers.patch +Patch0143: virtio-bugfix-add-rcu_read_lock-when-vring_avail_idx.patch +Patch0144: virtio-print-the-guest-virtio_net-features-that-host.patch +Patch0145: virtio-bugfix-check-the-value-of-caches-before-acces.patch +Patch0146: virtio-net-set-the-max-of-queue-size-to-4096.patch +Patch0147: virtio-net-update-the-default-and-max-of-rx-tx_queue.patch +Patch0148: vhost-user-add-unregister_savevm-when-vhost-user-cle.patch +Patch0149: qemu-img-block-dont-blk_make_zero-if-discard_zeroes-.patch +Patch0150: vhost-user-Add-support-reconnect-vhost-user-socket.patch +Patch0151: vhost-user-Set-the-acked_features-to-vm-s-featrue.patch +Patch0152: vhost-user-add-vhost_set_mem_table-when-vm-load_setu.patch +Patch0153: vhost-user-add-separate-memslot-counter-for-vhost-us.patch +Patch0154: vhost-user-quit-infinite-loop-while-used-memslots-is.patch +Patch0155: qmp-add-command-to-query-used-memslots-of-vhost-net-.patch +Patch0156: vhost-user-scsi-add-support-for-SPDK-hot-upgrade.patch +Patch0157: i6300esb-watchdog-bugfix-Add-a-runstate-transition.patch +Patch0158: bugfix-irq-Avoid-covering-object-refcount-of-qemu_ir.patch +Patch0159: seabios-add-check-to-avoid-dereference-NULL-pointer.patch +Patch0160: qemu-img-add-qemu-img-direct-create.patch +Patch0161: log-Delete-redudant-qemu_log.patch +Patch0162: bios-tables-test-Update-expected-q35-SSDT.dimmpxm-fi.patch +Patch0163: qapi-machine.json-Fix-incorrect-description-for-die-.patch +Patch0164: tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch +Patch0165: tests-unit-test-smp-parse-Split-the-generic-test-in-.patch +Patch0166: tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch +Patch0167: tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch +Patch0168: tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch +Patch0169: tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch +Patch0170: tests-unit-test-smp-parse-Constify-some-pointer-stru.patch +Patch0171: hw-core-Rename-smp_parse-machine_parse_smp_config.patch +Patch0172: qemu-options-Improve-readability-of-SMP-related-Docs.patch +Patch0173: hw-core-machine-Introduce-CPU-cluster-topology-suppo.patch +Patch0174: tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch +Patch0175: tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch +Patch0176: tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch +Patch0177: hw-arm-virt-Support-CPU-cluster-on-ARM-virt-machine.patch +Patch0178: hw-arm-virt-Support-cluster-level-in-DT-cpu-map.patch +Patch0179: hw-acpi-aml-build-Improve-scalability-of-PPTT-genera.patch +Patch0180: tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch +Patch0181: hw-acpi-aml-build-Support-cluster-level-in-PPTT-gene.patch +Patch0182: tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch +Patch0183: softmmu-device_tree-Silence-compiler-warning-with-en.patch +Patch0184: softmmu-device_tree-Remove-redundant-pointer-assignm.patch +Patch0185: hw-arm64-add-vcpu-cache-info-support.patch +Patch0186: arm64-Add-the-cpufreq-device-to-show-cpufreq-info-to.patch +Patch0187: Revert-qmp-add-command-to-query-used-memslots-of-vho.patch +Patch0188: target-arm-Fix-some-compile-errors.patch +Patch0189: pl031-support-rtc-timer-property-for-pl031.patch +Patch0190: i386-cpu-fix-compile-error-in-all-target-configure.patch +Patch0191: acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch +Patch0192: hw-arm-virt-Assign-virt_madt_cpu_entry-to-acpi_ged-m.patch +Patch0193: arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch +Patch0194: acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch +Patch0195: acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch +Patch0196: arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch +Patch0197: tests-acpi-bios-tables-test-Allow-changes-to-virt-DS.patch +Patch0198: arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch +Patch0199: tests-acpi-bios-table-test-Update-expected-virt-DSDT.patch +Patch0200: arm-virt-Add-CPU-hotplug-framework.patch +Patch0201: arm-virt-Add-CPU-topology-support.patch +Patch0202: test-numa-Adjust-aarch64-numa-test.patch +Patch0203: hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch +Patch0204: hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch +Patch0205: arm-virt-gic-Construct-irqs-connection-from-create_g.patch +Patch0206: intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch +Patch0207: intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch +Patch0208: intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch +Patch0209: hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch +Patch0210: accel-kvm-Add-pre-park-vCPU-support.patch +Patch0211: intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch +Patch0212: acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch +Patch0213: arm-virt-Add-cpu_hotplug_enabled-field.patch +Patch0214: arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch +Patch0215: arm-virt-Pre-sizing-MADT-GICC-GICv3-and-Pre-park-KVM.patch +Patch0216: arm-virt-Start-up-CPU-hot-plug-and-cold-plug.patch +Patch0217: pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch +Patch0218: qcow2-fix-memory-leak-in-qcow2_read_extensions.patch +Patch0219: scsi-disk-define-props-in-scsi_block_disk-to-avoid-m.patch +Patch0220: pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch +Patch0221: pcie-Compat-with-devices-which-do-not-support-Link-W.patch +Patch0222: scsi-bus-fix-unmatched-object_unref.patch +Patch0223: tools-virtiofsd-Add-rseq-syscall-to-the-seccomp-allo.patch +Patch0224: sw_64-Add-sw64-architecture-support.patch +Patch0225: coro-support-live-patch-for-libcare.patch +Patch0226: qemu-img-create-cache-paramter-only-use-for-reg-file.patch +Patch0227: scsi-bus-fix-incorrect-call-for-blk_error_retry_rese.patch +Patch0228: Revert-monitor-limit-io-error-qmp-event-to-at-most-o.patch +Patch0229: vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch +Patch0230: virtio-net-fix-map-leaking-on-error-during-receive.patch +Patch0231: vfio-pci-Ascend710-change-to-bar2-quirk.patch +Patch0232: display-qxl-render-fix-race-condition-in-qxl_cursor-.patch +Patch0233: ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch +Patch0234: hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch +Patch0235: softmmu-physmem-Simplify-flatview_write-and-address_.patch +Patch0236: softmmu-physmem-Introduce-MemTxAttrs-memory-field-an.patch +Patch0237: acpi-modify-build_ppt-del-macro-add-arm-build_pptt.patch +Patch0238: acpi-fix-QEMU-crash-when-started-with-SLIC-table.patch +Patch0239: tests-acpi-whitelist-expected-blobs-before-changing-.patch +Patch0240: tests-acpi-add-SLIC-table-test.patch +Patch0241: tests-acpi-SLIC-update-expected-blobs.patch +Patch0242: hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch +Patch0243: tests-qtest-fdc-test-Add-a-regression-test-for-CVE-2.patch +Patch0244: hw-scsi-megasas-Use-uint32_t-for-reply-queue-head-ta.patch +Patch0245: dma-Let-dma_memory_valid-take-MemTxAttrs-argument.patch +Patch0246: dma-Let-dma_memory_set-take-MemTxAttrs-argument.patch +Patch0247: dma-Let-dma_memory_rw_relaxed-take-MemTxAttrs-argume.patch +Patch0248: dma-Let-dma_memory_rw-take-MemTxAttrs-argument.patch +Patch0249: dma-Let-dma_memory_read-write-take-MemTxAttrs-argume.patch +Patch0250: dma-Let-dma_memory_map-take-MemTxAttrs-argument.patch +Patch0251: dma-Have-dma_buf_rw-take-a-void-pointer.patch +Patch0252: dma-Have-dma_buf_read-dma_buf_write-take-a-void-poin.patch +Patch0253: pci-Let-pci_dma_rw-take-MemTxAttrs-argument.patch +Patch0254: dma-Let-dma_buf_rw-take-MemTxAttrs-argument.patch +Patch0255: dma-Let-dma_buf_write-take-MemTxAttrs-argument.patch +Patch0256: dma-Let-dma_buf_read-take-MemTxAttrs-argument.patch +Patch0257: dma-Let-dma_buf_rw-propagate-MemTxResult.patch +Patch0258: dma-Let-st-_dma-take-MemTxAttrs-argument.patch +Patch0259: dma-Let-ld-_dma-take-MemTxAttrs-argument.patch +Patch0260: dma-Let-st-_dma-propagate-MemTxResult.patch +Patch0261: dma-Let-ld-_dma-propagate-MemTxResult.patch +Patch0262: pci-Let-st-_pci_dma-take-MemTxAttrs-argument.patch +Patch0263: pci-Let-ld-_pci_dma-take-MemTxAttrs-argument.patch +Patch0264: pci-Let-st-_pci_dma-propagate-MemTxResult.patch +Patch0265: pci-Let-ld-_pci_dma-propagate-MemTxResult.patch +Patch0266: hw-audio-intel-hda-Do-not-ignore-DMA-overrun-errors.patch +Patch0267: hw-audio-intel-hda-Restrict-DMA-engine-to-memories-n.patch +Patch0268: tests-qtest-intel-hda-test-Add-reproducer-for-issue-.patch +Patch0269: hw-nvme-fix-CVE-2021-3929.patch +Patch0270: acpi-validate-hotplug-selector-on-access.patch +Patch0271: virtiofsd-Drop-membership-of-all-supplementary-group.patch +Patch0272: softmmu-Always-initialize-xlat-in-address_space_tran.patch +Patch0273: numa-Enable-numa-for-SGX-EPC-sections.patch +Patch0274: numa-Support-SGX-numa-in-the-monitor-and-Libvirt-int.patch +Patch0275: doc-Add-the-SGX-numa-description.patch +Patch0276: qapi-Cleanup-SGX-related-comments-and-restore-sectio.patch +Patch0277: target-ppc-add-error-report-when-fopen-fails-in-kvmp.patch +Patch0278: target-ppc-enhance-error-report-in-kvmppc_read_int_c.patch +Patch0279: target-ppc-use-g_autofree-in-kvmppc_read_int_cpu_dt.patch +Patch0280: target-ppc-exit-1-on-failure-in-kvmppc_get_clockfreq.patch +Patch0281: bugfix-pointer-double-free-in-func-qemu_savevm_state.patch +Patch0282: vhost-user-remove-VirtQ-notifier-restore.patch +Patch0283: vhost-user-fix-VirtQ-notifier-cleanup.patch +Patch0284: nbd-allow-reconnect-on-open-with-corresponding-new-o.patch +Patch0285: block-nbd-Delete-reconnect-delay-timer-when-done.patch +Patch0286: block-nbd-Delete-open-timer-when-done.patch +Patch0287: block-nbd-Assert-there-are-no-timers-when-closed.patch +Patch0288: block-nbd-Move-s-ioc-on-AioContext-change.patch +Patch0289: hw-scsi-lsi53c895a-Do-not-abort-when-DMA-requested-a.patch +Patch0291: tests-qtest-Add-fuzz-lsi53c895a-test.patch +Patch0292: scsi-lsi53c895a-fix-use-after-free-in-lsi_do_msgout-.patch +Patch0293: scsi-lsi53c895a-really-fix-use-after-free-in-lsi_do_.patch +Patch0294: hw-usb-hcd-xhci-Fix-unbounded-loop-in-xhci_ring_chai.patch +Patch0295: net-tulip-Restrict-DMA-engine-to-memories.patch +Patch0296: exec-memory-Extract-address_space_set-from-dma_memor.patch +Patch0297: hw-elf_ops-clear-uninitialized-segment-space.patch +Patch0298: vhost-also-check-queue-state-in-the-vhost_dev_set_lo.patch +Patch0299: vhost-net-fix-improper-cleanup-in-vhost_net_start.patch +Patch0300: virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch +Patch0301: job.c-add-missing-notifier-initialization.patch +Patch0302: uas-add-missing-return.patch +Patch0303: qom-assert-integer-does-not-overflow.patch +Patch0304: pci-expose-TYPE_XIO3130_DOWNSTREAM-name.patch +Patch0305: acpi-pcihp-pcie-set-power-on-cap-on-parent-slot.patch +Patch0306: hw-display-ati_2d-Fix-buffer-overflow-in-ati_2d_blt-.patch +Patch0307: ui-vnc-clipboard-fix-integer-underflow-in-vnc_client.patch +Patch0308: Remove-the-unused-local-variable-records.patch +Patch0309: Remove-this-redundant-return.patch +Patch0310: hw-vhost-user-blk-turn-on-VIRTIO_BLK_F_SIZE_MAX-feat.patch +Patch0311: migration-dirtyrate-Replace-malloc-with-g_new.patch +Patch0312: accel-kvm-kvm-all-Refactor-per-vcpu-dirty-ring-reapi.patch +Patch0313: cpus-Introduce-cpu_list_generation_id.patch +Patch0314: migration-dirtyrate-Refactor-dirty-page-rate-calcula.patch +Patch0315: softmmu-dirtylimit-Implement-vCPU-dirtyrate-calculat.patch +Patch0316: accel-kvm-kvm-all-Introduce-kvm_dirty_ring_size-func.patch +Patch0317: softmmu-dirtylimit-Implement-virtual-CPU-throttle.patch +Patch0318: softmmu-dirtylimit-Implement-dirty-page-rate-limit.patch +Patch0319: tests-Add-dirty-page-rate-limit-test.patch +Patch0320: linux-headers-include-missing-changes-from-5.17.patch +Patch0321: x86-Fix-the-64-byte-boundary-enumeration-for-extende.patch +Patch0322: x86-Add-AMX-XTILECFG-and-XTILEDATA-components.patch +Patch0323: x86-Grant-AMX-permission-for-guest.patch +Patch0324: x86-Add-XFD-faulting-bit-for-state-components.patch +Patch0325: x86-Add-AMX-CPUIDs-enumeration.patch +Patch0326: x86-add-support-for-KVM_CAP_XSAVE2-and-AMX-state-mig.patch +Patch0327: x86-Support-XFD-and-AMX-xsave-data-migration.patch +Patch0328: target-i386-kvm-do-not-access-uninitialized-variable.patch +Patch0329: KVM-x86-workaround-invalid-CPUID-0xD-9-info-on-some-.patch +Patch0330: fix-compilation-errors-of-sw64-architecture-on-x86-p.patch +Patch0331: fixed-the-error-that-no-bios-file-soft-link-was-crea.patch +Patch0332: arm-virt-Fix-vcpu-hotplug-idx_from_topo_ids.patch +Patch0333: vfio-migration-Fix-incorrect-initialization-value-fo.patch +Patch0334: hostmem-default-the-amount-of-prealloc-threads-to-sm.patch +Patch0335: Revert-vfio-common-Add-address-alignment-check-in-vf.patch +Patch0336: Revert-vfio-common-Fix-incorrect-address-alignment-i.patch +Patch0337: Revert-hw-arm-smmuv3-Post-load-stage-1-configuration.patch +Patch0338: Revert-vfio-Add-vfio_prereg_listener_global_log_star.patch +Patch0339: Revert-vfio-Add-vfio_prereg_listener_log_clear-to-re.patch +Patch0340: Revert-vfio-Add-vfio_prereg_listener_log_sync-in-nes.patch +Patch0341: Revert-vfio-Introduce-helpers-to-mark-dirty-pages-of.patch +Patch0342: Revert-vfio-common-Avoid-unmap-ram-section-at-vfio_l.patch +Patch0343: Revert-vfio-pci-Implement-return_page_response-page-.patch +Patch0344: Revert-pci-Add-return_page_response-pci-ops.patch +Patch0345: Revert-hw-arm-smmuv3-Allow-MAP-notifiers.patch +Patch0346: Revert-hw-arm-smmuv3-Implement-fault-injection.patch +Patch0347: Revert-hw-arm-smmuv3-Pass-stage-1-configurations-to-.patch +Patch0348: Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-leaf-field-.patch +Patch0349: Revert-hw-arm-smmuv3-Fill-the-IOTLBEntry-arch_id-on-.patch +Patch0350: Revert-hw-arm-smmuv3-Store-the-PASID-table-GPA-in-th.patch +Patch0351: Revert-hw-arm-smmuv3-Advertise-MSI_TRANSLATE-attribu.patch +Patch0352: Revert-vfio-pci-Implement-the-DMA-fault-handler.patch +Patch0353: Revert-vfio-pci-Set-up-the-DMA-FAULT-region.patch +Patch0354: Revert-vfio-pci-Register-handler-for-iommu-fault.patch +Patch0355: Revert-vfio-Helper-to-get-IRQ-info-including-capabil.patch +Patch0356: Revert-vfio-Pass-stage-1-MSI-bindings-to-the-host.patch +Patch0357: Revert-vfio-Set-up-nested-stage-mappings.patch +Patch0359: Revert-vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM.patch +Patch0360: Revert-vfio-Introduce-hostwin_from_range-helper.patch +Patch0361: Revert-vfio-Force-nested-if-iommu-requires-it.patch +Patch0362: Revert-pci-introduce-PCIPASIDOps-to-PCIDevice.patch +Patch0363: Revert-iommu-Introduce-generic-header.patch +Patch0364: Revert-memory-Introduce-IOMMU-Memory-Region-inject_f.patch +Patch0365: Revert-memory-Add-IOMMU_ATTR_MSI_TRANSLATE-IOMMU-mem.patch +Patch0366: Revert-memory-Add-IOMMU_ATTR_VFIO_NESTED-IOMMU-memor.patch +Patch0367: Revert-hw-arm-smmu-common-Allow-domain-invalidation-.patch +Patch0368: Revert-hw-arm-smmuv3-Improve-stage1-ASID-invalidatio.patch +Patch0369: Revert-memory-Add-new-fields-in-IOTLBEntry.patch +Patch0370: Revert-vfio.h-and-iommu.h-header-update-against-5.10.patch +Patch0371: Revert-update-linux-headers-Import-iommu.h.patch +Patch0372: memory-Fix-wrong-end-address-dump.patch +Patch0373: tests-vm-use-o-IdentitiesOnly-yes-for-ssh.patch +Patch0374: linux-user-always-translate-cmsg-when-recvmsg.patch +Patch0375: target-arm-Copy-the-entire-vector-in-DO_ZIP.patch +Patch0376: hw-mem-nvdimm-fix-error-message-for-unarmed-flag.patch +Patch0377: gdb-xml-Fix-size-of-EFER-register-on-i386-architectu.patch +Patch0378: tcg-tci-fix-logic-error-when-registering-helpers-via.patch +Patch0379: virtio-mem-Don-t-skip-alignment-checks-when-warning-.patch +Patch0380: qemu-binfmt-conf.sh-fix-F-option.patch +Patch0381: Fix-several-typos-in-documentation-found-by-codespel.patch +Patch0382: hw-arm-virt-Fix-devicetree-warnings-about-the-virtio.patch +Patch0383: target-hppa-Fix-deposit-assert-from-trans_shrpw_imm.patch +Patch0384: tcg-optimize-Fix-folding-of-vector-ops.patch +Patch0385: target-arm-Add-missing-FEAT_TLBIOS-instructions.patch +Patch0386: target-riscv-pmp-fix-no-pmp-illegal-intrs.patch +Patch0387: configure-Remove-unused-python_version-variable.patch +Patch0388: configure-Remove-unused-meson_args-variable.patch +Patch0389: target-imx-reload-cmp-timer-outside-of-the-reload-pt.patch +Patch0390: configure-Add-missing-quoting-for-some-easy-cases.patch +Patch0391: hw-core-resettable-fix-reset-level-counting.patch +Patch0392: hw-usb-hcd-xhci-Reset-the-XHCIState-with-device_cold.patch +Patch0393: hw-ppc-spapr_pci.c-Use-device_cold_reset-rather-than.patch +Patch0394: hw-ide-microdrive-Use-device_cold_reset-for-self-res.patch +Patch0395: hw-i386-Use-device_cold_reset-to-reset-the-APIC.patch +Patch0396: hw-hyperv-hyperv.c-Use-device_cold_reset-instead-of-.patch +Patch0397: configure-Add-.-on-front-of-glob-of-config-devices.m.patch +Patch0398: configure-Check-mkdir-result-directly-not-via.patch +Patch0399: hw-char-pl011-fix-baud-rate-calculation.patch +Patch0400: target-i386-kvm-fix-kvmclock_current_nsec-Assertion-.patch +Patch0401: linux-headers-Update-headers-to-Linux-5.18-rc6.patch +Patch0402: virtio-get-class_id-and-pci-device-id-by-the-virtio-.patch +Patch0403: vdpa-add-vdpa-dev-support.patch +Patch0404: vdpa-add-vdpa-dev-pci-support.patch +Patch0405: vdpa-dev-mark-the-device-as-unmigratable.patch +Patch0406: docs-Add-generic-vhost-vdpa-device-documentation.patch +Patch0407: vhost-vdpa-add-memslot-getter-setter-for-vhost-vdpa.patch +Patch0408: chardev-fix-segfault-in-finalize.patch +Patch0409: tests-avocado-raspi2_initrd-Wait-for-guest-shutdown-.patch +Patch0410: Add-flex-bison-to-debian-hexagon-cross.patch +Patch0411: hw-net-can-fix-Xilinx-ZynqMP-CAN-RX-FIFO-logic.patch +Patch0412: libdecnumber-dpd-decimal64-Fix-compiler-warning-from.patch +Patch0413: Fix-several-typos-in-documentation.patch +Patch0414: tests-avocado-use-new-rootfs-for-orangepi-test.patch +Patch0415: replay-Fix-declaration-of-replay_read_next_clock.patch +Patch0416: vhost-user-Refactor-vhost-acked-features-saving.patch +Patch0417: vhost-user-Refactor-the-chr_closed_bh.patch +Patch0418: vhost-user-Fix-the-virtio-features-negotiation-flaw.patch +Patch0419: tests-qtest-libqos-e1000e-Refer-common-PCI-ID-defini.patch +Patch0420: hw-display-qxl-Have-qxl_log_command-Return-early-if-.patch +Patch0421: hw-display-qxl-Document-qxl_phys2virt.patch +Patch0422: hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch +Patch0423: hw-display-qxl-Avoid-buffer-overrun-in-qxl_phys2virt.patch +Patch0424: hw-display-qxl-Assert-memory-slot-fits-in-preallocat.patch +Patch0425: target-arm-Use-kvm_arm_sve_supported-in-kvm_arm_get_.patch +Patch0426: target-arm-Set-KVM_ARM_VCPU_SVE-while-probing-the-ho.patch +Patch0427: target-arm-Move-sve-probe-inside-kvm-4.15-branch.patch +Patch0428: migration-report-migration-related-thread-pid-to-lib.patch +Patch0429: migration-report-multiFd-related-thread-pid-to-libvi.patch +Patch0430: vhost_net-keep-acked_feature-only-for-NET_CLIENT_DRI.patch +Patch0431: linux-user-Add-strace-output-for-timer_settime64-sys.patch +Patch0432: fix-qemu-core-when-vhost-user-net-config-with-server.patch +Patch0433: fix-qmp-command-migrate-set-parameters.patch +Patch0434: hw-acpi-Add-ospm_status-hook-implementation-for-acpi.patch +Patch0435: hw-acpi-Support-acpi-ged-to-report-CPU-s-OST-info.patch +Patch0436: arm-virt-Correct-timing-of-executing-cpu_synchronize.patch +Patch0437: arm-virt-Correct-timing-of-pause-all-vcpus-for-hot-p.patch +Patch0438: hw-core-machine-Fix-the-missing-consideration-of-clu.patch +Patch0439: tests-tcg-Fix-target-specific-Makefile-variables-pat.patch +Patch0440: tests-add-riscv-virt-machine-mapping-to-testenv.patch +Patch0441: curl-Fix-error-path-in-curl_open.patch +Patch0442: hw-riscv-virt-Simplify-virt_-get-set-_aclint.patch +Patch0443: hw-pci-Fix-a-typo.patch +Patch0444: hw-pci-Trace-IRQ-routing-on-PCI-topology.patch +Patch0445: Add-PowerManager-support.patch +Patch0446: Add-RTC-support.patch +Patch0447: Add-loongarch-machine.patch +Patch0448: Add-target-loongarch64.patch +Patch0449: Add-linux-headers-and-linux-user.patch +Patch0450: Add-disas-gdb.patch +Patch0451: Add-command-line.patch +Patch0452: Add-tcg.patch +Patch0453: Add-bios.patch +Patch0454: Add-compile-script.patch +Patch0455: hw-pvrdma-Protect-against-buggy-or-malicious-guest-d.patch +Patch0456: hw-audio-intel-hda-fix-stream-reset.patch +Patch0457: dsoundaudio-fix-crackling-audio-recordings.patch +Patch0458: linux-headers-include-missing-changes-from-6.0.patch +Patch0459: i386-kvm-extend-kvm_-get-put-_vcpu_events-to-support.patch +Patch0460: kvm-allow-target-specific-accelerator-properties.patch +Patch0461: kvm-expose-struct-KVMState.patch +Patch0462: i386-add-notify-VM-exit-support.patch +Patch0463: block-backend-prevent-dangling-BDS-pointers-across-a.patch +Patch0464: net-Fix-uninitialized-data-usage.patch +Patch0465: net-eth-Don-t-consider-ESP-to-be-an-IPv6-option-head.patch +Patch0466: hw-net-vmxnet3-Log-guest-triggerable-errors-using-LO.patch +Patch0467: fixup-compile-on-loongarch64-machine.patch +Patch0468: vhost-user-blk-fix-the-resize-crash.patch +Patch0469: plugins-make-qemu_plugin_user_exit-s-locking-order-c.patch +Patch0470: linux-user-fix-strace-build-w-out-munlockall.patch +Patch0471: ui-fix-crash-on-serial-reset-during-init.patch +Patch0472: qga-win-vss-requester_freeze-changes.patch +Patch0473: migration-fix-populate_vfio_info.patch +Patch0474: block-rbd-workaround-for-ceph-issue-53784.patch +Patch0475: target-i386-add-FZRM-FSRS-FSRC.patch +Patch0476: i386-Add-new-CPU-model-SapphireRapids.patch +Patch0477: core-cpu-common-Fix-the-wrong-ifdef-__aarch64__.patch +Patch0478: target-i386-Fix-sanity-check-on-max-APIC-ID-X2APIC-e.patch +Patch0479: target-i386-Set-maximum-APIC-ID-to-KVM-prior-to-vCPU.patch +Patch0480: hw-usb-imx-Fix-out-of-bounds-access-in-imx_usbphy_re.patch +Patch0481: target-i386-Add-SGX-aex-notify-and-EDECCSSA-support.patch +Patch0482: aio-posix-fix-race-between-epoll-upgrade-and-aio_set.patch +Patch0483: hw-nvme-fix-memory-leak-in-nvme_dsm.patch +Patch0484: target-i386-add-FSRM-to-TCG.patch +Patch0485: target-i386-KVM-allow-fast-string-operations-if-host.patch +Patch0486: configure-meson-move-AVX-tests-to-meson.patch +Patch0487: AVX512-support-for-xbzrle_encode_buffer.patch +Patch0488: Update-bench-code-for-addressing-CI-problem.patch +Patch0489: migration-xbzrle-use-ctz64-to-avoid-undefined-result.patch +Patch0490: migration-xbzrle-fix-out-of-bounds-write-with-axv512.patch +Patch0491: hw-nvme-fix-missing-DNR-on-compare-failure.patch +Patch0492: virtio-fix-reachable-assertion-due-to-stale-value-of.patch +Patch0493: hw-nvme-Change-alignment-in-dma-functions-for-nvme_b.patch +Patch0494: Fix-smp.cores-value-and-Fix-divide-0-error.patch +Patch0495: Add-lbt-support-for-kvm.patch +Patch0496: migration-report-compress-thread-pid-to-libvirt.patch +Patch0497: hw-ppc-Kconfig-MAC_NEWWORLD-should-always-select-USB.patch +Patch0498: virtio-gpu-add-a-FIXME-for-virtio_gpu_load.patch +Patch0499: block-monitor-Fix-crash-when-executing-HMP-commit.patch +Patch0500: vnc-avoid-underflow-when-accessing-user-provided-add.patch +Patch0501: qga-vss-win32-fix-warning-for-clang-15.patch +Patch0502: hw-net-vmxnet3-allow-VMXNET3_MAX_MTU-itself-as-a-val.patch +Patch0503: tests-tcg-fix-unused-variable-in-linux-test.patch +Patch0504: block-iscsi-fix-double-free-on-BUSY-or-similar-statu.patch +Patch0505: vfio-pci-Fix-a-segfault-in-vfio_realize.patch +Patch0506: gitlab-Disable-plugins-for-cross-i386-tci.patch +Patch0507: tcg-Reduce-tcg_assert_listed_vecop-scope.patch +Patch0508: 9pfs-prevent-opening-special-files-CVE-2023-2861.patch +Patch0509: accel-tcg-Optimize-jump-cache-flush-during-tlb-range.patch +Patch0510: hw-net-virtio-net-make-some-VirtIONet-const.patch +Patch0511: Allow-setting-up-to-8-bytes-with-the-generic-loader.patch +Patch0512: accel-tcg-cpu-exec-Fix-precise-single-stepping-after.patch +Patch0513: hw-virtio-vdpa-Fix-leak-of-host-notifier-memory-regi.patch +Patch0514: host-vdpa-make-notifiers-_init-_uninit-symmetric.patch +Patch0515: hw-pci-bridge-pxb-Fix-missing-swizzle.patch +Patch0516: ide-Increment-BB-in-flight-counter-for-TRIM-BH.patch +Patch0517: qga-win32-Remove-change-action-from-MSI-installer.patch +Patch0518: qga-win32-Use-rundll-for-VSS-installation.patch +Patch0519: test-vmstate-fix-bad-GTree-usage-use-after-free.patch +Patch0520: Check-and-report-for-incomplete-global-option-format.patch +Patch0521: migration-ram-Fix-populate_read_range.patch +Patch0522: vfio-Fix-vfio_get_dev_region-trace-event.patch +Patch0523: disas-riscv-Fix-ctzw-disassemble.patch +Patch0524: qapi-block-Tidy-up-block-latency-histogram-set-docum.patch +Patch0525: chardev-char-socket-set-s-listener-NULL-in-char_sock.patch +Patch0526: QGA-VSS-Add-wrapper-to-send-log-to-debugger-and-stde.patch +Patch0527: xen-block-Avoid-leaks-on-new-error-path.patch +Patch0528: docs-about-build-platforms-Refine-the-distro-support.patch +Patch0529: migration-ram-Fix-error-handling-in-ram_write_tracki.patch +Patch0530: hw-xen-xen_pt-fix-uninitialized-variable.patch +Patch0531: qapi-qdev-Tidy-up-device_add-documentation.patch +Patch0532: block-nfs-Fix-32-bit-Windows-build.patch +Patch0533: block-nbd.c-Fixed-IO-request-coroutine-not-being-wak.patch +Patch0534: block-rbd-fix-write-zeroes-with-growing-images.patch +Patch0535: block-Fix-misleading-hexadecimal-format.patch +Patch0536: qapi-support-updating-expected-test-output-via-make.patch +Patch0537: tests-vhost-user-test-release-mutex-on-protocol-viol.patch +Patch0538: qga-Fix-suspend-on-Linux-guests-without-systemd.patch +Patch0539: vhost-vdpa-do-not-cleanup-the-vdpa-vhost-net-structu.patch +Patch0540: virtio-crypto-verify-src-dst-buffer-length-for-sym-r.patch +Patch0541: sw_64-Added-sw64-architecture-related-updates.patch +Patch0542: aio-posix-fix-build-failure-io_uring-2.2.patch +Patch0543: test-Fix-test-crypto-secret-when-compiling-without-k.patch +Patch0544: accel-kvm-Free-as-when-an-error-occurred.patch +Patch0545: accel-kvm-Make-kvm_dirty_ring_reaper_init-void.patch +Patch0546: vhost-user-Use-correct-macro-name-TARGET_PPC64.patch +Patch0547: hw-rx-rx-gdbsim-DTB-load-address-aligned-of-16byte.patch +Patch0548: hw-arm-virt-Check-for-attempt-to-use-TrustZone-with-.patch +Patch0549: virtio-iommu-use-after-free-fix.patch +Patch0550: vhost-Drop-unused-eventfd_add-del-hooks.patch +Patch0551: chardev-report-the-handshake-error.patch +Patch0552: hw-ssi-Fix-Linux-driver-init-issue-with-xilinx_spi.patch +Patch0553: io-remove-io-watch-if-TLS-channel-is-closed-during-h.patch +Patch0554: hw-char-fix-qcode-array-bounds-check-in-ESCC-impl.patch +Patch0555: tulip-Assign-default-MAC-address-if-not-specified.patch +Patch0556: target-ppc-Fix-the-order-of-kvm_enable-judgment-abou.patch +Patch0557: tests-qtest-pflash-Clean-up-local-variable-shadowing.patch +Patch0558: ui-fix-crash-when-there-are-no-active_console.patch +Patch0559: ppc-vof-Fix-missed-fields-in-VOF-cleanup.patch +Patch0560: hw-nvme-Avoid-dynamic-stack-allocation.patch +Patch0561: aio-posix-zero-out-io_uring-sqe-user_data.patch +Patch0562: qtest-npcm7xx_pwm-test-Fix-memory-leak-in-mft_qom_se.patch +Patch0563: target-i386-fix-INVD-vmexit.patch +Patch0564: target-ppc-Fix-tlbie.patch +Patch0565: hw-net-Fix-read-of-uninitialized-memory-in-ftgmac100.patch +Patch0566: replay-fix-event-queue-flush-for-qemu-shutdown.patch +Patch0567: hw-vfio-pci-quirks-Support-alternate-offset-for-GPUD.patch +Patch0568: hw-vfio-pci-quirks-Sanitize-capability-pointer.patch +Patch0569: vhost-user-fs-Back-up-vqs-before-cleaning-up-vhost_d.patch +Patch0570: migration-rdma-zore-out-head.repeat-to-make-the-erro.patch +Patch0571: thread-pool-optimize-scheduling-of-completion-bottom.patch +Patch0572: hw-arm-xlnx-zynqmp-fix-unsigned-error-when-checking-.patch +Patch0573: hw-i2c-pmbus_device-Fix-modifying-QOM-class-internal.patch +Patch0574: crypto-remove-shadowed-ret-variable.patch +Patch0575: target-i386-add-support-for-FLUSH_L1D-feature.patch +Patch0576: target-i386-add-support-for-FB_CLEAR-feature.patch +Patch0577: target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch +Patch0578: target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch +Patch0579: target-i386-Allow-MCDT_NO-if-host-supports.patch +Patch0580: target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch +Patch0581: target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch +Patch0582: ui-vnc-clipboard-fix-infinite-loop-in-inflate_buffer.patch +Patch0583: qga-Fix-memory-leak-when-output-stream-is-unused.patch +Patch0584: disas-riscv-Fix-the-typo-of-inverted-order-of-pmpadd.patch +Patch0585: softmmu-dirtylimit-Add-parameter-check-for-hmp-set_v.patch +Patch0586: tests-Fix-printf-format-string-in-acpi-utils.c.patch +Patch0587: hw-virtio-virtio-pmem-Replace-impossible-check-by-as.patch +Patch0588: target-i386-Export-GDS_NO-bit-to-guests.patch +Patch0589: semihosting-fix-memleak-at-semihosting_arg_fallback.patch +Patch0590: semihosting-config-Merge-semihosting-config-option-g.patch +Patch0591: qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch +Patch0592: hw-usb-hcd-ehci-fix-writeback-order.patch +Patch0593: pci-fix-overflow-in-snprintf-string-formatting.patch +Patch0594: tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch +Patch0595: hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch +Patch0596: pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch +Patch0597: virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch +Patch0598: virtio-pci-decouple-notifier-from-interrupt-process.patch +Patch0599: virtio-pci-decouple-the-single-vector-from-the-inter.patch +Patch0600: vhost-vdpa-add-support-for-config-interrupt.patch +Patch0601: virtio-add-support-for-configure-interrupt.patch +Patch0602: vhost-add-support-for-configure-interrupt.patch +Patch0603: virtio-net-add-support-for-configure-interrupt.patch +Patch0604: virtio-mmio-add-support-for-configure-interrupt.patch +Patch0605: virtio-pci-add-support-for-configure-interrupt.patch +Patch0606: vhost-vdpa-stick-to-errno-error-return-convention.patch +Patch0607: vhost-user-stick-to-errno-error-return-convention.patch +Patch0608: vhost-stick-to-errno-error-return-convention.patch +Patch0609: vhost-introduce-new-VhostOps-vhost_set_config_call.patch +Patch0610: e1000-set-RX-descriptor-status-in-a-separate-operati.patch +Patch0611: virtio-iommu-Fix-the-partial-copy-of-probe-request.patch +Patch0612: artist-set-memory-region-owners-for-buffers-to-the-a.patch +Patch0613: qom-object-Remove-circular-include-dependency.patch +Patch0614: vga-avoid-crash-if-no-default-vga-card.patch +Patch0615: hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch +Patch0616: tracetool-avoid-invalid-escape-in-Python-string.patch +Patch0617: target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch +Patch0618: target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch +Patch0619: target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch +Patch0620: target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch +Patch0621: target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch +Patch0622: target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch +Patch0623: target-i386-Add-new-CPU-model-GraniteRapids.patch +Patch0624: target-i386-Adjust-feature-level-according-to-FEAT_7.patch +Patch0625: virtio-signal-after-wrapping-packed-used_idx.patch +Patch0626: Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch +Patch0627: Revert-virtio-pci-add-support-for-configure-interrup.patch +Patch0628: Revert-virtio-mmio-add-support-for-configure-interru.patch +Patch0629: Revert-virtio-net-add-support-for-configure-interrup.patch +Patch0630: Revert-vhost-add-support-for-configure-interrupt.patch +Patch0631: Revert-virtio-add-support-for-configure-interrupt.patch +Patch0632: Revert-vhost-vdpa-add-support-for-config-interrupt.patch +Patch0633: Revert-virtio-pci-decouple-the-single-vector-from-th.patch +Patch0634: Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch +Patch0635: Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch +Patch0636: vdpa-Make-ncs-autofree.patch +Patch0637: vhost-Add-VhostShadowVirtqueue.patch +Patch0638: vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch +Patch0639: vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch +Patch0640: vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch +Patch0641: virtio-Add-vhost_svq_get_vring_addr.patch +Patch0642: vdpa-adapt-vhost_ops-callbacks-to-svq.patch +Patch0643: vhost-Shadow-virtqueue-buffers-forwarding.patch +Patch0644: util-Add-iova_tree_alloc_map.patch +Patch0645: util-add-iova_tree_find_iova.patch +Patch0646: vhost-Add-VhostIOVATree.patch +Patch0647: vdpa-Add-custom-IOTLB-translations-to-SVQ.patch +Patch0648: vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch +Patch0649: vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch +Patch0650: vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch +Patch0651: virtio-fix-enable-vhost-user-build-on-non-Linux.patch +Patch0652: vhost-vdpa-fix-typo-in-a-comment.patch +Patch0653: vdpa-Add-missing-tracing-to-batch-mapping-functions.patch +Patch0654: vhost-Track-descriptor-chain-in-private-at-SVQ.patch +Patch0655: vhost-Fix-device-s-used-descriptor-dequeue.patch +Patch0656: vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch +Patch0657: vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch +Patch0658: vhost-Fix-element-in-vhost_svq_add-failure.patch +Patch0659: hw-virtio-add-vhost_user_-read-write-trace-points.patch +Patch0660: include-hw-start-documenting-the-vhost-API.patch +Patch0661: virtio-add-vhost-support-for-virtio-devices.patch +Patch0662: virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch +Patch0663: vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch +Patch0664: vhost-vdpa-backend-feature-should-set-only-once.patch +Patch0665: vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch +Patch0666: virtio-net-don-t-handle-mq-request-in-userspace-hand.patch +Patch0667: util-Return-void-on-iova_tree_remove.patch +Patch0668: vhost-move-descriptor-translation-to-vhost_svq_vring.patch +Patch0669: virtio-net-Expose-MAC_TABLE_ENTRIES.patch +Patch0670: virtio-net-Expose-ctrl-virtqueue-logic.patch +Patch0671: vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch +Patch0672: vhost-Reorder-vhost_svq_kick.patch +Patch0673: vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch +Patch0674: vhost-Check-for-queue-full-at-vhost_svq_add.patch +Patch0675: vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch +Patch0676: vhost-Add-SVQDescState.patch +Patch0677: vhost-Track-number-of-descs-in-SVQDescState.patch +Patch0678: vhost-add-vhost_svq_push_elem.patch +Patch0679: vhost-Expose-vhost_svq_add.patch +Patch0680: vhost-add-vhost_svq_poll.patch +Patch0681: vhost-Add-svq-avail_handler-callback.patch +Patch0682: vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch +Patch0683: vdpa-manual-forward-CVQ-buffers.patch +Patch0684: vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch +Patch0685: vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch +Patch0686: vdpa-Add-device-migration-blocker.patch +Patch0687: vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch +Patch0688: vhost-Get-vring-base-from-vq-not-svq.patch +Patch0689: vdpa-Fix-memory-listener-deletions-of-iova-tree.patch +Patch0690: vdpa-Fix-file-descriptor-leak-on-get-features-error.patch +Patch0691: vdpa-Skip-the-maps-not-in-the-iova-tree.patch +Patch0692: vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch +Patch0693: util-accept-iova_tree_remove_parameter-by-value.patch +Patch0694: vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch +Patch0695: vdpa-Make-SVQ-vring-unmapping-return-void.patch +Patch0696: vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch +Patch0697: vhost_net-Add-NetClientInfo-start-callback.patch +Patch0698: vhost_net-Add-NetClientInfo-stop-callback.patch +Patch0699: vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch +Patch0700: vdpa-Move-command-buffers-map-to-start-of-net-device.patch +Patch0701: vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch +Patch0702: vhost_net-add-NetClientState-load-callback.patch +Patch0703: vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch +Patch0704: vdpa-Delete-CVQ-migration-blocker.patch +Patch0705: vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch +Patch0706: vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch +Patch0707: vdpa-Add-vhost_vdpa_net_load_mq.patch +Patch0708: vdpa-validate-MQ-CVQ-commands.patch +Patch0709: virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch +Patch0710: vdpa-Allow-MQ-feature-in-SVQ.patch +Patch0711: hw-virtio-add-some-vhost-user-trace-events.patch +Patch0712: vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch +Patch0713: vdpa-Remove-shadow-CVQ-command-check.patch +Patch0714: vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch +Patch0715: net-vhost-vdpa.c-Fix-clang-compilation-failure.patch +Patch0716: vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch +Patch0717: vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch +Patch0718: vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch +Patch0719: vhost-set-SVQ-device-call-handler-at-SVQ-start.patch +Patch0720: vhost-allocate-SVQ-device-file-descriptors-at-device.patch +Patch0721: vdpa-add-vhost_vdpa_net_valid_svq_features.patch +Patch0722: vdpa-request-iova_range-only-once.patch +Patch0723: vdpa-move-SVQ-vring-features-check-to-net.patch +Patch0724: vdpa-allocate-SVQ-array-unconditionally.patch +Patch0725: vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch +Patch0726: vdpa-store-x-svq-parameter-in-VhostVDPAState.patch +Patch0727: vdpa-add-shadow_data-to-vhost_vdpa.patch +Patch0728: vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch +Patch0729: hw-virtio-vhost-Fix-typo-in-comment.patch +Patch0730: hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch +Patch0731: vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch +Patch0732: vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch +Patch0733: vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch +Patch0734: virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch +Patch0735: virtio-pci-decouple-notifier-from-interrupt-process-new.patch +Patch0736: virtio-pci-decouple-the-single-vector-from-the-inter-new.patch +Patch0737: vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch +Patch0738: vhost-vdpa-add-support-for-config-interrupt-new.patch +Patch0739: virtio-add-support-for-configure-interrupt-new.patch +Patch0740: vhost-add-support-for-configure-interrupt-new.patch +Patch0741: virtio-net-add-support-for-configure-interrupt-new.patch +Patch0742: virtio-mmio-add-support-for-configure-interrupt-new.patch +Patch0743: virtio-pci-add-support-for-configure-interrupt-new.patch +Patch0744: vdpa-dev-get-iova-range-explicitly.patch +Patch0745: vdpa-harden-the-error-path-if-get_iova_range-failed.patch +Patch0746: vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch +Patch0747: virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch +Patch0748: vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch +Patch0749: vhost-move-iova_tree-set-to-vhost_svq_start.patch +Patch0750: vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch +Patch0751: vhost-Fix-false-positive-out-of-bounds.patch +Patch0752: hw-virtio-fix-vhost_user_read-tracepoint.patch +Patch0753: vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch +Patch0754: vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch +Patch0755: vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch +Patch0756: vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch +Patch0757: vdpa-net-block-migration-if-the-device-has-CVQ.patch +Patch0758: vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch +Patch0759: vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch +Patch0760: virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch +Patch0761: hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch +Patch0762: virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch +Patch0763: vhost-fix-the-fd-leak.patch +Patch0764: vhost-release-virtqueue-objects-in-error-path.patch +Patch0765: vdpa-stop-all-svq-on-device-deletion.patch +Patch0766: net-Fix-a-misleading-error-message.patch +Patch0767: qsd-Unlink-absolute-PID-file-path.patch +Patch0768: libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch +Patch0769: io_uring-fix-short-read-slow-path.patch +Patch0770: libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch +Patch0771: tests-qtest-check-the-return-value.patch +Patch0772: hw-net-cadence_gem.c-spelling-fixes-Octects.patch +Patch0773: hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch +Patch0774: xen-pass-through-don-t-create-needless-register-grou.patch +Patch0775: spapr-pci-Correct-does-not-support-hotplugging-error.patch +Patch0776: hmp-Improve-sync-profile-error-message.patch +Patch0777: qga-Improve-guest-exec-status-error-message.patch +Patch0778: ui-qmp-cmds-Improve-two-error-messages.patch +Patch0779: tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch +Patch0780: disas-hppa-Show-hexcode-of-instruction-along-with-di.patch +Patch0781: target-arm-Don-t-set-syndrome-ISS-for-loads-and-stor.patch +Patch0782: balloon-Fix-a-misleading-error-message.patch +Patch0783: target-i386-cpu-Improve-error-message-for-property-v.patch +Patch0784: tests-qtest-migration-test.c-spelling-fix-bandwith.patch +Patch0785: xen-pass-through-merge-emulated-bits-correctly.patch +Patch0786: hw-display-next-fb-Fix-comment-typo.patch +Patch0787: hw-virtio-virtio-iommu-pci-Enforce-the-device-is-plu.patch +Patch0788: hw-ide-atapi.c-Correct-typos-CD-CDROM-CD-ROM.patch +Patch0789: trivial-typos-namesapce.patch +Patch0790: tests-qtest-Fix-two-format-strings.patch +Patch0791: sphinx-change-default-language-to-en.patch +Patch0792: block-use-unsigned-for-in_flight-field-on-driver-sta.patch +Patch0793: Fix-STM32F2XX-USART-data-register-readout.patch +Patch0794: Revert-hw-virtio-virtio-iommu-pci-Enforce-the-device.patch +Patch0795: hw-riscv-boot-Reduce-FDT-address-alignment-constrain.patch +Patch0796: vhost-user-blk-propagate-error-return-from-generic-v.patch +Patch0797: vhost-user-blk-reconnect-on-any-error-during-realize.patch +Patch0798: hw-arm-ast2600-Fix-address-mapping-of-second-SPI-con.patch +Patch0799: Add-dummy-Aspeed-AST2600-Display-Port-MCU-DPMCU.patch +Patch0800: hw-net-npcm7xx_emc-fix-missing-queue_flush.patch +Patch0801: block-nvme-fix-infinite-loop-in-nvme_free_req_queue_.patch +Patch0802: scripts-entitlement.sh-Use-backward-compatible-cp-fl.patch +Patch0803: migration-colo-More-accurate-update-checkpoint-time.patch +Patch0804: Fixed-a-QEMU-hang-when-guest-poweroff-in-COLO-mode.patch +Patch0805: hw-intc-arm_gicv3-ICC_PMR_EL1-high-bits-should-be-RA.patch +Patch0806: target-ppc-cpu-models-Remove-the-default-CPU-alias.patch +Patch0807: hw-usb-dev-mtp-Use-g_mkdir.patch +Patch0808: ui-gtk-prevent-ui-lock-up-when-dpy_gl_update-called-.patch +Patch0809: vhost-fix-null-pointer-access.patch +Patch0810: vhost-vdpa-add-VHOST_BACKEND_F_BYTEMAPLOG.patch +Patch0811: vhost-vdpa-add-migration-log-ops-for-VhostOps.patch +Patch0812: vhost-introduce-bytemap-for-vhost-backend-logging.patch +Patch0813: vhost-add-vhost_dev_suspend-resume_op.patch +Patch0814: vhost-implement-vhost-vdpa-suspend-resume.patch +Patch0815: vhost-implement-vhost_vdpa_device_suspend-resume.patch +Patch0816: vhost-implement-savevm_hanlder-for-vdpa-device.patch +Patch0817: vhost-implement-migration-state-notifier-for-vdpa-de.patch +Patch0818: vhost-implement-post-resume-bh.patch +Patch0819: vdpa-implement-vdpa-device-migration.patch +Patch0820: vdpa-move-memory-listener-to-the-realize-stage.patch +Patch0821: hw-usb-hcd-xhci.c-spelling-tranfer.patch +Patch0822: ui-vnc-clipboard-fix-inflate_buffer.patch +Patch0823: i386-sev-Avoid-SEV-ES-crash-due-to-missing-MSR_EFER_.patch +Patch0824: tests-avocado-mark-ReplayKernelNormal.test_mips64el_.patch +Patch0825: tests-unit-fix-a-Wformat-truncation-warning.patch +Patch0826: hw-qdev-Cosmetic-around-documentation.patch +Patch0827: pci-Export-the-pci_intx-function.patch +Patch0828: pcie_aer-Don-t-trigger-a-LSI-if-none-are-defined.patch +Patch0829: hw-i386-pc-Add-missing-property-descriptions.patch +Patch0830: hw-scsi-vhost-scsi-don-t-leak-vqs-on-error.patch +Patch0831: virtio-vhost-vsock-don-t-double-close-vhostfd-remove.patch +Patch0832: hw-scsi-vhost-scsi-don-t-double-close-vhostfd-on-err.patch +Patch0833: ppc-spelling-fixes.patch +Patch0834: s390x-Fix-spelling-errors.patch +Patch0835: migration-fix-RAMBlock-add-NULL-check.patch +Patch0836: iotests-fix-default-machine-type-detection.patch +Patch0837: gdb-xml-fix-duplicate-register-in-arm-neon.xml.patch +Patch0838: migration-Set-downtime_start-even-for-postcopy.patch +Patch0839: revert-tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch +Patch0840: shadow_dev-introduce-shadow-dev-for-virtio-net-devic.patch +Patch0841: vdpa-set-vring-enable-only-if-the-vring-address-has-.patch +Patch0842: vdpa-correct-param-passed-in-when-unregister-save.patch +Patch0843: vdpa-support-vdpa-device-suspend-resume.patch +Patch0844: vdpa-don-t-suspend-resume-device-when-vdpa-device-no.patch +Patch0845: vdpa-suspend-function-return-0-when-the-vdpa-device-.patch +Patch0846: ui-vnc-fix-debug-output-for-invalid-audio-message.patch +Patch0847: tests-avocado-fix-waiting-for-vm-shutdown-in-replay_.patch +Patch0848: iotests-fix-194-filter-out-racy-postcopy-active-even.patch +Patch0849: vhost_vdpa-fix-the-input-in-trace_vhost_vdpa_listene.patch +Patch0850: linux-user-fix-sockaddr_in6-endianness.patch +Patch0851: migration-multifd-Remove-unnecessary-usage-of-local-.patch +Patch0852: hw-i386-Fix-comment-style-in-topology.h.patch +Patch0853: ui-vnc.c-Fixed-a-deadlock-bug.patch +Patch0854: memory-prevent-dma-reentracy-issues.patch +Patch0855: net-Provide-MemReentrancyGuard-to-qemu_new_nic.patch +Patch0856: net-Update-MemReentrancyGuard-for-NIC-CVE-2023-3019.patch +Patch0857: hw-scsi-lsi53c895a-Fix-reentrancy-issues-in-the-LSI-.patch +Patch0858: hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch +Patch0859: esp-restrict-non-DMA-transfer-length-to-that-of-avai.patch +Patch0860: ui-clipboard-mark-type-as-not-available-when-there-i.patch +Patch0861: virtio-net-correctly-copy-vnet-header-when-flushing-.patch +Patch0862: hw-timer-fix-systick-trace-message.patch +Patch0863: qga-win-Fix-guest-get-fsinfo-multi-disks-collection.patch BuildRequires: flex BuildRequires: gcc +BuildRequires: make BuildRequires: bison BuildRequires: texinfo BuildRequires: perl-podlators -BuildRequires: kernel BuildRequires: chrpath BuildRequires: gettext BuildRequires: python-sphinx +BuildRequires: ninja-build BuildRequires: zlib-devel BuildRequires: zstd-devel @@ -588,7 +909,6 @@ BuildRequires: libattr-devel BuildRequires: libcurl-devel BuildRequires: libjpeg-devel BuildRequires: libpng-devel -BuildRequires: brlapi-devel BuildRequires: pixman-devel BuildRequires: libusbx-devel BuildRequires: bzip2-devel @@ -599,17 +919,24 @@ BuildRequires: libudev-devel BuildRequires: pam-devel BuildRequires: perl-Test-Harness BuildRequires: python3-devel +%if %{with rbd} BuildRequires: librbd-devel +%endif BuildRequires: krb5-devel BuildRequires: libssh-devel BuildRequires: glib2 -BuildRequires: spice-server-devel >= 0.12.5 -BuildRequires: spice-protocol >= 0.12.3 -%ifarch aarch64 BuildRequires: libfdt-devel BuildRequires: virglrenderer-devel +BuildRequires: libslirp-devel +BuildRequires: liburing-devel +%ifarch loongarch64 +BuildRequires: spice-server-devel %endif +# for upgrade from qemu-kvm +Provides: qemu-kvm +Obsoletes: qemu-kvm < 10:6.2.0 + Requires(post): /usr/bin/getent Requires(post): /usr/sbin/groupadd Requires(post): /usr/sbin/useradd @@ -617,6 +944,10 @@ Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units Requires(postun): qemu-block-iscsi +Requires(postun): qemu-block-curl +Requires(postun): qemu-hw-usb-host +Requires: libgcc +Requires: liburing %description @@ -654,10 +985,12 @@ Summary: QEMU command line tool for manipulating disk images %description img This package provides a command line tool for manipulating disk images +%if %{with rbd} %package block-rbd Summary: Qemu-block-rbd %description block-rbd This package provides RBD support for Qemu +%endif %package block-ssh Summary: Qemu-block-ssh @@ -669,6 +1002,16 @@ Summary: Qemu-block-iscsi %description block-iscsi This package provides block-iscsi support for Qemu +%package block-curl +Summary: Qemu-block-curl +%description block-curl +This package provides block-curl support for Qemu + +%package hw-usb-host +Summary: Qemu-hw-usb-host +%description hw-usb-host +This package provides hw-usb-host support for Qemu + %ifarch %{ix86} x86_64 %package seabios Summary: QEMU seabios @@ -676,6 +1019,42 @@ Summary: QEMU seabios This package include bios-256k.bin and bios.bin of seabios %endif +%package system-aarch64 +Summary: Qemu-system-aarch64 +Requires: qemu +%description system-aarch64 +This package provides the QEMU system emulator for AArch64. + +%package system-arm +Summary: Qemu-system-arm +Requires: qemu +%description system-arm +This package provides the QEMU system emulator for ARM. + +%package system-x86_64 +Summary: Qemu-system-x86_64 +Requires: qemu +%description system-x86_64 +This package provides the QEMU system emulator for x86_64. + +%package system-ppc64 +Summary: Qemu-system-ppc64 +Requires: qemu +%description system-ppc64 +This package provides the QEMU system emulator for ppc64le. + +%package system-riscv +Summary: Qemu-system-riscv32, Qemu-system-riscv64 +Requires: qemu +%description system-riscv +This package provides the QEMU system emulator for riscv. + +%package system-loongarch64 +Summary: Qemu-system-loongarch64 +Requires: qemu +%description system-loongarch64 +This package provides the QEMU system emulator for loongarch64. + %prep %setup -q -n qemu-%{version}%{?rcstr} %autopatch -p1 @@ -683,20 +1062,44 @@ This package include bios-256k.bin and bios.bin of seabios %build %ifarch x86_64 buildarch="x86_64-softmmu" +targetarch="aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" %endif %ifarch aarch64 buildarch="aarch64-softmmu" +targetarch="x86_64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +%endif + +%ifarch ppc64le +buildarch="ppc64-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +%endif + +%ifarch loongarch64 +buildarch="loongarch64-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +%endif + +%ifarch riscv64 +buildarch="riscv64-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu" %endif buildldflags="VL_LDFLAGS=-Wl,--build-id" +qemubuilddir="build" + +tar xf %{SOURCE4} +cd BinDir/ +\cp -r -a * ../ +cd ../ + ./configure \ --prefix=%{_prefix} \ - --target-list=${buildarch} \ - --extra-cflags="%{optflags} -fPIE -DPIE -fPIC" \ - --extra-ldflags="-Wl,--build-id -pie -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack" \ + --target-list="${buildarch} ${targetarch}" \ + --extra-cflags="%{optflags} -fPIE -DPIE -fPIC -ftls-model=initial-exec" \ + --extra-ldflags="-Wl,--build-id -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack" \ --datadir=%{_datadir} \ - --docdir=%{_docdir}/%{name} \ + --docdir=%{_docdir}/ \ --libdir=%{_libdir} \ --libexecdir=%{_libexecdir} \ --localstatedir=%{_localstatedir} \ @@ -705,7 +1108,8 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --firmwarepath=%{_datadir}/%{name} \ --with-pkgversion=%{name}-%{version}-%{release} \ --python=/usr/bin/python3 \ - --disable-slirp \ + --enable-slirp=system \ + --enable-slirp-smbd \ --enable-gtk \ --enable-docs \ --enable-guest-agent \ @@ -718,33 +1122,42 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --enable-tcg \ --enable-rdma \ --enable-linux-aio \ + --enable-linux-io-uring \ --enable-cap-ng \ --enable-vhost-user \ + --enable-vhost-net \ + --enable-vhost-kernel \ + --enable-vhost-user-blk-server \ + --enable-vhost-vdpa \ + --enable-vhost-vsock \ --enable-tpm \ --enable-modules \ --enable-libssh \ - --enable-spice \ -%ifarch aarch64 --enable-fdt \ --enable-virglrenderer \ -%endif --enable-cap-ng \ --enable-libusb \ - --disable-bluez \ +%if %{with rbd} + --enable-rbd \ +%else + --disable-rbd \ +%endif --disable-dmg \ --disable-qcow1 \ --disable-vdi \ --disable-vvfat \ --disable-qed \ --disable-parallels \ - --disable-sheepdog \ --disable-capstone \ --disable-smartcard \ - --enable-zstd + --enable-zstd \ + --disable-brlapi \ + --disable-plugins \ + --enable-debug make %{?_smp_mflags} $buildldflags V=1 -cp -a ${buildarch}/qemu-system-* qemu-kvm +cp ${qemubuilddir}/${buildarch}/qemu-system-* qemu-kvm %install @@ -755,7 +1168,6 @@ make %{?_smp_mflags} DESTDIR=%{buildroot} \ install -m 0755 qemu-kvm %{buildroot}%{_libexecdir}/ ln -s %{_libexecdir}/qemu-kvm %{buildroot}/%{_bindir}/qemu-kvm -rm %{buildroot}/%{_bindir}/qemu-system-* install -D -p -m 0644 contrib/systemd/qemu-pr-helper.service %{buildroot}%{_unitdir}/qemu-pr-helper.service install -D -p -m 0644 contrib/systemd/qemu-pr-helper.socket %{buildroot}%{_unitdir}/qemu-pr-helper.socket install -D -p -m 0644 qemu.sasl %{buildroot}%{_sysconfdir}/sasl2/qemu.conf @@ -772,55 +1184,70 @@ touch %{buildroot}%{_localstatedir}/log/qga-fsfreeze-hook.log # For qemu docs package %global qemudocdir %{_docdir}/%{name} rm -rf %{buildroot}%{qemudocdir}/specs -install -D -p -m 0644 -t %{buildroot}%{qemudocdir} Changelog README COPYING COPYING.LIB LICENSE +rm -rf %{buildroot}%{qemudocdir}/.buildinfo +rm -rf %{buildroot}%{qemudocdir}/objects.inv +rm -rf %{buildroot}%{qemudocdir}/genindex.html +rm -rf %{buildroot}%{qemudocdir}/index.html +install -D -p -m 0644 -t %{buildroot}%{qemudocdir} README.rst COPYING COPYING.LIB LICENSE chmod -x %{buildroot}%{_mandir}/man1/* - -%ifarch aarch64 -rm -rf %{buildroot}%{_datadir}/%{name}/vgabios*bin -rm -rf %{buildroot}%{_datadir}/%{name}/bios*.bin -rm -rf %{buildroot}%{_datadir}/%{name}/linuxboot.bin -rm -rf %{buildroot}%{_datadir}/%{name}/kvmvapic.bin -rm -rf %{buildroot}%{_datadir}/%{name}/sgabios.bin -rm -rf %{buildroot}%{_datadir}/%{name}/multiboot.bin -rm -rf %{buildroot}%{_datadir}/%{name}/linuxboot_dma.bin -rm -rf %{buildroot}%{_datadir}/%{name}/pvh.bin -%endif -%ifarch x86_64 rm -rf %{buildroot}%{_datadir}/%{name}/vgabios-ati.bin -%endif +rm -rf %{buildroot}%{_datadir}/%{name}/bios-microvm.bin rm -rf %{buildroot}%{_datadir}/%{name}/openbios-* -rm -rf %{buildroot}%{_datadir}/%{name}/slof.bin rm -rf %{buildroot}%{_datadir}/%{name}/QEMU,*.bin rm -rf %{buildroot}%{_datadir}/%{name}/bamboo.dtb rm -rf %{buildroot}%{_datadir}/%{name}/canyonlands.dtb rm -rf %{buildroot}%{_datadir}/%{name}/hppa-firmware.img rm -rf %{buildroot}%{_datadir}/%{name}/palcode-clipper rm -rf %{buildroot}%{_datadir}/%{name}/petalogix-* -rm -rf %{buildroot}%{_datadir}/%{name}/ppc_* rm -rf %{buildroot}%{_datadir}/%{name}/qemu_vga.ndrv rm -rf %{buildroot}%{_datadir}/%{name}/s390-* +%ifnarch ppc64le +rm -rf %{buildroot}%{_datadir}/%{name}/slof.bin rm -rf %{buildroot}%{_datadir}/%{name}/skiboot.lid rm -rf %{buildroot}%{_datadir}/%{name}/spapr-* +rm -rf %{buildroot}%{_datadir}/%{name}/ppc_* +%endif rm -rf %{buildroot}%{_datadir}/%{name}/u-boot* +rm -rf %{buildroot}%{_datadir}/%{name}/core3-hmcode +rm -rf %{buildroot}%{_datadir}/%{name}/core3-reset +rm -rf %{buildroot}%{_datadir}/%{name}/uefi-bios-sw rm -rf %{buildroot}%{_bindir}/ivshmem* rm -f %{buildroot}%{_datadir}/%{name}/edk2* rm -rf %{buildroot}%{_datadir}/%{name}/firmware -rm -rf %{buildroot}%{_datadir}/%{name}/opensbi* rm -rf %{buildroot}%{_datadir}/%{name}/qemu-nsis.bmp -rm -rf %{buildroot}%{_libdir}/%{name}/audio-oss.so rm -rf %{buildroot}%{_libdir}/%{name}/audio-pa.so -rm -rf %{buildroot}%{_libdir}/%{name}/block-curl.so rm -rf %{buildroot}%{_libdir}/%{name}/block-gluster.so +rm -rf %{buildroot}%{_libdir}/%{name}/ui-sdl.so +rm -rf %{buildroot}%{_libdir}/%{name}/chardev-baum.so +%ifnarch loongarch64 +rm -rf %{buildroot}%{_libdir}/%{name}/audio-oss.so +rm -rf %{buildroot}%{_libdir}/%{name}/audio-spice.so rm -rf %{buildroot}%{_libdir}/%{name}/ui-curses.so rm -rf %{buildroot}%{_libdir}/%{name}/ui-gtk.so -rm -rf %{buildroot}%{_libdir}/%{name}/ui-sdl.so +rm -rf %{buildroot}%{_libdir}/%{name}/chardev-spice.so +rm -rf %{buildroot}%{_libdir}/%{name}/hw-display-qxl.so +rm -rf %{buildroot}%{_libdir}/%{name}/hw-s390x-virtio-gpu-ccw.so +rm -rf %{buildroot}%{_libdir}/%{name}/hw-usb-redirect.so +rm -rf %{buildroot}%{_libdir}/%{name}/ui-opengl.so +rm -rf %{buildroot}%{_libdir}/%{name}/ui-spice-app.so +rm -rf %{buildroot}%{_libdir}/%{name}/ui-spice-core.so +%endif + rm -rf %{buildroot}%{_libexecdir}/vhost-user-gpu rm -rf %{buildroot}%{_datadir}/%{name}/vhost-user/50-qemu-gpu.json +rm -rf %{buildroot}%{_datadir}/%{name}/vhost-user/50-qemu-virtiofsd.json +%ifarch ppc64le +rm -rf %{buildroot}%{_datadir}/%{name}/opensbi-riscv*.elf +%endif +%if %{with rbd} strip %{buildroot}%{_libdir}/%{name}/block-rbd.so +%endif strip %{buildroot}%{_libdir}/%{name}/block-iscsi.so +strip %{buildroot}%{_libdir}/%{name}/block-curl.so strip %{buildroot}%{_libdir}/%{name}/block-ssh.so +strip %{buildroot}%{_libdir}/%{name}/hw-usb-host.so for f in %{buildroot}%{_bindir}/* %{buildroot}%{_libdir}/* \ %{buildroot}%{_libexecdir}/*; do @@ -828,7 +1255,9 @@ for f in %{buildroot}%{_bindir}/* %{buildroot}%{_libdir}/* \ done %check -make check V=1 +echo "#define CONFIG_DISABLE_QEMU_LOG" >> build/config-host.h +make %{?_smp_mflags} $buildldflags V=1 +make check V=1 %{?_smp_mflags} %pre getent group kvm >/dev/null || groupadd -g 36 -r kvm @@ -848,6 +1277,16 @@ getent passwd qemu >/dev/null || \ %dir %{_datadir}/%{name}/ %{_libexecdir}/qemu-kvm %{_bindir}/qemu-kvm +%{_libdir}/%{name}/accel-qtest-*.so +%ifarch x86_64 +%{_libdir}/%{name}/accel-tcg-*.so +%{_libdir}/%{name}/hw-display-virtio-vga-gl.so +%{_libdir}/%{name}/hw-display-virtio-vga.so +%endif +%{_libdir}/%{name}/hw-display-virtio-gpu-gl.so +%{_libdir}/%{name}/hw-display-virtio-gpu-pci-gl.so +%{_libdir}/%{name}/hw-display-virtio-gpu-pci.so +%{_libdir}/%{name}/hw-display-virtio-gpu.so %{_datadir}/%{name}/efi-virtio.rom %{_datadir}/%{name}/efi-e1000.rom %{_datadir}/%{name}/efi-e1000e.rom @@ -862,6 +1301,7 @@ getent passwd qemu >/dev/null || \ %{_datadir}/%{name}/pxe-pcnet.rom %{_datadir}/%{name}/pxe-rtl8139.rom %{_datadir}/%{name}/pxe-eepro100.rom +%{_datadir}/%{name}/qboot.rom %{_datadir}/%{name}/trace-events-all %{_datadir}/applications/qemu.desktop %{_datadir}/icons/hicolor/*/apps/* @@ -870,7 +1310,8 @@ getent passwd qemu >/dev/null || \ %{_bindir}/qemu-edid %{_bindir}/qemu-keymap %{_bindir}/qemu-pr-helper -%{_bindir}/virtfs-proxy-helper +%{_libexecdir}/virtfs-proxy-helper +%{_libexecdir}/virtiofsd %{_unitdir}/qemu-pr-helper.service %{_unitdir}/qemu-pr-helper.socket %attr(4755, root, root) %{_libexecdir}/qemu-bridge-helper @@ -896,34 +1337,108 @@ getent passwd qemu >/dev/null || \ %{_datadir}/%{name}/linuxboot_dma.bin %{_datadir}/%{name}/pvh.bin %{_datadir}/%{name}/multiboot.bin +%{_datadir}/%{name}/multiboot_dma.bin +%{_datadir}/%{name}/kvmvapic.bin +%{_datadir}/%{name}/sgabios.bin +%endif + +%files system-aarch64 +%{_bindir}/qemu-system-aarch64 + +%files system-arm +%{_bindir}/qemu-system-arm +%{_datadir}/%{name}/npcm7xx_bootrom.bin + +%files system-x86_64 +%{_bindir}/qemu-system-x86_64 +%ifnarch x86_64 +%{_libdir}/%{name}/accel-tcg-*.so +%{_libdir}/%{name}/hw-display-virtio-vga-gl.so +%{_libdir}/%{name}/hw-display-virtio-vga.so +%{_datadir}/%{name}/bios.bin +%{_datadir}/%{name}/bios-256k.bin +%{_datadir}/%{name}/vgabios.bin +%{_datadir}/%{name}/vgabios-cirrus.bin +%{_datadir}/%{name}/vgabios-qxl.bin +%{_datadir}/%{name}/vgabios-stdvga.bin +%{_datadir}/%{name}/vgabios-vmware.bin +%{_datadir}/%{name}/vgabios-virtio.bin +%{_datadir}/%{name}/vgabios-ramfb.bin +%{_datadir}/%{name}/vgabios-bochs-display.bin +%{_datadir}/%{name}/linuxboot.bin +%{_datadir}/%{name}/linuxboot_dma.bin +%{_datadir}/%{name}/pvh.bin +%{_datadir}/%{name}/multiboot.bin +%{_datadir}/%{name}/multiboot_dma.bin %{_datadir}/%{name}/kvmvapic.bin %{_datadir}/%{name}/sgabios.bin %endif +%ifarch ppc64le +%files system-ppc64 +%{_bindir}/qemu-system-ppc64 +%{_datadir}/%{name}/slof.bin +%{_datadir}/%{name}/skiboot.lid +%endif + +%files system-riscv +%{_bindir}/qemu-system-riscv32 +%{_bindir}/qemu-system-riscv64 +%{_datadir}/%{name}/opensbi-riscv*.bin +%ifnarch ppc64le +%{_datadir}/%{name}/opensbi-riscv*.elf +%endif + +%ifarch loongarch64 +%files system-loongarch64 +%{_bindir}/qemu-system-loongarch64 +%{_datadir}/%{name}/loongarch_*.bin +%{_libdir}/%{name}/audio-oss.so +%{_libdir}/%{name}/ui-curses.so +%{_libdir}/%{name}/ui-gtk.so +%{_libdir}/%{name}/audio-spice.so +%{_libdir}/%{name}/chardev-spice.so +%{_libdir}/%{name}/hw-display-qxl.so +%{_libdir}/%{name}/hw-s390x-virtio-gpu-ccw.so +%{_libdir}/%{name}/hw-usb-redirect.so +%{_libdir}/%{name}/ui-opengl.so +%{_libdir}/%{name}/ui-spice-app.so +%{_libdir}/%{name}/ui-spice-core.so +%endif + +%ifnarch loongarch64 +%exclude %{_datadir}/%{name}/loongarch_*.bin +%endif + %files help %dir %{qemudocdir} -%doc %{qemudocdir}/qemu-doc.html -%doc %{qemudocdir}/qemu-doc.txt -%doc %{qemudocdir}/qemu-ga-ref.html -%doc %{qemudocdir}/qemu-ga-ref.txt -%doc %{qemudocdir}/qemu-qmp-ref.html -%doc %{qemudocdir}/qemu-qmp-ref.txt +%doc %{qemudocdir}/about +%doc %{qemudocdir}/devel %doc %{qemudocdir}/interop -%doc %{qemudocdir}/README -%doc %{qemudocdir}/Changelog +%doc %{qemudocdir}/search* +%doc %{qemudocdir}/_static +%doc %{qemudocdir}/system +%doc %{qemudocdir}/tools +%doc %{qemudocdir}/user +%doc %{qemudocdir}/README.rst %{_mandir}/man1/qemu.1* +%{_mandir}/man1/qemu-img.1* +%{_mandir}/man1/qemu-storage-daemon.1* %{_mandir}/man1/virtfs-proxy-helper.1* +%{_mandir}/man1/virtiofsd.1* %{_mandir}/man7/qemu-block-drivers.7* %{_mandir}/man7/qemu-cpu-models.7* %{_mandir}/man7/qemu-ga-ref.7* %{_mandir}/man7/qemu-qmp-ref.7* -%{_mandir}/man1/qemu-img.1* +%{_mandir}/man7/qemu-storage-daemon-qmp-ref.7* +%{_mandir}/man8/qemu-ga.8* %{_mandir}/man8/qemu-nbd.8* +%{_mandir}/man8/qemu-pr-helper.8* + %files guest-agent %defattr(-,root,root,-) %{_bindir}/qemu-ga -%{_mandir}/man8/qemu-ga.8* %{_unitdir}/qemu-guest-agent.service %{_udevdir}/99-qemu-guest-agent.rules %ghost %{_localstatedir}/log/qga-fsfreeze-hook.log @@ -932,9 +1447,12 @@ getent passwd qemu >/dev/null || \ %{_bindir}/qemu-img %{_bindir}/qemu-io %{_bindir}/qemu-nbd +%{_bindir}/qemu-storage-daemon +%if %{with rbd} %files block-rbd %{_libdir}/%{name}/block-rbd.so +%endif %files block-ssh %{_libdir}/%{name}/block-ssh.so @@ -942,6 +1460,12 @@ getent passwd qemu >/dev/null || \ %files block-iscsi %{_libdir}/%{name}/block-iscsi.so +%files block-curl +%{_libdir}/%{name}/block-curl.so + +%files hw-usb-host +%{_libdir}/%{name}/hw-usb-host.so + %ifarch %{ix86} x86_64 %files seabios %{_datadir}/%{name}/bios-256k.bin @@ -949,19 +1473,812 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Wed Aug 04 2021 Chen Qun -- vfio: Support host translation granule size -- vfio/migrate: Move switch of dirty tracking into vfio_memory_listener -- vfio: Fix unregister SaveVMHandler in vfio_migration_finalize -- migration/ram: Reduce unnecessary rate limiting -- migration/ram: Optimize ram_save_host_page() -- qdev/monitors: Fix reundant error_setg of qdev_add_device +* Sat Mar 9 2024 - 10:6.2.0-89 +- qga-win: Fix guest-get-fsinfo multi-disks collection +- hw/timer: fix systick trace message +- virtio-net: correctly copy vnet header when flushing TX (CVE-2023-6693) +- ui/clipboard: mark type as not available when there is no data (CVE-2023-6683) +- esp: restrict non-DMA transfer length to that of available data (CVE-2024-24474) +- hw/scsi/lsi53c895a: add missing decrement of reentrancy counter +- hw/scsi/lsi53c895a: Fix reentrancy issues in the LSI controller (CVE-2023-0330) +- net: Update MemReentrancyGuard for NIC (CVE-2023-3019) +- net: Provide MemReentrancyGuard * to qemu_new_nic() + +* Wed Feb 21 2024 - 10:6.2.0-88 +- ui/vnc.c: Fixed a deadlock bug. +- hw/i386: Fix comment style in topology.h +- migration/multifd: Remove unnecessary usage of local Error +- linux-user: fix sockaddr_in6 endianness +- vhost_vdpa: fix the input in trace_vhost_vdpa_listener_region_del() +- iotests: fix 194: filter out racy postcopy-active event +- tests/avocado: fix waiting for vm shutdown in replay_linux +- ui/vnc: fix debug output for invalid audio message + +* Fri Dec 22 2023 - 10:6.2.0-87 +- vdpa: suspend function return 0 when the vdpa device is stopped +- vdpa: don't suspend/resume device when vdpa device not started +- vdpa: support vdpa device suspend/resume +- vdpa: correct param passed in when unregister save +- vdpa: set vring enable only if the vring address has already been set +- shadow_dev: introduce shadow dev for virtio-net device +- revert "tcg/loongarch64: Fix tcg_out_mov() Aborted" +- migration: Set downtime_start even for postcopy +- gdb-xml: fix duplicate register in arm-neon.xml +- iotests: fix default machine type detection +- migration: fix RAMBlock add NULL check +- s390x: Fix spelling errors +- ppc: spelling fixes +- hw/scsi/vhost-scsi: don't double close vhostfd on error +- virtio/vhost-vsock: don't double close vhostfd, remove redundant cleanup +- hw/scsi/vhost-scsi: don't leak vqs on error +- hw/i386/pc: Add missing property descriptions +- pcie_aer: Don't trigger a LSI if none are defined +- pci: Export the pci_intx() function +- hw/qdev: Cosmetic around documentation +- tests/unit: fix a -Wformat-truncation warning +- tests/avocado: mark ReplayKernelNormal.test_mips64el_malta as flaky +- i386/sev: Avoid SEV-ES crash due to missing MSR_EFER_LMA bit +- ui/vnc-clipboard: fix inflate_buffer +- hw/usb/hcd-xhci.c: spelling: tranfer + +* Tue Dec 5 2023 - 10:6.2.0-86 +- vdpa: move memory listener to the realize stage +- vdpa: implement vdpa device migration +- vhost: implement post resume bh +- vhost: implement migration state notifier for vdpa device +- vhost: implement savevm_hanlder for vdpa device +- vhost: implement vhost_vdpa_device_suspend/resume +- vhost: implement vhost-vdpa suspend/resume +- vhost: add vhost_dev_suspend/resume_op +- vhost: introduce bytemap for vhost backend logging +- vhost-vdpa: add migration log ops for VhostOps +- vhost-vdpa: add VHOST_BACKEND_F_BYTEMAPLOG +- vhost: fix null pointer access +- ui/gtk: prevent ui lock up when dpy_gl_update called again before current draw event occurs +- hw/usb: dev-mtp: Use g_mkdir() +- target/ppc/cpu-models: Remove the "default" CPU alias +- hw/intc/arm_gicv3: ICC_PMR_EL1 high bits should be RAZ +- Fixed a QEMU hang when guest poweroff in COLO mode +- migration/colo: More accurate update checkpoint time +- scripts/entitlement.sh: Use backward-compatible cp flags +- block/nvme: fix infinite loop in nvme_free_req_queue_cb() +- hw/net: npcm7xx_emc fix missing queue_flush +- Add dummy Aspeed AST2600 Display Port MCU (DPMCU) +- hw/arm: ast2600: Fix address mapping of second SPI controller +- vhost-user-blk: reconnect on any error during realize +- vhost-user-blk: propagate error return from generic vhost +- hw/riscv: boot: Reduce FDT address alignment constraints +- Revert "hw/virtio/virtio-iommu-pci: Enforce the device is plugged on the root bus" +- Fix STM32F2XX USART data register readout +- block: use 'unsigned' for in_flight field on driver state +- sphinx: change default language to 'en' +- tests/qtest: Fix two format strings +- trivial typos: namesapce +- hw/ide/atapi.c: Correct typos (CD-CDROM -> CD-ROM) +- hw/virtio/virtio-iommu-pci: Enforce the device is plugged on the root bus +- hw/display/next-fb: Fix comment typo +- xen/pass-through: merge emulated bits correctly mainline inclusion commit be9c61da9fc57eb7d293f380d0805ca6f46c2657 category: bugfix +- tests/qtest/migration-test.c: spelling fix: bandwith +- target/i386/cpu: Improve error message for property "vendor" +- balloon: Fix a misleading error message +- target/arm: Don't set syndrome ISS for loads and stores with writeback mainline inclusion commit 53ae2fdef1f5661cbaa2ea571c517f98e6041cb8 category: bugfix +- disas/hppa: Show hexcode of instruction along with disassembly +- tcg/loongarch64: Fix tcg_out_mov() Aborted +- ui/qmp-cmds: Improve two error messages +- qga: Improve guest-exec-status error message +- hmp: Improve sync-profile error message +- spapr/pci: Correct "does not support hotplugging error messages +- xen/pass-through: don't create needless register group mainline inclusion commit c0e86b7624cb9d6db03e0d48cf82659e5b89a6a6 category: bugfix + +* Fri Dec 1 2023 - 10:6.2.0-85 +- spec: Add support for the ppc64le platform + +* Tue Nov 28 2023 - 10:6.2.0-84 +- hw/arm/fsl-imx: Do not ignore Error argument +- hw/net/cadence_gem.c: spelling fixes: Octects +- tests/qtest: check the return value +- libvhost-user: Fix VHOST_USER_GET_MAX_MEM_SLOTS reply mainline inclusion commit 69a5daec06f423843ce1bb9be5fb049314996f78 category: bugfix +- io_uring: fix short read slow path mainline inclusion commit c06fc7ce147e57ab493bad9263f1601b8298484b category: bugfix +- libvhost-user: Fix VHOST_USER_ADD_MEM_REG reply mainline inclusion commit 7f27d20ded2f480f3e66d03f90ea71507b834276 category: bugfix +- qsd: Unlink absolute PID file path mainline inclusion commit 9d8f8233b9fa525a7e37350fbc18877051128c5d category: bugfix +- net: Fix a misleading error message +- vdpa: stop all svq on device deletion +- vhost: release virtqueue objects in error path +- vhost: fix the fd leak +- virtio: i2c: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX +- hw/virtio: fix typo in VIRTIO_CONFIG_IRQ_IDX comments +- virtio-net: clear guest_announce feature if no cvq backend +- vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check +- vdpa: do not block migration if device has cvq and x-svq=on +- vdpa net: block migration if the device has CVQ +- vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mq() +- vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mac() +- vdpa: fix not using CVQ buffer in case of error +- vdpa: Fix possible use-after-free for VirtQueueElement +- hw/virtio: fix vhost_user_read tracepoint +- vhost: Fix false positive out-of-bounds +- vhost: fix possible wrap in SVQ descriptor ring +- vhost: move iova_tree set to vhost_svq_start +- vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd +- virtio-crypto: verify src&dst buffer length for sym request +- vdpa: commit all host notifier MRs in a single MR transaction +- vdpa: harden the error path if get_iova_range failed +- vdpa-dev: get iova range explicitly +- virtio-pci: add support for configure interrupt +- virtio-mmio: add support for configure interrupt +- virtio-net: add support for configure interrupt +- vhost: add support for configure interrupt +- virtio: add support for configure interrupt +- vhost-vdpa: add support for config interrupt +- vhost: introduce new VhostOps vhost_set_config_call +- virtio-pci: decouple the single vector from the interrupt process +- virtio-pci: decouple notifier from interrupt process +- virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX +- vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa +- vdpa: handle VIRTIO_NET_CTRL_ANNOUNCE in vhost_vdpa_net_handle_ctrl_avail +- vhost: fix vq dirty bitmap syncing when vIOMMU is enabled +- hw/virtio: gracefully handle unset vhost_dev vdev +- hw/virtio/vhost: Fix typo in comment. +- vdpa: always start CVQ in SVQ mode if possible +- vdpa: add shadow_data to vhost_vdpa +- vdpa: store x-svq parameter in VhostVDPAState +- vdpa: add asid parameter to vhost_vdpa_dma_map/unmap +- vdpa: allocate SVQ array unconditionally +- vdpa: move SVQ vring features check to net/ +- vdpa: request iova_range only once +- vdpa: add vhost_vdpa_net_valid_svq_features +- vhost: allocate SVQ device file descriptors at device start +- vhost: set SVQ device call handler at SVQ start +- vdpa: use v->shadow_vqs_enabled in vhost_vdpa_svqs_start & stop +- vhost: enable vrings in vhost_dev_start() for vhost-user devices +- vhost-vdpa: fix assert !virtio_net_get_subqueue(nc)->async_tx.elem in virtio_net_reset +- net/vhost-vdpa.c: Fix clang compilation failure +- vhost-vdpa: allow passing opened vhostfd to vhost-vdpa +- vdpa: Remove shadow CVQ command check +- vdpa: Delete duplicated vdpa_feature_bits entry +- hw/virtio: add some vhost-user trace events +- vdpa: Allow MQ feature in SVQ +- virtio-net: Update virtio-net curr_queue_pairs in vdpa backends +- vdpa: validate MQ CVQ commands +- vdpa: Add vhost_vdpa_net_load_mq +- vdpa: extract vhost_vdpa_net_load_mac from vhost_vdpa_net_load +- vdpa: Make VhostVDPAState cvq_cmd_in_buffer control ack type +- vdpa: Delete CVQ migration blocker +- vdpa: Add virtio-net mac address via CVQ at start +- vhost_net: add NetClientState->load() callback +- vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail +- vdpa: Move command buffers map to start of net device +- vdpa: add net_vhost_vdpa_cvq_info NetClientInfo +- vhost_net: Add NetClientInfo stop callback +- vhost_net: Add NetClientInfo start callback +- vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring +- vdpa: Make SVQ vring unmapping return void +- vdpa: Remove SVQ vring from iova_tree at shutdown +- util: accept iova_tree_remove_parameter by value +- vdpa: do not save failed dma maps in SVQ iova tree +- vdpa: Skip the maps not in the iova tree +- vdpa: Fix file descriptor leak on get features error +- vdpa: Fix memory listener deletions of iova tree +- vhost: Get vring base from vq, not svq +- vdpa: Add x-svq to NetdevVhostVDPAOptions +- vdpa: Add device migration blocker +- vdpa: Extract get features part from vhost_vdpa_get_max_queue_pairs +- vdpa: Buffer CVQ support on shadow virtqueue +- vdpa: manual forward CVQ buffers +- vdpa: Export vhost_vdpa_dma_map and unmap calls +- vhost: Add svq avail_handler callback +- vhost: add vhost_svq_poll +- vhost: Expose vhost_svq_add +- vhost: add vhost_svq_push_elem +- vhost: Track number of descs in SVQDescState +- vhost: Add SVQDescState +- vhost: Decouple vhost_svq_add from VirtQueueElement +- vhost: Check for queue full at vhost_svq_add +- vhost: Move vhost_svq_kick call to vhost_svq_add +- vhost: Reorder vhost_svq_kick +- vdpa: Avoid compiler to squash reads to used idx +- virtio-net: Expose ctrl virtqueue logic +- virtio-net: Expose MAC_TABLE_ENTRIES +- vhost: move descriptor translation to vhost_svq_vring_write_descs +- util: Return void on iova_tree_remove +- virtio-net: don't handle mq request in userspace handler for vhost-vdpa +- vhost-vdpa: change name and polarity for vhost_vdpa_one_time_request() +- vhost-vdpa: backend feature should set only once +- vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa +- virtio-net: align ctrl_vq index for non-mq guest for vhost_vdpa +- virtio: add vhost support for virtio devices +- include/hw: start documenting the vhost API +- hw/virtio: add vhost_user_[read|write] trace points +- vhost: Fix element in vhost_svq_add failure +- vdpa: Fix index calculus at vhost_vdpa_svqs_start +- vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base +- vhost: Fix device's used descriptor dequeue +- vhost: Track descriptor chain in private at SVQ +- vdpa: Add missing tracing to batch mapping functions +- vhost-vdpa: fix typo in a comment +- virtio: fix --enable-vhost-user build on non-Linux +- vdpa: Expose VHOST_F_LOG_ALL on SVQ +- vdpa: Never set log_base addr if SVQ is enabled +- vdpa: Adapt vhost_vdpa_get_vring_base to SVQ +- vdpa: Add custom IOTLB translations to SVQ +- vhost: Add VhostIOVATree +- util: add iova_tree_find_iova +- util: Add iova_tree_alloc_map +- vhost: Shadow virtqueue buffers forwarding +- vdpa: adapt vhost_ops callbacks to svq +- virtio: Add vhost_svq_get_vring_addr +- vhost: Add vhost_svq_valid_features to shadow vq +- vhost: Add Shadow VirtQueue call forwarding capabilities +- vhost: Add Shadow VirtQueue kick forwarding capabilities +- vhost: Add VhostShadowVirtqueue +- vdpa: Make ncs autofree +- Revert "virtio: introduce macro IRTIO_CONFIG_IRQ_IDX" +- Revert "virtio-pci: decouple notifier from interrupt process" +- Revert "virtio-pci: decouple the single vector from the interrupt process" +- Revert "vhost-vdpa: add support for config interrupt" +- Revert "virtio: add support for configure interrupt" +- Revert "vhost: add support for configure interrupt" +- Revert "virtio-net: add support for configure interrupt" +- Revert "virtio-mmio: add support for configure interrupt" +- Revert "virtio-pci: add support for configure interrupt" +- Revert "vhost: introduce new VhostOps vhost_set_config_call" +- virtio: signal after wrapping packed used_idx +- target/i386: Adjust feature level according to FEAT_7_1_EDX +- target/i386: Add new CPU model GraniteRapids +- target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration +- target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration +- target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration +- target/i386: Add support for AVX-IFMA in CPUID enumeration +- target/i386: Add support for AMX-FP16 in CPUID enumeration +- target/i386: Add support for CMPCCXADD in CPUID enumeration +- tracetool: avoid invalid escape in Python string +- hw/pvrdma: Protect against buggy or malicious guest driver +- vga: avoid crash if no default vga card mainline inclusion commit 6985d8ede92494f3b791de01e8ee9306eb6d5e4a category: bugfix +- qom/object: Remove circular include dependency mainline inclusion commit 5bba9bcfbb42e7c016626420e148a1bf1b080835 category: bugfix +- artist: set memory region owners for buffers to the artist device mainline inclusion commit 39fbaeca096a9bf6cbe2af88572c1cb2aa62aa8c category: bugfix +- virtio-iommu: Fix the partial copy of probe request mainline inclusion commit 45461aace83d961e933b27519b81d17b4c690514 category: bugfix +- e1000: set RX descriptor status in a separate operation mainline inclusion commit 034d00d4858161e1d4cff82d8d230bce874a04d3 category: bugfix +- vhost: introduce new VhostOps vhost_set_config_call +- vhost: stick to -errno error return convention +- vhost-user: stick to -errno error return convention +- vhost-vdpa: stick to -errno error return convention +- virtio-pci: add support for configure interrupt +- virtio-mmio: add support for configure interrupt +- virtio-net: add support for configure interrupt +- vhost: add support for configure interrupt +- virtio: add support for configure interrupt +- vhost-vdpa: add support for config interrupt +- virtio-pci: decouple the single vector from the interrupt process +- virtio-pci: decouple notifier from interrupt process +- virtio: introduce macro IRTIO_CONFIG_IRQ_IDX +- pci: Fix the update of interrupt disable bit in PCI_COMMAND register +- hw/timer/npcm7xx_timer: Prevent timer from counting down past zero +- tpm_crb: mark command buffer as dirty on request completion mainline inclusion commit e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 category: bugfix +- pci: fix overflow in snprintf string formatting mainline inclusion commit 36f18c6989a3d1ff1d7a0e50b0868ef3958299b4 category: bugfix +- hw/usb/hcd-ehci: fix writeback order mainline inclusion commit f471e8b060798f26a7fc339c6152f82f22a7b33d category: bugfix +- qemu-timer: Skip empty timer lists before locking in qemu_clock_deadline_ns_all mainline inclusion commit 3f42906c9ab2c777a895b48b87b8107167e4a275 category: bugfix +- semihosting/config: Merge --semihosting-config option groups mainline inclusion commit 90c072e063737e9e8f431489bbd334452f89056e category: bugfix +- semihosting: fix memleak at semihosting_arg_fallback +- target/i386: Export GDS_NO bit to guests + +* Mon Oct 30 2023 - 10:6.2.0-83 +- hw/virtio/virtio-pmem: Replace impossible check by assertion +- tests: Fix printf format string in acpi-utils.c +- softmmu/dirtylimit: Add parameter check for hmp "set_vcpu_dirty_limit" +- disas/riscv: Fix the typo of inverted order of pmpaddr13 and pmpaddr14 +- qga: Fix memory leak when output stream is unused +- ui/vnc-clipboard: fix infinite loop in inflate_buffer (CVE-2023-3255) +- target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model +- target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES +- target/i386: Allow MCDT_NO if host supports +- target/i386: Add support for MCDT_NO in CPUID enumeration +- target/i386: Export MSR_ARCH_CAPABILITIES bits to guests +- target/i386: add support for FB_CLEAR feature +- target/i386: add support for FLUSH_L1D feature +- crypto: remove shadowed 'ret' variable +- hw/i2c/pmbus_device: Fix modifying QOM class internals from instance +- hw/arm/xlnx-zynqmp: fix unsigned error when checking the RPUs number + +* Mon Oct 30 2023 - 10:6.2.0-82 +- thread-pool: optimize scheduling of completion bottom half +- migration/rdma: zore out head.repeat to make the error more clear +- vhost-user-fs: Back up vqs before cleaning up vhost_dev +- hw/vfio/pci-quirks: Sanitize capability pointer +- hw/vfio/pci-quirks: Support alternate offset for GPUDirect Cliques +- replay: fix event queue flush for qemu shutdown +- hw/net: Fix read of uninitialized memory in ftgmac100 +- target/ppc: Fix tlbie +- target/i386: fix INVD vmexit +- qtest/npcm7xx_pwm-test: Fix memory leak in mft_qom_set +- aio-posix: zero out io_uring sqe user_data + +* Mon Oct 30 2023 - 10:6.2.0-81 +- hw/nvme: Avoid dynamic stack allocation +- ppc/vof: Fix missed fields in VOF cleanup +- ui: fix crash when there are no active_console +- tests/qtest/pflash: Clean up local variable shadowing +- target/ppc: Fix the order of kvm_enable judgment about kvmppc_set_interrupt() +- tulip: Assign default MAC address if not specified +- hw/char: fix qcode array bounds check in ESCC impl + +* Sat Sep 9 2023 - 10:6.2.0-80 +- io: remove io watch if TLS channel is closed during handshake +- hw/ssi: Fix Linux driver init issue with xilinx_spi +- chardev: report the handshake error +- vhost: Drop unused eventfd_add|del hooks +- virtio-iommu: use-after-free fix +- hw/arm/virt: Check for attempt to use TrustZone with KVM or HVF +- hw/rx: rx-gdbsim DTB load address aligned of 16byte +- vhost-user: Use correct macro name TARGET_PPC64 +- accel/kvm: Make kvm_dirty_ring_reaper_init() void +- accel/kvm: Free as when an error occurred + +* Mon Aug 28 2023 - 10:6.2.0-79 +- test: Fix test-crypto-secret when compiling without keyring support +- aio-posix: fix build failure io_uring 2.2 + +* Tue Aug 15 2023 - 10:6.2.0-78 +- sw_64: Added sw64 architecture related updates +- virtio-crypto: verify src&dst buffer length for sym request +- vhost-vdpa: do not cleanup the vdpa/vhost-net structures if peer nic is present +- qga: Fix suspend on Linux guests without systemd +- tests: vhost-user-test: release mutex on protocol violation +- qapi: support updating expected test output via make +- block: Fix misleading hexadecimal format +- block/rbd: fix write zeroes with growing images +- block/nbd.c: Fixed IO request coroutine not being wakeup when kill NBD server +- block/nfs: Fix 32-bit Windows build +- qapi/qdev: Tidy up device_add documentation +- hw/xen/xen_pt: fix uninitialized variable +- migration/ram: Fix error handling in ram_write_tracking_start() +- docs/about/build-platforms: Refine the distro support policy +- xen-block: Avoid leaks on new error path +- QGA VSS: Add wrapper to send log to debugger and stderr +- chardev/char-socket: set s->listener = NULL in char_socket_finalize +- qapi/block: Tidy up block-latency-histogram-set documentation +- disas/riscv Fix ctzw disassemble +- vfio: Fix vfio_get_dev_region() trace event +- migration/ram: Fix populate_read_range() +- Check and report for incomplete 'global' option format + +* Mon Aug 7 2023 - 10:6.2.0-77 +- test-vmstate: fix bad GTree usage, use-after-free + +* Fri Jul 28 2023 - 10:6.2.0-76 +- qga/win32: Use rundll for VSS installation +- qga/win32: Remove change action from MSI installer +- ide: Increment BB in-flight counter for TRIM BH +- hw/pci-bridge/pxb: Fix missing swizzle +- host-vdpa: make notifiers _init()/_uninit() symmetric +- hw/virtio: vdpa: Fix leak of host-notifier memory-region +- accel/tcg/cpu-exec: Fix precise single-stepping after interrupt +- Allow setting up to 8 bytes with the generic loader +- hw/net/virtio-net: make some VirtIONet const +- accel/tcg: Optimize jump cache flush during tlb range flush +- 9pfs: prevent opening special files (CVE-2023-2861) +- tcg: Reduce tcg_assert_listed_vecop() scope +- gitlab: Disable plugins for cross-i386-tci +- vfio/pci: Fix a segfault in vfio_realize +- block/iscsi: fix double-free on BUSY or similar statuses +- tests/tcg: fix unused variable in linux-test +- hw/net/vmxnet3: allow VMXNET3_MAX_MTU itself as a value +- qga/vss-win32: fix warning for clang++-15 +- vnc: avoid underflow when accessing user-provided address +- block/monitor: Fix crash when executing HMP commit +- virtio-gpu: add a FIXME for virtio_gpu_load() +- hw/ppc/Kconfig: MAC_NEWWORLD should always select USB_OHCI_PCI +- migration: report compress thread pid to libvirt + +* Thu Jun 29 2023 - 10:6.2.0-75 +- Add lbt support for kvm. +- Fix smp.cores value and Fix divide 0 error +- hw/nvme: Change alignment in dma functions for nvme_blk_* +- virtio: fix reachable assertion due to stale value of cached region size +- hw/nvme: fix missing DNR on compare failure + +* Thu May 25 2023 - 10:6.2.0-74 +- spec: delete repetitive man8/qemu-ga.8* from qemu-guest-agent package + +* Fri May 19 2023 - 10:6.2.0-73 +- spec: delete useless core3-hmcode/core3-reset/uefi-bios-sw + +* Wed May 17 2023 - 10:6.2.0-72 +- migration/xbzrle: fix out-of-bounds write with axv512 +- migration/xbzrle: use ctz64 to avoid undefined result +- Update bench-code for addressing CI problem +- AVX512 support for xbzrle_encode_buffer +- configure, meson: move AVX tests to meson +- target/i386: KVM: allow fast string operations if host supports them +- target/i386: add FSRM to TCG +- hw/nvme: fix memory leak in nvme_dsm +- aio-posix: fix race between epoll upgrade and aio_set_fd_handler() +- target/i386: Add SGX aex-notify and EDECCSSA support +- hw/usb/imx: Fix out of bounds access in imx_usbphy_read() +- target/i386: Set maximum APIC ID to KVM prior to vCPU creation +- target/i386: Fix sanity check on max APIC ID / X2APIC enablement + +* Sat Apr 22 2023 - 10:6.2.0-71 +- vhost-user-blk: fix the resize crash +- plugins: make qemu_plugin_user_exit's locking order consistent with fork_start's +- linux-user: fix strace build w/out munlockall +- ui: fix crash on serial reset, during init +- qga/win/vss: requester_freeze changes +- migration: fix populate_vfio_info +- block/rbd: workaround for ceph issue #53784 +- target/i386: add FZRM, FSRS, FSRC +- i386: Add new CPU model SapphireRapids +- core/cpu-common: Fix the wrong '#ifdef __aarch64__' + +* Thu Mar 30 2023 - 10:6.2.0-70 +- Add spice buildrequires for loongarch. + +* Wed Mar 29 2023 - 10:6.2.0-69 +- fixup compile error. Add function kvm_arch_accel_class_init definition on loongarch64 machine. + +* Wed Mar 29 2023 - 10:6.2.0-68 +- modify qemu.spec to add (riscv virt) machine mapping to testenv from v7.0.0 + +* Tue Mar 28 2023 - 10:6.2.0-67 +- hw/net/vmxnet3: Log guest-triggerable errors using LOG_GUEST_ERROR mainline +- net/eth: Don't consider ESP to be an IPv6 option header mainline +- net: Fix uninitialized data usage mainline +- block-backend: prevent dangling BDS pointers across aio_poll() mainline inclusion +- i386: add notify VM exit support +- kvm: expose struct KVMState +- kvm: allow target-specific accelerator properties +- i386: kvm: extend kvm_{get, put}_vcpu_events to support pending triple fault +- linux-headers: include missing changes from 6.0 +- dsoundaudio: fix crackling audio recordings mainline +- hw/audio/intel-hda: fix stream reset mainline +- hw/pvrdma: Protect against buggy or malicious guest driver +- qemu support for loongarch +- hw/pci: Trace IRQ routing on PCI topology +- hw/pci: Fix a typo +- hw/riscv: virt: Simplify virt_{get,set}_aclint() +- curl: Fix error path in curl_open() +- tests: add (riscv virt) machine mapping to testenv from v7.0.0 +- tests/tcg: Fix target-specific Makefile variables path for user-mode mainline +- hw/core/machine:Fix the missing consideration of cluster-id +- arm/virt: Correct timing of pause all vcpus for hot-plugged CPUs +- arm/virt: Correct timing of executing cpu_synchronize_post_init for hot-plugged cpus +- hw/acpi: Support acpi-ged to report CPU's OST info +- hw/acpi: Add ospm_status hook implementation for acpi-ged +- fix qmp command migrate-set-parameters + +* Wed Mar 22 2023 MinMin Ren - 10:6.2.0-66 +- spec: Add multiboot_dma.bin + +* Tue Dec 20 2022 yezengruan - 10:6.2.0-65 +- linux-user: Add strace output for timer_settime64() syscall +- fix qemu-core when vhost-user-net config with server mode + +* Wed Dec 14 2022 yezengruan - 10:6.2.0-64 +- target/arm: Fix kvm probe of ID_AA64ZFR0 +- migration: report migration/multiFd related thread pid to libvirt +- vhost_net: keep acked_feature only for NET_CLIENT_DRIVER_VHOST_USER + +* Mon Dec 12 2022 Qiang Wei - 10:6.2.0-63 +- Use bcond_without to control conditional build + +* Thu Dec 8 2022 Qiang Wei - 10:6.2.0-62 +- Make Ceph rbd support an optional feature. + +* Wed Dec 07 2022 yezengruan - 10:6.2.0-61 +- BuildRequires add make + +* Tue Dec 06 2022 yezengruan - 10:6.2.0-60 +- sync some bugfix patches from upstream +- fix the virtio features negotiation flaw +- fix CVE-2022-4144 + +* Tue Nov 22 2022 yezengruan - 10:6.2.0-59 +- arm/virt: Fix vcpu hotplug idx_from_topo_ids +- Revert patches related to the vSVA +- sync some bugfix patches from upstream +- add generic vDPA device support + +* Mon Nov 14 2022 weishaokun - 10:6.2.0-58 +- support io-uring by adding --enable-io-uring compilation option + +* Tue Nov 08 2022 yezengruan - 10:6.2.0-57 +- build: make check with -j + +* Mon Nov 07 2022 yuelongguang - 10:6.2.0-56 +- support rbd by adding --enable-rbd compilation option + +* Thu Nov 03 2022 yezengruan - 10:6.2.0-55 +- support dirty restraint on vCPU +- support SPR AMX in Qemu +- fix compilation errors of sw64 + +* Mon Oct 24 2022 fushanqing - 10:6.2.0-54 +- add '--enable-slirp' compilation options + +* Fri Oct 21 2022 yezengruan - 10:6.2.0-53 +- ui/vnc-clipboard: fix integer underflow in vnc_client_cut_text_ext (CVE-2022-3165) + +* Fri Sep 30 2022 wanbo - 10:6.2.0-52 +- job.c: add missing notifier initialization +- uas: add missing return +- qom: assert integer does not overflow +- pci: expose TYPE_XI03130_DOWNSTREAM name +- acpi: pcihp: pcie: set power on cap on parent slot +- hw/display/ati_2d: Fix buffer overflow in ati_2d_blt + +* Fri Sep 30 2022 zhangxinhao - 10:6.2.0-51 +- exec/memory: Extract address_space_set() from dma_memory_set() +- hw/elf_ops: clear uninitialized segment space +- vhost: also check queue state in the vhost_dev_set_log +- vhost-net: fix improper cleanup in vhost_net_start +- virtio-net: setup vhost_dev and notifiers for cvq only + +* Fri Sep 30 2022 zhangbo - 10:6.2.0-50 +- net: tulip: Restrict DMA engine to memories (CVE-2020-14394) + +* Sat Sep 03 2022 yezengruan - 10:6.2.0-49 +- hw/usb/hcd-xhci: Fix unbounded loop in xhci_ring_chain_length() (CVE-2020-14394) + +* Tue Aug 30 2022 yezengruan - 10:6.2.0-48 +- hw/scsi/lsi53c895a: Do not abort when DMA requested and no data queued +- tests/qtest: Add fuzz-lsi53c895a-test +- scsi/lsi53c895a: fix use-after-free in lsi_do_msgout (CVE-2022-0216) +- scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout (CVE-2022-0216) + +* Mon Aug 29 2022 Zhang Bo - 10:6.2.0-47 +- backport nbd related patches to avoid vm crash during migration + +* Thu Aug 25 2022 yezengruan - 10:6.2.0-46 +- vhost-user: remove VirtQ notifier restore +- vhost-user: fix VirtQ notifier cleanup +- enable vDPA build params +- Provides qemu-kvm for upgrade + +* Thu Aug 11 2022 yezengruan - 2:6.2.0-45 +- numa: Enable numa for SGX EPC sections +- target/ppc: enhance error handling in kvmppc_read_int* +- fix pointer double free in func qemu_savevm_state_complete_precopy_non_iterable + +* Mon Jul 25 2022 yezengruan - 2:6.2.0-44 +- add Requires libgcc + +* Tue Jul 19 2022 cenhuilin - 2:6.2.0-43 +- softmmu Always initialize xlat in address_space_tran (CVE-2022-35414) + +* Tue Jul 12 2022 liuxiangdong - 2:6.2.0-42 +- acpi: validate hotplug selector on access +- virtiofsd: Drop membership of all supplementary groups (CVE-2022-0358) + +* Wed Jun 22 2022 yezengruan - 2:6.2.0-41 +- hw/nvme: fix CVE-2021-3929 + +* Mon Jun 20 2022 zhangziyang - 2:6.2.0-40 +- add qemu-system-riscv rpm package build + +* Thu Jun 09 2022 yezengruan - 2:6.2.0-39 +- hw/scsi/megasas: Use uint32_t for reply queue head/tail values +- dma: Let dma_memory_valid() take MemTxAttrs argument +- dma: Let dma_memory_set() take MemTxAttrs argument +- dma: Let dma_memory_rw_relaxed() take MemTxAttrs argument +- dma: Let dma_memory_rw() take MemTxAttrs argument +- dma: Let dma_memory_read/write() take MemTxAttrs argument +- dma: Let dma_memory_map() take MemTxAttrs argument +- dma: Have dma_buf_rw() take a void pointer +- dma: Have dma_buf_read() / dma_buf_write() take a void pointer +- pci: Let pci_dma_rw() take MemTxAttrs argument +- dma: Let dma_buf_rw() take MemTxAttrs argument +- dma: Let dma_buf_write() take MemTxAttrs argument +- dma: Let dma_buf_read() take MemTxAttrs argument +- dma: Let dma_buf_rw() propagate MemTxResult +- dma: Let st*_dma() take MemTxAttrs argument +- dma: Let ld*_dma() take MemTxAttrs argument +- dma: Let st*_dma() propagate MemTxResult +- dma: Let ld*_dma() propagate MemTxResult +- pci: Let st*_pci_dma() take MemTxAttrs argument +- pci: Let ld*_pci_dma() take MemTxAttrs argument +- pci: Let st*_pci_dma() propagate MemTxResult +- pci: Let ld*_pci_dma() propagate MemTxResult +- hw/audio/intel-hda: Do not ignore DMA overrun errors +- hw/audio/intel-hda: Restrict DMA engine to memories (not MMIO devices) +- tests/qtest/intel-hda-test: Add reproducer for issue #542 + +* Mon May 30 2022 yezengruan - 2:6.2.0-38 +- acpi: fix QEMU crash when started with SLIC table +- tests: acpi: whitelist expected blobs before changing them +- tests: acpi: add SLIC table test +- tests: acpi: SLIC: update expected blobs +- hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507) +- tests/qtest/fdc-test: Add a regression test for CVE-2021-3507 + +* Mon May 30 2022 zhangziyang - 2:6.2.0-37 +- add qemu-system-x86_64, qemu-system-aarch64, qemu-system-arm rpm package build + +* Thu May 26 2022 Jun Yang - 2:6.2.0-36 +- Remove unnecessary dependency of kernel package + +* Sat May 21 2022 yezengruan - 2:6.2.0-35 +- hw/intc/arm_gicv3: Check for !MEMTX_OK instead of MEMTX_ERROR (CVE-2021-3750) +- softmmu/physmem: Simplify flatview_write and address_space_access_valid +- softmmu/physmem: Introduce MemTxAttrs::memory field and MEMTX_ACCESS_ERROR + +* Tue May 10 2022 yezengruan - 2:6.2.0-34 +- display/qxl-render: fix race condition in qxl_cursor (CVE-2021-4207) +- ui/cursor: fix integer overflow in cursor_alloc (CVE-2021-4206) + +* Wed Apr 27 2022 yezengruan - 6.2.0-33 +- update the format of changelog + +* Wed Apr 27 2022 yezengruan - 6.2.0-32 +- vfio/pci: Ascend710 change to bar2 quirk + +* Fri Apr 15 2022 yezengruan - 6.2.0-31 +- vhost-vsock: detach the virqueue element in case of error (CVE-2022-26354) +- virtio-net: fix map leaking on error during receive (CVE-2022-26353) + +* Wed Mar 30 2022 yezengruan - 6.2.0-30 +- scsi-bus: fix incorrect call for blk_error_retry_reset_timeout() +- Revert "monitor: limit io error qmp event to at most once per 60s" + +* Fri Mar 25 2022 Jinhua Cao - 6.2.0-29 +- qemu-img create: 'cache' paramter only use for reg file image + +* Thu Mar 24 2022 Yan Wang - 6.2.0-28 +- spec: add hw-usb-host rpm package + +* Fri Mar 18 2022 yezengruan - 6.2.0-27 +- coro: support live patch for libcare +- add patch for sw64 support + +* Tue Mar 15 2022 jiangdawei - 6.2.0-26 +- cflags: add ftls-mode=initial-exec + +* Tue Mar 15 2022 yezengruan - 6.2.0-25 +- sw_64: Add sw64 architecture support +- update BinDir + +* Mon Mar 14 2022 jiangdawei - 6.2.0-24 +- qemu.spec: Add --enable-debug parameter to configure + +* Thu Mar 03 2022 Chen Qun - 6.2.0-23 +- tools/virtiofsd: Add rseq syscall to the seccomp allowlist + +* Thu Mar 03 2022 Chen Qun - 6.2.0-23 +- scsi-bus: fix unmatched object_unref() + +* Sat Feb 26 2022 Yan Wang - 6.2.0-22 +- pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch +- qcow2-fix-memory-leak-in-qcow2_read_extensions.patch +- scsi-disk-define-props-in-scsi_block_disk-to-avoid-m.patch +- pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch +- pcie-Compat-with-devices-which-do-not-support-Link-W.patch + +* Wed Feb 23 2022 Chen Qun - 6.2.0-21 +- acpi/madt: Factor out the building of MADT GICC struct +- hw/arm/virt: Assign virt_madt_cpu_entry to acpi_ged madt_cpu hook +- arm/virt/acpi: Factor out CPPC building from DSDT CPU aml +- acpi/cpu: Prepare build_cpus_aml for arm virt +- acpi/ged: Extend ACPI GED to support CPU hotplug +- arm/cpu: assign arm_get_arch_id handler to get_arch_id hook +- tests/acpi/bios-tables-test: Allow changes to virt/DSDT file +- arm/virt: Attach ACPI CPU hotplug support to virt +- tests/acpi/bios-table-test: Update expected virt/DSDT file +- arm/virt: Add CPU hotplug framework +- arm/virt: Add CPU topology support +- test/numa: Adjust aarch64 numa test +- hw/arm/virt: Factor out some CPU init codes to pre_plug hook +- hw/arm/boot: Add manually register and trigger of CPU reset +- arm/virt/gic: Construct irqs connection from create_gic +- intc/gicv3_common: Factor out arm_gicv3_common_cpu_realize +- intc/gicv3_cpuif: Factor out gicv3_init_one_cpuif +- intc/kvm_gicv3: Factor out kvm_arm_gicv3_cpu_realize +- hw/intc/gicv3: Add CPU hotplug realize hook +- accel/kvm: Add pre-park vCPU support +- intc/gicv3: Add pre-sizing capability to GICv3 +- acpi/madt: Add pre-sizing capability to MADT GICC struct +- arm/virt: Add cpu_hotplug_enabled field +- arm/virt/acpi: Extend cpufreq to support max_cpus +- arm/virt: Pre-sizing MADT-GICC GICv3 and Pre-park KVM vCPU +- arm/virt: Start up CPU hot-plug and cold-plug + +* Mon Feb 21 2022 Chen Qun - 6.2.0-20 +- i386/cpu: fix compile error in all target configure + +* Mon Feb 21 2022 Chen Qun - 6.2.0-19 +- pl031: support rtc-timer property for pl031 + +* Mon Feb 21 2022 Chen Qun - 6.2.0-19 +- target/arm: Fix some compile errors + +* Mon Feb 21 2022 Chen Qun - 6.2.0-19 +- Revert "qmp: add command to query used memslots of vhost-net and vhost-user" + +* Thu Feb 17 2022 imxcc - 6.2.0-19 +- qapi/machine.json: Fix incorrect description for die-id +- tests/unit/test-smp-parse: Pass machine type as +- tests/unit/test-smp-parse: Split the 'generic' test in +- tests/unit/test-smp-parse: Add 'smp-with-dies' machine +- tests/unit/test-smp-parse: Add 'smp-generic-invalid' +- tests/unit/test-smp-parse: Add 'smp-generic-valid' +- tests/unit/test-smp-parse: Simplify pointer to compound +- tests/unit/test-smp-parse: Constify some pointer/struct +- hw/core: Rename smp_parse() -> +- qemu-options: Improve readability of SMP related Docs +- hw/core/machine: Introduce CPU cluster topology support +- tests/unit/test-smp-parse: Add testcases for CPU +- tests/unit/test-smp-parse: No need to explicitly zero +- tests/unit/test-smp-parse: Keep default MIN/MAX CPUs in +- hw/arm/virt: Support CPU cluster on ARM virt machine +- hw/arm/virt: Support cluster level in DT cpu-map +- hw/acpi/aml-build: Improve scalability of PPTT +- tests/acpi/bios-tables-test: Allow changes to virt/PPTT +- hw/acpi/aml-build: Support cluster level in PPTT +- tests/acpi/bios-table-test: Update expected virt/PPTT +- update BinDir +- softmmu/device_tree: Silence compiler warning with +- softmmu/device_tree: Remove redundant pointer +- hw/arm64: add vcpu cache info support +- update BinDir +- arm64: Add the cpufreq device to show cpufreq info to +- update BinDir + +* Thu Feb 17 2022 imxcc - 6.2.0-18 +- bios-tables-test: Update expected q35/SSDT.dimmpxm file +- spec: add BinDir + +* Tue Feb 15 2022 Liuxiangdong - 6.2.0-17 +- feature: disable spice protocol + +* Mon Feb 14 2022 Chen Qun - 6.2.0-16 +- log: Delete redudant qemu_log + +* Mon Feb 14 2022 Chen Qun - 6.2.0-15 +- qemu-img: add qemu-img direct create + +* Mon Feb 14 2022 eillon - 6.2.0-15 +- seabios: add check to avoid dereference NULL pointer + +* Sat Feb 12 2022 Chen Qun - 6.2.0-14 +- bugfix: irq: Avoid covering object refcount of qemu_irq + +* Sat Feb 12 2022 Chen Qun - 6.2.0-13 +- virtio-scsi: bugfix: fix qemu crash for hotplug scsi disk with dataplane +- virtio: net-tap: bugfix: del net client if net_init_tap_one failed +- virtio: bugfix: clean up callback when del virtqueue +- virtio-net: bugfix: do not delete netdev before virtio net +- virtio-net: fix max vring buf size when set ring num +- virtio: check descriptor numbers +- virtio: bugfix: add rcu_read_lock when vring_avail_idx is called +- virtio: print the guest virtio_net features that host does not support +- virtio: bugfix: check the value of caches before accessing it +- virtio-net: set the max of queue size to 4096 +- virtio-net: update the default and max of rx/tx_queue_size +- vhost-user: add unregister_savevm when vhost-user cleanup +- qemu-img: block: dont blk_make_zero if discard_zeroes false +- vhost-user: Add support reconnect vhost-user socket +- vhost-user: Set the acked_features to vm's featrue +- vhost-user: add vhost_set_mem_table when vm load_setup at destination +- vhost-user: add separate memslot counter for vhost-user +- vhost-user: quit infinite loop while used memslots is more than the backend limit +- qmp: add command to query used memslots of vhost-net and vhost-user +- vhost-user-scsi: add support for SPDK hot upgrade +- i6300esb watchdog: bugfix: Add a runstate transition + +* Sat Feb 12 2022 Chen Qun - 6.2.0-13 +- bugfix: fix some illegal memory access and memory leak +- bugfix: fix possible memory leak +- bugfix: fix eventfds may double free when vm_id reused in ivshmem +- block/mirror: fix file-system went to read-only after block-mirror +- bugfix: fix mmio information leak and ehci vm escape 0-day vulnerability +- target-i386: Fix the RES memory inc which caused by the coroutine created + +* Sat Feb 12 2022 Chen Qun - 6.2.0-13 +- log: Add log at boot & cpu init for aarch64 +- feature: Add log for each modules +- feature: Add logs for vm start and destroy + +* Sat Feb 12 2022 Chen Qun - 6.2.0-12 - linux-headers: update against 5.10 and manual clear vfio dirty log series - vfio: Maintain DMA mapping range for the container - vfio/migration: Add support for manual clear vfio dirty log -- hw/arm/smmuv3: Support 16K translation granule -- hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly -- hw/vfio/common: trace vfio_connect_container operations - update-linux-headers: Import iommu.h - vfio.h and iommu.h header update against 5.10 - memory: Add new fields in IOTLBEntry @@ -996,615 +2313,139 @@ getent passwd qemu >/dev/null || \ - vfio: Add vfio_prereg_listener_log_clear to re-enable mark dirty pages - vfio: Add vfio_prereg_listener_global_log_start/stop in nested stage - hw/arm/smmuv3: Post-load stage 1 configurations to the host +- vfio/common: Fix incorrect address alignment in vfio_dma_map_ram_section +- vfio/common: Add address alignment check in vfio_listener_region_del -* Tue Aug 03 2021 Chen Qun -- kvm: split too big memory section on several memslots -- kvm: Reallocate dirty_bmap when we change a slot -- accel: kvm: Fix memory waste under mismatch page size -- memory: Skip dirty tracking for un-migratable memory regions -- Fix use after free in vfio_migration_probe -- vfio: Make migration support experimental -- vfio: Change default dirty pages tracking behavior during migration -- vfio: Fix vfio_listener_log_sync function name typo - -* Thu Jul 29 2021 Chen Qun -- vfio: Move the saving of the config space to the right place in VFIO migration -- vfio: Set the priority of the VFIO VM state change handler explicitly -- vfio: Avoid disabling and enabling vectors repeatedly in VFIO migration - -* Thu Jul 29 2021 imxcc -- hw/net: fix vmxnet3 live migration -- include: Make headers more self-contained -- migration: register_savevm_live doesn't need dev -- vmstate: add qom interface to get id -- linux headers: Update against "Add migration support for VFIO devices" -- vfio: Add function to unmap VFIO region -- vfio: Add vfio_get_object callback to VFIODeviceOps -- vfio: Add save and load functions for VFIO PCI devices -- vfio: Add migration region initialization and finalize function -- vfio: Add VM state change handler to know state of VM -- vfio: Add migration state change notifier -- vfio: Register SaveVMHandlers for VFIO device -- vfio: Add save state functions to SaveVMHandlers -- vfio: Add load state functions to SaveVMHandlers -- memory: Set DIRTY_MEMORY_MIGRATION when IOMMU is enabled -- vfio: Get migration capability flags for container -- vfio: Add function to start and stop dirty pages tracking -- vfio: Add vfio_listener_log_sync to mark dirty pages -- vfio: Dirty page tracking when vIOMMU is enabled -- vfio: Add ioctl to get dirty pages bitmap during dma unmap -- vfio: Make vfio-pci device migration capable -- qapi: Add VFIO devices migration stats in Migration stats - -* Wed Jul 28 2021 imxcc -- object: return self in object_ref() -- file-posix: Fix leaked fd in raw_open_common() error path -- qga/commands-posix: fix use after free of local_err -- qmp: fix leak on callbacks that return both value and error -- migration: fix cleanup_bh leak on resume -- Fixed integer overflow in e1000e -- lm32-do-not-leak-memory-on-object_new-object_unref.patch -- cris-do-not-leak-struct-cris_disasm_data.patch -- hppa-fix-leak-from-g_strdup_printf.patch -- mcf5208-fix-leak-from-qemu_allocate_irqs.patch -- microblaze-fix-leak-of-fdevice-tree-blob.patch -- ide-fix-leak-from-qemu_allocate_irqs.patch -- make-check-unit-use-after-free-in-test-opts-visitor.patch -- virtio-pci: fix queue_enable write -- hw/block/nvme: fix pci doorbell size calculation -- hw/block/nvme: fix pin-based interrupt behavior -- colo-compare: Fix memory leak in packet_enqueue() -- chardev/tcp: Fix error message double free error -- qga: Plug unlikely memory leak in guest-set-memory-blocks -- migration: Count new_dirty instead of real_dirty -- char: fix use-after-free with dup chardev & reconnect -- qga: fix assert regression on guest-shutdown -- xhci: fix valid.max_access_size to access address registers -- block/qcow2: do free crypto_opts in qcow2_close() -- qemu-img: free memory before re-assign -- block/qcow2-threads: fix qcow2_decompress -- block: Avoid memleak on qcow2 image info failure -- block: bdrv_set_backing_bs: fix use-after-free -- hmp/vnc: Fix info vnc list leak -- migration/colo: fix use after free of local_err -- migration/ram: fix use after free of local_err -- block/mirror: fix use after free of local_err -- block: fix bdrv_root_attach_child forget to unref child_bs -- virtio-serial-bus: Plug memory leak on realize() error paths -- virtio-blk: delete vqs on the error path in realize() -- fix vhost_user_blk_watch crash -- vhost-user-blk: delay vhost_user_blk_disconnect -- hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch -- linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch -- migration-rdma-cleanup-rdma-context-before-g_free-to.patch -- pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch -- usbredir-fix-buffer-overflow-on-vmload.patch -- apic: Use 32bit APIC ID for migration instance-ID -- audio: fix integer overflow -- display/bochs-display: fix memory leak -- migration: Change SaveStateEntry.instance_id into uint32_t -- migration: Define VMSTATE_INSTANCE_ID_ANY -- migration/multifd: clean pages after filling packet -- migration/multifd: not use multifd during postcopy -- virtio: add ability to delete vq through a pointer -- virtio-pmem: do delete rq_vq in virtio_pmem_unrealize -- virtio-crypto: do delete ctrl_vq in virtio_crypto_device_unrealize -- vhost-user-blk: delete virtioqueues in unrealize to fix memleaks -- vhost-user-blk: convert to new virtio_delete_queue -- block/nbd: extract the common cleanup code -- virtio: gracefully handle invalid region caches -- migration/savevm: release gslist after dump_vmstate_json -- virtio-input: fix memory leak on unrealize +* Sat Feb 12 2022 Chen Qun - 6.2.0-11 +- log: Add some logs on VM runtime path +- qdev/monitors: Fix reundant error_setg of qdev_add_device +- bios-tables-test: Allow changes to q35/SSDT.dimmpxm file +- smbios: Add missing member of type 4 for smbios 3.0 +- net: eepro100: validate various address valuesi(CVE-2021-20255) +- pci: check bus pointer before dereference +- ide: ahci: add check to avoid null dereference (CVE-2019-12067) +- tap: return err when tap TUNGETIFF fail +- xhci: check reg to avoid OOB read +- monitor: Discard BLOCK_IO_ERROR event when VM rebooted +- monitor: limit io error qmp event to at most once per 60s + +* Sat Feb 12 2022 Chen Qun - 6.2.0-11 +- util/log: add CONFIG_DISABLE_QEMU_LOG macro + +* Sat Feb 12 2022 Yan Wang - 6.2.0-11 +- ipxe: IPv6 add support for IPv6 protocol +- u-boot: Use post increment only in inffast.c + +* Sat Feb 12 2022 jiangdongxu - 6.2.0-10 +- seabios: convert value of be16_to_cpu to u64 before shifting +- seabios: do not give back high ram +- seabios: fix memory leak when pci check +- seabios: drop yield() in smp_setup() +- seabios: increase the seabios minibiostable +- seabios: increase the seabios high mem zone size + +* Fri Feb 11 2022 Chen Qun - 6.2.0-9 +- hw/net/rocker: fix security vulnerability +- tests: Disable filemonitor testcase + +* Fri Feb 11 2022 Chen Qun - 6.2.0-8 +- hw/usb: reduce the vpcu cost of UHCI when VNC disconnect + +* Fri Feb 11 2022 Chen Qun - 6.2.0-8 +- freeclock: add qmp command to get time offset of vm in seconds +- freeclock: set rtc_date_diff for arm +- freeclock: set rtc_date_diff for X86 + +* Fri Feb 11 2022 Chen Qun - 6.2.0-8 +- target/arm: convert isar regs to array +- target/arm: parse cpu feature related options +- target/arm: register CPU features for property +- target/arm: Allow ID registers to synchronize to KVM +- target/arm: introduce CPU feature dependency mechanism +- target/arm: introduce KVM_CAP_ARM_CPU_FEATURE +- target/arm: Add CPU features to query-cpu-model-expansion +- target/arm: Add more CPU features +- target/arm: ignore evtstrm and cpuid CPU features - target/arm: only set ID_PFR1_EL1.GIC for AArch32 guest +- target/arm: Fix write redundant values to kvm - target/arm: clear EL2 and EL3 only when kvm is not enabled - target/arm: Update the ID registers of Kunpeng-920 -* Fri Jul 23 2021 imxcc -- hw/arm/virt: Init PMU for hotplugged vCPU - -* Fri Jul 23 2021 Chen Qun -- vl: Don't mismatch g_strsplit()/g_free() -- seqlock: fix seqlock_write_unlock_impl function -- target/i386: kvm: initialize microcode revision from KVM -- target/i386: check for availability of MSR_IA32_UCODE_REV as an emulated MSR - -* Thu Jul 22 2021 Chen Qun -- qapi/block-core: Introduce BackupCommon -- drive-backup: create do_backup_common -- blockdev-backup: utilize do_backup_common -- qapi: add BitmapSyncMode enum -- block/backup: Add mirror sync mode 'bitmap' -- block/backup: add 'never' policy to bitmap sync mode -- block/backup: loosen restriction on readonly bitmaps -- block/backup: hoist bitmap check into QMP interface -- block/backup: deal with zero detection -- mirror: Fix bdrv_has_zero_init() use -- blockdev: fix coding style issues in drive_backup_prepare -- blockdev: unify qmp_drive_backup and drive-backup transaction paths -- blockdev: unify qmp_blockdev_backup and blockdev-backup transaction paths -- blockdev: honor bdrv_try_set_aio_context() context requirements -- blockdev: Return bs to the proper context on snapshot abort -- block: Fix cross-AioContext blockdev-snapshot - -* Thu Jul 22 2021 Chen Qun -- hw/pci/pcie: Move hot plug capability check to pre_plug callback - -* Thu Jul 22 2021 Chen Qun -- migration: use migration_is_active to represent active state -- migration: Rate limit inside host pages - -* Thu Jul 22 2021 Chen Qun -- virtio-net: delete also control queue when TX/RX deleted -- target/i386: enable monitor and ucode revision with -cpu max -- target/i386: set the CPUID level to 0x14 on old machine-type -- target/i386: kvm: initialize feature MSRs very early -- target/i386: add a ucode-rev property - -* Thu Jul 22 2021 Chen Qun -- qcow2: Fix qcow2_alloc_cluster_abort() for external data file -- mirror: Wait only for in-flight operations - -* Wed Jul 21 2021 Chen Qun -- block/curl: HTTP header fields allow whitespace around values -- block/curl: HTTP header field names are case insensitive -- backup: Improve error for bdrv_getlength() failure -- mirror: Make sure that source and target size match -- iotests/143: Create socket in $SOCK_DIR -- nbd/server: Avoid long error message assertions CVE-2020-10761 -- block: Call attention to truncation of long NBD exports -- qemu-img convert: Don't pre-zero images - -* Wed Jul 21 2021 Chen Qun -- virtio: don't enable notifications during polling -- usbredir: Prevent recursion in usbredir_write -- xhci: recheck slot status -- vhost: Add names to section rounded warning -- vhost-user: Print unexpected slave message types -- contrib/libvhost-user: Protect slave fd with mutex -- libvhost-user: Fix some memtable remap cases -- xics: Don't deassert outputs -- i386: Resolve CPU models to v1 by default - -* Wed Jul 21 2021 imxcc -- target/i386: handle filtered_features in a new function mark_unavailable_features -- target/i386: introduce generic feature dependency mechanism -- target/i386: expand feature words to 64 bits -- target/i386: add VMX definitions -- vmxcap: correct the name of the variables -- target/i386: add VMX features -- target/i386: work around KVM_GET_MSRS bug for secondary execution controls -- target/i386: add VMX features to named CPU models -- target/i386: add two missing VMX features for Skylake and CascadeLake Server -- target/i386: disable VMX features if nested=0 -- i386/cpu: Don't add unavailable_features to env->user_features -- target/i386: do not set unsupported VMX secondary execution controls -- migration: fix multifd_send_pages() next channel -- migration: Make sure that we don't call write() in case of error - -* Tue Jul 20 2021 Chen Qun -- crypto: add support for nettle's native XTS impl -- crypto: add support for gcrypt's native XTS impl -- tests: benchmark crypto with fixed data size, not time period -- tests: allow filtering crypto cipher benchmark tests - -* Tue Jul 20 2021 Chen Qun -- target/i386: Introduce Denverton CPU model -- target/i386: Add Snowridge-v2 (no MPX) CPU model -- i386: Add CPUID bit for CLZERO and XSAVEERPTR - -* Mon Jul 19 2021 Chen Qun -- x86: Intel AVX512_BF16 feature enabling -- i386: Add MSR feature bit for MDS-NO -- i386: Add macro for stibp -- i386: Add new CPU model Cooperlake -- target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES -- target/i386: Add missed security features to Cooperlake CPU model -- target/i386: add PSCHANGE_NO bit for the ARCH_CAPABILITIES MSR -- target/i386: Export TAA_NO bit to guests - -* Mon Jul 19 2021 Chen Qun -- hw/net/rocker_of_dpa: fix double free bug of rocker device - -* Mon Jun 28 2021 imxcc -- spec: add gcc buildrequire - -* Mon Jun 21 2021 Chen Qun -- ide: ahci: add check to avoid null dereference (CVE-2019-12067) -- hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register -- usb: limit combined packets to 1 MiB (CVE-2021-3527) - -* Tue Jun 15 2021 Chen Qun -- vhost-user-gpu: fix resource leak in 'vg_resource_create_2d' (CVE-2021-3544) -- vhost-user-gpu: fix memory leak in vg_resource_attach_backing (CVE-2021-3544) -- vhost-user-gpu: fix memory leak while calling 'vg_resource_unref' (CVE-2021-3544) -- vhost-user-gpu: fix memory leak in 'virgl_cmd_resource_unref' (CVE-2021-3544) -- vhost-user-gpu: fix memory leak in 'virgl_resource_attach_backing' (CVE-2021-3544) -- vhost-user-gpu: fix memory disclosure in virgl_cmd_get_capset_info (CVE-2021-3545) -- vhost-user-gpu: fix OOB write in 'virgl_cmd_get_capset' (CVE-2021-3546) - -* Fri May 28 2021 Chen Qun -- blockjob: Fix crash with IOthread when block commit after snapshot - -* Thu 20 May 2021 zhouli57 -- arm/cpu: Fixed function undefined error at compile time under arm - -* Wed May 19 2021 Ming Yang -- add strip for block-iscsi.so, block-rbd.so and block-ssh.so. - -* Wed 19 May 2021 zhouli57 -- util/cacheinfo: fix crash when compiling with uClibc - -* Fri Mar 26 2021 Chen Qun -- hw/pci-host: add pci-intack write method -- pci-host: add pcie-msi read method -- vfio: add quirk device write method -- prep: add ppc-parity write method -- nvram: add nrf51_soc flash read method -- spapr_pci: add spapr msi read method -- tz-ppc: add dummy read/write methods -- imx7-ccm: add digprog mmio write method - -* Thu Mar 18 2021 Chen Qun +* Fri Feb 11 2022 Chen Qun - 6.2.0-8 +- i386: cache passthrough: Update Intel CPUID4.EAX[25:14] based on vCPU topo +- i386: cache passthrough: Update AMD 8000_001D.EAX[25:14] based on vCPU topo + +* Fri Feb 11 2022 Chen Qun - 6.2.0-8 +- nbd/server.c: fix invalid read after client was already free +- qemu-nbd: make native as the default aio mode +- qemu-nbd: set timeout to qemu-nbd socket +- qemu-pr: fixed ioctl failed for multipath disk +- block: enable cache mode of empty cdrom +- block: disallow block jobs when there is a BDRV_O_INACTIVE flag +- scsi: cdrom: Fix crash after remote cdrom detached +- block: bugfix: disable process AIO when attach scsi disk +- block: bugfix: Don't pause vm when NOSPACE EIO happened +- scsi: bugfix: fix division by zero + +* Fri Feb 11 2022 imxcc - 6.2.0-8 +- migration: skip cache_drop for bios bootloader and +- ps2: fix oob in ps2 kbd +- Currently, while kvm and qemu can not handle some kvm +- cpu/features: fix bug for memory leakage +- monitor/qmp: drop inflight rsp if qmp client broken +- oslib-posix: optimise vm startup time for 1G hugepage + +* Fri Feb 11 2022 imxcc - 6.2.0-7 +- scsi-bus: Refactor the code that retries requests +- scsi-disk: Add support for retry on errors +- block-backend: Stop retrying when draining - block: Add sanity check when setting retry parameters -* Wed Mar 17 2021 Huawei Technologies Co., Ltd -- qemu.spec: enable strip for qemu-block-rbd.so and qemu-block-ssh.so - -* Fri Mar 12 2021 Chen Qun -- net: vmxnet3: validate configuration values during activate (CVE-2021-20203) - -* Fri Mar 12 2021 Chen Qun -- migration: fix memory leak in qmp_migrate_set_parameters -- migration/tls: fix inverted semantics in multifd_channel_connect -- migration/tls: add error handling in multifd_tls_handshake_thread +* Fri Feb 11 2022 imxcc - 6.2.0-7 +- vfio/pci: Ascend310 need 4Bytes quirk in bar4 +- vfio/pci: Ascend710 need 4Bytes quirk in bar0 +- vfio/pci: Ascend910 need 4Bytes quirk in bar0 -* Thu Mar 11 2021 Huawei Technologies Co., Ltd -- qemu.spec: add iscsi rpm package requirement +* Fri Feb 11 2022 imxcc - 6.2.0-7 +- hugepages: hugepages files maybe leftover +- Patch0024: target-i386: Modify the VM's physical bits value set -* Wed Mar 10 2021 Huawei Technologies Co., Ltd -- qemu.spec: make iscsi rpm package +* Fri Feb 11 2022 Yan Wang - 6.2.0-7 +- log: disable qemu_log function for "make check V=1" -* Tue Mar 02 2021 Huawei Technologies Co., Ltd -- qemu.spec: Add --enable-zstd compile parameter +* Fri Feb 11 2022 Yan Wang - 6.2.0-6 +- chardev/baum: disable unused brlapi -* Fri Feb 26 2021 Huawei Technologies Co., Ltd -- block-backend: Stop retrying when draining - -* Fri Feb 26 2021 Huawei Technologies Co., Ltd -- ide:atapi: check io_buffer_index in ide_atapi_cmd_reply_end - -* Fri Feb 19 2021 Huawei Technologies Co., Ltd -- ati: use vga_read_byte in ati_cursor_define -- sd: sdhci: assert data_count is within fifo_buffer -- msix: add valid.accepts methods to check address - -* Thu Feb 04 2021 Huawei Technologies Co., Ltd -- migration: Add multi-thread compress method -- migration: Refactoring multi-thread compress migration -- migration: Add multi-thread compress ops -- migration: Add zstd support in multi-thread compression -- migration: Add compress_level sanity check -- doc: Update multi-thread compression doc -- configure: Enable test and libs for zstd +* Fri Feb 11 2022 imxcc - 6.2.0-5 +- Revert "cpu: parse +/- feature to avoid failure" +- Revert "cpu: add Cortex-A72 processor kvm target support" +- cpu: add Cortex-A72 processor kvm target support -* Sat Jan 30 2021 Huawei Technologies Co., Ltd -- scsi-bus: Refactor the code that retries requests -- scsi-disk: Add support for retry on errors +* Thu Feb 10 2022 imxcc - 6.2.0-4 +- qapi/block-core: Add retry option for error action - qapi/block-core: Add retry option for error action - block-backend: Introduce retry timer - block-backend: Add device specific retry callback - block-backend: Enable retry action on errors - block-backend: Add timeout support for retry - block: Add error retry param setting -- virtio-blk: Refactor the code that processes queued requests -- virtio-blk: On restart, process queued requests in the proper context - virtio_blk: Add support for retry on errors +- vhost: cancel migration when vhost-user restarted +- migration: Add multi-thread compress method +- migration: Refactoring multi-thread compress migration +- migration: Add multi-thread compress ops +- migration: Add zstd support in multi-thread compression +- migration: Add compress_level sanity check +- doc: Update multi-thread compression doc -* Mon Jan 18 2021 Huawei Technologies Co., Ltd -- feature: enable spice protocol - -* Mon Jan 18 2021 Huawei Technologies Co., Ltd -- reorder changelog in desceding order - -* Fri Jan 15 2021 Huawei Technologies Co., Ltd -- memory: clamp cached translation in case it points to an MMIO region - -* Wed Dec 9 2020 Huawei Technologies Co., Ltd -- target/arm: Fix write redundant values to kvm - -* Fri Dec 11 2020 Huawei Technologies Co., Ltd -- hostmem: Fix up free host_nodes list right after visited - -* Fri Dec 25 2020 Huawei Technologies Co., Ltd -- add qemu-block-rbd package -- add qemu-block-ssh package - -* Fri Dec 11 2020 Huawei Technologies Co., Ltd -- hostmem: Fix up free host_nodes list right after visited - -* Fri Dec 11 2020 Huawei Technologies Co., Ltd -- slirp: check pkt_len before reading protocol header for fixing CVE-2020-29129 and CVE-2020-29130 - -* Wed Dec 9 2020 Huawei Technologies Co., Ltd -- target/arm: Fix write redundant values to kvm - -* Wed Dec 2 2020 Huawei Technologies Co., Ltd -- migration/tls: save hostname into MigrationState -- migration/tls: extract migration_tls_client_create for common-use -- migration/tls: add tls_hostname into MultiFDSendParams -- migration/tls: extract cleanup function for common-use -- migration/tls: add support for multifd tls-handshake -- migration/tls: add trace points for multifd-tls -- qemu-file: Don't do IO after shutdown -- multifd: Make sure that we don't do any IO after an error -- migration: Don't send data if we have stopped -- migration: Create migration_is_running() -- migration: fix COLO broken caused by a previous commit -- migration/multifd: fix hangup with TLS-Multifd due to blocking handshake -- multifd/tls: fix memoryleak of the QIOChannelSocket object when cancelling migration - -* Wed Nov 18 2020 Huawei Technologies Co., Ltd -- ati: check x y display parameter values - -* Fri Nov 13 2020 Huawei Technologies Co., Ltd -- json: Fix a memleak in parse_pair() - -* Wed Nov 11 2020 Huawei Technologies Co., Ltd -- hw: usb: hcd-ohci: check for processed TD before retire -- hw: ehci: check return value of 'usb_packet_map' -- hw: usb: hcd-ohci: check len and frame_number variables -- hw/net/e1000e: advance desc_offset in case of null descriptor - -* Fri Oct 30 2020 Huawei Technologies Co., Ltd -- migration/dirtyrate: setup up query-dirtyrate framwork -- migration/dirtyrate: add DirtyRateStatus to denote calculation status -- migration/dirtyrate: Add RamblockDirtyInfo to store sampled page info -- migration/dirtyrate: Add dirtyrate statistics series functions -- migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h -- migration/dirtyrate: Record hash results for each sampled page -- migration/dirtyrate: Compare page hash results for recorded sampled page -- migration/dirtyrate: skip sampling ramblock with size below MIN_RAMBLOCK_SIZE -- migration/dirtyrate: Implement set_sample_page_period() and is_sample_period_valid() -- migration/dirtyrate: Implement calculate_dirtyrate() function -- migration/dirtyrate: Implement qmp_cal_dirty_rate()/qmp_get_dirty_rate() function -- migration/dirtyrate: Add trace_calls to make it easier to debug -- migration/dirtyrate: record start_time and calc_time while at the measuring state -- migration/dirtyrate: present dirty rate only when querying the rate has completed -- migration/dirtyrate: simplify includes in dirtyrate.c - -* Fri Oct 30 2020 Huawei Technologies Co., Ltd -- elf2dmp: Fix memory leak on main() error paths -- io: Don't use '#' flag of printf format -- hw/display/omap_lcdc: Fix potential NULL pointer dereference -- hw/display/exynos4210_fimd: Fix potential NULL pointer dereference -- block/vvfat: Fix bad printf format specifiers -- block: Remove unused include -- ssi: Fix bad printf format specifiers -- net/l2tpv3: Remove redundant check in net_init_l2tpv3() - -* Thu Oct 29 2020 Huawei Technologies Co., Ltd -- Bugfix: hw/acpi: Use max_cpus instead of cpus when build PPTT table - -* Wed Oct 21 2020 Huawei Technologies Co., Ltd -- net: remove an assert call in eth_get_gso_type - -* Wed Oct 14 2020 Prasad J Pandit -- pci: check bus pointer before dereference -- hw/ide: check null block before _cancel_dma_sync - -* Mon Sep 28 2020 Huawei Technologies Co., Ltd -- sm501: Replace hand written implementation with pixman where possible -- sm501: Clean up local variables in sm501_2d_operation -- sm501: Use BIT(x) macro to shorten constant -- sm501: Shorten long variable names in sm501_2d_operation -- sm501: Convert printf + abort to qemu_log_mask -- hw/net/net_tx_pkt: fix assertion failure in net_tx_pkt_add_raw_fragment -- hw/net/xgmac: Fix buffer overflow in xgmac_enet_send() - -* Fri Sep 18 2020 Huawei Technologies Co., Ltd -- hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch -- hw-xhci-check-return-value-of-usb_packet_map.patch - -* Fri Sep 11 2020 Huawei Technologies Co., Ltd -- slirp/src/ip6_input.c: fix out-of-bounds read information vulnerability - -* Tue Sep 08 2020 Huawei Technologies Co., Ltd -- target/arm: ignore evtstrm and cpuid CPU features - -* Fri Aug 21 2020 Huawei Technologies Co., Ltd -- hw/usb/core.c: fix buffer overflow in do_token_setup function - -* Wed Aug 19 2020 Huawei Technologies Co., Ltd -- target-arm-convert-isar-regs-to-array.patch -- target-arm-parse-cpu-feature-related-options.patch -- target-arm-register-CPU-features-for-property.patch -- target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch -- target-arm-introduce-CPU-feature-dependency-mechanis.patch -- target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch -- target-arm-Add-CPU-features-to-query-cpu-model-expan.patch -- target-arm-Update-ID-fields.patch -- target-arm-Add-more-CPU-features.patch - -* Wed Aug 19 2020 Huawei Technologies Co., Ltd -- target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch -- target-arm-Add-ID_AA64MMFR2_EL1.patch -- target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch -- target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch -- target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch -- target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch -- target-arm-Stop-assuming-DBGDIDR-always-exists.patch -- target-arm-Move-DBGDIDR-into-ARMISARegisters.patch -- target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch -- target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch -- target-arm-Read-debug-related-ID-registers-from-KVM.patch -- target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch -- target-arm-monitor-query-cpu-model-expansion-crashed.patch - -* Tue Aug 18 2020 Huawei Technologies Co., Ltd -- hw/acpi/aml-build.c: build smt processor structure to support smt topology - -* Thu Aug 13 2020 Huawei Technologies Co., Ltd --target/arm: Aarch64 support vtpm - -* Wed Aug 12 2020 Huawei Technologies Co., Ltd -- backport upstream patch to support SHPCHotplug in arm - -* Thu Aug 6 2020 Huawei Technologies Co., Ltd -- es1370: check total frame count against current frame -- exec: set map length to zero when returning NULL -- ati-vga: check mm_index before recursive call (CVE-2020-13800) -- megasas: use unsigned type for reply_queue_head and check index -- megasas: avoid NULL pointer dereference -- megasas: use unsigned type for positive numeric fields -- hw/scsi/megasas: Fix possible out-of-bounds array access in tracepoints - -* Thu Aug 6 2020 Huawei Technologies Co., Ltd -- tests: Disalbe filemonitor testcase - -* Sat Jun 20 2020 Huawei Technologies Co., Ltd -- target/arm: Fix PAuth sbox functions -- fix two patches' format which can cause git am failed - -* Fri May 29 2020 Huawei Technologies Co., Ltd -- target/arm: Add the kvm_adjvtime vcpu property for Cortex-A72 - -* Wed May 27 2020 Huawei Technologies Co., Ltd. -- Revert: "vtimer: compat cross version migration from v4.0.1" -- ARM64: record vtimer tick when cpu is stopped -- hw/arm/virt: add missing compat for kvm-no-adjvtime -- migration: Compat virtual timer adjust for v4.0.1 and v4.1.0 -- vtimer: Drop vtimer virtual timer adjust - -* Fri May 22 2020 Huawei Technologies Co., Ltd. -- ip_reass: Fix use after free -- bt: use size_t type for length parameters instead of int -- log: Add some logs on VM runtime path - -* Fri May 15 2020 Huawei Technologies Co., Ltd. -- ide: Fix incorrect handling of some PRDTs in ide_dma_cb() -- ati-vga: Fix checks in ati_2d_blt() to avoid crash -- slirp: tftp: restrict relative path access - -* Tue May 12 2020 Huawei Technologies Co., Ltd. -- arm/virt: Support CPU cold plug - -* Sat May 9 2020 Huawei Technologies Co., Ltd. -- migration/ram: do error_free after migrate_set_error to avoid memleaks. -- migration/ram: fix memleaks in multifd_new_send_channel_async. -- migration/rdma: fix a memleak on error path in rdma_start_incoming_migration. - -* Fri May 8 2020 Huawei Technologies Co., Ltd. -- vtimer: compat cross version migration from v4.0.1 - -* Fri Apr 24 2020 Huawei Technologies Co., Ltd. -- migration: backport migration patches from upstream - -* Fri Apr 24 2020 Huawei Technologies Co., Ltd. -- arm/virt: Add CPU hotplug support - -* Wed Apr 22 2020 Huawei Technologies Co., Ltd. -- backport patch to enable arm/virt memory hotplug - -* Wed Apr 22 2020 Huawei Technologies Co., Ltd. -- backport patch to enable target/arm/kvm Adjust virtual time - -* Fri Apr 17 2020 Huawei Technologies Co., Ltd. -- backport patch bundles from qemu stable v4.1.1 - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- aio-wait: delegate polling of main AioContext if BQL not held -- async: use explicit memory barriers - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- pcie: Add pcie-root-port fast plug/unplug feature -- pcie: Compat with devices which do not support Link Width, such as ioh3420 - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- qcow2-bitmap: Fix uint64_t left-shift overflow - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- COLO-compare: Fix incorrect `if` logic - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- block/backup: fix max_transfer handling for copy_range -- block/backup: fix backup_cow_with_offload for last cluster -- qcow2: Limit total allocation range to INT_MAX -- mirror: Do not dereference invalid pointers - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- file-posix: Handle undetectable alignment - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- vhost: Fix memory region section comparison -- memory: Provide an equality function for MemoryRegionSections -- memory: Align MemoryRegionSections fields - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- block/iscsi: use MIN() between mx_sb_len and sb_len_wr -- moniter: fix memleak in monitor_fdset_dup_fd_find_remove - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- tcp_emu: fix unsafe snprintf() usages -- util: add slirp_fmt() helpers -- slirp: use correct size while emulating commands -- slirp: use correct size while emulating IRC commands -- tcp_emu: Fix oob access -- iscsi: Cap block count from GET LBA STATUS (CVE-2020-1711) - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- 9pfs: local: Fix possible memory leak in local_link() -- scsi-disk: define props in scsi_block_disk to avoid memleaks -- arm/translate-a64: fix uninitialized variable warning -- block: fix memleaks in bdrv_refresh_filename -- vnc: fix memory leak when vnc disconnect -- block: fix memleaks in bdrv_refresh_filename - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- linux headers: update against "KVM/ARM: Fix >256 vcpus" -- intc/arm_gic: Support IRQ injection for more than 256 vcpus -- ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- vnc: fix memory leak when vnc disconnect - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- pcie: disable the PCI_EXP_LINKSTA_DLLA cap for pcie-root-port by default - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- cpu: add Kunpeng-920 cpu support +* Wed Feb 09 2022 Chen Qun - 6.2.0-3 - cpu: parse +/- feature to avoid failure +- cpu: add Kunpeng-920 cpu support - cpu: add Cortex-A72 processor kvm target support +- add Phytium's CPU models: FT-2000+ and Tengyun-S2500. -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- vhost-user-scsi: prevent using uninitialized vqs - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- util/async: hold AioContext ref to prevent use-after-free - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- xhci: Fix memory leak in xhci_address_slot -- xhci: Fix memory leak in xhci_kick_epctx -- ehci: fix queue->dev null ptr dereference - -* Thu Apr 16 2020 Huawei Technologies Co., Ltd. -- tests/bios-tables-test: disable this testcase -- hw/arm/virt: Introduce cpu topology support -- hw/arm64: add vcpu cache info support - -* Wed Apr 15 2020 Huawei Technologies Co., Ltd. -- smbios: Add missing member of type 4 for smbios 3.0 - -* Wed Apr 15 2020 Huawei Technologies Co., Ltd. -- bios-tables-test: prepare to change ARM virt ACPI DSDT -- arm64: Add the cpufreq device to show cpufreq info to guest - -* Wed Apr 15 2020 Huawei Technologies Co., Ltd. -- qcow2: fix memory leak in qcow2_read_extensions - -* Wed Apr 15 2020 Huawei Technologies Co., Ltd. -- pl011: reset read FIFIO when UARTTIMSC=0 & UARTICR=0xff -- pl031: support rtc-timer property for pl031 -- vhost: cancel migration when vhost-user restarted +* Tue Feb 8 2022 Xiangdong Liu - 6.2.0-2 +- net/dump.c: Suppress spurious compiler warning -* Mon Apr 13 2020 openEuler Buildteam - version-release +* Thu Jan 27 2022 Xiangdong Liu - 6.2.0-1 - Package init diff --git a/qga-Fix-memory-leak-when-output-stream-is-unused.patch b/qga-Fix-memory-leak-when-output-stream-is-unused.patch new file mode 100644 index 0000000000000000000000000000000000000000..b05a65c262263afc90258847c63fcb063c43787c --- /dev/null +++ b/qga-Fix-memory-leak-when-output-stream-is-unused.patch @@ -0,0 +1,56 @@ +From 877d97f7e7b88c9cb8754bece152dc27a2a0f47a Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 16 Oct 2023 10:22:03 +0800 +Subject: [PATCH] qga: Fix memory leak when output stream is unused + +cheery-pick from d6f67b83b81bf49b5c62e77143ed39c020e51830 + +If capture-output is requested but one of the channels goes unused (eg. +we attempt to capture stderr but the command never writes to stderr), we +can leak memory. + +guest_exec_output_watch() is (from what I understand) unconditionally +called for both streams if output capture is requested. The first call +will always pass the `p->size == p->length` check b/c both values are +0. Then GUEST_EXEC_IO_SIZE bytes will be allocated for the stream. + +But when we reap the exited process there's a `gei->err.length > 0` +check to actually free the buffer. Which does not get run if the command +doesn't write to the stream. + +Fix by making free() unconditional. + +Reviewed-by: Konstantin Kostiuk +Signed-off-by: Daniel Xu +Signed-off-by: Konstantin Kostiuk +Signed-off-by: qihao_yewu +--- + qga/commands.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/qga/commands.c b/qga/commands.c +index 80501e4a73..05f89725be 100644 +--- a/qga/commands.c ++++ b/qga/commands.c +@@ -210,16 +210,16 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) + if (gei->out.length > 0) { + ges->has_out_data = true; + ges->out_data = g_base64_encode(gei->out.data, gei->out.length); +- g_free(gei->out.data); + ges->has_out_truncated = gei->out.truncated; + } ++ g_free(gei->out.data); + + if (gei->err.length > 0) { + ges->has_err_data = true; + ges->err_data = g_base64_encode(gei->err.data, gei->err.length); +- g_free(gei->err.data); + ges->has_err_truncated = gei->err.truncated; + } ++ g_free(gei->err.data); + + QTAILQ_REMOVE(&guest_exec_state.processes, gei, next); + g_free(gei); +-- +2.41.0.windows.1 + diff --git a/qga-Fix-suspend-on-Linux-guests-without-systemd.patch b/qga-Fix-suspend-on-Linux-guests-without-systemd.patch new file mode 100644 index 0000000000000000000000000000000000000000..309e7276a603b81cc54f9a0e38d6a5d6621a5f24 --- /dev/null +++ b/qga-Fix-suspend-on-Linux-guests-without-systemd.patch @@ -0,0 +1,57 @@ +From 9f4819201fb35b419ea21d37755c4cb62454a270 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 10 Aug 2023 13:59:53 +0800 +Subject: [PATCH] qga: Fix suspend on Linux guests without systemd + +cheery-pick from 86dcb6ab9b603450eb6d896cdc95286de2c7d561 + +Allow the Linux guest agent to attempt each of the suspend methods +(systemctl, pm-* and writing to /sys) in turn. + +Prior to this guests without systemd failed to suspend due to +`guest_suspend` returning early regardless of the return value of +`systemd_supports_mode`. + +Signed-off-by: Mark Somerville +Reviewed-by: Konstantin Kostiuk +Signed-off-by: Konstantin Kostiuk +Signed-off-by: qihao_yewu +--- + qga/commands-posix.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/qga/commands-posix.c b/qga/commands-posix.c +index 75dbaab68e..4e06271889 100644 +--- a/qga/commands-posix.c ++++ b/qga/commands-posix.c +@@ -2104,10 +2104,10 @@ static void guest_suspend(SuspendMode mode, Error **errp) + if (systemd_supports_mode(mode, &local_err)) { + mode_supported = true; + systemd_suspend(mode, &local_err); +- } + +- if (!local_err) { +- return; ++ if (!local_err) { ++ return; ++ } + } + + error_free(local_err); +@@ -2116,10 +2116,10 @@ static void guest_suspend(SuspendMode mode, Error **errp) + if (pmutils_supports_mode(mode, &local_err)) { + mode_supported = true; + pmutils_suspend(mode, &local_err); +- } + +- if (!local_err) { +- return; ++ if (!local_err) { ++ return; ++ } + } + + error_free(local_err); +-- +2.41.0.windows.1 + diff --git a/qga-Improve-guest-exec-status-error-message.patch b/qga-Improve-guest-exec-status-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..debbba7942c2ece1ea3f38ec47cfae531a8ace81 --- /dev/null +++ b/qga-Improve-guest-exec-status-error-message.patch @@ -0,0 +1,42 @@ +From f28bc5e3a6418d8477e84b52e06dcab5db7cbf15 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 15:52:06 +0800 +Subject: [PATCH] qga: Improve guest-exec-status error message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from b665165938d89c8e1f83f970d3722f507ce87acd + +When the PID passed to guest-exec-status does not exist, we report + + "Invalid parameter 'pid'" + +Improve this to + + "PID 1234 does not exist" + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-4-armbru@redhat.com> +Reviewed-by: Konstantin Kostiuk +Reviewed-by: Philippe Mathieu-Daudé +--- + qga/commands.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qga/commands.c b/qga/commands.c +index 05f89725be..9fe73786fc 100644 +--- a/qga/commands.c ++++ b/qga/commands.c +@@ -156,7 +156,7 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) + + gei = guest_exec_info_find(pid); + if (gei == NULL) { +- error_setg(errp, QERR_INVALID_PARAMETER, "pid"); ++ error_setg(errp, "PID " PRId64 " does not exist"); + return NULL; + } + +-- +2.27.0 + diff --git a/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch b/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch deleted file mode 100644 index a901a500181bb9a36f9bd307d8bdee5929b6144f..0000000000000000000000000000000000000000 --- a/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 1580682eafb489eaf417456778267662629cf696 Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Tue, 30 Jun 2020 11:03:33 +0200 -Subject: [PATCH 05/11] qga: Plug unlikely memory leak in - guest-set-memory-blocks - -transfer_memory_block() leaks an Error object when reading file -/sys/devices/system/memory/memory/state fails with errno other -than ENOENT, and @sys2memblk is false, i.e. when the state file exists -but cannot be read (seems quite unlikely), and this is -guest-set-memory-blocks, not guest-get-memory-blocks. - -Plug the leak. - -Fixes: bd240fca42d5f072fb758a71720d9de9990ac553 -Cc: Michael Roth -Cc: Hailiang Zhang -Signed-off-by: Markus Armbruster -Reviewed-by: zhanghailiang -Message-Id: <20200630090351.1247703-9-armbru@redhat.com> -Signed-off-by: BiaoXiang Ye ---- - qga/commands-posix.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/qga/commands-posix.c b/qga/commands-posix.c -index dfc05f5b..c318cee7 100644 ---- a/qga/commands-posix.c -+++ b/qga/commands-posix.c -@@ -2420,6 +2420,7 @@ static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk, - if (sys2memblk) { - error_propagate(errp, local_err); - } else { -+ error_free(local_err); - result->response = - GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED; - } --- -2.27.0.dirty - diff --git a/qga-commands-posix-fix-use-after-free-of-local_err.patch b/qga-commands-posix-fix-use-after-free-of-local_err.patch deleted file mode 100644 index 9628d0c59445c9d29ddaa39e6fb271fe73a5c274..0000000000000000000000000000000000000000 --- a/qga-commands-posix-fix-use-after-free-of-local_err.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 15847279f29b0bd67b95daefff395cab8fad80d3 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 24 Mar 2020 18:36:30 +0300 -Subject: [PATCH 4/5] qga/commands-posix: fix use after free of local_err - -local_err is used several times in guest_suspend(). Setting non-NULL -local_err will crash, so let's zero it after freeing. Also fix possible -leak of local_err in final if(). - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20200324153630.11882-7-vsementsov@virtuozzo.com> -Reviewed-by: Richard Henderson -Signed-off-by: Markus Armbruster -Signed-off-by: Zhenyu Ye ---- - qga/commands-posix.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/qga/commands-posix.c b/qga/commands-posix.c -index dfc05f5b..66164e6c 100644 ---- a/qga/commands-posix.c -+++ b/qga/commands-posix.c -@@ -1760,6 +1760,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) - } - - error_free(local_err); -+ local_err = NULL; - - if (pmutils_supports_mode(mode, &local_err)) { - mode_supported = true; -@@ -1771,6 +1772,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) - } - - error_free(local_err); -+ local_err = NULL; - - if (linux_sys_state_supports_mode(mode, &local_err)) { - mode_supported = true; -@@ -1778,6 +1780,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) - } - - if (!mode_supported) { -+ error_free(local_err); - error_setg(errp, - "the requested suspend mode is not supported by the guest"); - } else { --- -2.22.0.windows.1 - diff --git a/qga-fix-assert-regression-on-guest-shutdown.patch b/qga-fix-assert-regression-on-guest-shutdown.patch deleted file mode 100644 index c5f1e1069b5097ff1adf2328bea6a25e9483cda1..0000000000000000000000000000000000000000 --- a/qga-fix-assert-regression-on-guest-shutdown.patch +++ /dev/null @@ -1,47 +0,0 @@ -From aeccff89333c565c7a894f99c17c0044d7d43be2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Thu, 4 Jun 2020 11:44:25 +0200 -Subject: [PATCH 02/11] qga: fix assert regression on guest-shutdown -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since commit 781f2b3d1e ("qga: process_event() simplification"), -send_response() is called unconditionally, but will assert when "rsp" is -NULL. This may happen with QCO_NO_SUCCESS_RESP commands, such as -"guest-shutdown". - -Fixes: 781f2b3d1e5ef389b44016a897fd55e7a780bf35 -Cc: Michael Roth -Reported-by: Christian Ehrhardt -Signed-off-by: Marc-André Lureau -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Christian Ehrhardt -Tested-by: Christian Ehrhardt -Cc: qemu-stable@nongnu.org -Signed-off-by: Michael Roth -Signed-off-by: BiaoXiang Ye ---- - qga/main.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/qga/main.c b/qga/main.c -index c35c2a21..12fa463f 100644 ---- a/qga/main.c -+++ b/qga/main.c -@@ -529,7 +529,11 @@ static int send_response(GAState *s, const QDict *rsp) - QString *payload_qstr, *response_qstr; - GIOStatus status; - -- g_assert(rsp && s->channel); -+ g_assert(s->channel); -+ -+ if (!rsp) { -+ return 0; -+ } - - payload_qstr = qobject_to_json(QOBJECT(rsp)); - if (!payload_qstr) { --- -2.27.0.dirty - diff --git a/qga-vss-win32-fix-warning-for-clang-15.patch b/qga-vss-win32-fix-warning-for-clang-15.patch new file mode 100644 index 0000000000000000000000000000000000000000..f4dfc2cbecc8b83e8929b4d879eb25c81ec8b448 --- /dev/null +++ b/qga-vss-win32-fix-warning-for-clang-15.patch @@ -0,0 +1,47 @@ +From b9212c3d72363f67d621dd4e16e507e4a677158e Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 27 Jun 2023 22:45:24 +0800 +Subject: [PATCH] qga/vss-win32: fix warning for clang++-15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from a3f531cee66b12041098f7a809c2a7d6ecb6ad7d + +Reported when compiling with clang-windows-arm64. + +../qga/vss-win32/install.cpp:537:9: error: variable 'hr' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] + if (!(ControlService(service, SERVICE_CONTROL_STOP, NULL))) { + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../qga/vss-win32/install.cpp:545:12: note: uninitialized use occurs here + return hr; + ^~ + +Signed-off-by: Pierrick Bouvier +Fixes: 917ebcb170 ("qga-win: Fix QGA VSS Provider service stop failure") +Reviewed-by: Konstantin Kostiuk +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Kostiantyn Kostiuk +(cherry picked from commit 0fcd574b025fccdf14d5140687cafe2bc30b634f) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + qga/vss-win32/install.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qga/vss-win32/install.cpp b/qga/vss-win32/install.cpp +index 40de133774..e90a03c1cf 100644 +--- a/qga/vss-win32/install.cpp ++++ b/qga/vss-win32/install.cpp +@@ -513,7 +513,7 @@ namespace _com_util + /* Stop QGA VSS provider service using Winsvc API */ + STDAPI StopService(void) + { +- HRESULT hr; ++ HRESULT hr = S_OK; + SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + SC_HANDLE service = NULL; + +-- +2.41.0.windows.1 + diff --git a/qga-win-Fix-guest-get-fsinfo-multi-disks-collection.patch b/qga-win-Fix-guest-get-fsinfo-multi-disks-collection.patch new file mode 100644 index 0000000000000000000000000000000000000000..2683affb524e9f60809c785b5ec8b33865127eaf --- /dev/null +++ b/qga-win-Fix-guest-get-fsinfo-multi-disks-collection.patch @@ -0,0 +1,40 @@ +From bf48c640251cfe8d9ed7744bc88f5a858b694275 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 7 Feb 2024 17:26:58 +0800 +Subject: [PATCH] qga-win: Fix guest-get-fsinfo multi-disks collection + +cheery-pick from 7c4486350a79532580a37d42abdeb1dc7e4fa6c9 + +When a volume has more than one disk, all disks cannot be +returned correctly because there is not enough malloced memory +for disk extents, so before executing DeviceIoControl for the +second time, get the correct size of the required memory space +to store all disk extents. + +Details: +https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-volume_disk_extents + +Signed-off-by: Peng Ji +Reviewed-by: Konstantin Kostiuk +Signed-off-by: Konstantin Kostiuk +Signed-off-by: qihao_yewu +--- + qga/commands-win32.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qga/commands-win32.c b/qga/commands-win32.c +index 4e84afd83b..30e50f1769 100644 +--- a/qga/commands-win32.c ++++ b/qga/commands-win32.c +@@ -904,6 +904,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) + DWORD last_err = GetLastError(); + if (last_err == ERROR_MORE_DATA) { + /* Try once more with big enough buffer */ ++ size = sizeof(VOLUME_DISK_EXTENTS) + ++ (sizeof(DISK_EXTENT) * (extents->NumberOfDiskExtents - 1)); + g_free(extents); + extents = g_malloc0(size); + if (!DeviceIoControl( +-- +2.27.0 + diff --git a/qga-win-vss-requester_freeze-changes.patch b/qga-win-vss-requester_freeze-changes.patch new file mode 100644 index 0000000000000000000000000000000000000000..18ee0aa8efc5e3eff5dd824c4742dc0fc71175bb --- /dev/null +++ b/qga-win-vss-requester_freeze-changes.patch @@ -0,0 +1,41 @@ +From 977331440154d500d434258c61eb3542e01dea38 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Tue, 4 Apr 2023 18:36:27 +0800 +Subject: [PATCH] qga/win/vss: requester_freeze changes + +Change requester_freeze so that the VSS backup type queried from the registry + +cheery-pick from 0961f929c66ceb5e9e95756bfe418b9ef34510eb + +Signed-off-by: jipengfei_yewu +Signed-off-by: Kfir Manor +Reviewed-by: Konstantin Kostiuk +Signed-off-by: Konstantin Kostiuk +--- + qga/vss-win32/requester.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp +index 940a2c8f55..418b9b6e4e 100644 +--- a/qga/vss-win32/requester.cpp ++++ b/qga/vss-win32/requester.cpp +@@ -248,6 +248,7 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) + int num_fixed_drives = 0, i; + int num_mount_points = 0; + ++ VSS_BACKUP_TYPE vss_bt = get_vss_backup_type(); + if (vss_ctx.pVssbc) { /* already frozen */ + *num_vols = 0; + return; +@@ -294,7 +295,7 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) + goto out; + } + +- hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); ++ hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false); + if (FAILED(hr)) { + err_set(errset, hr, "failed to set backup state"); + goto out; +-- +2.27.0 + diff --git a/qga-win32-Remove-change-action-from-MSI-installer.patch b/qga-win32-Remove-change-action-from-MSI-installer.patch new file mode 100644 index 0000000000000000000000000000000000000000..3ebd4e7fd4cde1d4984b5ba1d9752a5d2a698fe2 --- /dev/null +++ b/qga-win32-Remove-change-action-from-MSI-installer.patch @@ -0,0 +1,35 @@ +From 38a72d2fbaf732d0804fefca034c24b2ad068ad1 Mon Sep 17 00:00:00 2001 +From: Konstantin Kostiuk +Date: Fri, 3 Mar 2023 21:20:07 +0200 +Subject: [PATCH] qga/win32: Remove change action from MSI installer + +Remove the 'change' button from "Programs and Features" because it does +not checks if a user is an admin or not. The installer has no components +to choose from and always installs everything. So the 'change' button is +not obviously needed but can create a security issue. + +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2167423 +fixes: CVE-2023-0664 (part 1 of 2) + +Signed-off-by: Konstantin Kostiuk +Reviewed-by: Yan Vugenfirer +Reported-by: Brian Wiltse +--- + qga/installer/qemu-ga.wxs | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs +index 0950e8c6be..b62e709a4c 100644 +--- a/qga/installer/qemu-ga.wxs ++++ b/qga/installer/qemu-ga.wxs +@@ -58,6 +58,7 @@ + /> + + ++ + +-- +2.41.0.windows.1 + diff --git a/qga-win32-Use-rundll-for-VSS-installation.patch b/qga-win32-Use-rundll-for-VSS-installation.patch new file mode 100644 index 0000000000000000000000000000000000000000..36ddb7f251cfed771c67f7490cea3b3bfdaaa9bf --- /dev/null +++ b/qga-win32-Use-rundll-for-VSS-installation.patch @@ -0,0 +1,99 @@ +From bc472314a51895f67112e3ac35439df63292f101 Mon Sep 17 00:00:00 2001 +From: Konstantin Kostiuk +Date: Fri, 3 Mar 2023 21:20:08 +0200 +Subject: [PATCH] qga/win32: Use rundll for VSS installation + +The custom action uses cmd.exe to run VSS Service installation +and removal which causes an interactive command shell to spawn. +This shell can be used to execute any commands as a SYSTEM user. +Even if call qemu-ga.exe directly the interactive command shell +will be spawned as qemu-ga.exe is a console application and used +by users from the console as well as a service. + +As VSS Service runs from DLL which contains the installer and +uninstaller code, it can be run directly by rundll32.exe without +any interactive command shell. + +Add specific entry points for rundll which is just a wrapper +for COMRegister/COMUnregister functions with proper arguments. + +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2167423 +fixes: CVE-2023-0664 (part 2 of 2) + +Signed-off-by: Konstantin Kostiuk +Reviewed-by: Yan Vugenfirer +Reported-by: Brian Wiltse +--- + qga/installer/qemu-ga.wxs | 10 +++++----- + qga/vss-win32/install.cpp | 9 +++++++++ + qga/vss-win32/qga-vss.def | 2 ++ + 3 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs +index b62e709a4c..11b66a22e6 100644 +--- a/qga/installer/qemu-ga.wxs ++++ b/qga/installer/qemu-ga.wxs +@@ -143,22 +143,22 @@ + + + +- ++ + + + + + + +diff --git a/qga/vss-win32/install.cpp b/qga/vss-win32/install.cpp +index e90a03c1cf..8b7400e4e5 100644 +--- a/qga/vss-win32/install.cpp ++++ b/qga/vss-win32/install.cpp +@@ -352,6 +352,15 @@ out: + return hr; + } + ++STDAPI_(void) CALLBACK DLLCOMRegister(HWND, HINSTANCE, LPSTR, int) ++{ ++ COMRegister(); ++} ++ ++STDAPI_(void) CALLBACK DLLCOMUnregister(HWND, HINSTANCE, LPSTR, int) ++{ ++ COMUnregister(); ++} + + static BOOL CreateRegistryKey(LPCTSTR key, LPCTSTR value, LPCTSTR data) + { +diff --git a/qga/vss-win32/qga-vss.def b/qga/vss-win32/qga-vss.def +index 927782c31b..ee97a81427 100644 +--- a/qga/vss-win32/qga-vss.def ++++ b/qga/vss-win32/qga-vss.def +@@ -1,6 +1,8 @@ + LIBRARY "QGA-PROVIDER.DLL" + + EXPORTS ++ DLLCOMRegister ++ DLLCOMUnregister + COMRegister PRIVATE + COMUnregister PRIVATE + DllCanUnloadNow PRIVATE +-- +2.41.0.windows.1 + diff --git a/qmp-add-command-to-query-used-memslots-of-vhost-net-.patch b/qmp-add-command-to-query-used-memslots-of-vhost-net-.patch new file mode 100644 index 0000000000000000000000000000000000000000..10d69dd73c18a4748c4afcc7f89acac49b4d3ae4 --- /dev/null +++ b/qmp-add-command-to-query-used-memslots-of-vhost-net-.patch @@ -0,0 +1,131 @@ +From 1545a60a8b78490c7dc8909b7012bca63dba63cd Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Sat, 12 Feb 2022 15:41:08 +0800 +Subject: [PATCH] qmp: add command to query used memslots of vhost-net and + vhost-user + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost-backend.c | 2 +- + hw/virtio/vhost-user.c | 2 +- + include/hw/virtio/vhost-backend.h | 2 ++ + monitor/qmp-cmds.c | 12 ++++++++++++ + qapi/net.json | 18 ++++++++++++++++++ + qapi/pragma.json | 4 +++- + 6 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c +index 2acfb750fd..d8e1710758 100644 +--- a/hw/virtio/vhost-backend.c ++++ b/hw/virtio/vhost-backend.c +@@ -300,7 +300,7 @@ static void vhost_kernel_set_used_memslots(struct vhost_dev *dev) + vhost_kernel_used_memslots = dev->mem->nregions; + } + +-static unsigned int vhost_kernel_get_used_memslots(void) ++unsigned int vhost_kernel_get_used_memslots(void) + { + return vhost_kernel_used_memslots; + } +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 176cae9244..8f69a3b850 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -2544,7 +2544,7 @@ static void vhost_user_set_used_memslots(struct vhost_dev *dev) + vhost_user_used_memslots = counter; + } + +-static unsigned int vhost_user_get_used_memslots(void) ++unsigned int vhost_user_get_used_memslots(void) + { + return vhost_user_used_memslots; + } +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index a64708f456..7bbc658161 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -190,4 +190,6 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, + + int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd); + ++unsigned int vhost_kernel_get_used_memslots(void); ++unsigned int vhost_user_get_used_memslots(void); + #endif /* VHOST_BACKEND_H */ +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index 98868cee03..f3e80ec8a7 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -36,6 +36,7 @@ + #include "qapi/qapi-commands-machine.h" + #include "qapi/qapi-commands-misc.h" + #include "qapi/qapi-commands-ui.h" ++#include "qapi/qapi-commands-net.h" + #include "qapi/type-helpers.h" + #include "qapi/qmp/qerror.h" + #include "exec/ramlist.h" +@@ -43,6 +44,7 @@ + #include "hw/acpi/acpi_dev_interface.h" + #include "hw/intc/intc.h" + #include "hw/rdma/rdma.h" ++#include "hw/virtio/vhost-backend.h" + + NameInfo *qmp_query_name(Error **errp) + { +@@ -471,3 +473,13 @@ int64_t qmp_query_rtc_date_diff(Error **errp) + { + return get_rtc_date_diff(); + } ++ ++uint32_t qmp_query_vhost_kernel_used_memslots(Error **errp) ++{ ++ return vhost_kernel_get_used_memslots(); ++} ++ ++uint32_t qmp_query_vhost_user_used_memslots(Error **errp) ++{ ++ return vhost_user_get_used_memslots(); ++} +diff --git a/qapi/net.json b/qapi/net.json +index 7fab2e7cd8..c9ff849eed 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -696,3 +696,21 @@ + ## + { 'event': 'FAILOVER_NEGOTIATED', + 'data': {'device-id': 'str'} } ++ ++## ++# @query-vhost-kernel-used-memslots: ++# ++# Get vhost-kernel nic used memslots ++# ++# Since: 4.1 ++## ++{ 'command': 'query-vhost-kernel-used-memslots', 'returns': 'uint32' } ++ ++## ++# @query-vhost-user-used-memslots: ++# ++# Get vhost-user nic used memslots ++# ++# Since: 4.1 ++## ++{ 'command': 'query-vhost-user-used-memslots', 'returns': 'uint32' } +diff --git a/qapi/pragma.json b/qapi/pragma.json +index b37f6de445..d35c897acb 100644 +--- a/qapi/pragma.json ++++ b/qapi/pragma.json +@@ -27,7 +27,9 @@ + 'query-tpm-models', + 'query-tpm-types', + 'ringbuf-read', +- 'query-rtc-date-diff' ], ++ 'query-rtc-date-diff', ++ 'query-vhost-user-used-memslots', ++ 'query-vhost-kernel-used-memslots' ], + # Externally visible types whose member names may use uppercase + 'member-name-exceptions': [ # visible in: + 'ACPISlotType', # query-acpi-ospm-status +-- +2.27.0 + diff --git a/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch b/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch deleted file mode 100644 index 1ceb1e70b84f1e1a9a3f785ff2d4d55b697a7cb4..0000000000000000000000000000000000000000 --- a/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 1f1949368d4ac7a18973aa83a074daf01daf97ad Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 25 Mar 2020 19:47:22 +0100 -Subject: [PATCH 3/5] qmp: fix leak on callbacks that return both value and - error -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Direct leak of 4120 byte(s) in 1 object(s) allocated from: - #0 0x7fa114931887 in __interceptor_calloc (/lib64/libasan.so.6+0xb0887) - #1 0x7fa1144ad8f0 in g_malloc0 (/lib64/libglib-2.0.so.0+0x588f0) - #2 0x561e3c9c8897 in qmp_object_add /home/elmarco/src/qemu/qom/qom-qmp-cmds.c:291 - #3 0x561e3cf48736 in qmp_dispatch /home/elmarco/src/qemu/qapi/qmp-dispatch.c:155 - #4 0x561e3c8efb36 in monitor_qmp_dispatch /home/elmarco/src/qemu/monitor/qmp.c:145 - #5 0x561e3c8f09ed in monitor_qmp_bh_dispatcher /home/elmarco/src/qemu/monitor/qmp.c:234 - #6 0x561e3d08c993 in aio_bh_call /home/elmarco/src/qemu/util/async.c:136 - #7 0x561e3d08d0a5 in aio_bh_poll /home/elmarco/src/qemu/util/async.c:164 - #8 0x561e3d0a535a in aio_dispatch /home/elmarco/src/qemu/util/aio-posix.c:380 - #9 0x561e3d08e3ca in aio_ctx_dispatch /home/elmarco/src/qemu/util/async.c:298 - #10 0x7fa1144a776e in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x5276e) - -Signed-off-by: Marc-André Lureau -Message-Id: <20200325184723.2029630-3-marcandre.lureau@redhat.com> -Reviewed-by: Markus Armbruster -Signed-off-by: Paolo Bonzini -Signed-off-by: Zhenyu Ye ---- - qapi/qmp-dispatch.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c -index 6dfdad57..a635abb9 100644 ---- a/qapi/qmp-dispatch.c -+++ b/qapi/qmp-dispatch.c -@@ -189,6 +189,8 @@ QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, - - ret = do_qmp_dispatch(cmds, request, allow_oob, &err); - if (err) { -+ /* or assert(!ret) after reviewing all handlers: */ -+ qobject_unref(ret); - rsp = qmp_error_response(err); - } else if (ret) { - rsp = qdict_new(); --- -2.22.0.windows.1 - diff --git a/qom-assert-integer-does-not-overflow.patch b/qom-assert-integer-does-not-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..6a3314d67584b901aaeb5906f0c238e489ca7006 --- /dev/null +++ b/qom-assert-integer-does-not-overflow.patch @@ -0,0 +1,58 @@ +From 7d94ca45a9c0ef8a4f1917f41496a826ecda90fb Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Fri, 25 Feb 2022 08:40:27 -0500 +Subject: [PATCH 3/6] qom: assert integer does not overflow + +QOM reference counting is not designed with an infinite amount of +references in mind, trying to take a reference in a loop without +dropping a reference will overflow the integer. + +It is generally a symptom of a reference leak (a missing deref, commonly +as part of error handling - such as one fixed here: +https://lore.kernel.org/r/20220228095058.27899-1-sgarzare%40redhat.com ). + +All this can lead to either freeing the object too early (memory +corruption) or never freeing it (memory leak). + +If we happen to dereference at just the right time (when it's wrapping +around to 0), we might eventually assert when dereferencing, but the +real problem is an extra object_ref so let's assert there to make such +issues cleaner and easier to debug. + +Some micro-benchmarking shows using fetch and add this is essentially +free on x86. + +Since multiple threads could be incrementing in parallel, we assert +around INT_MAX to make sure none of these approach the wrap around +point: this way we get a memory leak and not a memory corruption, the +former is generally easier to debug. + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: wanbo +--- + qom/object.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/qom/object.c b/qom/object.c +index 4f0677cca9..5db3974f04 100644 +--- a/qom/object.c ++++ b/qom/object.c +@@ -1167,10 +1167,14 @@ GSList *object_class_get_list_sorted(const char *implements_type, + Object *object_ref(void *objptr) + { + Object *obj = OBJECT(objptr); ++ uint32_t ref; ++ + if (!obj) { + return NULL; + } +- qatomic_inc(&obj->ref); ++ ref = qatomic_fetch_inc(&obj->ref); ++ /* Assert waaay before the integer overflows */ ++ g_assert(ref < INT_MAX); + return obj; + } + +-- +2.27.0 + diff --git a/qom-object-Remove-circular-include-dependency.patch b/qom-object-Remove-circular-include-dependency.patch new file mode 100644 index 0000000000000000000000000000000000000000..f527a3b04c15a0aa76b7cc07efe4b19c94fc5b66 --- /dev/null +++ b/qom-object-Remove-circular-include-dependency.patch @@ -0,0 +1,41 @@ +From e4393667e45bdcf04150ada3840a6d87e3188d36 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:13:07 +0000 +Subject: [PATCH] qom/object: Remove circular include dependency mainline + inclusion commit 5bba9bcfbb42e7c016626420e148a1bf1b080835 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +"qom/object.h" doesn't need to include itself. + +Fixes: db1015e92e04 ("Move QOM typedefs and add missing includes") +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Damien Hedde +Reviewed-by: Peter Maydell +Reviewed-by: Markus Armbruster +Message-Id: <20220509084659.52076-1-philippe.mathieu.daude@gmail.com> +Signed-off-by: Laurent Vivier + +Signed-off-by: tangbinzy +--- + include/qom/object.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/include/qom/object.h b/include/qom/object.h +index fae096f51c..f658e1e0a0 100644 +--- a/include/qom/object.h ++++ b/include/qom/object.h +@@ -16,7 +16,6 @@ + + #include "qapi/qapi-builtin-types.h" + #include "qemu/module.h" +-#include "qom/object.h" + + struct TypeImpl; + typedef struct TypeImpl *Type; +-- +2.27.0 + diff --git a/qsd-Unlink-absolute-PID-file-path.patch b/qsd-Unlink-absolute-PID-file-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..7c5138ad713432506c1bae7df83e78bdb9c402e8 --- /dev/null +++ b/qsd-Unlink-absolute-PID-file-path.patch @@ -0,0 +1,81 @@ +From 43668bdb7ebaa64536277d4b5b47875e58a3452a Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 07:00:39 +0000 +Subject: [PATCH] qsd: Unlink absolute PID file path mainline inclusion commit + 9d8f8233b9fa525a7e37350fbc18877051128c5d category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +After writing the PID file, we register an atexit() handler to unlink it +when the process terminates. However, if the process has changed its +working directory in the meantime (e.g. in os_setup_post() when +daemonizing), this will not work when the PID file path was relative. +Therefore, pass the absolute path (created with realpath()) to the +unlink() call in the atexit() handler. + +(realpath() needs a path pointing to an existing file, so we cannot use +it before qemu_write_pidfile().) + +Reproducer: +$ cd /tmp +$ qemu-storage-daemon --daemonize --pidfile qsd.pid +$ file qsd.pid +qsd.pid: ASCII text +$ kill $(cat qsd.pid) +$ file qsd.pid +qsd.pid: ASCII text + +(qsd.pid should be gone after the process has terminated.) + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2092322 +Signed-off-by: Hanna Reitz +Message-Id: <20220609122701.17172-2-hreitz@redhat.com> +Reviewed-by: Daniel P. Berrangé + +Signed-off-by: tangbinzy +--- + storage-daemon/qemu-storage-daemon.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c +index 52cf17e8ac..f3d8c4ca11 100644 +--- a/storage-daemon/qemu-storage-daemon.c ++++ b/storage-daemon/qemu-storage-daemon.c +@@ -60,6 +60,7 @@ + #include "trace/control.h" + + static const char *pid_file; ++static char *pid_file_realpath; + static volatile bool exit_requested = false; + + void qemu_system_killed(int signal, pid_t pid) +@@ -292,7 +293,7 @@ static void process_options(int argc, char *argv[]) + + static void pid_file_cleanup(void) + { +- unlink(pid_file); ++ unlink(pid_file_realpath); + } + + static void pid_file_init(void) +@@ -308,6 +309,14 @@ static void pid_file_init(void) + exit(EXIT_FAILURE); + } + ++ pid_file_realpath = g_malloc(PATH_MAX); ++ if (!realpath(pid_file, pid_file_realpath)) { ++ error_report("cannot resolve PID file path: %s: %s", ++ pid_file, strerror(errno)); ++ unlink(pid_file); ++ exit(EXIT_FAILURE); ++ } ++ + atexit(pid_file_cleanup); + } + +-- +2.27.0 + diff --git a/qtest-npcm7xx_pwm-test-Fix-memory-leak-in-mft_qom_se.patch b/qtest-npcm7xx_pwm-test-Fix-memory-leak-in-mft_qom_se.patch new file mode 100644 index 0000000000000000000000000000000000000000..3da09c8d3113e398bf13c8222456c91d7fb63b14 --- /dev/null +++ b/qtest-npcm7xx_pwm-test-Fix-memory-leak-in-mft_qom_se.patch @@ -0,0 +1,39 @@ +From b76d4a1a4d7d0635044cd8542564803318ac5412 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 26 Sep 2023 07:49:12 +0000 +Subject: [PATCH] qtest/npcm7xx_pwm-test: Fix memory leak in mft_qom_set + mainline inclusion commit d412597ec5a8406b2af6aa5fb7740e77c1bd3f8c category: + bugfix + +--------------------------------------------------------------- + +g_strdup_printf() allocated memory for path, we should free it with +g_free() when no longer needed. + +Signed-off-by: Miaoqian Lin +Reviewed-by: Hao Wu +Message-Id: <20220531080921.4704-1-linmq006@gmail.com> +Signed-off-by: Thomas Huth + +Signed-off-by: tangbinzy +--- + tests/qtest/npcm7xx_pwm-test.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c +index a54fd70d27..ddfc120df0 100644 +--- a/tests/qtest/npcm7xx_pwm-test.c ++++ b/tests/qtest/npcm7xx_pwm-test.c +@@ -268,6 +268,9 @@ static void mft_qom_set(QTestState *qts, int index, const char *name, + path, name, value); + /* The qom set message returns successfully. */ + g_assert_true(qdict_haskey(response, "return")); ++ ++ qobject_unref(response); ++ g_free(path); + } + + static uint32_t get_pll(uint32_t con) +-- +2.41.0.windows.1 + diff --git a/replay-Fix-declaration-of-replay_read_next_clock.patch b/replay-Fix-declaration-of-replay_read_next_clock.patch new file mode 100644 index 0000000000000000000000000000000000000000..5c0049f5f3d44a0fbb2964e747524ada31fb5ffa --- /dev/null +++ b/replay-Fix-declaration-of-replay_read_next_clock.patch @@ -0,0 +1,50 @@ +From 8c499e212fedfaa4323541d97a33187ea96ba555 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 1 Dec 2022 18:58:34 +0800 +Subject: [PATCH 08/17] replay: Fix declaration of replay_read_next_clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes the build with gcc 13: + +replay/replay-time.c:34:6: error: conflicting types for \ + 'replay_read_next_clock' due to enum/integer mismatch; \ + have 'void(ReplayClockKind)' [-Werror=enum-int-mismatch] + 34 | void replay_read_next_clock(ReplayClockKind kind) + | ^~~~~~~~~~~~~~~~~~~~~~ +In file included from ../qemu/replay/replay-time.c:14: +replay/replay-internal.h:139:6: note: previous declaration of \ + 'replay_read_next_clock' with type 'void(unsigned int)' + 139 | void replay_read_next_clock(unsigned int kind); + | ^~~~~~~~~~~~~~~~~~~~~~ + +Fixes: 8eda206e090 ("replay: recording and replaying clock ticks") +Signed-off-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Wilfred Mallawa +Reviewed-by: Pavel Dovgalyuk +Signed-off-by: Stefan Hajnoczi +Message-Id: <20221129010547.284051-1-richard.henderson@linaro.org> + +Signed-off-by: tangzhongrui +--- + replay/replay-internal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/replay/replay-internal.h b/replay/replay-internal.h +index 97649ed8d7..b4238226f4 100644 +--- a/replay/replay-internal.h ++++ b/replay/replay-internal.h +@@ -141,7 +141,7 @@ bool replay_next_event_is(int event); + /*! Reads next clock value from the file. + If clock kind read from the file is different from the parameter, + the value is not used. */ +-void replay_read_next_clock(unsigned int kind); ++void replay_read_next_clock(ReplayClockKind kind); + + /* Asynchronous events queue */ + +-- +2.27.0 + diff --git a/replay-fix-event-queue-flush-for-qemu-shutdown.patch b/replay-fix-event-queue-flush-for-qemu-shutdown.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c129eedb484d01b09ad193255c9de4e15ebd3ea --- /dev/null +++ b/replay-fix-event-queue-flush-for-qemu-shutdown.patch @@ -0,0 +1,40 @@ +From d15694ef4ae7f7ebdbdac250a8a793ab66254655 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 26 Sep 2023 08:16:21 +0000 +Subject: [PATCH] replay: fix event queue flush for qemu shutdown mainline + inclusion commit c4b8ffcbb8531206e12cf3ad92fa90f7c80ed464 category: bugfix + +--------------------------------------------------------------- + +This patch fixes event queue flush in the case of emulator +shutdown. replay_finish_events should be called when replay_mode +is not cleared. + +Signed-off-by: Pavel Dovgalyuk +Reviewed-by: Richard Henderson +Message-Id: <165364836758.688121.7959245442743676491.stgit@pasha-ThinkPad-X280> +Signed-off-by: Paolo Bonzini + +Signed-off-by: tangbinzy +--- + replay/replay.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/replay/replay.c b/replay/replay.c +index 6df2abc18c..2d3607998a 100644 +--- a/replay/replay.c ++++ b/replay/replay.c +@@ -387,9 +387,8 @@ void replay_finish(void) + g_free(replay_snapshot); + replay_snapshot = NULL; + +- replay_mode = REPLAY_MODE_NONE; +- + replay_finish_events(); ++ replay_mode = REPLAY_MODE_NONE; + } + + void replay_add_blocker(Error *reason) +-- +2.41.0.windows.1 + diff --git a/revert-tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch b/revert-tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf0869e44fd4e75c194d2ac4ff4b9dd241ddead9 --- /dev/null +++ b/revert-tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch @@ -0,0 +1,30 @@ +From 7eff40be327d0c591e4b842cd954ec5dabb75848 Mon Sep 17 00:00:00 2001 +From: xianglai li +Date: Tue, 19 Dec 2023 02:34:39 -0500 +Subject: [PATCH] revert "tcg/loongarch64: Fix tcg_out_mov() Aborted" + +openEuler loongarch64 does not support qemu tcg, +so no TCG-related patch is required for synchronization. + +Signed-off-by: xianglai li +--- + tcg/loongarch64/tcg-target.c.inc | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc +index ee7d4d728d..0b28b30002 100644 +--- a/tcg/loongarch64/tcg-target.c.inc ++++ b/tcg/loongarch64/tcg-target.c.inc +@@ -255,9 +255,6 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) + */ + tcg_out_opc_or(s, ret, arg, TCG_REG_ZERO); + break; +- case TCG_TYPE_V128: +- tcg_out_opc_vori_b(s, ret, arg, 0); +- break; + default: + g_assert_not_reached(); + } +-- +2.27.0 + diff --git a/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch b/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch deleted file mode 100644 index 00e672662ddd5d848fc031967a0efdcf9dc4432b..0000000000000000000000000000000000000000 --- a/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch +++ /dev/null @@ -1,54 +0,0 @@ -From fc5afb1a9230fe21d76bcef527b0d3cee90a2cd3 Mon Sep 17 00:00:00 2001 -From: Michael Roth -Date: Thu, 12 Sep 2019 18:12:02 -0500 -Subject: [PATCH] roms/Makefile.edk2: don't pull in submodules when building - from tarball -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently the `make efi` target pulls submodules nested under the -roms/edk2 submodule as dependencies. However, when we attempt to build -from a tarball this fails since we are no longer in a git tree. - -A preceding patch will pre-populate these submodules in the tarball, -so assume this build dependency is only needed when building from a -git tree. - -Cc: Laszlo Ersek -Cc: Bruce Rogers -Cc: qemu-stable@nongnu.org # v4.1.0 -Reported-by: Bruce Rogers -Reviewed-by: Laszlo Ersek -Reviewed-by: Philippe Mathieu-Daudé -Tested-by: Philippe Mathieu-Daudé -Signed-off-by: Michael Roth -Message-Id: <20190912231202.12327-3-mdroth@linux.vnet.ibm.com> -Signed-off-by: Philippe Mathieu-Daudé -(cherry picked from commit f3e330e3c319160ac04954399b5a10afc965098c) -Signed-off-by: Michael Roth ---- - roms/Makefile.edk2 | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/roms/Makefile.edk2 b/roms/Makefile.edk2 -index c2f2ff59d5..33a074d3a4 100644 ---- a/roms/Makefile.edk2 -+++ b/roms/Makefile.edk2 -@@ -46,8 +46,13 @@ all: $(foreach flashdev,$(flashdevs),../pc-bios/edk2-$(flashdev).fd.bz2) \ - # files. - .INTERMEDIATE: $(foreach flashdev,$(flashdevs),../pc-bios/edk2-$(flashdev).fd) - -+# Fetch edk2 submodule's submodules. If it is not in a git tree, assume -+# we're building from a tarball and that they've already been fetched by -+# make-release/tarball scripts. - submodules: -- cd edk2 && git submodule update --init --force -+ if test -d edk2/.git; then \ -+ cd edk2 && git submodule update --init --force; \ -+ fi - - # See notes on the ".NOTPARALLEL" target and the "+" indicator in - # "tests/uefi-test-tools/Makefile". --- -2.23.0 diff --git a/s390x-Fix-spelling-errors.patch b/s390x-Fix-spelling-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..192657105faafdd180310d2d955a0455e499040f --- /dev/null +++ b/s390x-Fix-spelling-errors.patch @@ -0,0 +1,246 @@ +From 8f9bdcfe073479ba0170d3b01023d9a00f3b1e31 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Thu, 7 Dec 2023 17:47:34 -0800 +Subject: [PATCH] s390x: Fix spelling errors + +mainline inclusion +commit 44ee69ea16bd0390082ed88d4e82d6cea3a18b46 +category: bugfix + +--------------------------------------------------------------- + +Fix typos (discovered with the 'codespell' utility). +Note: Though "migrateable" still seems to be a valid spelling, we change +it to "migratable" since this is the way more common spelling here. + +Message-Id: <20221111182828.282251-1-thuth@redhat.com> +Reviewed-by: Stefan Weil +Reviewed-by: Ilya Leoshkevich +Signed-off-by: Thomas Huth +Signed-off-by: zhujun2 +--- + hw/s390x/ipl.h | 2 +- + hw/s390x/s390-virtio-ccw.c | 6 +++--- + pc-bios/s390-ccw/cio.h | 2 +- + pc-bios/s390-ccw/iplb.h | 2 +- + pc-bios/s390-ccw/start.S | 2 +- + target/s390x/cpu_models.h | 4 ++-- + target/s390x/ioinst.c | 2 +- + target/s390x/tcg/excp_helper.c | 2 +- + target/s390x/tcg/fpu_helper.c | 2 +- + target/s390x/tcg/misc_helper.c | 2 +- + target/s390x/tcg/translate.c | 4 ++-- + target/s390x/tcg/translate_vx.c.inc | 6 +++--- + 12 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h +index dfc6dfd89c..7fc86e7905 100644 +--- a/hw/s390x/ipl.h ++++ b/hw/s390x/ipl.h +@@ -140,7 +140,7 @@ void s390_ipl_clear_reset_request(void); + * have an offset of 4 + n * 8 bytes within the struct in order + * to keep it double-word aligned. + * The total size of the struct must never exceed 28 bytes. +- * This definition must be kept in sync with the defininition ++ * This definition must be kept in sync with the definition + * in pc-bios/s390-ccw/iplb.h. + */ + struct QemuIplParameters { +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 653587ea62..c84b89ba43 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -345,7 +345,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) + } + + error_setg(&pv_mig_blocker, +- "protected VMs are currently not migrateable."); ++ "protected VMs are currently not migratable."); + rc = migrate_add_blocker(pv_mig_blocker, &local_err); + if (rc) { + ram_block_discard_disable(false); +@@ -434,7 +434,7 @@ static void s390_machine_reset(MachineState *machine) + break; + case S390_RESET_MODIFIED_CLEAR: + /* +- * Susbsystem reset needs to be done before we unshare memory ++ * Subsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); +@@ -447,7 +447,7 @@ static void s390_machine_reset(MachineState *machine) + break; + case S390_RESET_LOAD_NORMAL: + /* +- * Susbsystem reset needs to be done before we unshare memory ++ * Subsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); +diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h +index 1e5d4e92e1..88a88adfd2 100644 +--- a/pc-bios/s390-ccw/cio.h ++++ b/pc-bios/s390-ccw/cio.h +@@ -20,7 +20,7 @@ struct pmcw { + __u32 intparm; /* interruption parameter */ + __u32 qf:1; /* qdio facility */ + __u32 w:1; +- __u32 isc:3; /* interruption sublass */ ++ __u32 isc:3; /* interruption subclass */ + __u32 res5:3; /* reserved zeros */ + __u32 ena:1; /* enabled */ + __u32 lm:2; /* limit mode */ +diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h +index 772d5c57c9..cb6ac8a880 100644 +--- a/pc-bios/s390-ccw/iplb.h ++++ b/pc-bios/s390-ccw/iplb.h +@@ -81,7 +81,7 @@ extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); + #define QIPL_FLAG_BM_OPTS_ZIPL 0x40 + + /* +- * This definition must be kept in sync with the defininition ++ * This definition must be kept in sync with the definition + * in hw/s390x/ipl.h + */ + struct QemuIplParameters { +diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S +index 4d5ad21653..6072906df4 100644 +--- a/pc-bios/s390-ccw/start.S ++++ b/pc-bios/s390-ccw/start.S +@@ -19,7 +19,7 @@ _start: + larl %r2, __bss_start + larl %r3, _end + slgr %r3, %r2 /* get sizeof bss */ +- ltgr %r3,%r3 /* bss emtpy? */ ++ ltgr %r3,%r3 /* bss empty? */ + jz done + aghi %r3,-1 + srlg %r4,%r3,8 /* how many 256 byte chunks? */ +diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h +index 74d1f87e4f..fb1adc8b21 100644 +--- a/target/s390x/cpu_models.h ++++ b/target/s390x/cpu_models.h +@@ -24,13 +24,13 @@ struct S390CPUDef { + uint8_t gen; /* hw generation identification */ + uint16_t type; /* cpu type identification */ + uint8_t ec_ga; /* EC GA version (on which also the BC is based) */ +- uint8_t mha_pow; /* Maximum Host Adress Power, mha = 2^pow-1 */ ++ uint8_t mha_pow; /* maximum host address power, mha = 2^pow-1 */ + uint32_t hmfai; /* hypervisor-managed facilities */ + /* base/min features, must never be changed between QEMU versions */ + S390FeatBitmap base_feat; + /* used to init base_feat from generated data */ + S390FeatInit base_init; +- /* deafault features, QEMU version specific */ ++ /* default features, QEMU version specific */ + S390FeatBitmap default_feat; + /* used to init default_feat from generated data */ + S390FeatInit default_init; +diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c +index bdae5090bc..e6347d1801 100644 +--- a/target/s390x/ioinst.c ++++ b/target/s390x/ioinst.c +@@ -285,7 +285,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, + /* + * As operand exceptions have a lower priority than access exceptions, + * we check whether the memory area is writeable (injecting the +- * access execption if it is not) first. ++ * access exception if it is not) first. + */ + if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { + s390_program_interrupt(env, PGM_OPERAND, ra); +diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c +index 4e7648f301..6a4f7585b8 100644 +--- a/target/s390x/tcg/excp_helper.c ++++ b/target/s390x/tcg/excp_helper.c +@@ -551,7 +551,7 @@ try_deliver: + /* don't trigger a cpu_loop_exit(), use an interrupt instead */ + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT); + } else if (cs->halted) { +- /* unhalt if we had a WAIT PSW somehwere in our injection chain */ ++ /* unhalt if we had a WAIT PSW somewhere in our injection chain */ + s390_cpu_unhalt(cpu); + } + } +diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c +index 4067205405..be80b2373c 100644 +--- a/target/s390x/tcg/fpu_helper.c ++++ b/target/s390x/tcg/fpu_helper.c +@@ -89,7 +89,7 @@ static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) + /* + * invalid/divbyzero cannot coexist with other conditions. + * overflow/underflow however can coexist with inexact, we have to +- * handle it separatly. ++ * handle it separately. + */ + if (s390_exc & ~S390_IEEE_MASK_INEXACT) { + if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { +diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c +index aab9c47747..7a975aaf94 100644 +--- a/target/s390x/tcg/misc_helper.c ++++ b/target/s390x/tcg/misc_helper.c +@@ -326,7 +326,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) + /* same as machine type number in STORE CPU ID, but in EBCDIC */ + snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type); + ebcdic_put(sysib.sysib_111.type, type, 4); +- /* model number (not stored in STORE CPU ID for z/Architecure) */ ++ /* model number (not stored in STORE CPU ID for z/Architecture) */ + ebcdic_put(sysib.sysib_111.model, "QEMU ", 16); + ebcdic_put(sysib.sysib_111.sequence, "QEMU ", 16); + ebcdic_put(sysib.sysib_111.plant, "QEMU", 4); +diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c +index dcc249a197..62fbc90d5e 100644 +--- a/target/s390x/tcg/translate.c ++++ b/target/s390x/tcg/translate.c +@@ -434,7 +434,7 @@ static void gen_program_exception(DisasContext *s, int code) + { + TCGv_i32 tmp; + +- /* Remember what pgm exeption this was. */ ++ /* Remember what pgm exception this was. */ + tmp = tcg_const_i32(code); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); + tcg_temp_free_i32(tmp); +@@ -490,7 +490,7 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) + + /* + * Note that d2 is limited to 20 bits, signed. If we crop negative +- * displacements early we create larger immedate addends. ++ * displacements early we create larger immediate addends. + */ + if (b2 && x2) { + tcg_gen_add_i64(tmp, regs[b2], regs[x2]); +diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc +index 28bf5a23b6..d1fe4df1b5 100644 +--- a/target/s390x/tcg/translate_vx.c.inc ++++ b/target/s390x/tcg/translate_vx.c.inc +@@ -797,7 +797,7 @@ static DisasJumpType op_vpk(DisasContext *s, DisasOps *o) + } + break; + case 0x94: +- /* If sources and destination dont't overlap -> fast path */ ++ /* If sources and destination don't overlap -> fast path */ + if (v1 != v2 && v1 != v3) { + const uint8_t src_es = get_field(s, m4); + const uint8_t dst_es = src_es - 1; +@@ -1793,7 +1793,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) + l2 = tcg_temp_new_i64(); + h2 = tcg_temp_new_i64(); + +- /* Multipy both even elements from v2 and v3 */ ++ /* Multiply both even elements from v2 and v3 */ + read_vec_element_i64(l1, get_field(s, v2), 0, ES_64); + read_vec_element_i64(h1, get_field(s, v3), 0, ES_64); + tcg_gen_mulu2_i64(l1, h1, l1, h1); +@@ -1802,7 +1802,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) + tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1); + } + +- /* Multipy both odd elements from v2 and v3 */ ++ /* Multiply both odd elements from v2 and v3 */ + read_vec_element_i64(l2, get_field(s, v2), 1, ES_64); + read_vec_element_i64(h2, get_field(s, v3), 1, ES_64); + tcg_gen_mulu2_i64(l2, h2, l2, h2); +-- +2.27.0 + diff --git a/scripts-entitlement.sh-Use-backward-compatible-cp-fl.patch b/scripts-entitlement.sh-Use-backward-compatible-cp-fl.patch new file mode 100644 index 0000000000000000000000000000000000000000..6139fc97205503e47538d872a4bb89f448bf3005 --- /dev/null +++ b/scripts-entitlement.sh-Use-backward-compatible-cp-fl.patch @@ -0,0 +1,35 @@ +From 66da71e852323bf1eb7b75b93cfb13eb748ad10f Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 10:09:12 +0800 +Subject: [PATCH] scripts/entitlement.sh: Use backward-compatible cp flags + +cherry picked from commit 4006a27c5e44734350009262efb0e2ec8da5ff09 + +Older versions of Mac OS X do not support cp -a. The cp man page indicates +that -a is equivalent to -pPR. + +Signed-off-by: Evan Miller +Message-Id: <40635C6E-059A-4146-B1E2-F6376700EE85@gmail.com> +[Leave out -R, these are files and not directories. - Paolo] +Signed-off-by: Paolo Bonzini +Signed-off-by: Luo Yifan +--- + scripts/entitlement.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/entitlement.sh b/scripts/entitlement.sh +index e2c956a3ac..0f412949ec 100755 +--- a/scripts/entitlement.sh ++++ b/scripts/entitlement.sh +@@ -15,7 +15,7 @@ ENTITLEMENT="$4" + + if $in_place; then + trap 'rm "$DST.tmp"' exit +- cp -af "$SRC" "$DST.tmp" ++ cp -pPf "$SRC" "$DST.tmp" + SRC="$DST.tmp" + else + cd "$MESON_INSTALL_DESTDIR_PREFIX" +-- +2.27.0 + diff --git a/scsi-bugfix-fix-division-by-zero.patch b/scsi-bugfix-fix-division-by-zero.patch new file mode 100644 index 0000000000000000000000000000000000000000..685c8d54e320562b912323497637ad1b2fd7c9c6 --- /dev/null +++ b/scsi-bugfix-fix-division-by-zero.patch @@ -0,0 +1,57 @@ +From ba8fd8a3d11655da0b51148e69c01b78794a3f69 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 16:34:05 +0800 +Subject: [PATCH] scsi: bugfix: fix division by zero + +Error of PRDM disk may cause divide by zero in +scsi_read_complete(), so add LOG and assert(). + +Signed-off-by: wangjian161 +--- + hw/scsi/scsi-generic.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 0306ccc7b1..1f51586048 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -179,6 +179,10 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len) + (r->req.cmd.buf[1] & 0x01)) { + page = r->req.cmd.buf[2]; + if (page == 0xb0) { ++ if (s->blocksize == 0) { ++ qemu_log("device blocksize is 0!\n"); ++ abort(); ++ } + uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); + uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk); + +@@ -314,11 +318,23 @@ static void scsi_read_complete(void * opaque, int ret) + /* Snoop READ CAPACITY output to set the blocksize. */ + if (r->req.cmd.buf[0] == READ_CAPACITY_10 && + (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { +- s->blocksize = ldl_be_p(&r->buf[4]); ++ int new_blocksize = ldl_be_p(&r->buf[4]); ++ if (s->blocksize != new_blocksize) { ++ qemu_log("device id=%s type=%d: blocksize %d change to %d\n", ++ s->qdev.id ? s->qdev.id : "null", s->type, ++ s->blocksize, new_blocksize); ++ } ++ s->blocksize = new_blocksize; + s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; + } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && + (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { +- s->blocksize = ldl_be_p(&r->buf[8]); ++ int new_blocksize = ldl_be_p(&r->buf[8]); ++ if (s->blocksize != new_blocksize) { ++ qemu_log("device id=%s type=%d: blocksize %d change to %d\n", ++ s->qdev.id ? s->qdev.id : "null", s->type, ++ s->blocksize, new_blocksize); ++ } ++ s->blocksize = new_blocksize; + s->max_lba = ldq_be_p(&r->buf[0]); + } + blk_set_guest_block_size(s->conf.blk, s->blocksize); +-- +2.27.0 + diff --git a/scsi-bus-Refactor-the-code-that-retries-requests.patch b/scsi-bus-Refactor-the-code-that-retries-requests.patch index eae42b854e2ba7818ff3c5e9812c7e3ed7f94ac9..84802c483fb08d03c8e101106f33bdc0ce31461c 100644 --- a/scsi-bus-Refactor-the-code-that-retries-requests.patch +++ b/scsi-bus-Refactor-the-code-that-retries-requests.patch @@ -1,7 +1,7 @@ -From eb55d7c4f6e0adae2aab8bd750dccf9cd7a8c784 Mon Sep 17 00:00:00 2001 +From 391dd8f1458c8db0b848450718af5c69285e5705 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:54 +0800 -Subject: [PATCH] scsi-bus: Refactor the code that retries requests +Subject: [PATCH 6/9] scsi-bus: Refactor the code that retries requests Move the code that retries requests from scsi_dma_restart_bh() to its own, non-static, function. This will allow us to call it from the @@ -9,17 +9,18 @@ retry_request_cb() of scsi-disk in a future patch. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- hw/scsi/scsi-bus.c | 16 +++++++++++----- include/hw/scsi/scsi.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index fdc3a0e4e0..9dc09b5f3e 100644 +index 77325d8cc7..5e6f891b9d 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c -@@ -99,14 +99,10 @@ void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host, - qbus_set_bus_hotplug_handler(BUS(bus), &error_abort); +@@ -143,14 +143,10 @@ void scsi_bus_init_named(SCSIBus *bus, size_t bus_size, DeviceState *host, + qbus_set_bus_hotplug_handler(BUS(bus)); } -static void scsi_dma_restart_bh(void *opaque) @@ -34,8 +35,8 @@ index fdc3a0e4e0..9dc09b5f3e 100644 aio_context_acquire(blk_get_aio_context(s->conf.blk)); QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) { scsi_req_ref(req); -@@ -128,6 +124,16 @@ static void scsi_dma_restart_bh(void *opaque) - aio_context_release(blk_get_aio_context(s->conf.blk)); +@@ -174,6 +170,16 @@ static void scsi_dma_restart_bh(void *opaque) + object_unref(OBJECT(s)); } +static void scsi_dma_restart_bh(void *opaque) @@ -52,10 +53,10 @@ index fdc3a0e4e0..9dc09b5f3e 100644 { /* No need to save a reference, because scsi_dma_restart_bh just diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h -index 426566a5c6..1231d30b35 100644 +index a567a5ed86..e5d90cd9dc 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h -@@ -184,6 +184,7 @@ void scsi_req_cancel_complete(SCSIRequest *req); +@@ -212,6 +212,7 @@ void scsi_req_cancel_complete(SCSIRequest *req); void scsi_req_cancel(SCSIRequest *req); void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier); void scsi_req_retry(SCSIRequest *req); diff --git a/scsi-bus-fix-incorrect-call-for-blk_error_retry_rese.patch b/scsi-bus-fix-incorrect-call-for-blk_error_retry_rese.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f4804f16550ce3b85091a32d08f399e7b41b352 --- /dev/null +++ b/scsi-bus-fix-incorrect-call-for-blk_error_retry_rese.patch @@ -0,0 +1,80 @@ +From 3ab10a5ad9bf1cbf3b4603f5a930a7924a07ad5a Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Tue, 29 Mar 2022 12:05:56 +0800 +Subject: [PATCH 1/2] scsi-bus: fix incorrect call for + blk_error_retry_reset_timeout() + +Fix commit 52115ca0("scsi-disk: Add support for retry on errors"). +Call Stack: + ... + scsi_read_data() + scsi_do_read(r, 0) + scsi_disk_req_check_error() + blk_error_retry_reset_timeout() + blk->retry_start_time = 0; + +It will cause IO hang when storage network disconnected. Before the +storage network recovered, the upper call stack will reset the +retry_start_time, and cause the next IO operation not returned immediately. + +Signed-off-by: Yan Wang +--- + hw/scsi/scsi-disk.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index 8661932a15..a66d2b0a98 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -255,10 +255,8 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) + } + } + +-static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) ++static bool scsi_disk_req_handle_error(SCSIDiskReq *r, int ret, bool acct_failed) + { +- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); +- + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); + return true; +@@ -268,6 +266,17 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) + return scsi_handle_rw_error(r, ret, acct_failed); + } + ++ return false; ++} ++ ++static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) ++{ ++ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); ++ ++ if (r->req.io_canceled || ret < 0) { ++ return scsi_disk_req_handle_error(r, ret, acct_failed); ++ } ++ + blk_error_retry_reset_timeout(s->qdev.conf.blk); + return false; + } +@@ -418,7 +427,7 @@ static void scsi_do_read(SCSIDiskReq *r, int ret) + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); + + assert (r->req.aiocb == NULL); +- if (scsi_disk_req_check_error(r, ret, false)) { ++ if (scsi_disk_req_handle_error(r, ret, false)) { + goto done; + } + +@@ -458,6 +467,9 @@ static void scsi_do_read_cb(void *opaque, int ret) + block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); + } else { + block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); ++ if (!r->req.io_canceled) { ++ blk_error_retry_reset_timeout(s->qdev.conf.blk); ++ } + } + scsi_do_read(opaque, ret); + aio_context_release(blk_get_aio_context(s->qdev.conf.blk)); +-- +2.27.0 + diff --git a/scsi-bus-fix-unmatched-object_unref.patch b/scsi-bus-fix-unmatched-object_unref.patch new file mode 100644 index 0000000000000000000000000000000000000000..0cb39a07610c8da0396119e87e942b400dbdddf5 --- /dev/null +++ b/scsi-bus-fix-unmatched-object_unref.patch @@ -0,0 +1,42 @@ +From 239ffdcf42e0795b5f025f87fa19ce01642811f2 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Tue, 1 Mar 2022 20:12:12 +0800 +Subject: [PATCH] scsi-bus: fix unmatched object_unref() + +Fix commit 391dd8f1("scsi-bus: Refactor the code that retries requests"), +which split scsi_dma_restart_bh(), but the object_unref() belongs to +scsi_dma_restart_bh(). +So, we should mv object_unref() from scsi_retry_requests() to +scsi_dma_restart_bh(). + +Signed-off-by: Yan Wang +--- + hw/scsi/scsi-bus.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c +index 5e6f891b9d..9d37f490ce 100644 +--- a/hw/scsi/scsi-bus.c ++++ b/hw/scsi/scsi-bus.c +@@ -166,8 +166,6 @@ void scsi_retry_requests(SCSIDevice *s) + scsi_req_unref(req); + } + aio_context_release(blk_get_aio_context(s->conf.blk)); +- /* Drop the reference that was acquired in scsi_dma_restart_cb */ +- object_unref(OBJECT(s)); + } + + static void scsi_dma_restart_bh(void *opaque) +@@ -178,6 +176,9 @@ static void scsi_dma_restart_bh(void *opaque) + s->bh = NULL; + + scsi_retry_requests(s); ++ ++ /* Drop the reference that was acquired in scsi_dma_restart_cb */ ++ object_unref(OBJECT(s)); + } + + void scsi_req_retry(SCSIRequest *req) +-- +2.27.0 + diff --git a/scsi-cdrom-Fix-crash-after-remote-cdrom-detached.patch b/scsi-cdrom-Fix-crash-after-remote-cdrom-detached.patch new file mode 100644 index 0000000000000000000000000000000000000000..d1147fce44d9bd2cc06e8bbd2b2da1f1ac8083af --- /dev/null +++ b/scsi-cdrom-Fix-crash-after-remote-cdrom-detached.patch @@ -0,0 +1,35 @@ +From 77496578b22e127eb50a5a8c463e92fb3245a7e0 Mon Sep 17 00:00:00 2001 +From: WangJian +Date: Wed, 9 Feb 2022 11:42:47 +0800 +Subject: [PATCH] scsi: cdrom: Fix crash after remote cdrom detached + +There is a small window between the twice blk_is_available in +scsi_disk_emulate_command which would cause crash due to the later +assertion if the remote cdrom is detached in this window. + +So this patch replaces assertions with return to avoid qemu crash. + +Signed-off-by: wangjian161 +--- + hw/scsi/scsi-disk.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index d4914178ea..a1053f4036 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -1930,7 +1930,10 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) + memset(outbuf, 0, r->buflen); + switch (req->cmd.buf[0]) { + case TEST_UNIT_READY: +- assert(blk_is_available(s->qdev.conf.blk)); ++ if (!blk_is_available(s->qdev.conf.blk)) { ++ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); ++ return 0; ++ } + break; + case INQUIRY: + buflen = scsi_disk_emulate_inquiry(req, outbuf); +-- +2.27.0 + diff --git a/scsi-disk-Add-support-for-retry-on-errors.patch b/scsi-disk-Add-support-for-retry-on-errors.patch index e0bd91ec86fd13c70499567df0c18f9761e06c35..69f76143bc27c0ea1f121d7419b88ae2764e07dc 100644 --- a/scsi-disk-Add-support-for-retry-on-errors.patch +++ b/scsi-disk-Add-support-for-retry-on-errors.patch @@ -1,22 +1,34 @@ -From 34f1552a6d7e05f2f2146ebc6d50deb2de7e5fd4 Mon Sep 17 00:00:00 2001 +From 52115ca0ad925b1d719eb46e22c455aa5839534a Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:55 +0800 -Subject: [PATCH] scsi-disk: Add support for retry on errors +Subject: [PATCH 7/9] scsi-disk: Add support for retry on errors Mark failed requests as to be retried and implement retry_request_cb to handle these requests. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- hw/scsi/scsi-disk.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index cd90cd780e..93fdd913fe 100644 +index d4914178ea..d278efc701 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c -@@ -184,6 +184,8 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) +@@ -246,6 +246,10 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) + scsi_req_retry(&r->req); + return true; + ++ case BLOCK_ERROR_ACTION_RETRY: ++ scsi_req_retry(&r->req); ++ return true; ++ + default: + g_assert_not_reached(); + } +@@ -253,6 +257,8 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) { @@ -25,26 +37,15 @@ index cd90cd780e..93fdd913fe 100644 if (r->req.io_canceled) { scsi_req_cancel_complete(&r->req); return true; -@@ -193,6 +195,7 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) - return scsi_handle_rw_error(r, -ret, acct_failed); +@@ -262,6 +268,7 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) + return scsi_handle_rw_error(r, ret, acct_failed); } + blk_error_retry_reset_timeout(s->qdev.conf.blk); return false; } -@@ -480,6 +483,10 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) - } - } - -+ if (action == BLOCK_ERROR_ACTION_RETRY) { -+ scsi_req_retry(&r->req); -+ } -+ - blk_error_action(s->qdev.conf.blk, action, is_read, error); - if (action == BLOCK_ERROR_ACTION_IGNORE) { - scsi_req_complete(&r->req, 0); -@@ -2252,6 +2259,13 @@ static void scsi_disk_resize_cb(void *opaque) +@@ -2278,6 +2285,13 @@ static void scsi_disk_resize_cb(void *opaque) } } @@ -58,7 +59,7 @@ index cd90cd780e..93fdd913fe 100644 static void scsi_cd_change_media_cb(void *opaque, bool load, Error **errp) { SCSIDiskState *s = opaque; -@@ -2300,10 +2314,12 @@ static const BlockDevOps scsi_disk_removable_block_ops = { +@@ -2326,10 +2340,12 @@ static const BlockDevOps scsi_disk_removable_block_ops = { .is_medium_locked = scsi_cd_is_medium_locked, .resize_cb = scsi_disk_resize_cb, diff --git a/scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch b/scsi-disk-define-props-in-scsi_block_disk-to-avoid-m.patch similarity index 74% rename from scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch rename to scsi-disk-define-props-in-scsi_block_disk-to-avoid-m.patch index a180aa1a08062f11cd313f5019d35933cd55747c..f3befe79a7e6f6b9b4513cecd5614b3aea91054e 100644 --- a/scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch +++ b/scsi-disk-define-props-in-scsi_block_disk-to-avoid-m.patch @@ -1,7 +1,7 @@ -From 79da8e2e18610ae22a3bd640c117ba56b911038d Mon Sep 17 00:00:00 2001 +From e026850b32231abb97d7790a04d7c94515bd1081 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Mon, 13 Jan 2020 15:53:32 +0800 -Subject: [PATCH] scsi-disk: define props in scsi_block_disk to avoid +Subject: [PATCH 3/6] scsi-disk: define props in scsi_block_disk to avoid memleaks scsi_block_realize() use scsi_realize() to init some props, but @@ -11,19 +11,20 @@ not be freed. This patch defines these prop in scsi_block_disk_properties to avoid memleaks. Signed-off-by: Pan Nengyuan +Signed-off-by: Yan Wang --- hw/scsi/scsi-disk.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index e7e865ab..233afb4a 100644 +index d491417..1d7799d 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c -@@ -3026,9 +3026,7 @@ static const TypeInfo scsi_cd_info = { +@@ -3107,9 +3107,7 @@ static const TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { -- DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ +- DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), - DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), - DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), + DEFINE_SCSI_DISK_PROPERTIES(), @@ -31,6 +32,5 @@ index e7e865ab..233afb4a 100644 DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, DEFAULT_MAX_UNMAP_SIZE), -- -2.18.1 - +1.9.1 diff --git a/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch b/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch deleted file mode 100644 index 5d20a9f009c9bd52f9eef578344c5b0012ee8942..0000000000000000000000000000000000000000 --- a/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 051c9b3cbcb4beb42a6ed017c2146ec3e7a754fb Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 14 Aug 2019 17:35:21 +0530 -Subject: [PATCH] scsi: lsi: exit infinite loop while executing script - (CVE-2019-12068) - -When executing script in lsi_execute_script(), the LSI scsi adapter -emulator advances 's->dsp' index to read next opcode. This can lead -to an infinite loop if the next opcode is empty. Move the existing -loop exit after 10k iterations so that it covers no-op opcodes as -well. - -Reported-by: Bugs SysSec -Signed-off-by: Paolo Bonzini -Signed-off-by: Prasad J Pandit -Signed-off-by: Paolo Bonzini -(cherry picked from commit de594e47659029316bbf9391efb79da0a1a08e08) -Signed-off-by: Michael Roth ---- - hw/scsi/lsi53c895a.c | 41 +++++++++++++++++++++++++++-------------- - 1 file changed, 27 insertions(+), 14 deletions(-) - -diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c -index 10468c1ec1..72f7b59ab5 100644 ---- a/hw/scsi/lsi53c895a.c -+++ b/hw/scsi/lsi53c895a.c -@@ -185,6 +185,9 @@ static const char *names[] = { - /* Flag set if this is a tagged command. */ - #define LSI_TAG_VALID (1 << 16) - -+/* Maximum instructions to process. */ -+#define LSI_MAX_INSN 10000 -+ - typedef struct lsi_request { - SCSIRequest *req; - uint32_t tag; -@@ -1132,7 +1135,21 @@ static void lsi_execute_script(LSIState *s) - - s->istat1 |= LSI_ISTAT1_SRUN; - again: -- insn_processed++; -+ if (++insn_processed > LSI_MAX_INSN) { -+ /* Some windows drivers make the device spin waiting for a memory -+ location to change. If we have been executed a lot of code then -+ assume this is the case and force an unexpected device disconnect. -+ This is apparently sufficient to beat the drivers into submission. -+ */ -+ if (!(s->sien0 & LSI_SIST0_UDC)) { -+ qemu_log_mask(LOG_GUEST_ERROR, -+ "lsi_scsi: inf. loop with UDC masked"); -+ } -+ lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); -+ lsi_disconnect(s); -+ trace_lsi_execute_script_stop(); -+ return; -+ } - insn = read_dword(s, s->dsp); - if (!insn) { - /* If we receive an empty opcode increment the DSP by 4 bytes -@@ -1569,19 +1586,7 @@ again: - } - } - } -- if (insn_processed > 10000 && s->waiting == LSI_NOWAIT) { -- /* Some windows drivers make the device spin waiting for a memory -- location to change. If we have been executed a lot of code then -- assume this is the case and force an unexpected device disconnect. -- This is apparently sufficient to beat the drivers into submission. -- */ -- if (!(s->sien0 & LSI_SIST0_UDC)) { -- qemu_log_mask(LOG_GUEST_ERROR, -- "lsi_scsi: inf. loop with UDC masked"); -- } -- lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); -- lsi_disconnect(s); -- } else if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { -+ if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { - if (s->dcntl & LSI_DCNTL_SSM) { - lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); - } else { -@@ -1969,6 +1974,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) - case 0x2f: /* DSP[24:31] */ - s->dsp &= 0x00ffffff; - s->dsp |= val << 24; -+ /* -+ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one -+ * instruction. Is this correct? -+ */ - if ((s->dmode & LSI_DMODE_MAN) == 0 - && (s->istat1 & LSI_ISTAT1_SRUN) == 0) - lsi_execute_script(s); -@@ -1987,6 +1996,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) - break; - case 0x3b: /* DCNTL */ - s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); -+ /* -+ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one -+ * instruction. Is this correct? -+ */ - if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) - lsi_execute_script(s); - break; --- -2.23.0 diff --git a/scsi-lsi53c895a-fix-use-after-free-in-lsi_do_msgout-.patch b/scsi-lsi53c895a-fix-use-after-free-in-lsi_do_msgout-.patch new file mode 100644 index 0000000000000000000000000000000000000000..c617b98277d5801334492c498e1175af4b939080 --- /dev/null +++ b/scsi-lsi53c895a-fix-use-after-free-in-lsi_do_msgout-.patch @@ -0,0 +1,37 @@ +From 87d97af840d61122e801a37a89e6bf48a2cbe8e2 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Tue, 5 Jul 2022 22:05:43 +0200 +Subject: [PATCH 3/4] scsi/lsi53c895a: fix use-after-free in lsi_do_msgout + (CVE-2022-0216) + +Set current_req->req to NULL to prevent reusing a free'd buffer in case of +repeated SCSI cancel requests. Thanks to Thomas Huth for suggesting the patch. + +Fixes: CVE-2022-0216 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 +Signed-off-by: Mauro Matteo Cascella +Reviewed-by: Thomas Huth +Message-Id: <20220705200543.2366809-1-mcascell@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/lsi53c895a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 4c431adb77..4c91854df9 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1028,8 +1028,9 @@ static void lsi_do_msgout(LSIState *s) + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + trace_lsi_do_msgout_abort(current_tag); +- if (current_req) { ++ if (current_req && current_req->req) { + scsi_req_cancel(current_req->req); ++ current_req->req = NULL; + } + lsi_disconnect(s); + break; +-- +2.27.0 + diff --git a/scsi-lsi53c895a-really-fix-use-after-free-in-lsi_do_.patch b/scsi-lsi53c895a-really-fix-use-after-free-in-lsi_do_.patch new file mode 100644 index 0000000000000000000000000000000000000000..637a78e1fbde6f28daa8aa8b7fbfbc459f1651f4 --- /dev/null +++ b/scsi-lsi53c895a-really-fix-use-after-free-in-lsi_do_.patch @@ -0,0 +1,141 @@ +From b0a1db1428e8d92693a323b9d479764071d08247 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Mon, 11 Jul 2022 14:33:16 +0200 +Subject: [PATCH 4/4] scsi/lsi53c895a: really fix use-after-free in + lsi_do_msgout (CVE-2022-0216) + +Set current_req to NULL, not current_req->req, to prevent reusing a free'd +buffer in case of repeated SCSI cancel requests. Also apply the fix to +CLEAR QUEUE and BUS DEVICE RESET messages as well, since they also cancel +the request. + +Thanks to Alexander Bulekov for providing a reproducer. + +Fixes: CVE-2022-0216 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 +Signed-off-by: Mauro Matteo Cascella +Tested-by: Alexander Bulekov +Message-Id: <20220711123316.421279-1-mcascell@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/lsi53c895a.c | 3 +- + tests/qtest/fuzz-lsi53c895a-test.c | 75 ++++++++++++++++++++++++++++++ + 2 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 4c91854df9..b9c9eb0dac 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s) + trace_lsi_do_msgout_abort(current_tag); + if (current_req && current_req->req) { + scsi_req_cancel(current_req->req); +- current_req->req = NULL; ++ current_req = NULL; + } + lsi_disconnect(s); + break; +@@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) + /* clear the current I/O process */ + if (s->current) { + scsi_req_cancel(s->current->req); ++ current_req = NULL; + } + + /* As the current implemented devices scsi_disk and scsi_generic +diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c +index ba5d468970..0f968024c8 100644 +--- a/tests/qtest/fuzz-lsi53c895a-test.c ++++ b/tests/qtest/fuzz-lsi53c895a-test.c +@@ -8,6 +8,79 @@ + #include "qemu/osdep.h" + #include "libqos/libqtest.h" + ++/* ++ * This used to trigger a UAF in lsi_do_msgout() ++ * https://gitlab.com/qemu-project/qemu/-/issues/972 ++ */ ++static void test_lsi_do_msgout_cancel_req(void) ++{ ++ QTestState *s; ++ ++ if (sizeof(void *) == 4) { ++ g_test_skip("memory size too big for 32-bit build"); ++ return; ++ } ++ ++ s = qtest_init("-M q35 -m 4G -display none -nodefaults " ++ "-device lsi53c895a,id=scsi " ++ "-device scsi-hd,drive=disk0 " ++ "-drive file=null-co://,id=disk0,if=none,format=raw"); ++ ++ qtest_outl(s, 0xcf8, 0x80000810); ++ qtest_outl(s, 0xcf8, 0xc000); ++ qtest_outl(s, 0xcf8, 0x80000810); ++ qtest_outw(s, 0xcfc, 0x7); ++ qtest_outl(s, 0xcf8, 0x80000810); ++ qtest_outl(s, 0xcfc, 0xc000); ++ qtest_outl(s, 0xcf8, 0x80000804); ++ qtest_outw(s, 0xcfc, 0x05); ++ qtest_writeb(s, 0x69736c10, 0x08); ++ qtest_writeb(s, 0x69736c13, 0x58); ++ qtest_writeb(s, 0x69736c1a, 0x01); ++ qtest_writeb(s, 0x69736c1b, 0x06); ++ qtest_writeb(s, 0x69736c22, 0x01); ++ qtest_writeb(s, 0x69736c23, 0x07); ++ qtest_writeb(s, 0x69736c2b, 0x02); ++ qtest_writeb(s, 0x69736c48, 0x08); ++ qtest_writeb(s, 0x69736c4b, 0x58); ++ qtest_writeb(s, 0x69736c52, 0x04); ++ qtest_writeb(s, 0x69736c53, 0x06); ++ qtest_writeb(s, 0x69736c5b, 0x02); ++ qtest_outl(s, 0xc02d, 0x697300); ++ qtest_writeb(s, 0x5a554662, 0x01); ++ qtest_writeb(s, 0x5a554663, 0x07); ++ qtest_writeb(s, 0x5a55466a, 0x10); ++ qtest_writeb(s, 0x5a55466b, 0x22); ++ qtest_writeb(s, 0x5a55466c, 0x5a); ++ qtest_writeb(s, 0x5a55466d, 0x5a); ++ qtest_writeb(s, 0x5a55466e, 0x34); ++ qtest_writeb(s, 0x5a55466f, 0x5a); ++ qtest_writeb(s, 0x5a345a5a, 0x77); ++ qtest_writeb(s, 0x5a345a5b, 0x55); ++ qtest_writeb(s, 0x5a345a5c, 0x51); ++ qtest_writeb(s, 0x5a345a5d, 0x27); ++ qtest_writeb(s, 0x27515577, 0x41); ++ qtest_outl(s, 0xc02d, 0x5a5500); ++ qtest_writeb(s, 0x364001d0, 0x08); ++ qtest_writeb(s, 0x364001d3, 0x58); ++ qtest_writeb(s, 0x364001da, 0x01); ++ qtest_writeb(s, 0x364001db, 0x26); ++ qtest_writeb(s, 0x364001dc, 0x0d); ++ qtest_writeb(s, 0x364001dd, 0xae); ++ qtest_writeb(s, 0x364001de, 0x41); ++ qtest_writeb(s, 0x364001df, 0x5a); ++ qtest_writeb(s, 0x5a41ae0d, 0xf8); ++ qtest_writeb(s, 0x5a41ae0e, 0x36); ++ qtest_writeb(s, 0x5a41ae0f, 0xd7); ++ qtest_writeb(s, 0x5a41ae10, 0x36); ++ qtest_writeb(s, 0x36d736f8, 0x0c); ++ qtest_writeb(s, 0x36d736f9, 0x80); ++ qtest_writeb(s, 0x36d736fa, 0x0d); ++ qtest_outl(s, 0xc02d, 0x364000); ++ ++ qtest_quit(s); ++} ++ + /* + * This used to trigger the assert in lsi_do_dma() + * https://bugs.launchpad.net/qemu/+bug/697510 +@@ -46,6 +119,8 @@ int main(int argc, char **argv) + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", + test_lsi_do_dma_empty_queue); ++ qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req", ++ test_lsi_do_msgout_cancel_req); + } + + return g_test_run(); +-- +2.27.0 + diff --git a/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch b/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch deleted file mode 100644 index e38bfaa471d280a7de334e81906747938ab57b7c..0000000000000000000000000000000000000000 --- a/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch +++ /dev/null @@ -1,65 +0,0 @@ -From e8d2655821caa2b8efce429c0036a93342b8383d Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Mon, 8 Feb 2021 17:14:21 +0800 -Subject: [PATCH] sd: sdhci: assert data_count is within fifo_buffer -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2020-17380 - -While doing multi block SDMA, transfer block size may exceed -the 's->fifo_buffer[s->buf_maxsz]' size. It may leave the -current element pointer 's->data_count' pointing out of bounds. -Leading the subsequent DMA r/w operation to OOB access issue. -Assert that 's->data_count' is within fifo_buffer. - - -> https://ruhr-uni-bochum.sciebo.de/s/NNWP2GfwzYKeKwE?path=%2Fsdhci_oob_write1 - ==1459837==ERROR: AddressSanitizer: heap-buffer-overflow - WRITE of size 54722048 at 0x61500001e280 thread T3 - #0 __interceptor_memcpy (/lib64/libasan.so.6+0x3a71d) - #1 flatview_read_continue ../exec.c:3245 - #2 flatview_read ../exec.c:3278 - #3 address_space_read_full ../exec.c:3291 - #4 address_space_rw ../exec.c:3319 - #5 dma_memory_rw_relaxed ../include/sysemu/dma.h:87 - #6 dma_memory_rw ../include/sysemu/dma.h:110 - #7 dma_memory_read ../include/sysemu/dma.h:116 - #8 sdhci_sdma_transfer_multi_blocks ../hw/sd/sdhci.c:629 - #9 sdhci_write ../hw/sd/sdhci.c:1097 - #10 memory_region_write_accessor ../softmmu/memory.c:483 - ... - -Reported-by: Ruhr-University -Suggested-by: Philippe Mathieu-Daudé -Signed-off-by: Prasad J Pandit - -patch link: https://lists.nongnu.org/archive/html/qemu-devel/2020-09/msg01175.html -Signed-off-by: Jiajie Li ---- - hw/sd/sdhci.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c -index 7b80b1d93f..e51573fe3c 100644 ---- a/hw/sd/sdhci.c -+++ b/hw/sd/sdhci.c -@@ -613,6 +613,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) - s->blkcnt--; - } - } -+ assert(s->data_count <= s->buf_maxsz && s->data_count > begin); - dma_memory_write(s->dma_as, s->sdmasysad, - &s->fifo_buffer[begin], s->data_count - begin); - s->sdmasysad += s->data_count - begin; -@@ -635,6 +636,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) - s->data_count = block_size; - boundary_count -= block_size - begin; - } -+ assert(s->data_count <= s->buf_maxsz && s->data_count > begin); - dma_memory_read(s->dma_as, s->sdmasysad, - &s->fifo_buffer[begin], s->data_count - begin); - s->sdmasysad += s->data_count - begin; --- -2.27.0 - diff --git a/seabios-add-check-to-avoid-dereference-NULL-pointer.patch b/seabios-add-check-to-avoid-dereference-NULL-pointer.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c94c4681c2a74df31ea77ed2a83c5d775b1d429 --- /dev/null +++ b/seabios-add-check-to-avoid-dereference-NULL-pointer.patch @@ -0,0 +1,36 @@ +From e6b133311a7a5a618b48c6f38e3c3bb9e9a395c9 Mon Sep 17 00:00:00 2001 +From: eillon +Date: Mon, 14 Feb 2022 15:35:28 +0800 +Subject: [PATCH] seabios: add check to avoid dereference NULL pointer + +alloc_find_lowest() may return NULL, check it. + +Signed-off-by: eillon +--- + roms/seabios/src/malloc.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/roms/seabios/src/malloc.c b/roms/seabios/src/malloc.c +index 5827a6523..99fa3b7e0 100644 +--- a/roms/seabios/src/malloc.c ++++ b/roms/seabios/src/malloc.c +@@ -544,10 +544,12 @@ malloc_prepboot(void) + + // Clear unused f-seg ram. + struct allocinfo_s *info = alloc_find_lowest(&ZoneFSeg); +- u32 size = info->range_end - info->range_start; +- memset(memremap(info->range_start, size), 0, size); +- dprintf(1, "Space available for UMB: %x-%x, %x-%x\n" +- , RomEnd, base, info->range_start, info->range_end); ++ if (info) { ++ u32 size = info->range_end - info->range_start; ++ memset(memremap(info->range_start, size), 0, size); ++ dprintf(1, "Space available for UMB: %x-%x, %x-%x\n" ++ , RomEnd, base, info->range_start, info->range_end); ++ } + + // We should not give back unused high ram, to support some special + // guest OS, like oracle linux series. +-- +2.27.0 + diff --git a/seabios-convert-value-of-be16_to_cpu-to-u64-before-s.patch b/seabios-convert-value-of-be16_to_cpu-to-u64-before-s.patch new file mode 100644 index 0000000000000000000000000000000000000000..be0218f935178a0cd5ad9bfdbef24199acdbba2f --- /dev/null +++ b/seabios-convert-value-of-be16_to_cpu-to-u64-before-s.patch @@ -0,0 +1,31 @@ +From c2ec0efb903e27f83cb9a54041764f76e2e1d390 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:12:21 +0800 +Subject: [PATCH 1/6] seabios: convert value of be16_to_cpu to u64 before + shifting + +be16_to_cpu(scsi_lun->lun[i]) is 16 bits and left shifting by more than 16 will have undefined behaviour. +convert it to u64 before shifting. + +Signed-off-by: liuxiangdong +Signed-off-by: jiangdongxu +--- + roms/seabios/src/hw/blockcmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/roms/seabios/src/hw/blockcmd.c b/roms/seabios/src/hw/blockcmd.c +index 6b6fea9707..af6d33544f 100644 +--- a/roms/seabios/src/hw/blockcmd.c ++++ b/roms/seabios/src/hw/blockcmd.c +@@ -210,7 +210,7 @@ static u64 scsilun2u64(struct scsi_lun *scsi_lun) + int i; + u64 ret = 0; + for (i = 0; i < ARRAY_SIZE(scsi_lun->lun); i++) +- ret |= be16_to_cpu(scsi_lun->lun[i]) << (16 * i); ++ ret |= (u64)be16_to_cpu(scsi_lun->lun[i]) << (16 * i); + return ret; + } + +-- +2.27.0 + diff --git a/seabios-do-not-give-back-high-ram.patch b/seabios-do-not-give-back-high-ram.patch new file mode 100644 index 0000000000000000000000000000000000000000..df40892f44b00f51ba244ae5d8af14e69c99e7e5 --- /dev/null +++ b/seabios-do-not-give-back-high-ram.patch @@ -0,0 +1,43 @@ +From 74f052de33cb14d7a1656079a53102a7cbbb6e75 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:16:05 +0800 +Subject: [PATCH 2/6] seabios: do not give back high ram + +Oracle 6 and 7 series virtual machines will use the high ram returned by +sebios. Since these high ram will not be initialized before kernel used, +this will cause a system exception. This patch removes the logic for +returning high ram, making the virtual machine will not use this part +of the memory, thus avoiding this kernel bug. + +Signed-off-by: wangxin +Signed-off-by: Fangyi +Signed-off-by: jiangdongxu +--- + roms/seabios/src/malloc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/roms/seabios/src/malloc.c b/roms/seabios/src/malloc.c +index 3733855caf..5827a6523a 100644 +--- a/roms/seabios/src/malloc.c ++++ b/roms/seabios/src/malloc.c +@@ -549,6 +549,9 @@ malloc_prepboot(void) + dprintf(1, "Space available for UMB: %x-%x, %x-%x\n" + , RomEnd, base, info->range_start, info->range_end); + ++ // We should not give back unused high ram, to support some special ++ // guest OS, like oracle linux series. ++#ifdef HIGH_MEM_BACK + // Give back unused high ram. + info = alloc_find_lowest(&ZoneHigh); + if (info) { +@@ -556,6 +559,7 @@ malloc_prepboot(void) + e820_add(info->range_start, giveback, E820_RAM); + dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback); + } ++#endif + + calcRamSize(); + } +-- +2.27.0 + diff --git a/seabios-drop-yield-in-smp_setup.patch b/seabios-drop-yield-in-smp_setup.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c55aa0da4c4eecf6eeeb5b0d9dc5451d99672e6 --- /dev/null +++ b/seabios-drop-yield-in-smp_setup.patch @@ -0,0 +1,39 @@ +From 1a8defda890d6fe3efe2238cff1ef2ae6ca8928c Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:31:25 +0800 +Subject: [PATCH 4/6] seabios: drop yield() in smp_setup() + +Fix SeaBIOS stuck problem becuase SeaBIOS open hardware interrupt +by invoking yield(). That's dangerous and unnecessary. Let's drop +it, and make the processing of setup smp more security in SeaBIOS. + +Signed-off-by: liuxiangdong +Signed-off-by: jiangdongxu +--- + roms/seabios/src/fw/smp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/roms/seabios/src/fw/smp.c b/roms/seabios/src/fw/smp.c +index 46d1da1784..e5e407be0c 100644 +--- a/roms/seabios/src/fw/smp.c ++++ b/roms/seabios/src/fw/smp.c +@@ -149,6 +149,7 @@ smp_scan(void) + + // Wait for other CPUs to process the SIPI. + u16 expected_cpus_count = qemu_get_present_cpus_count(); ++ dprintf(1,"expected_cpus_count=%d\n", expected_cpus_count); + while (expected_cpus_count != CountCPUs) + asm volatile( + // Release lock and allow other processors to use the stack. +@@ -160,7 +161,7 @@ smp_scan(void) + " jc 1b\n" + : "+m" (SMPLock), "+m" (SMPStack) + : : "cc", "memory"); +- yield(); ++ dprintf(1, "finish smp\n"); + + // Restore memory. + *(u64*)BUILD_AP_BOOT_ADDR = old; +-- +2.27.0 + diff --git a/seabios-fix-memory-leak-when-pci-check.patch b/seabios-fix-memory-leak-when-pci-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..01d1ea06864f719c1bcd057b05506a546e9de4bc --- /dev/null +++ b/seabios-fix-memory-leak-when-pci-check.patch @@ -0,0 +1,34 @@ +From 73cb83af0649f958bb31b5b76f46c164c6f2952c Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:28:55 +0800 +Subject: [PATCH 3/6] seabios: fix memory leak when pci check + +fix code memory leak when pci check failed +free busses memory when pci_bios_check_devices function returns error in pci_setup() + +Signed-off-by: liuxiangodng +Signed-off-by: jiangdongxu +--- + roms/seabios/src/fw/pciinit.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/roms/seabios/src/fw/pciinit.c b/roms/seabios/src/fw/pciinit.c +index d25931bb05..9df35d05d1 100644 +--- a/roms/seabios/src/fw/pciinit.c ++++ b/roms/seabios/src/fw/pciinit.c +@@ -1171,8 +1171,11 @@ pci_setup(void) + return; + } + memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1)); +- if (pci_bios_check_devices(busses)) ++ if (pci_bios_check_devices(busses)) { ++ dprintf(1, "pci_bios_check_devices(busses) failed!\n"); ++ free(busses); + return; ++ } + + dprintf(1, "=== PCI new allocation pass #2 ===\n"); + pci_bios_map_devices(busses); +-- +2.27.0 + diff --git a/seabios-increase-the-seabios-high-mem-zone-size.patch b/seabios-increase-the-seabios-high-mem-zone-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..01c16d1db2827e6948158e9bcac0823467668554 --- /dev/null +++ b/seabios-increase-the-seabios-high-mem-zone-size.patch @@ -0,0 +1,34 @@ +From bf72a9439d06fe35e3c7246b60e1c5b7b8058459 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:34:23 +0800 +Subject: [PATCH 6/6] seabios: increase the seabios high mem zone size + +In terms of version and specification, under the maximum configuration +specification of the number of vcpus, virtio blocks and other features, +there exists bottleneck in seabios high_mem_zone, which results in the +memory application failure and causes the vm to fail to start. + +Increase BUILD_MAX_HIGHTABLE to 512k. + +Signed-off-by: liuxiangdong +Signed-off-by: jiangdongxu +--- + roms/seabios/src/config.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/roms/seabios/src/config.h b/roms/seabios/src/config.h +index 93c8dbc2d5..9abd43474e 100644 +--- a/roms/seabios/src/config.h ++++ b/roms/seabios/src/config.h +@@ -17,7 +17,7 @@ + // Maximum number of map entries in the e820 map + #define BUILD_MAX_E820 32 + // Space to reserve in high-memory for tables +-#define BUILD_MAX_HIGHTABLE (256*1024) ++#define BUILD_MAX_HIGHTABLE (512*1024) + // Largest supported externaly facing drive id + #define BUILD_MAX_EXTDRIVE 16 + // Number of bytes the smbios may be and still live in the f-segment +-- +2.27.0 + diff --git a/seabios-increase-the-seabios-minibiostable.patch b/seabios-increase-the-seabios-minibiostable.patch new file mode 100644 index 0000000000000000000000000000000000000000..bd3cfa461ecc6b436b43ac55775ece42b62d4aea --- /dev/null +++ b/seabios-increase-the-seabios-minibiostable.patch @@ -0,0 +1,33 @@ +From 764113a4a24e1d842a45fb62fc09279c87057616 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Fri, 11 Feb 2022 16:33:04 +0800 +Subject: [PATCH 5/6] seabios: increase the seabios minibiostable + +Increase the BUILD_MIN_BIOSTABLE to 4096; +support 25 virtio-blk(data) + 1 virtio-scsi(sys) + 1 virtio-net + +Increase the BUILD_MIN_BIOSTABLE to 5120; +support 18 virtio-scsi while vm starts with IDE boot disk + +Signed-off-by: liuxiangdong +Signed-off-by: jiangdongxu +--- + roms/seabios/scripts/layoutrom.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/roms/seabios/scripts/layoutrom.py b/roms/seabios/scripts/layoutrom.py +index abebf0211f..e2732db8f9 100755 +--- a/roms/seabios/scripts/layoutrom.py ++++ b/roms/seabios/scripts/layoutrom.py +@@ -66,7 +66,7 @@ def setSectionsStart(sections, endaddr, minalign=1, segoffset=0): + BUILD_ROM_START = 0xc0000 + BUILD_LOWRAM_END = 0xa0000 + # Space to reserve in f-segment for dynamic allocations +-BUILD_MIN_BIOSTABLE = 2048 ++BUILD_MIN_BIOSTABLE = 5120 + + # Layout the 16bit code. This ensures sections with fixed offset + # requirements are placed in the correct location. It also places the +-- +2.27.0 + diff --git a/semihosting-config-Merge-semihosting-config-option-g.patch b/semihosting-config-Merge-semihosting-config-option-g.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7c9e59be4b675152c4379ab50661eda348147ce --- /dev/null +++ b/semihosting-config-Merge-semihosting-config-option-g.patch @@ -0,0 +1,54 @@ +From ff7918646e3c696d13732fb22f032d7d78c34fe1 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 08:15:13 +0000 +Subject: [PATCH] semihosting/config: Merge --semihosting-config option groups + mainline inclusion commit 90c072e063737e9e8f431489bbd334452f89056e category: + bugfix + +--------------------------------------------------------------- + +Currently we mishandle the --semihosting-config option if the +user specifies it on the command line more than once. For +example with: + --semihosting-config target=gdb --semihosting-config arg=foo,arg=bar + +the function qemu_semihosting_config_options() is called twice, once +for each argument. But that function expects to be called only once, +and it always unconditionally sets the semihosting.enabled, +semihost_chardev and semihosting.target variables. This means that +if any of those options were set anywhere except the last +--semihosting-config option on the command line, those settings are +ignored. In the example above, 'target=gdb' in the first option is +overridden by an implied default 'target=auto' in the second. + +The QemuOptsList machinery has a flag for handling this kind of +"option group is setting global state": by setting + .merge_lists = true; +we make the machinery merge all the --semihosting-config arguments +the user passes into a single set of options and call our +qemu_semihosting_config_options() just once. + +Signed-off-by: Peter Maydell +Reviewed-by: Luc Michel +Message-id: 20220526190053.521505-3-peter.maydell@linaro.org + +Signed-off-by: tangbinzy +--- + semihosting/config.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/semihosting/config.c b/semihosting/config.c +index 137171b717..ba3e310a61 100644 +--- a/semihosting/config.c ++++ b/semihosting/config.c +@@ -27,6 +27,7 @@ + + QemuOptsList qemu_semihosting_config_opts = { + .name = "semihosting-config", ++ .merge_lists = true, + .implied_opt_name = "enable", + .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head), + .desc = { +-- +2.27.0 + diff --git a/semihosting-fix-memleak-at-semihosting_arg_fallback.patch b/semihosting-fix-memleak-at-semihosting_arg_fallback.patch new file mode 100644 index 0000000000000000000000000000000000000000..ccee1a5bb1ca43518d5376480569873626a121b1 --- /dev/null +++ b/semihosting-fix-memleak-at-semihosting_arg_fallback.patch @@ -0,0 +1,47 @@ +From 47a24e233e335025ed37ab0ba4a4e728719a2ad3 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 6 Nov 2023 18:14:06 +0800 +Subject: [PATCH] semihosting: fix memleak at semihosting_arg_fallback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 2eb71a0c20a6a77be128a76c1ef8fb5dc7028a8b + +We duplicate "cmd" as strtok may modify its argument, but we forgot +to free it later. Furthermore, add_semihosting_arg doesn't take +responsibility for this memory either (it strdup's the argument). + +Signed-off-by: Matheus Tavares Bernardino +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <03d81c56bfc3d08224e4106efca5949d8894cfa5.1697801632.git.quic_mathbern@quicinc.com> +Reviewed-by: Richard Henderson +Signed-off-by: Alex Bennée +Message-Id: <20231029145033.592566-18-alex.bennee@linaro.org> +Signed-off-by: qihao_yewu +--- + semihosting/config.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/semihosting/config.c b/semihosting/config.c +index 137171b717..303338f647 100644 +--- a/semihosting/config.c ++++ b/semihosting/config.c +@@ -109,12 +109,13 @@ static int add_semihosting_arg(void *opaque, + void semihosting_arg_fallback(const char *file, const char *cmd) + { + char *cmd_token; ++ g_autofree char *cmd_dup = g_strdup(cmd); + + /* argv[0] */ + add_semihosting_arg(&semihosting, "arg", file, NULL); + + /* split -append and initialize argv[1..n] */ +- cmd_token = strtok(g_strdup(cmd), " "); ++ cmd_token = strtok(cmd_dup, " "); + while (cmd_token) { + add_semihosting_arg(&semihosting, "arg", cmd_token, NULL); + cmd_token = strtok(NULL, " "); +-- +2.27.0 + diff --git a/seqlock-fix-seqlock_write_unlock_impl-function.patch b/seqlock-fix-seqlock_write_unlock_impl-function.patch deleted file mode 100644 index f7f8c7cf6e044a663886db1b89f6c8bda36e2d25..0000000000000000000000000000000000000000 --- a/seqlock-fix-seqlock_write_unlock_impl-function.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 96e00e040cd8ae23cebf183cf3a8dc9cf1f6149d Mon Sep 17 00:00:00 2001 -From: Luc Michel -Date: Wed, 29 Jan 2020 15:49:48 +0100 -Subject: [PATCH] seqlock: fix seqlock_write_unlock_impl function -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The seqlock write unlock function was incorrectly calling -seqlock_write_begin() instead of seqlock_write_end(), and was releasing -the lock before incrementing the sequence. This could lead to a race -condition and a corrupted sequence number becoming odd even though the -lock is not held. - -Signed-off-by: Luc Michel -Reviewed-by: Philippe Mathieu-Daudé -Message-Id: <20200129144948.2161551-1-luc.michel@greensocs.com> -Fixes: 988fcafc73 ("seqlock: add QemuLockable support", 2018-08-23) -Signed-off-by: Paolo Bonzini ---- - include/qemu/seqlock.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h -index fd408b7ec5..8b6b4ee4bb 100644 ---- a/include/qemu/seqlock.h -+++ b/include/qemu/seqlock.h -@@ -55,11 +55,11 @@ static inline void seqlock_write_lock_impl(QemuSeqLock *sl, QemuLockable *lock) - #define seqlock_write_lock(sl, lock) \ - seqlock_write_lock_impl(sl, QEMU_MAKE_LOCKABLE(lock)) - --/* Lock out other writers and update the count. */ -+/* Update the count and release the lock. */ - static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock) - { -+ seqlock_write_end(sl); - qemu_lockable_unlock(lock); -- seqlock_write_begin(sl); - } - #define seqlock_write_unlock(sl, lock) \ - seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock)) --- -2.27.0 - diff --git a/shadow_dev-introduce-shadow-dev-for-virtio-net-devic.patch b/shadow_dev-introduce-shadow-dev-for-virtio-net-devic.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef1164d6ca802901261df0e6e46f6b55d5c60db9 --- /dev/null +++ b/shadow_dev-introduce-shadow-dev-for-virtio-net-devic.patch @@ -0,0 +1,195 @@ +From 0a6c08bd3a16543b8021c8b65a45f7ebb701a9aa Mon Sep 17 00:00:00 2001 +From: Dongxu Sun +Date: Fri, 15 Dec 2023 17:44:54 +0800 +Subject: [PATCH] shadow_dev: introduce shadow dev for virtio-net device + +for virtio net devices, create the shadow device for vlpi +bypass inject supported. + +Signed-off-by: Wang Haibin +Signed-off-by: Yu Zenghui +Signed-off-by: Chen Qun +Signed-off-by: KunKun Jiang +Signed-off-by: Dongxu Sun +--- + hw/virtio/virtio-pci.c | 32 ++++++++++++++++++++++++++ + include/sysemu/kvm.h | 5 +++++ + linux-headers/linux/kvm.h | 13 +++++++++++ + target/arm/kvm.c | 47 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 97 insertions(+) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 82706b8b32..6b45683280 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -873,18 +873,44 @@ undo: + } + return ret; + } ++ ++#ifdef __aarch64__ ++int __attribute__((weak)) kvm_create_shadow_device(PCIDevice *dev) ++{ ++ return 0; ++} ++ ++int __attribute__((weak)) kvm_delete_shadow_device(PCIDevice *dev) ++{ ++ return 0; ++} ++#endif ++ + static int kvm_virtio_pci_vector_vq_use(VirtIOPCIProxy *proxy, int nvqs) + { + int queue_no; + int ret = 0; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + ++#ifdef __aarch64__ ++ if (!strcmp(vdev->name, "virtio-net")) { ++ kvm_create_shadow_device(&proxy->pci_dev); ++ } ++#endif ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; + } + ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + } ++ ++#ifdef __aarch64__ ++ if (!strcmp(vdev->name, "virtio-net") && ret != 0) { ++ kvm_delete_shadow_device(&proxy->pci_dev); ++ } ++#endif ++ + return ret; + } + +@@ -927,6 +953,12 @@ static void kvm_virtio_pci_vector_vq_release(VirtIOPCIProxy *proxy, int nvqs) + } + kvm_virtio_pci_vector_release_one(proxy, queue_no); + } ++ ++#ifdef __aarch64__ ++ if (!strcmp(vdev->name, "virtio-net")) { ++ kvm_delete_shadow_device(&proxy->pci_dev); ++ } ++#endif + } + + static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 1ec9432493..9f52d08ce0 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -553,4 +553,9 @@ bool kvm_arch_cpu_check_are_resettable(void); + bool kvm_dirty_ring_enabled(void); + + uint32_t kvm_dirty_ring_size(void); ++ ++#ifdef __aarch64__ ++int kvm_create_shadow_device(PCIDevice *dev); ++int kvm_delete_shadow_device(PCIDevice *dev); ++#endif + #endif +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 2008fbc173..cd0885f523 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1127,6 +1127,8 @@ struct kvm_ppc_resize_hpt { + + #define KVM_CAP_ARM_CPU_FEATURE 555 + ++#define KVM_CAP_ARM_VIRT_MSI_BYPASS 799 ++ + #ifdef KVM_CAP_IRQ_ROUTING + + struct kvm_irq_routing_irqchip { +@@ -1431,6 +1433,17 @@ struct kvm_s390_ucas_mapping { + #define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config) + #define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data) + #define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data) ++ ++#ifdef __aarch64__ ++struct kvm_master_dev_info ++{ ++ __u32 nvectors; /* number of msi vectors */ ++ struct kvm_msi msi[0]; ++}; ++#define KVM_CREATE_SHADOW_DEV _IOW(KVMIO, 0xf0, struct kvm_master_dev_info) ++#define KVM_DEL_SHADOW_DEV _IOW(KVMIO, 0xf1, __u32) ++#endif ++ + /* Available with KVM_CAP_PIT_STATE2 */ + #define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2) + #define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2) +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 22ac5bcb97..38d80adfb7 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -27,6 +27,8 @@ + #include "trace.h" + #include "internals.h" + #include "hw/pci/pci.h" ++#include "hw/pci/msi.h" ++#include "hw/pci/msix.h" + #include "exec/memattrs.h" + #include "exec/address-spaces.h" + #include "hw/boards.h" +@@ -1075,6 +1077,51 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, + return 0; + } + ++int kvm_create_shadow_device(PCIDevice *dev) ++{ ++ KVMState *s = kvm_state; ++ struct kvm_master_dev_info *mdi; ++ MSIMessage msg; ++ uint32_t vector, nvectors = msix_nr_vectors_allocated(dev); ++ uint32_t request_id; ++ int ret; ++ ++ if (!kvm_vm_check_extension(s, KVM_CAP_ARM_VIRT_MSI_BYPASS) || !nvectors) { ++ return 0; ++ } ++ ++ mdi = g_malloc0(sizeof(uint32_t) + sizeof(struct kvm_msi) * nvectors); ++ mdi->nvectors = nvectors; ++ request_id = pci_requester_id(dev); ++ ++ for (vector = 0; vector < nvectors; vector++) { ++ msg = msix_get_message(dev, vector); ++ mdi->msi[vector].address_lo = extract64(msg.address, 0, 32); ++ mdi->msi[vector].address_hi = extract64(msg.address, 32, 32); ++ mdi->msi[vector].data = le32_to_cpu(msg.data); ++ mdi->msi[vector].flags = KVM_MSI_VALID_DEVID; ++ mdi->msi[vector].devid = request_id; ++ memset(mdi->msi[vector].pad, 0, sizeof(mdi->msi[vector].pad)); ++ } ++ ++ ret = kvm_vm_ioctl(s, KVM_CREATE_SHADOW_DEV, mdi); ++ g_free(mdi); ++ return ret; ++} ++ ++int kvm_delete_shadow_device(PCIDevice *dev) ++{ ++ KVMState *s = kvm_state; ++ uint32_t request_id, nvectors = msix_nr_vectors_allocated(dev); ++ ++ if (!kvm_vm_check_extension(s, KVM_CAP_ARM_VIRT_MSI_BYPASS) || !nvectors) { ++ return 0; ++ } ++ ++ request_id = pci_requester_id(dev); ++ return kvm_vm_ioctl(s, KVM_DEL_SHADOW_DEV, &request_id); ++} ++ + int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, + int vector, PCIDevice *dev) + { +-- +2.27.0 + diff --git a/slirp-check-pkt_len-before-reading-protocol-header.patch b/slirp-check-pkt_len-before-reading-protocol-header.patch deleted file mode 100644 index 506e31e1cb809bba769e857177c4e2ad70f4293f..0000000000000000000000000000000000000000 --- a/slirp-check-pkt_len-before-reading-protocol-header.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c2df0d478b2605da10363ab57825cdbc34caa680 Mon Sep 17 00:00:00 2001 -From: Alex Chen -Date: Mon, 14 Dec 2020 15:39:46 +0800 -Subject: [PATCH] slirp: check pkt_len before reading protocol header -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While processing ARP/NCSI packets in 'arp_input' or 'ncsi_input' -routines, ensure that pkt_len is large enough to accommodate the -respective protocol headers, lest it should do an OOB access. -Add check to avoid it. - -CVE-2020-29129 CVE-2020-29130 - QEMU: slirp: out-of-bounds access while processing ARP/NCSI packets - -> https://www.openwall.com/lists/oss-security/2020/11/27/1 - -Reported-by: Qiuhao Li -Signed-off-by: Prasad J Pandit -Message-Id: <20201126135706.273950-1-ppandit@redhat.com> -Reviewed-by: Marc-André Lureau -(cherry-picked from 2e1dcbc0) -Signed-off-by: Alex Chen ---- - slirp/src/ncsi.c | 4 ++++ - slirp/src/slirp.c | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/slirp/src/ncsi.c b/slirp/src/ncsi.c -index 6864b735..251c0d2b 100644 ---- a/slirp/src/ncsi.c -+++ b/slirp/src/ncsi.c -@@ -147,6 +147,10 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) - uint32_t checksum; - uint32_t *pchecksum; - -+ if (pkt_len < ETH_HLEN + sizeof(struct ncsi_pkt_hdr)) { -+ return; /* packet too short */ -+ } -+ - memset(ncsi_reply, 0, sizeof(ncsi_reply)); - - memset(reh->h_dest, 0xff, ETH_ALEN); -diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c -index b0194cb3..86b0f52d 100644 ---- a/slirp/src/slirp.c -+++ b/slirp/src/slirp.c -@@ -700,6 +700,10 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) - return; - } - -+ if (pkt_len < ETH_HLEN + sizeof(struct slirp_arphdr)) { -+ return; /* packet too short */ -+ } -+ - ar_op = ntohs(ah->ar_op); - switch (ar_op) { - case ARPOP_REQUEST: --- -2.23.0 - diff --git a/slirp-tftp-restrict-relative-path-access.patch b/slirp-tftp-restrict-relative-path-access.patch deleted file mode 100644 index b7f09462525437c9048b4ab249b6e4208adda4ef..0000000000000000000000000000000000000000 --- a/slirp-tftp-restrict-relative-path-access.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 2fc07f4ce31a2cc9973cfb1c20897c6a4babd8b8 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 15 May 2020 16:45:28 +0800 -Subject: [PATCH] slirp: tftp: restrict relative path access - -tftp restricts relative or directory path access on Linux systems. -Apply same restrictions on Windows systems too. It helps to avoid -directory traversal issue. - -Fixes: https://bugs.launchpad.net/qemu/+bug/1812451Reported-by: default avatarPeter Maydell -Signed-off-by: default avatarPrasad J Pandit -Reviewed-by: Samuel Thibault's avatarSamuel Thibault -Message-Id: <20200113121431.156708-1-ppandit@redhat.com> - -diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c -index 093c2e06..2b4176cc 100644 ---- a/slirp/src/tftp.c -+++ b/slirp/src/tftp.c -@@ -344,8 +344,13 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, - k += 6; /* skipping octet */ - - /* do sanity checks on the filename */ -- if (!strncmp(req_fname, "../", 3) || -- req_fname[strlen(req_fname) - 1] == '/' || strstr(req_fname, "/../")) { -+ if ( -+#ifdef G_OS_WIN32 -+ strstr(req_fname, "..\\") || -+ req_fname[strlen(req_fname) - 1] == '\\' || -+#endif -+ strstr(req_fname, "../") || -+ req_fname[strlen(req_fname) -1] == '/') { - tftp_send_error(spt, 2, "Access violation", tp); - return; - } --- -2.23.0 - diff --git a/slirp-use-correct-size-while-emulating-IRC-commands.patch b/slirp-use-correct-size-while-emulating-IRC-commands.patch deleted file mode 100644 index 1b4039e1da3c0bcd08b97f4c61983ef3adac3823..0000000000000000000000000000000000000000 --- a/slirp-use-correct-size-while-emulating-IRC-commands.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 011880f527ff317a40769ea8673a6353e5db53ac Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 14 Apr 2020 18:23:23 +0800 -Subject: [PATCH] slirp: use correct size while emulating IRC commands - -While emulating IRC DCC commands, tcp_emu() uses 'mbuf' size -'m->m_size' to write DCC commands via snprintf(3). This may -lead to OOB write access, because 'bptr' points somewhere in -the middle of 'mbuf' buffer, not at the start. Use M_FREEROOM(m) -size to avoid OOB access. -Reported-by: default avatarVishnu Dev TJ -Signed-off-by: default avatarPrasad J Pandit -Reviewed-by: Samuel Thibault's avatarSamuel Thibault -Message-Id: <20200109094228.79764-2-ppandit@redhat.com> ---- - slirp/src/tcp_subr.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index 9c94c03a..2a15b16a 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -778,7 +778,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size, "DCC CHAT chat %lu %u%c\n", -+ m->m_len += snprintf(bptr, M_FREEROOM(m), -+ "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); - } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, -@@ -789,7 +790,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, m->m_size, "DCC SEND %s %lu %u %u%c\n", buff, -+ snprintf(bptr, M_FREEROOM(m), -+ "DCC SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, -@@ -800,7 +802,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, m->m_size, "DCC MOVE %s %lu %u %u%c\n", buff, -+ snprintf(bptr, M_FREEROOM(m), -+ "DCC MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } --- -2.23.0 diff --git a/slirp-use-correct-size-while-emulating-commands.patch b/slirp-use-correct-size-while-emulating-commands.patch deleted file mode 100644 index 25f64e2738e2ae3cbff541719b726dff963007d2..0000000000000000000000000000000000000000 --- a/slirp-use-correct-size-while-emulating-commands.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 662aa4f1d168b32335a4dc40782e816329afcac0 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 14 Apr 2020 18:36:12 +0800 -Subject: [PATCH] slirp: use correct size while emulating commands - -While emulating services in tcp_emu(), it uses 'mbuf' size -'m->m_size' to write commands via snprintf(3). Use M_FREEROOM(m) -size to avoid possible OOB access. -Signed-off-by: default avatarPrasad J Pandit -Signed-off-by: Samuel Thibault's avatarSamuel Thibault -Message-Id: <20200109094228.79764-3-ppandit@redhat.com> ---- - slirp/src/tcp_subr.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index 2a15b16a..019b637a 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -696,7 +696,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size - m->m_len, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, - n5, n6, x == 7 ? buff : ""); - return 1; -@@ -732,7 +732,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, m->m_size - m->m_len, -+ snprintf(bptr, M_FREEROOM(m), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); - -@@ -759,7 +759,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) - (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, - htons(lport), SS_FACCEPTONCE)) != NULL) - m->m_len = -- snprintf(m->m_data, m->m_size, "%d", ntohs(so->so_fport)) + 1; -+ snprintf(m->m_data, M_ROOM(m), -+ "%d", ntohs(so->so_fport)) + 1; - return 1; - - case EMU_IRC: --- -2.23.0 diff --git a/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch b/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch deleted file mode 100644 index 66e54cdd42053d31cfa05ffa9ee15fca183254ea..0000000000000000000000000000000000000000 --- a/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 6186d3de416825e3a737dd3da31da475f50d66d0 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Thu, 21 May 2020 21:39:44 +0200 -Subject: [PATCH] sm501: Clean up local variables in sm501_2d_operation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Make variables local to the block they are used in to make it clearer -which operation they are needed for. - -Signed-off-by: BALATON Zoltan -Reviewed-by: Philippe Mathieu-Daudé -Message-id: ae59f8138afe7f6a5a4a82539d0f61496a906b06.1590089984.git.balaton@eik.bme.hu -Signed-off-by: Gerd Hoffmann ---- - hw/display/sm501.c | 31 ++++++++++++++++--------------- - 1 file changed, 16 insertions(+), 15 deletions(-) - -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index f3d11d0b23..98b3b97f7b 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -699,28 +699,19 @@ static inline void hwc_invalidate(SM501State *s, int crt) - - static void sm501_2d_operation(SM501State *s) - { -- /* obtain operation parameters */ - int cmd = (s->twoD_control >> 16) & 0x1F; - int rtl = s->twoD_control & BIT(27); -- int src_x = (s->twoD_source >> 16) & 0x01FFF; -- int src_y = s->twoD_source & 0xFFFF; -- int dst_x = (s->twoD_destination >> 16) & 0x01FFF; -- int dst_y = s->twoD_destination & 0xFFFF; -- int width = (s->twoD_dimension >> 16) & 0x1FFF; -- int height = s->twoD_dimension & 0xFFFF; -- uint32_t color = s->twoD_foreground; - int format = (s->twoD_stretch >> 20) & 0x3; - int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ - /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ - int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; - int rop = s->twoD_control & 0xFF; -- uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; -+ int dst_x = (s->twoD_destination >> 16) & 0x01FFF; -+ int dst_y = s->twoD_destination & 0xFFFF; -+ int width = (s->twoD_dimension >> 16) & 0x1FFF; -+ int height = s->twoD_dimension & 0xFFFF; - uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; -- -- /* get frame buffer info */ -- uint8_t *src = s->local_mem + src_base; - uint8_t *dst = s->local_mem + dst_base; -- int src_pitch = s->twoD_pitch & 0x1FFF; - int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; - int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; - int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); -@@ -758,6 +749,13 @@ static void sm501_2d_operation(SM501State *s) - - switch (cmd) { - case 0x00: /* copy area */ -+ { -+ int src_x = (s->twoD_source >> 16) & 0x01FFF; -+ int src_y = s->twoD_source & 0xFFFF; -+ uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; -+ uint8_t *src = s->local_mem + src_base; -+ int src_pitch = s->twoD_pitch & 0x1FFF; -+ - #define COPY_AREA(_bpp, _pixel_type, rtl) { \ - int y, x, index_d, index_s; \ - for (y = 0; y < height; y++) { \ -@@ -793,8 +791,11 @@ static void sm501_2d_operation(SM501State *s) - break; - } - break; -- -+ } - case 0x01: /* fill rectangle */ -+ { -+ uint32_t color = s->twoD_foreground; -+ - #define FILL_RECT(_bpp, _pixel_type) { \ - int y, x; \ - for (y = 0; y < height; y++) { \ -@@ -819,7 +820,7 @@ static void sm501_2d_operation(SM501State *s) - break; - } - break; -- -+ } - default: - qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", - cmd); --- -2.23.0 - diff --git a/sm501-Convert-printf-abort-to-qemu_log_mask.patch b/sm501-Convert-printf-abort-to-qemu_log_mask.patch deleted file mode 100644 index 14a530bd78510f91daf5f78e9b9103f1b729f9cf..0000000000000000000000000000000000000000 --- a/sm501-Convert-printf-abort-to-qemu_log_mask.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 428e3a78ddf1de3dfb914043d6a8668f73ef8bb3 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Thu, 21 May 2020 21:39:44 +0200 -Subject: [PATCH] sm501: Convert printf + abort to qemu_log_mask -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Some places already use qemu_log_mask() to log unimplemented features -or errors but some others have printf() then abort(). Convert these to -qemu_log_mask() and avoid aborting to prevent guests to easily cause -denial of service. - -Signed-off-by: BALATON Zoltan -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 305af87f59d81e92f2aaff09eb8a3603b8baa322.1590089984.git.balaton@eik.bme.hu -Signed-off-by: Gerd Hoffmann ---- - hw/display/sm501.c | 57 ++++++++++++++++++++++------------------------ - 1 file changed, 27 insertions(+), 30 deletions(-) - -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index 5918f59b2b..aa4b202a48 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -727,8 +727,8 @@ static void sm501_2d_operation(SM501State *s) - int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); - - if (addressing != 0x0) { -- printf("%s: only XY addressing is supported.\n", __func__); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); -+ return; - } - - if (rop_mode == 0) { -@@ -754,8 +754,8 @@ static void sm501_2d_operation(SM501State *s) - - if ((s->twoD_source_base & 0x08000000) || - (s->twoD_destination_base & 0x08000000)) { -- printf("%s: only local memory is supported.\n", __func__); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); -+ return; - } - - switch (operation) { -@@ -823,9 +823,9 @@ static void sm501_2d_operation(SM501State *s) - break; - - default: -- printf("non-implemented SM501 2D operation. %d\n", operation); -- abort(); -- break; -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", -+ operation); -+ return; - } - - if (dst_base >= get_fb_addr(s, crt) && -@@ -892,9 +892,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, - break; - - default: -- printf("sm501 system config : not implemented register read." -- " addr=%x\n", (int)addr); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" -+ "register read. addr=%" HWADDR_PRIx "\n", addr); - } - - return ret; -@@ -948,15 +947,15 @@ static void sm501_system_config_write(void *opaque, hwaddr addr, - break; - case SM501_ENDIAN_CONTROL: - if (value & 0x00000001) { -- printf("sm501 system config : big endian mode not implemented.\n"); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: system config big endian mode not" -+ " implemented.\n"); - } - break; - - default: -- printf("sm501 system config : not implemented register write." -- " addr=%x, val=%x\n", (int)addr, (uint32_t)value); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" -+ "register write. addr=%" HWADDR_PRIx -+ ", val=%" PRIx64 "\n", addr, value); - } - } - -@@ -1207,9 +1206,8 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, - break; - - default: -- printf("sm501 disp ctrl : not implemented register read." -- " addr=%x\n", (int)addr); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " -+ "read. addr=%" HWADDR_PRIx "\n", addr); - } - - return ret; -@@ -1345,9 +1343,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, - break; - - default: -- printf("sm501 disp ctrl : not implemented register write." -- " addr=%x, val=%x\n", (int)addr, (unsigned)value); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " -+ "write. addr=%" HWADDR_PRIx -+ ", val=%" PRIx64 "\n", addr, value); - } - } - -@@ -1433,9 +1431,8 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, - ret = 0; /* Should return interrupt status */ - break; - default: -- printf("sm501 disp ctrl : not implemented register read." -- " addr=%x\n", (int)addr); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " -+ "read. addr=%" HWADDR_PRIx "\n", addr); - } - - return ret; -@@ -1520,9 +1517,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr, - /* ignored, writing 0 should clear interrupt status */ - break; - default: -- printf("sm501 2d engine : not implemented register write." -- " addr=%x, val=%x\n", (int)addr, (unsigned)value); -- abort(); -+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2d engine register " -+ "write. addr=%" HWADDR_PRIx -+ ", val=%" PRIx64 "\n", addr, value); - } - } - -@@ -1670,9 +1667,9 @@ static void sm501_update_display(void *opaque) - draw_line = draw_line32_funcs[dst_depth_index]; - break; - default: -- printf("sm501 update display : invalid control register value.\n"); -- abort(); -- break; -+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display" -+ "invalid control register value.\n"); -+ return; - } - - /* set up to draw hardware cursor */ --- -2.23.0 - diff --git a/sm501-Replace-hand-written-implementation-with-pixma.patch b/sm501-Replace-hand-written-implementation-with-pixma.patch deleted file mode 100644 index 42fa23aa934b29c19921f869530b93f1f24e1def..0000000000000000000000000000000000000000 --- a/sm501-Replace-hand-written-implementation-with-pixma.patch +++ /dev/null @@ -1,261 +0,0 @@ -From bbbf2c2f4201eb84a5bcd07a92399fe166d682e9 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Thu, 21 May 2020 21:39:44 +0200 -Subject: [PATCH] sm501: Replace hand written implementation with pixman where - possible - -Besides being faster this should also prevent malicious guests to -abuse 2D engine to overwrite data or cause a crash. - -Signed-off-by: BALATON Zoltan -Message-id: 58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu -Signed-off-by: Gerd Hoffmann ---- - hw/display/sm501.c | 207 ++++++++++++++++++++++++++------------------- - 1 file changed, 119 insertions(+), 88 deletions(-) - -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index 98b3b97f7b..7dc4bb18b7 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -706,13 +706,12 @@ static void sm501_2d_operation(SM501State *s) - /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ - int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; - int rop = s->twoD_control & 0xFF; -- int dst_x = (s->twoD_destination >> 16) & 0x01FFF; -- int dst_y = s->twoD_destination & 0xFFFF; -- int width = (s->twoD_dimension >> 16) & 0x1FFF; -- int height = s->twoD_dimension & 0xFFFF; -+ unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF; -+ unsigned int dst_y = s->twoD_destination & 0xFFFF; -+ unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF; -+ unsigned int height = s->twoD_dimension & 0xFFFF; - uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; -- uint8_t *dst = s->local_mem + dst_base; -- int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; -+ unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; - int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; - int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); - -@@ -721,104 +720,136 @@ static void sm501_2d_operation(SM501State *s) - return; - } - -- if (rop_mode == 0) { -- if (rop != 0xcc) { -- /* Anything other than plain copies are not supported */ -- qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not " -- "supported.\n", rop); -- } -- } else { -- if (rop2_source_is_pattern && rop != 0x5) { -- /* For pattern source, we support only inverse dest */ -- qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and " -- "rop %x is not supported.\n", rop); -- } else { -- if (rop != 0x5 && rop != 0xc) { -- /* Anything other than plain copies or inverse dest is not -- * supported */ -- qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not " -- "supported.\n", rop); -- } -- } -- } -- - if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { - qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); - return; - } - -+ if (!dst_pitch) { -+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n"); -+ return; -+ } -+ -+ if (!width || !height) { -+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n"); -+ return; -+ } -+ -+ if (rtl) { -+ dst_x -= width - 1; -+ dst_y -= height - 1; -+ } -+ -+ if (dst_base >= get_local_mem_size(s) || dst_base + -+ (dst_x + width + (dst_y + height) * (dst_pitch + width)) * -+ (1 << format) >= get_local_mem_size(s)) { -+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); -+ return; -+ } -+ - switch (cmd) { -- case 0x00: /* copy area */ -+ case 0: /* BitBlt */ - { -- int src_x = (s->twoD_source >> 16) & 0x01FFF; -- int src_y = s->twoD_source & 0xFFFF; -+ unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF; -+ unsigned int src_y = s->twoD_source & 0xFFFF; - uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; -- uint8_t *src = s->local_mem + src_base; -- int src_pitch = s->twoD_pitch & 0x1FFF; -- --#define COPY_AREA(_bpp, _pixel_type, rtl) { \ -- int y, x, index_d, index_s; \ -- for (y = 0; y < height; y++) { \ -- for (x = 0; x < width; x++) { \ -- _pixel_type val; \ -- \ -- if (rtl) { \ -- index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ -- index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ -- } else { \ -- index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ -- index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ -- } \ -- if (rop_mode == 1 && rop == 5) { \ -- /* Invert dest */ \ -- val = ~*(_pixel_type *)&dst[index_d]; \ -- } else { \ -- val = *(_pixel_type *)&src[index_s]; \ -- } \ -- *(_pixel_type *)&dst[index_d] = val; \ -- } \ -- } \ -- } -- switch (format) { -- case 0: -- COPY_AREA(1, uint8_t, rtl); -- break; -- case 1: -- COPY_AREA(2, uint16_t, rtl); -- break; -- case 2: -- COPY_AREA(4, uint32_t, rtl); -- break; -+ unsigned int src_pitch = s->twoD_pitch & 0x1FFF; -+ -+ if (!src_pitch) { -+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n"); -+ return; -+ } -+ -+ if (rtl) { -+ src_x -= width - 1; -+ src_y -= height - 1; -+ } -+ -+ if (src_base >= get_local_mem_size(s) || src_base + -+ (src_x + width + (src_y + height) * (src_pitch + width)) * -+ (1 << format) >= get_local_mem_size(s)) { -+ qemu_log_mask(LOG_GUEST_ERROR, -+ "sm501: 2D op src is outside vram.\n"); -+ return; -+ } -+ -+ if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) { -+ /* Invert dest, is there a way to do this with pixman? */ -+ unsigned int x, y, i; -+ uint8_t *d = s->local_mem + dst_base; -+ -+ for (y = 0; y < height; y++) { -+ i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format); -+ for (x = 0; x < width; x++, i += (1 << format)) { -+ switch (format) { -+ case 0: -+ d[i] = ~d[i]; -+ break; -+ case 1: -+ *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i]; -+ break; -+ case 2: -+ *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i]; -+ break; -+ } -+ } -+ } -+ } else { -+ /* Do copy src for unimplemented ops, better than unpainted area */ -+ if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) || -+ (!rop_mode && rop != 0xcc)) { -+ qemu_log_mask(LOG_UNIMP, -+ "sm501: rop%d op %x%s not implemented\n", -+ (rop_mode ? 2 : 3), rop, -+ (rop2_source_is_pattern ? -+ " with pattern source" : "")); -+ } -+ /* Check for overlaps, this could be made more exact */ -+ uint32_t sb, se, db, de; -+ sb = src_base + src_x + src_y * (width + src_pitch); -+ se = sb + width + height * (width + src_pitch); -+ db = dst_base + dst_x + dst_y * (width + dst_pitch); -+ de = db + width + height * (width + dst_pitch); -+ if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { -+ /* regions may overlap: copy via temporary */ -+ int llb = width * (1 << format); -+ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); -+ uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * -+ height); -+ pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, -+ src_pitch * (1 << format) / sizeof(uint32_t), -+ tmp_stride, 8 * (1 << format), 8 * (1 << format), -+ src_x, src_y, 0, 0, width, height); -+ pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], -+ tmp_stride, -+ dst_pitch * (1 << format) / sizeof(uint32_t), -+ 8 * (1 << format), 8 * (1 << format), -+ 0, 0, dst_x, dst_y, width, height); -+ g_free(tmp); -+ } else { -+ pixman_blt((uint32_t *)&s->local_mem[src_base], -+ (uint32_t *)&s->local_mem[dst_base], -+ src_pitch * (1 << format) / sizeof(uint32_t), -+ dst_pitch * (1 << format) / sizeof(uint32_t), -+ 8 * (1 << format), 8 * (1 << format), -+ src_x, src_y, dst_x, dst_y, width, height); -+ } - } - break; - } -- case 0x01: /* fill rectangle */ -+ case 1: /* Rectangle Fill */ - { - uint32_t color = s->twoD_foreground; - --#define FILL_RECT(_bpp, _pixel_type) { \ -- int y, x; \ -- for (y = 0; y < height; y++) { \ -- for (x = 0; x < width; x++) { \ -- int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ -- *(_pixel_type *)&dst[index] = (_pixel_type)color; \ -- } \ -- } \ -- } -- -- switch (format) { -- case 0: -- FILL_RECT(1, uint8_t); -- break; -- case 1: -- color = cpu_to_le16(color); -- FILL_RECT(2, uint16_t); -- break; -- case 2: -+ if (format == 2) { - color = cpu_to_le32(color); -- FILL_RECT(4, uint32_t); -- break; -+ } else if (format == 1) { -+ color = cpu_to_le16(color); - } -+ -+ pixman_fill((uint32_t *)&s->local_mem[dst_base], -+ dst_pitch * (1 << format) / sizeof(uint32_t), -+ 8 * (1 << format), dst_x, dst_y, width, height, color); - break; - } - default: --- -2.23.0 - diff --git a/sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch b/sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch deleted file mode 100644 index a2eefcba1e31e338ad6d934bf9e112a98d013b04..0000000000000000000000000000000000000000 --- a/sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch +++ /dev/null @@ -1,134 +0,0 @@ -From bc472e56b985db1de73a7ddab5ea8568d6e7f327 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Thu, 21 May 2020 21:39:44 +0200 -Subject: [PATCH] sm501: Shorten long variable names in sm501_2d_operation - -This increases readability and cleans up some confusing naming. - -Signed-off-by: BALATON Zoltan -Message-id: b9b67b94c46e945252a73c77dfd117132c63c4fb.1590089984.git.balaton@eik.bme.hu -Signed-off-by: Gerd Hoffmann ---- - hw/display/sm501.c | 45 ++++++++++++++++++++++----------------------- - 1 file changed, 22 insertions(+), 23 deletions(-) - -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index aa4b202a48..51e7ccc39d 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -700,17 +700,16 @@ static inline void hwc_invalidate(SM501State *s, int crt) - static void sm501_2d_operation(SM501State *s) - { - /* obtain operation parameters */ -- int operation = (s->twoD_control >> 16) & 0x1f; -+ int cmd = (s->twoD_control >> 16) & 0x1F; - int rtl = s->twoD_control & 0x8000000; - int src_x = (s->twoD_source >> 16) & 0x01FFF; - int src_y = s->twoD_source & 0xFFFF; - int dst_x = (s->twoD_destination >> 16) & 0x01FFF; - int dst_y = s->twoD_destination & 0xFFFF; -- int operation_width = (s->twoD_dimension >> 16) & 0x1FFF; -- int operation_height = s->twoD_dimension & 0xFFFF; -+ int width = (s->twoD_dimension >> 16) & 0x1FFF; -+ int height = s->twoD_dimension & 0xFFFF; - uint32_t color = s->twoD_foreground; -- int format_flags = (s->twoD_stretch >> 20) & 0x3; -- int addressing = (s->twoD_stretch >> 16) & 0xF; -+ int format = (s->twoD_stretch >> 20) & 0x3; - int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ - /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ - int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; -@@ -721,12 +720,12 @@ static void sm501_2d_operation(SM501State *s) - /* get frame buffer info */ - uint8_t *src = s->local_mem + src_base; - uint8_t *dst = s->local_mem + dst_base; -- int src_width = s->twoD_pitch & 0x1FFF; -- int dst_width = (s->twoD_pitch >> 16) & 0x1FFF; -+ int src_pitch = s->twoD_pitch & 0x1FFF; -+ int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; - int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; - int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); - -- if (addressing != 0x0) { -+ if ((s->twoD_stretch >> 16) & 0xF) { - qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); - return; - } -@@ -758,20 +757,20 @@ static void sm501_2d_operation(SM501State *s) - return; - } - -- switch (operation) { -+ switch (cmd) { - case 0x00: /* copy area */ - #define COPY_AREA(_bpp, _pixel_type, rtl) { \ - int y, x, index_d, index_s; \ -- for (y = 0; y < operation_height; y++) { \ -- for (x = 0; x < operation_width; x++) { \ -+ for (y = 0; y < height; y++) { \ -+ for (x = 0; x < width; x++) { \ - _pixel_type val; \ - \ - if (rtl) { \ -- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \ -- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \ -+ index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ -+ index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ - } else { \ -- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \ -- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ -+ index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ -+ index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ - } \ - if (rop_mode == 1 && rop == 5) { \ - /* Invert dest */ \ -@@ -783,7 +782,7 @@ static void sm501_2d_operation(SM501State *s) - } \ - } \ - } -- switch (format_flags) { -+ switch (format) { - case 0: - COPY_AREA(1, uint8_t, rtl); - break; -@@ -799,15 +798,15 @@ static void sm501_2d_operation(SM501State *s) - case 0x01: /* fill rectangle */ - #define FILL_RECT(_bpp, _pixel_type) { \ - int y, x; \ -- for (y = 0; y < operation_height; y++) { \ -- for (x = 0; x < operation_width; x++) { \ -- int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ -+ for (y = 0; y < height; y++) { \ -+ for (x = 0; x < width; x++) { \ -+ int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ - *(_pixel_type *)&dst[index] = (_pixel_type)color; \ - } \ - } \ - } - -- switch (format_flags) { -+ switch (format) { - case 0: - FILL_RECT(1, uint8_t); - break; -@@ -824,14 +823,14 @@ static void sm501_2d_operation(SM501State *s) - - default: - qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", -- operation); -+ cmd); - return; - } - - if (dst_base >= get_fb_addr(s, crt) && - dst_base <= get_fb_addr(s, crt) + fb_len) { -- int dst_len = MIN(fb_len, ((dst_y + operation_height - 1) * dst_width + -- dst_x + operation_width) * (1 << format_flags)); -+ int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch + -+ dst_x + width) * (1 << format)); - if (dst_len) { - memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len); - } --- -2.23.0 - diff --git a/sm501-Use-BIT-x-macro-to-shorten-constant.patch b/sm501-Use-BIT-x-macro-to-shorten-constant.patch deleted file mode 100644 index 697d0ee61d5cba82611b05f037a25397de5073b6..0000000000000000000000000000000000000000 --- a/sm501-Use-BIT-x-macro-to-shorten-constant.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 9f1e9012047639121eb275a4f8f5693d340e91f6 Mon Sep 17 00:00:00 2001 -From: BALATON Zoltan -Date: Thu, 21 May 2020 21:39:44 +0200 -Subject: [PATCH] sm501: Use BIT(x) macro to shorten constant -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: BALATON Zoltan -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 124bf5de8d7cf503b32b377d0445029a76bfbd49.1590089984.git.balaton@eik.bme.hu -Signed-off-by: Gerd Hoffmann ---- - hw/display/sm501.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index 51e7ccc39d..f3d11d0b23 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -701,7 +701,7 @@ static void sm501_2d_operation(SM501State *s) - { - /* obtain operation parameters */ - int cmd = (s->twoD_control >> 16) & 0x1F; -- int rtl = s->twoD_control & 0x8000000; -+ int rtl = s->twoD_control & BIT(27); - int src_x = (s->twoD_source >> 16) & 0x01FFF; - int src_y = s->twoD_source & 0xFFFF; - int dst_x = (s->twoD_destination >> 16) & 0x01FFF; -@@ -751,8 +751,7 @@ static void sm501_2d_operation(SM501State *s) - } - } - -- if ((s->twoD_source_base & 0x08000000) || -- (s->twoD_destination_base & 0x08000000)) { -+ if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { - qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); - return; - } --- -2.23.0 - diff --git a/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch b/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch index cfd1842d3f199ec1db6e324e448df37b4553ea2a..f1f9e91b6c6fa36fe8e362c1001c6ef3c68af72c 100644 --- a/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch +++ b/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch @@ -1,4 +1,4 @@ -From 2b8ad77678da175cb92c902955cb85827e661de3 Mon Sep 17 00:00:00 2001 +From 937e22eda2480a64095928ee8df0d37b3313bb64 Mon Sep 17 00:00:00 2001 From: Ying Fang Date: Tue, 14 Apr 2020 14:53:44 +0800 Subject: [PATCH] smbios: Add missing member of type 4 for smbios 3.0 @@ -16,16 +16,17 @@ The corresponding codes in kernel is like: } Signed-off-by: zhanghailiang +Signed-off-by: Yan Wang --- hw/smbios/smbios.c | 4 +++- include/hw/firmware/smbios.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c -index 7bcd67b0..51b00d44 100644 +index 7397e56737..66be9aee09 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c -@@ -603,7 +603,9 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) +@@ -688,7 +688,9 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) t->thread_count = ms->smp.threads; t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ t->processor_family2 = cpu_to_le16(0x01); /* Other */ @@ -37,7 +38,7 @@ index 7bcd67b0..51b00d44 100644 smbios_type4_count++; } diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h -index 02a0ced0..6887bca4 100644 +index 5a0dd0c8cf..5a696cf75a 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -193,6 +193,9 @@ struct smbios_type_4 { @@ -48,7 +49,8 @@ index 02a0ced0..6887bca4 100644 + uint16_t enabledcorecount2; + uint16_t threadcount2; } QEMU_PACKED; - + /* SMBIOS type 11 - OEM strings */ --- -2.23.0 +-- +2.27.0 + diff --git a/softmmu-Always-initialize-xlat-in-address_space_tran.patch b/softmmu-Always-initialize-xlat-in-address_space_tran.patch new file mode 100644 index 0000000000000000000000000000000000000000..f23ad768e77109f831f6637d5b30cc6c2c059395 --- /dev/null +++ b/softmmu-Always-initialize-xlat-in-address_space_tran.patch @@ -0,0 +1,68 @@ +From e6b719bf79d00dddde0b0371075a41890a8f95a4 Mon Sep 17 00:00:00 2001 +From: cenhuilin +Date: Tue, 19 Jul 2022 09:53:31 +0000 +Subject: [PATCH] softmmu Always initialize xlat in + address_space_translate_for_iotlb + +The bug is an uninitialized memory read, along the translate_fail +path, which results in garbage being read from iotlb_to_section, +which can lead to a crash in io_readx/io_writex. + +The bug may be fixed by writing any value with zero +in ~TARGET_PAGE_MASK, so that the call to iotlb_to_section using +the xlat'ed address returns io_mem_unassigned, as desired by the +translate_fail path. + +It is most useful to record the original physical page address, +which will eventually be logged by memory_region_access_valid +when the access is rejected by unassigned_mem_accepts. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1065 +Signed-off-by: Richard Henderson +Reviewed-by: Peter Maydell +Message-Id: <20220621153829.366423-1-richard.henderson@linaro.org> +--- + softmmu/physmem.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index ae26f7290..be39a49ce 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -668,7 +668,7 @@ void tcg_iommu_init_notifier_list(CPUState *cpu) + + /* Called from RCU critical section */ + MemoryRegionSection * +-address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, ++address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr, + hwaddr *xlat, hwaddr *plen, + MemTxAttrs attrs, int *prot) + { +@@ -677,6 +677,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, + IOMMUMemoryRegionClass *imrc; + IOMMUTLBEntry iotlb; + int iommu_idx; ++ hwaddr addr = orig_addr; + AddressSpaceDispatch *d = + qatomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); + +@@ -721,6 +722,16 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, + return section; + + translate_fail: ++ /* ++ * We should be given a page-aligned address -- certainly ++ * tlb_set_page_with_attrs() does so. The page offset of xlat ++ * is used to index sections[], and PHYS_SECTION_UNASSIGNED = 0. ++ * The page portion of xlat will be logged by memory_region_access_valid() ++ * when this memory access is rejected, so use the original untranslated ++ * physical address. ++ */ ++ assert((orig_addr & ~TARGET_PAGE_MASK) == 0); ++ *xlat = orig_addr; + return &d->map.sections[PHYS_SECTION_UNASSIGNED]; + } + +-- +2.33.0 + diff --git a/softmmu-device_tree-Remove-redundant-pointer-assignm.patch b/softmmu-device_tree-Remove-redundant-pointer-assignm.patch new file mode 100644 index 0000000000000000000000000000000000000000..c98a0588cbc31d5ff36d2e5216c8fd6d3f50d508 --- /dev/null +++ b/softmmu-device_tree-Remove-redundant-pointer-assignm.patch @@ -0,0 +1,58 @@ +From ebf1ac6c0ead3d6fbc32466028c286588333c1ea Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 11 Jan 2022 11:27:58 +0800 +Subject: [PATCH 22/24] softmmu/device_tree: Remove redundant pointer + assignment + +The pointer assignment "const char *p = path;" in function +qemu_fdt_add_path is unnecessary. Let's remove it and just +use the "path" passed in. No functional change. + +Suggested-by: Richard Henderson +Signed-off-by: Yanan Wang +Reviewed-by: Andrew Jones +Reviewed-by: Alistair Francis +Reviewed-by: Thomas Huth +Message-id: 20220111032758.27804-1-wangyanan55@huawei.com +Signed-off-by: Alistair Francis +--- + softmmu/device_tree.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c +index 9e96f5ecd5..8897c79ea4 100644 +--- a/softmmu/device_tree.c ++++ b/softmmu/device_tree.c +@@ -556,7 +556,6 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) + int qemu_fdt_add_path(void *fdt, const char *path) + { + const char *name; +- const char *p = path; + int namelen, retval; + int parent = 0; + +@@ -565,9 +564,9 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + do { +- name = p + 1; +- p = strchr(name, '/'); +- namelen = p != NULL ? p - name : strlen(name); ++ name = path + 1; ++ path = strchr(name, '/'); ++ namelen = path != NULL ? path - name : strlen(name); + + retval = fdt_subnode_offset_namelen(fdt, parent, name, namelen); + if (retval < 0 && retval != -FDT_ERR_NOTFOUND) { +@@ -584,7 +583,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + parent = retval; +- } while (p); ++ } while (path); + + return retval; + } +-- +2.27.0 + diff --git a/softmmu-device_tree-Silence-compiler-warning-with-en.patch b/softmmu-device_tree-Silence-compiler-warning-with-en.patch new file mode 100644 index 0000000000000000000000000000000000000000..68030155312cb20beca50b0e133e4c4b2ab536f4 --- /dev/null +++ b/softmmu-device_tree-Silence-compiler-warning-with-en.patch @@ -0,0 +1,60 @@ +From ecc0eb93e8856321ad940a85970f0db14ab9f146 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Fri, 7 Jan 2022 14:38:44 +0100 +Subject: [PATCH 21/24] softmmu/device_tree: Silence compiler warning with + --enable-sanitizers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If I configure my build with --enable-sanitizers, my GCC (v8.5.0) +complains: + +.../softmmu/device_tree.c: In function ‘qemu_fdt_add_path’: +.../softmmu/device_tree.c:560:18: error: ‘retval’ may be used uninitialized + in this function [-Werror=maybe-uninitialized] + int namelen, retval; + ^~~~~~ + +It's a false warning since the while loop is always executed at least +once (p has to be non-NULL, otherwise the derefence in the if-statement +earlier will crash). Thus let's switch to a do-while loop here instead +to make the compiler happy in all cases. + +Signed-off-by: Thomas Huth +Reviewed-by: Andrew Jones +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Reviewed-by: Alistair Francis +Reviewed-by: Yanan Wang +Message-id: 20220107133844.145039-1-thuth@redhat.com +Signed-off-by: Alistair Francis +--- + softmmu/device_tree.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c +index 3965c834ca..9e96f5ecd5 100644 +--- a/softmmu/device_tree.c ++++ b/softmmu/device_tree.c +@@ -564,7 +564,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + return -1; + } + +- while (p) { ++ do { + name = p + 1; + p = strchr(name, '/'); + namelen = p != NULL ? p - name : strlen(name); +@@ -584,7 +584,7 @@ int qemu_fdt_add_path(void *fdt, const char *path) + } + + parent = retval; +- } ++ } while (p); + + return retval; + } +-- +2.27.0 + diff --git a/softmmu-dirtylimit-Add-parameter-check-for-hmp-set_v.patch b/softmmu-dirtylimit-Add-parameter-check-for-hmp-set_v.patch new file mode 100644 index 0000000000000000000000000000000000000000..4fd759bc1aa684caf0add0e45c4ba4ac31885bd2 --- /dev/null +++ b/softmmu-dirtylimit-Add-parameter-check-for-hmp-set_v.patch @@ -0,0 +1,55 @@ +From 381500cc0b96e85165ae0314839c34976a4da1b2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Fri, 18 Nov 2022 10:08:54 +0800 +Subject: [PATCH] softmmu/dirtylimit: Add parameter check for hmp + "set_vcpu_dirty_limit" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dirty_rate paraemter of hmp command "set_vcpu_dirty_limit" is invalid +if less than 0, so add parameter check for it. + +Note that this patch also delete the unsolicited help message and +clean up the code. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Markus Armbruster +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Message-Id: <168618975839.6361.17407633874747688653-1@git.sr.ht> +Signed-off-by: Juan Quintela +--- + softmmu/dirtylimit.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c +index 8d98cb7f2c..5041c230d0 100644 +--- a/softmmu/dirtylimit.c ++++ b/softmmu/dirtylimit.c +@@ -515,14 +515,15 @@ void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) + int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); + Error *err = NULL; + +- qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); +- if (err) { +- hmp_handle_error(mon, err); +- return; ++ if (dirty_rate < 0) { ++ error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); ++ goto out; + } + +- monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " +- "dirty limit for virtual CPU]\n"); ++ qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); ++ ++out: ++ hmp_handle_error(mon, err); + } + + static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) +-- +2.41.0.windows.1 + diff --git a/softmmu-dirtylimit-Implement-dirty-page-rate-limit.patch b/softmmu-dirtylimit-Implement-dirty-page-rate-limit.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c56ed3cc3540f9d738fe3754d34cc5c1f44d6e4 --- /dev/null +++ b/softmmu-dirtylimit-Implement-dirty-page-rate-limit.patch @@ -0,0 +1,435 @@ +From 39d9c1f6de01abf003980f4c2fe3c08f9e6cd60c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:36 +0800 +Subject: [PATCH] softmmu/dirtylimit: Implement dirty page rate limit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implement dirtyrate calculation periodically basing on +dirty-ring and throttle virtual CPU until it reachs the quota +dirty page rate given by user. + +Introduce qmp commands "set-vcpu-dirty-limit", +"cancel-vcpu-dirty-limit", "query-vcpu-dirty-limit" +to enable, disable, query dirty page limit for virtual CPU. + +Meanwhile, introduce corresponding hmp commands +"set_vcpu_dirty_limit", "cancel_vcpu_dirty_limit", +"info vcpu_dirty_limit" so the feature can be more usable. + +"query-vcpu-dirty-limit" success depends on enabling dirty +page rate limit, so just add it to the list of skipped +command to ensure qmp-cmd-test run successfully. + +Signed-off-by: Hyman Huang(黄勇) +Acked-by: Markus Armbruster +Reviewed-by: Peter Xu +Message-Id: <4143f26706d413dd29db0b672fe58b3d3fbe34bc.1656177590.git.huangy81@chinatelecom.cn> +Signed-off-by: Dr. David Alan Gilbert +--- + hmp-commands-info.hx | 13 +++ + hmp-commands.hx | 32 ++++++ + include/monitor/hmp.h | 3 + + qapi/migration.json | 80 +++++++++++++++ + softmmu/dirtylimit.c | 194 +++++++++++++++++++++++++++++++++++++ + tests/qtest/qmp-cmd-test.c | 2 + + 6 files changed, 324 insertions(+) + +diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx +index 407a1da800..5dd3001af0 100644 +--- a/hmp-commands-info.hx ++++ b/hmp-commands-info.hx +@@ -863,6 +863,19 @@ SRST + Display the vcpu dirty rate information. + ERST + ++ { ++ .name = "vcpu_dirty_limit", ++ .args_type = "", ++ .params = "", ++ .help = "show dirty page limit information of all vCPU", ++ .cmd = hmp_info_vcpu_dirty_limit, ++ }, ++ ++SRST ++ ``info vcpu_dirty_limit`` ++ Display the vcpu dirty page limit information. ++ERST ++ + #if defined(TARGET_I386) + { + .name = "sgx", +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 70a9136ac2..5bedee2d49 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -1744,3 +1744,35 @@ ERST + "\n\t\t\t -b to specify dirty bitmap as method of calculation)", + .cmd = hmp_calc_dirty_rate, + }, ++ ++SRST ++``set_vcpu_dirty_limit`` ++ Set dirty page rate limit on virtual CPU, the information about all the ++ virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit`` ++ command. ++ERST ++ ++ { ++ .name = "set_vcpu_dirty_limit", ++ .args_type = "dirty_rate:l,cpu_index:l?", ++ .params = "dirty_rate [cpu_index]", ++ .help = "set dirty page rate limit, use cpu_index to set limit" ++ "\n\t\t\t\t\t on a specified virtual cpu", ++ .cmd = hmp_set_vcpu_dirty_limit, ++ }, ++ ++SRST ++``cancel_vcpu_dirty_limit`` ++ Cancel dirty page rate limit on virtual CPU, the information about all the ++ virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit`` ++ command. ++ERST ++ ++ { ++ .name = "cancel_vcpu_dirty_limit", ++ .args_type = "cpu_index:l?", ++ .params = "[cpu_index]", ++ .help = "cancel dirty page rate limit, use cpu_index to cancel" ++ "\n\t\t\t\t\t limit on a specified virtual cpu", ++ .cmd = hmp_cancel_vcpu_dirty_limit, ++ }, +diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h +index 96d014826a..478820e54f 100644 +--- a/include/monitor/hmp.h ++++ b/include/monitor/hmp.h +@@ -131,6 +131,9 @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict); + void hmp_replay_seek(Monitor *mon, const QDict *qdict); + void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict); + void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict); ++void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); ++void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); ++void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); + void hmp_human_readable_text_helper(Monitor *mon, + HumanReadableText *(*qmp_handler)(Error **)); + +diff --git a/qapi/migration.json b/qapi/migration.json +index d4ebc5f028..fee266017d 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -1874,6 +1874,86 @@ + ## + { 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' } + ++## ++# @DirtyLimitInfo: ++# ++# Dirty page rate limit information of a virtual CPU. ++# ++# @cpu-index: index of a virtual CPU. ++# ++# @limit-rate: upper limit of dirty page rate (MB/s) for a virtual ++# CPU, 0 means unlimited. ++# ++# @current-rate: current dirty page rate (MB/s) for a virtual CPU. ++# ++# Since: 6.2 ++# ++## ++{ 'struct': 'DirtyLimitInfo', ++ 'data': { 'cpu-index': 'int', ++ 'limit-rate': 'uint64', ++ 'current-rate': 'uint64' } } ++ ++## ++# @set-vcpu-dirty-limit: ++# ++# Set the upper limit of dirty page rate for virtual CPUs. ++# ++# Requires KVM with accelerator property "dirty-ring-size" set. ++# A virtual CPU's dirty page rate is a measure of its memory load. ++# To observe dirty page rates, use @calc-dirty-rate. ++# ++# @cpu-index: index of a virtual CPU, default is all. ++# ++# @dirty-rate: upper limit of dirty page rate (MB/s) for virtual CPUs. ++# ++# Since: 6.2 ++# ++# Example: ++# {"execute": "set-vcpu-dirty-limit"} ++# "arguments": { "dirty-rate": 200, ++# "cpu-index": 1 } } ++# ++## ++{ 'command': 'set-vcpu-dirty-limit', ++ 'data': { '*cpu-index': 'int', ++ 'dirty-rate': 'uint64' } } ++ ++## ++# @cancel-vcpu-dirty-limit: ++# ++# Cancel the upper limit of dirty page rate for virtual CPUs. ++# ++# Cancel the dirty page limit for the vCPU which has been set with ++# set-vcpu-dirty-limit command. Note that this command requires ++# support from dirty ring, same as the "set-vcpu-dirty-limit". ++# ++# @cpu-index: index of a virtual CPU, default is all. ++# ++# Since: 6.2 ++# ++# Example: ++# {"execute": "cancel-vcpu-dirty-limit"} ++# "arguments": { "cpu-index": 1 } } ++# ++## ++{ 'command': 'cancel-vcpu-dirty-limit', ++ 'data': { '*cpu-index': 'int'} } ++ ++## ++# @query-vcpu-dirty-limit: ++# ++# Returns information about virtual CPU dirty page rate limits, if any. ++# ++# Since: 6.2 ++# ++# Example: ++# {"execute": "query-vcpu-dirty-limit"} ++# ++## ++{ 'command': 'query-vcpu-dirty-limit', ++ 'returns': [ 'DirtyLimitInfo' ] } ++ + ## + # @snapshot-save: + # +diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c +index e5a4f970bd..8d98cb7f2c 100644 +--- a/softmmu/dirtylimit.c ++++ b/softmmu/dirtylimit.c +@@ -14,8 +14,12 @@ + #include "qapi/error.h" + #include "qemu/main-loop.h" + #include "qapi/qapi-commands-migration.h" ++#include "qapi/qmp/qdict.h" ++#include "qapi/error.h" + #include "sysemu/dirtyrate.h" + #include "sysemu/dirtylimit.h" ++#include "monitor/hmp.h" ++#include "monitor/monitor.h" + #include "exec/memory.h" + #include "hw/boards.h" + #include "sysemu/kvm.h" +@@ -405,3 +409,193 @@ void dirtylimit_vcpu_execute(CPUState *cpu) + usleep(cpu->throttle_us_per_full); + } + } ++ ++static void dirtylimit_init(void) ++{ ++ dirtylimit_state_initialize(); ++ dirtylimit_change(true); ++ vcpu_dirty_rate_stat_initialize(); ++ vcpu_dirty_rate_stat_start(); ++} ++ ++static void dirtylimit_cleanup(void) ++{ ++ vcpu_dirty_rate_stat_stop(); ++ vcpu_dirty_rate_stat_finalize(); ++ dirtylimit_change(false); ++ dirtylimit_state_finalize(); ++} ++ ++void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, ++ int64_t cpu_index, ++ Error **errp) ++{ ++ if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { ++ return; ++ } ++ ++ if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { ++ error_setg(errp, "incorrect cpu index specified"); ++ return; ++ } ++ ++ if (!dirtylimit_in_service()) { ++ return; ++ } ++ ++ dirtylimit_state_lock(); ++ ++ if (has_cpu_index) { ++ dirtylimit_set_vcpu(cpu_index, 0, false); ++ } else { ++ dirtylimit_set_all(0, false); ++ } ++ ++ if (!dirtylimit_state->limited_nvcpu) { ++ dirtylimit_cleanup(); ++ } ++ ++ dirtylimit_state_unlock(); ++} ++ ++void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) ++{ ++ int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); ++ Error *err = NULL; ++ ++ qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); ++ if (err) { ++ hmp_handle_error(mon, err); ++ return; ++ } ++ ++ monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " ++ "dirty limit for virtual CPU]\n"); ++} ++ ++void qmp_set_vcpu_dirty_limit(bool has_cpu_index, ++ int64_t cpu_index, ++ uint64_t dirty_rate, ++ Error **errp) ++{ ++ if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { ++ error_setg(errp, "dirty page limit feature requires KVM with" ++ " accelerator property 'dirty-ring-size' set'"); ++ return; ++ } ++ ++ if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { ++ error_setg(errp, "incorrect cpu index specified"); ++ return; ++ } ++ ++ if (!dirty_rate) { ++ qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp); ++ return; ++ } ++ ++ dirtylimit_state_lock(); ++ ++ if (!dirtylimit_in_service()) { ++ dirtylimit_init(); ++ } ++ ++ if (has_cpu_index) { ++ dirtylimit_set_vcpu(cpu_index, dirty_rate, true); ++ } else { ++ dirtylimit_set_all(dirty_rate, true); ++ } ++ ++ dirtylimit_state_unlock(); ++} ++ ++void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) ++{ ++ int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); ++ int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); ++ Error *err = NULL; ++ ++ qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); ++ if (err) { ++ hmp_handle_error(mon, err); ++ return; ++ } ++ ++ monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " ++ "dirty limit for virtual CPU]\n"); ++} ++ ++static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) ++{ ++ DirtyLimitInfo *info = NULL; ++ ++ info = g_malloc0(sizeof(*info)); ++ info->cpu_index = cpu_index; ++ info->limit_rate = dirtylimit_vcpu_get_state(cpu_index)->quota; ++ info->current_rate = vcpu_dirty_rate_get(cpu_index); ++ ++ return info; ++} ++ ++static struct DirtyLimitInfoList *dirtylimit_query_all(void) ++{ ++ int i, index; ++ DirtyLimitInfo *info = NULL; ++ DirtyLimitInfoList *head = NULL, **tail = &head; ++ ++ dirtylimit_state_lock(); ++ ++ if (!dirtylimit_in_service()) { ++ dirtylimit_state_unlock(); ++ return NULL; ++ } ++ ++ for (i = 0; i < dirtylimit_state->max_cpus; i++) { ++ index = dirtylimit_state->states[i].cpu_index; ++ if (dirtylimit_vcpu_get_state(index)->enabled) { ++ info = dirtylimit_query_vcpu(index); ++ QAPI_LIST_APPEND(tail, info); ++ } ++ } ++ ++ dirtylimit_state_unlock(); ++ ++ return head; ++} ++ ++struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) ++{ ++ if (!dirtylimit_in_service()) { ++ return NULL; ++ } ++ ++ return dirtylimit_query_all(); ++} ++ ++void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) ++{ ++ DirtyLimitInfoList *limit, *head, *info = NULL; ++ Error *err = NULL; ++ ++ if (!dirtylimit_in_service()) { ++ monitor_printf(mon, "Dirty page limit not enabled!\n"); ++ return; ++ } ++ ++ info = qmp_query_vcpu_dirty_limit(&err); ++ if (err) { ++ hmp_handle_error(mon, err); ++ return; ++ } ++ ++ head = info; ++ for (limit = head; limit != NULL; limit = limit->next) { ++ monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," ++ " current rate %"PRIi64 " (MB/s)\n", ++ limit->value->cpu_index, ++ limit->value->limit_rate, ++ limit->value->current_rate); ++ } ++ ++ g_free(info); ++} +diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c +index 7f103ea3fd..4b216a0435 100644 +--- a/tests/qtest/qmp-cmd-test.c ++++ b/tests/qtest/qmp-cmd-test.c +@@ -110,6 +110,8 @@ static bool query_is_ignored(const char *cmd) + "query-sev-capabilities", + "query-sgx", + "query-sgx-capabilities", ++ /* Success depends on enabling dirty page rate limit */ ++ "query-vcpu-dirty-limit", + NULL + }; + int i; +-- +2.27.0 + diff --git a/softmmu-dirtylimit-Implement-vCPU-dirtyrate-calculat.patch b/softmmu-dirtylimit-Implement-vCPU-dirtyrate-calculat.patch new file mode 100644 index 0000000000000000000000000000000000000000..f408a51eaf1dcad88e045d160fc0d142b7fcf2ec --- /dev/null +++ b/softmmu-dirtylimit-Implement-vCPU-dirtyrate-calculat.patch @@ -0,0 +1,214 @@ +From 1c1049bda8e91cc6015c32fc7cc9d0f16ad46b58 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:33 +0800 +Subject: [PATCH 1/3] softmmu/dirtylimit: Implement vCPU dirtyrate calculation + periodically +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce the third method GLOBAL_DIRTY_LIMIT of dirty +tracking for calculate dirtyrate periodly for dirty page +rate limit. + +Add dirtylimit.c to implement dirtyrate calculation periodly, +which will be used for dirty page rate limit. + +Add dirtylimit.h to export util functions for dirty page rate +limit implementation. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Peter Xu +Message-Id: <5d0d641bffcb9b1c4cc3e323b6dfecb36050d948.1656177590.git.huangy81@chinatelecom.cn> +Signed-off-by: Dr. David Alan Gilbert +--- + include/exec/memory.h | 5 +- + include/sysemu/dirtylimit.h | 22 +++++++ + softmmu/dirtylimit.c | 116 ++++++++++++++++++++++++++++++++++++ + softmmu/meson.build | 1 + + 4 files changed, 143 insertions(+), 1 deletion(-) + create mode 100644 include/sysemu/dirtylimit.h + create mode 100644 softmmu/dirtylimit.c + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 3e84d62e40..4326d74b95 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -69,7 +69,10 @@ static inline void fuzz_dma_read_cb(size_t addr, + /* Dirty tracking enabled because measuring dirty rate */ + #define GLOBAL_DIRTY_DIRTY_RATE (1U << 1) + +-#define GLOBAL_DIRTY_MASK (0x3) ++/* Dirty tracking enabled because dirty limit */ ++#define GLOBAL_DIRTY_LIMIT (1U << 2) ++ ++#define GLOBAL_DIRTY_MASK (0x7) + + extern unsigned int global_dirty_tracking; + +diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h +new file mode 100644 +index 0000000000..da459f03d6 +--- /dev/null ++++ b/include/sysemu/dirtylimit.h +@@ -0,0 +1,22 @@ ++/* ++ * Dirty page rate limit common functions ++ * ++ * Copyright (c) 2022 CHINA TELECOM CO.,LTD. ++ * ++ * Authors: ++ * Hyman Huang(黄勇) ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++#ifndef QEMU_DIRTYRLIMIT_H ++#define QEMU_DIRTYRLIMIT_H ++ ++#define DIRTYLIMIT_CALC_TIME_MS 1000 /* 1000ms */ ++ ++int64_t vcpu_dirty_rate_get(int cpu_index); ++void vcpu_dirty_rate_stat_start(void); ++void vcpu_dirty_rate_stat_stop(void); ++void vcpu_dirty_rate_stat_initialize(void); ++void vcpu_dirty_rate_stat_finalize(void); ++#endif +diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c +new file mode 100644 +index 0000000000..ebdc064c9d +--- /dev/null ++++ b/softmmu/dirtylimit.c +@@ -0,0 +1,116 @@ ++/* ++ * Dirty page rate limit implementation code ++ * ++ * Copyright (c) 2022 CHINA TELECOM CO.,LTD. ++ * ++ * Authors: ++ * Hyman Huang(黄勇) ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qemu/main-loop.h" ++#include "qapi/qapi-commands-migration.h" ++#include "sysemu/dirtyrate.h" ++#include "sysemu/dirtylimit.h" ++#include "exec/memory.h" ++#include "hw/boards.h" ++ ++struct { ++ VcpuStat stat; ++ bool running; ++ QemuThread thread; ++} *vcpu_dirty_rate_stat; ++ ++static void vcpu_dirty_rate_stat_collect(void) ++{ ++ VcpuStat stat; ++ int i = 0; ++ ++ /* calculate vcpu dirtyrate */ ++ vcpu_calculate_dirtyrate(DIRTYLIMIT_CALC_TIME_MS, ++ &stat, ++ GLOBAL_DIRTY_LIMIT, ++ false); ++ ++ for (i = 0; i < stat.nvcpu; i++) { ++ vcpu_dirty_rate_stat->stat.rates[i].id = i; ++ vcpu_dirty_rate_stat->stat.rates[i].dirty_rate = ++ stat.rates[i].dirty_rate; ++ } ++ ++ free(stat.rates); ++} ++ ++static void *vcpu_dirty_rate_stat_thread(void *opaque) ++{ ++ rcu_register_thread(); ++ ++ /* start log sync */ ++ global_dirty_log_change(GLOBAL_DIRTY_LIMIT, true); ++ ++ while (qatomic_read(&vcpu_dirty_rate_stat->running)) { ++ vcpu_dirty_rate_stat_collect(); ++ } ++ ++ /* stop log sync */ ++ global_dirty_log_change(GLOBAL_DIRTY_LIMIT, false); ++ ++ rcu_unregister_thread(); ++ return NULL; ++} ++ ++int64_t vcpu_dirty_rate_get(int cpu_index) ++{ ++ DirtyRateVcpu *rates = vcpu_dirty_rate_stat->stat.rates; ++ return qatomic_read_i64(&rates[cpu_index].dirty_rate); ++} ++ ++void vcpu_dirty_rate_stat_start(void) ++{ ++ if (qatomic_read(&vcpu_dirty_rate_stat->running)) { ++ return; ++ } ++ ++ qatomic_set(&vcpu_dirty_rate_stat->running, 1); ++ qemu_thread_create(&vcpu_dirty_rate_stat->thread, ++ "dirtyrate-stat", ++ vcpu_dirty_rate_stat_thread, ++ NULL, ++ QEMU_THREAD_JOINABLE); ++} ++ ++void vcpu_dirty_rate_stat_stop(void) ++{ ++ qatomic_set(&vcpu_dirty_rate_stat->running, 0); ++ qemu_mutex_unlock_iothread(); ++ qemu_thread_join(&vcpu_dirty_rate_stat->thread); ++ qemu_mutex_lock_iothread(); ++} ++ ++void vcpu_dirty_rate_stat_initialize(void) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ int max_cpus = ms->smp.max_cpus; ++ ++ vcpu_dirty_rate_stat = ++ g_malloc0(sizeof(*vcpu_dirty_rate_stat)); ++ ++ vcpu_dirty_rate_stat->stat.nvcpu = max_cpus; ++ vcpu_dirty_rate_stat->stat.rates = ++ g_malloc0(sizeof(DirtyRateVcpu) * max_cpus); ++ ++ vcpu_dirty_rate_stat->running = false; ++} ++ ++void vcpu_dirty_rate_stat_finalize(void) ++{ ++ free(vcpu_dirty_rate_stat->stat.rates); ++ vcpu_dirty_rate_stat->stat.rates = NULL; ++ ++ free(vcpu_dirty_rate_stat); ++ vcpu_dirty_rate_stat = NULL; ++} +diff --git a/softmmu/meson.build b/softmmu/meson.build +index d8e03018ab..95029a5db2 100644 +--- a/softmmu/meson.build ++++ b/softmmu/meson.build +@@ -15,6 +15,7 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( + 'vl.c', + 'cpu-timers.c', + 'runstate-action.c', ++ 'dirtylimit.c', + )]) + + specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( +-- +2.27.0 + diff --git a/softmmu-dirtylimit-Implement-virtual-CPU-throttle.patch b/softmmu-dirtylimit-Implement-virtual-CPU-throttle.patch new file mode 100644 index 0000000000000000000000000000000000000000..b515a73e3d7430643550213812c20982a3433760 --- /dev/null +++ b/softmmu-dirtylimit-Implement-virtual-CPU-throttle.patch @@ -0,0 +1,469 @@ +From 7b6ab56e68fb5031ea13b82743415413b1e70e71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:35 +0800 +Subject: [PATCH 3/3] softmmu/dirtylimit: Implement virtual CPU throttle +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Setup a negative feedback system when vCPU thread +handling KVM_EXIT_DIRTY_RING_FULL exit by introducing +throttle_us_per_full field in struct CPUState. Sleep +throttle_us_per_full microseconds to throttle vCPU +if dirtylimit is in service. + +Signed-off-by: Hyman Huang(黄勇) +Reviewed-by: Peter Xu +Message-Id: <977e808e03a1cef5151cae75984658b6821be618.1656177590.git.huangy81@chinatelecom.cn> +Signed-off-by: Dr. David Alan Gilbert +--- + accel/kvm/kvm-all.c | 20 ++- + include/hw/core/cpu.h | 6 + + include/sysemu/dirtylimit.h | 15 ++ + softmmu/dirtylimit.c | 291 ++++++++++++++++++++++++++++++++++++ + softmmu/trace-events | 7 + + 5 files changed, 338 insertions(+), 1 deletion(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index d0c4310507..946ccb260b 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -45,6 +45,7 @@ + #include "qemu/guest-random.h" + #include "sysemu/hw_accel.h" + #include "kvm-cpus.h" ++#include "sysemu/dirtylimit.h" + + #include "hw/boards.h" + +@@ -493,6 +494,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) + cpu->kvm_state = s; + cpu->vcpu_dirty = true; + cpu->dirty_pages = 0; ++ cpu->throttle_us_per_full = 0; + + mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size < 0) { +@@ -1486,6 +1488,11 @@ static void *kvm_dirty_ring_reaper_thread(void *data) + */ + sleep(1); + ++ /* keep sleeping so that dirtylimit not be interfered by reaper */ ++ if (dirtylimit_in_service()) { ++ continue; ++ } ++ + trace_kvm_dirty_ring_reaper("wakeup"); + r->reaper_state = KVM_DIRTY_RING_REAPER_REAPING; + +@@ -2965,8 +2972,19 @@ int kvm_cpu_exec(CPUState *cpu) + */ + trace_kvm_dirty_ring_full(cpu->cpu_index); + qemu_mutex_lock_iothread(); +- kvm_dirty_ring_reap(kvm_state, NULL); ++ /* ++ * We throttle vCPU by making it sleep once it exit from kernel ++ * due to dirty ring full. In the dirtylimit scenario, reaping ++ * all vCPUs after a single vCPU dirty ring get full result in ++ * the miss of sleep, so just reap the ring-fulled vCPU. ++ */ ++ if (dirtylimit_in_service()) { ++ kvm_dirty_ring_reap(kvm_state, cpu); ++ } else { ++ kvm_dirty_ring_reap(kvm_state, NULL); ++ } + qemu_mutex_unlock_iothread(); ++ dirtylimit_vcpu_execute(cpu); + ret = 0; + break; + case KVM_EXIT_SYSTEM_EVENT: +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index e948e81f1a..9631c1e2f6 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -411,6 +411,12 @@ struct CPUState { + */ + bool throttle_thread_scheduled; + ++ /* ++ * Sleep throttle_us_per_full microseconds once dirty ring is full ++ * if dirty page rate limit is enabled. ++ */ ++ int64_t throttle_us_per_full; ++ + bool ignore_memory_transaction_failures; + + struct hax_vcpu_state *hax_vcpu; +diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h +index da459f03d6..8d2c1f3a6b 100644 +--- a/include/sysemu/dirtylimit.h ++++ b/include/sysemu/dirtylimit.h +@@ -19,4 +19,19 @@ void vcpu_dirty_rate_stat_start(void); + void vcpu_dirty_rate_stat_stop(void); + void vcpu_dirty_rate_stat_initialize(void); + void vcpu_dirty_rate_stat_finalize(void); ++ ++void dirtylimit_state_lock(void); ++void dirtylimit_state_unlock(void); ++void dirtylimit_state_initialize(void); ++void dirtylimit_state_finalize(void); ++bool dirtylimit_in_service(void); ++bool dirtylimit_vcpu_index_valid(int cpu_index); ++void dirtylimit_process(void); ++void dirtylimit_change(bool start); ++void dirtylimit_set_vcpu(int cpu_index, ++ uint64_t quota, ++ bool enable); ++void dirtylimit_set_all(uint64_t quota, ++ bool enable); ++void dirtylimit_vcpu_execute(CPUState *cpu); + #endif +diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c +index ebdc064c9d..e5a4f970bd 100644 +--- a/softmmu/dirtylimit.c ++++ b/softmmu/dirtylimit.c +@@ -18,6 +18,26 @@ + #include "sysemu/dirtylimit.h" + #include "exec/memory.h" + #include "hw/boards.h" ++#include "sysemu/kvm.h" ++#include "trace.h" ++ ++/* ++ * Dirtylimit stop working if dirty page rate error ++ * value less than DIRTYLIMIT_TOLERANCE_RANGE ++ */ ++#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ ++/* ++ * Plus or minus vcpu sleep time linearly if dirty ++ * page rate error value percentage over ++ * DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT. ++ * Otherwise, plus or minus a fixed vcpu sleep time. ++ */ ++#define DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT 50 ++/* ++ * Max vcpu sleep time percentage during a cycle ++ * composed of dirty ring full and sleep time. ++ */ ++#define DIRTYLIMIT_THROTTLE_PCT_MAX 99 + + struct { + VcpuStat stat; +@@ -25,6 +45,30 @@ struct { + QemuThread thread; + } *vcpu_dirty_rate_stat; + ++typedef struct VcpuDirtyLimitState { ++ int cpu_index; ++ bool enabled; ++ /* ++ * Quota dirty page rate, unit is MB/s ++ * zero if not enabled. ++ */ ++ uint64_t quota; ++} VcpuDirtyLimitState; ++ ++struct { ++ VcpuDirtyLimitState *states; ++ /* Max cpus number configured by user */ ++ int max_cpus; ++ /* Number of vcpu under dirtylimit */ ++ int limited_nvcpu; ++} *dirtylimit_state; ++ ++/* protect dirtylimit_state */ ++static QemuMutex dirtylimit_mutex; ++ ++/* dirtylimit thread quit if dirtylimit_quit is true */ ++static bool dirtylimit_quit; ++ + static void vcpu_dirty_rate_stat_collect(void) + { + VcpuStat stat; +@@ -54,6 +98,9 @@ static void *vcpu_dirty_rate_stat_thread(void *opaque) + + while (qatomic_read(&vcpu_dirty_rate_stat->running)) { + vcpu_dirty_rate_stat_collect(); ++ if (dirtylimit_in_service()) { ++ dirtylimit_process(); ++ } + } + + /* stop log sync */ +@@ -86,9 +133,11 @@ void vcpu_dirty_rate_stat_start(void) + void vcpu_dirty_rate_stat_stop(void) + { + qatomic_set(&vcpu_dirty_rate_stat->running, 0); ++ dirtylimit_state_unlock(); + qemu_mutex_unlock_iothread(); + qemu_thread_join(&vcpu_dirty_rate_stat->thread); + qemu_mutex_lock_iothread(); ++ dirtylimit_state_lock(); + } + + void vcpu_dirty_rate_stat_initialize(void) +@@ -114,3 +163,245 @@ void vcpu_dirty_rate_stat_finalize(void) + free(vcpu_dirty_rate_stat); + vcpu_dirty_rate_stat = NULL; + } ++ ++void dirtylimit_state_lock(void) ++{ ++ qemu_mutex_lock(&dirtylimit_mutex); ++} ++ ++void dirtylimit_state_unlock(void) ++{ ++ qemu_mutex_unlock(&dirtylimit_mutex); ++} ++ ++static void ++__attribute__((__constructor__)) dirtylimit_mutex_init(void) ++{ ++ qemu_mutex_init(&dirtylimit_mutex); ++} ++ ++static inline VcpuDirtyLimitState *dirtylimit_vcpu_get_state(int cpu_index) ++{ ++ return &dirtylimit_state->states[cpu_index]; ++} ++ ++void dirtylimit_state_initialize(void) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ int max_cpus = ms->smp.max_cpus; ++ int i; ++ ++ dirtylimit_state = g_malloc0(sizeof(*dirtylimit_state)); ++ ++ dirtylimit_state->states = ++ g_malloc0(sizeof(VcpuDirtyLimitState) * max_cpus); ++ ++ for (i = 0; i < max_cpus; i++) { ++ dirtylimit_state->states[i].cpu_index = i; ++ } ++ ++ dirtylimit_state->max_cpus = max_cpus; ++ trace_dirtylimit_state_initialize(max_cpus); ++} ++ ++void dirtylimit_state_finalize(void) ++{ ++ free(dirtylimit_state->states); ++ dirtylimit_state->states = NULL; ++ ++ free(dirtylimit_state); ++ dirtylimit_state = NULL; ++ ++ trace_dirtylimit_state_finalize(); ++} ++ ++bool dirtylimit_in_service(void) ++{ ++ return !!dirtylimit_state; ++} ++ ++bool dirtylimit_vcpu_index_valid(int cpu_index) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ++ return !(cpu_index < 0 || ++ cpu_index >= ms->smp.max_cpus); ++} ++ ++static inline int64_t dirtylimit_dirty_ring_full_time(uint64_t dirtyrate) ++{ ++ static uint64_t max_dirtyrate; ++ uint32_t dirty_ring_size = kvm_dirty_ring_size(); ++ uint64_t dirty_ring_size_meory_MB = ++ dirty_ring_size * TARGET_PAGE_SIZE >> 20; ++ ++ if (max_dirtyrate < dirtyrate) { ++ max_dirtyrate = dirtyrate; ++ } ++ ++ return dirty_ring_size_meory_MB * 1000000 / max_dirtyrate; ++} ++ ++static inline bool dirtylimit_done(uint64_t quota, ++ uint64_t current) ++{ ++ uint64_t min, max; ++ ++ min = MIN(quota, current); ++ max = MAX(quota, current); ++ ++ return ((max - min) <= DIRTYLIMIT_TOLERANCE_RANGE) ? true : false; ++} ++ ++static inline bool ++dirtylimit_need_linear_adjustment(uint64_t quota, ++ uint64_t current) ++{ ++ uint64_t min, max; ++ ++ min = MIN(quota, current); ++ max = MAX(quota, current); ++ ++ return ((max - min) * 100 / max) > DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT; ++} ++ ++static void dirtylimit_set_throttle(CPUState *cpu, ++ uint64_t quota, ++ uint64_t current) ++{ ++ int64_t ring_full_time_us = 0; ++ uint64_t sleep_pct = 0; ++ uint64_t throttle_us = 0; ++ ++ if (current == 0) { ++ cpu->throttle_us_per_full = 0; ++ return; ++ } ++ ++ ring_full_time_us = dirtylimit_dirty_ring_full_time(current); ++ ++ if (dirtylimit_need_linear_adjustment(quota, current)) { ++ if (quota < current) { ++ sleep_pct = (current - quota) * 100 / current; ++ throttle_us = ++ ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); ++ cpu->throttle_us_per_full += throttle_us; ++ } else { ++ sleep_pct = (quota - current) * 100 / quota; ++ throttle_us = ++ ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); ++ cpu->throttle_us_per_full -= throttle_us; ++ } ++ ++ trace_dirtylimit_throttle_pct(cpu->cpu_index, ++ sleep_pct, ++ throttle_us); ++ } else { ++ if (quota < current) { ++ cpu->throttle_us_per_full += ring_full_time_us / 10; ++ } else { ++ cpu->throttle_us_per_full -= ring_full_time_us / 10; ++ } ++ } ++ ++ /* ++ * TODO: in the big kvm_dirty_ring_size case (eg: 65536, or other scenario), ++ * current dirty page rate may never reach the quota, we should stop ++ * increasing sleep time? ++ */ ++ cpu->throttle_us_per_full = MIN(cpu->throttle_us_per_full, ++ ring_full_time_us * DIRTYLIMIT_THROTTLE_PCT_MAX); ++ ++ cpu->throttle_us_per_full = MAX(cpu->throttle_us_per_full, 0); ++} ++ ++static void dirtylimit_adjust_throttle(CPUState *cpu) ++{ ++ uint64_t quota = 0; ++ uint64_t current = 0; ++ int cpu_index = cpu->cpu_index; ++ ++ quota = dirtylimit_vcpu_get_state(cpu_index)->quota; ++ current = vcpu_dirty_rate_get(cpu_index); ++ ++ if (!dirtylimit_done(quota, current)) { ++ dirtylimit_set_throttle(cpu, quota, current); ++ } ++ ++ return; ++} ++ ++void dirtylimit_process(void) ++{ ++ CPUState *cpu; ++ ++ if (!qatomic_read(&dirtylimit_quit)) { ++ dirtylimit_state_lock(); ++ ++ if (!dirtylimit_in_service()) { ++ dirtylimit_state_unlock(); ++ return; ++ } ++ ++ CPU_FOREACH(cpu) { ++ if (!dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { ++ continue; ++ } ++ dirtylimit_adjust_throttle(cpu); ++ } ++ dirtylimit_state_unlock(); ++ } ++} ++ ++void dirtylimit_change(bool start) ++{ ++ if (start) { ++ qatomic_set(&dirtylimit_quit, 0); ++ } else { ++ qatomic_set(&dirtylimit_quit, 1); ++ } ++} ++ ++void dirtylimit_set_vcpu(int cpu_index, ++ uint64_t quota, ++ bool enable) ++{ ++ trace_dirtylimit_set_vcpu(cpu_index, quota); ++ ++ if (enable) { ++ dirtylimit_state->states[cpu_index].quota = quota; ++ if (!dirtylimit_vcpu_get_state(cpu_index)->enabled) { ++ dirtylimit_state->limited_nvcpu++; ++ } ++ } else { ++ dirtylimit_state->states[cpu_index].quota = 0; ++ if (dirtylimit_state->states[cpu_index].enabled) { ++ dirtylimit_state->limited_nvcpu--; ++ } ++ } ++ ++ dirtylimit_state->states[cpu_index].enabled = enable; ++} ++ ++void dirtylimit_set_all(uint64_t quota, ++ bool enable) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ int max_cpus = ms->smp.max_cpus; ++ int i; ++ ++ for (i = 0; i < max_cpus; i++) { ++ dirtylimit_set_vcpu(i, quota, enable); ++ } ++} ++ ++void dirtylimit_vcpu_execute(CPUState *cpu) ++{ ++ if (dirtylimit_in_service() && ++ dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled && ++ cpu->throttle_us_per_full) { ++ trace_dirtylimit_vcpu_execute(cpu->cpu_index, ++ cpu->throttle_us_per_full); ++ usleep(cpu->throttle_us_per_full); ++ } ++} +diff --git a/softmmu/trace-events b/softmmu/trace-events +index 9c88887b3c..22606dc27b 100644 +--- a/softmmu/trace-events ++++ b/softmmu/trace-events +@@ -31,3 +31,10 @@ runstate_set(int current_state, const char *current_state_str, int new_state, co + system_wakeup_request(int reason) "reason=%d" + qemu_system_shutdown_request(int reason) "reason=%d" + qemu_system_powerdown_request(void) "" ++ ++#dirtylimit.c ++dirtylimit_state_initialize(int max_cpus) "dirtylimit state initialize: max cpus %d" ++dirtylimit_state_finalize(void) ++dirtylimit_throttle_pct(int cpu_index, uint64_t pct, int64_t time_us) "CPU[%d] throttle percent: %" PRIu64 ", throttle adjust time %"PRIi64 " us" ++dirtylimit_set_vcpu(int cpu_index, uint64_t quota) "CPU[%d] set dirty page rate limit %"PRIu64 ++dirtylimit_vcpu_execute(int cpu_index, int64_t sleep_time_us) "CPU[%d] sleep %"PRIi64 " us" +-- +2.27.0 + diff --git a/softmmu-physmem-Introduce-MemTxAttrs-memory-field-an.patch b/softmmu-physmem-Introduce-MemTxAttrs-memory-field-an.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d8e64d5df525714eb4d6ca0c31e141d67af7772 --- /dev/null +++ b/softmmu-physmem-Introduce-MemTxAttrs-memory-field-an.patch @@ -0,0 +1,151 @@ +From 96a6c8fa67298d52ccc27a0ac5bdddd6c42068cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 19:24:21 +0100 +Subject: [PATCH 3/3] softmmu/physmem: Introduce MemTxAttrs::memory field and + MEMTX_ACCESS_ERROR +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the 'memory' bit to the memory attributes to restrict bus +controller accesses to memories. + +Introduce flatview_access_allowed() to check bus permission +before running any bus transaction. + +Have read/write accessors return MEMTX_ACCESS_ERROR if an access is +restricted. + +There is no change for the default case where 'memory' is not set. + +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211215182421.418374-4-philmd@redhat.com> +Reviewed-by: Richard Henderson +Reviewed-by: Stefan Hajnoczi +[thuth: Replaced MEMTX_BUS_ERROR with MEMTX_ACCESS_ERROR, remove "inline"] +Signed-off-by: Thomas Huth +--- + include/exec/memattrs.h | 9 +++++++++ + softmmu/physmem.c | 44 +++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 51 insertions(+), 2 deletions(-) + +diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h +index 95f2d20d55..9fb98bc1ef 100644 +--- a/include/exec/memattrs.h ++++ b/include/exec/memattrs.h +@@ -35,6 +35,14 @@ typedef struct MemTxAttrs { + unsigned int secure:1; + /* Memory access is usermode (unprivileged) */ + unsigned int user:1; ++ /* ++ * Bus interconnect and peripherals can access anything (memories, ++ * devices) by default. By setting the 'memory' bit, bus transaction ++ * are restricted to "normal" memories (per the AMBA documentation) ++ * versus devices. Access to devices will be logged and rejected ++ * (see MEMTX_ACCESS_ERROR). ++ */ ++ unsigned int memory:1; + /* Requester ID (for MSI for example) */ + unsigned int requester_id:16; + /* Invert endianness for this page */ +@@ -66,6 +74,7 @@ typedef struct MemTxAttrs { + #define MEMTX_OK 0 + #define MEMTX_ERROR (1U << 0) /* device returned an error */ + #define MEMTX_DECODE_ERROR (1U << 1) /* nothing at that address */ ++#define MEMTX_ACCESS_ERROR (1U << 2) /* access denied */ + typedef uint32_t MemTxResult; + + #endif +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index 049e7b1454..ae26f72909 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -41,6 +41,7 @@ + #include "qemu/config-file.h" + #include "qemu/error-report.h" + #include "qemu/qemu-print.h" ++#include "qemu/log.h" + #include "exec/memory.h" + #include "exec/ioport.h" + #include "sysemu/dma.h" +@@ -2767,6 +2768,33 @@ static bool prepare_mmio_access(MemoryRegion *mr) + return release_lock; + } + ++/** ++ * flatview_access_allowed ++ * @mr: #MemoryRegion to be accessed ++ * @attrs: memory transaction attributes ++ * @addr: address within that memory region ++ * @len: the number of bytes to access ++ * ++ * Check if a memory transaction is allowed. ++ * ++ * Returns: true if transaction is allowed, false if denied. ++ */ ++static bool flatview_access_allowed(MemoryRegion *mr, MemTxAttrs attrs, ++ hwaddr addr, hwaddr len) ++{ ++ if (likely(!attrs.memory)) { ++ return true; ++ } ++ if (memory_region_is_ram(mr)) { ++ return true; ++ } ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Invalid access to non-RAM device at " ++ "addr 0x%" HWADDR_PRIX ", size %" HWADDR_PRIu ", " ++ "region '%s'\n", addr, len, memory_region_name(mr)); ++ return false; ++} ++ + /* Called within RCU critical section. */ + static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, + MemTxAttrs attrs, +@@ -2781,7 +2809,10 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, + const uint8_t *buf = ptr; + + for (;;) { +- if (!memory_access_is_direct(mr, true)) { ++ if (!flatview_access_allowed(mr, attrs, addr1, l)) { ++ result |= MEMTX_ACCESS_ERROR; ++ /* Keep going. */ ++ } else if (!memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + l = memory_access_size(mr, l, addr1); + /* XXX: could force current_cpu to NULL to avoid +@@ -2826,6 +2857,9 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, + + l = len; + mr = flatview_translate(fv, addr, &addr1, &l, true, attrs); ++ if (!flatview_access_allowed(mr, attrs, addr, len)) { ++ return MEMTX_ACCESS_ERROR; ++ } + return flatview_write_continue(fv, addr, attrs, buf, len, + addr1, l, mr); + } +@@ -2844,7 +2878,10 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, + + fuzz_dma_read_cb(addr, len, mr); + for (;;) { +- if (!memory_access_is_direct(mr, false)) { ++ if (!flatview_access_allowed(mr, attrs, addr1, l)) { ++ result |= MEMTX_ACCESS_ERROR; ++ /* Keep going. */ ++ } else if (!memory_access_is_direct(mr, false)) { + /* I/O case */ + release_lock |= prepare_mmio_access(mr); + l = memory_access_size(mr, l, addr1); +@@ -2887,6 +2924,9 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr, + + l = len; + mr = flatview_translate(fv, addr, &addr1, &l, false, attrs); ++ if (!flatview_access_allowed(mr, attrs, addr, len)) { ++ return MEMTX_ACCESS_ERROR; ++ } + return flatview_read_continue(fv, addr, attrs, buf, len, + addr1, l, mr); + } +-- +2.27.0 + diff --git a/softmmu-physmem-Simplify-flatview_write-and-address_.patch b/softmmu-physmem-Simplify-flatview_write-and-address_.patch new file mode 100644 index 0000000000000000000000000000000000000000..833fa849ba5afd9a7990aa611fadb47db9bb1267 --- /dev/null +++ b/softmmu-physmem-Simplify-flatview_write-and-address_.patch @@ -0,0 +1,60 @@ +From 105c54fca54e73f17abe244b457872926e43f8a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 15 Dec 2021 19:24:20 +0100 +Subject: [PATCH 2/3] softmmu/physmem: Simplify flatview_write and + address_space_access_valid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove unuseful local 'result' variables. + +Reviewed-by: Peter Xu +Reviewed-by: David Hildenbrand +Reviewed-by: Alexander Bulekov +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211215182421.418374-3-philmd@redhat.com> +Signed-off-by: Thomas Huth +--- + softmmu/physmem.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index 3b9a61448c..049e7b1454 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -2823,14 +2823,11 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, + hwaddr l; + hwaddr addr1; + MemoryRegion *mr; +- MemTxResult result = MEMTX_OK; + + l = len; + mr = flatview_translate(fv, addr, &addr1, &l, true, attrs); +- result = flatview_write_continue(fv, addr, attrs, buf, len, +- addr1, l, mr); +- +- return result; ++ return flatview_write_continue(fv, addr, attrs, buf, len, ++ addr1, l, mr); + } + + /* Called within RCU critical section. */ +@@ -3127,12 +3124,10 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs) + { + FlatView *fv; +- bool result; + + RCU_READ_LOCK_GUARD(); + fv = address_space_to_flatview(as); +- result = flatview_access_valid(fv, addr, len, is_write, attrs); +- return result; ++ return flatview_access_valid(fv, addr, len, is_write, attrs); + } + + static hwaddr +-- +2.27.0 + diff --git a/spapr-Implement-get_dt_compatible-callback.patch b/spapr-Implement-get_dt_compatible-callback.patch deleted file mode 100644 index e64a8746f498a68085824f6cace1bb2e958ce7c7..0000000000000000000000000000000000000000 --- a/spapr-Implement-get_dt_compatible-callback.patch +++ /dev/null @@ -1,68 +0,0 @@ -From c520d8e823431be94268daa2a911e224cab81521 Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Tue, 21 Jan 2020 10:29:31 -0500 -Subject: [PATCH 04/19] spapr: Implement get_dt_compatible() callback -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -For devices that cannot be statically initialized, implement a -get_dt_compatible() callback that allows us to ask the device for -the 'compatible' value. - -Signed-off-by: Stefan Berger -Reviewed-by: Marc-André Lureau -Reviewed-by: David Gibson -Message-Id: <20200121152935.649898-3-stefanb@linux.ibm.com> -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - hw/ppc/spapr_vio.c | 11 +++++++++-- - include/hw/ppc/spapr_vio.h | 1 + - 2 files changed, 10 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c -index 583c13de..4e50916f 100644 ---- a/hw/ppc/spapr_vio.c -+++ b/hw/ppc/spapr_vio.c -@@ -89,6 +89,7 @@ static int vio_make_devnode(SpaprVioDevice *dev, - SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - int vdevice_off, node_off, ret; - char *dt_name; -+ const char *dt_compatible; - - vdevice_off = fdt_path_offset(fdt, "/vdevice"); - if (vdevice_off < 0) { -@@ -115,9 +116,15 @@ static int vio_make_devnode(SpaprVioDevice *dev, - } - } - -- if (pc->dt_compatible) { -+ if (pc->get_dt_compatible) { -+ dt_compatible = pc->get_dt_compatible(dev); -+ } else { -+ dt_compatible = pc->dt_compatible; -+ } -+ -+ if (dt_compatible) { - ret = fdt_setprop_string(fdt, node_off, "compatible", -- pc->dt_compatible); -+ dt_compatible); - if (ret < 0) { - return ret; - } -diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h -index 04609f21..97951fc6 100644 ---- a/include/hw/ppc/spapr_vio.h -+++ b/include/hw/ppc/spapr_vio.h -@@ -56,6 +56,7 @@ typedef struct SpaprVioDeviceClass { - void (*realize)(SpaprVioDevice *dev, Error **errp); - void (*reset)(SpaprVioDevice *dev); - int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off); -+ const char *(*get_dt_compatible)(SpaprVioDevice *dev); - } SpaprVioDeviceClass; - - struct SpaprVioDevice { --- -2.23.0 - diff --git a/spapr-pci-Correct-does-not-support-hotplugging-error.patch b/spapr-pci-Correct-does-not-support-hotplugging-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb82a76b8f5921ec0e6db32fe1ddc787c2325243 --- /dev/null +++ b/spapr-pci-Correct-does-not-support-hotplugging-error.patch @@ -0,0 +1,45 @@ +From f647bc67bcdbfc2dd1cb1f1ba1abdb2b04c5c10f Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 16:19:33 +0800 +Subject: [PATCH] spapr/pci: Correct "does not support hotplugging error + messages + +cherry picked from db8227a68addb9db6392001c7e02d406282ea462 + +When dynamic-reconfiguration is off, hot plug / unplug can fail with +"Bus 'spapr-pci-host-bridge' does not support hotplugging". +spapr-pci-host-bridge is a device, not a bus. Report the name of the +bus it provides instead: 'pci.0'. + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-2-armbru@redhat.com> +Reviewed-by: Daniel Henrique Barboza +--- + hw/ppc/spapr_pci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c +index d3367e8578..3b518f1be9 100644 +--- a/hw/ppc/spapr_pci.c ++++ b/hw/ppc/spapr_pci.c +@@ -1554,7 +1554,7 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler, + */ + if (plugged_dev->hotplugged) { + error_setg(errp, QERR_BUS_NO_HOTPLUG, +- object_get_typename(OBJECT(phb))); ++ phb->parent_obj.bus->qbus.name); + return; + } + } +@@ -1677,7 +1677,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, + + if (!phb->dr_enabled) { + error_setg(errp, QERR_BUS_NO_HOTPLUG, +- object_get_typename(OBJECT(phb))); ++ phb->parent_obj.bus->qbus.name); + return; + } + +-- +2.27.0 + diff --git a/spapr_pci-add-spapr-msi-read-method.patch b/spapr_pci-add-spapr-msi-read-method.patch deleted file mode 100644 index 2cc4994f09171252daf5a435832480151c458f4b..0000000000000000000000000000000000000000 --- a/spapr_pci-add-spapr-msi-read-method.patch +++ /dev/null @@ -1,61 +0,0 @@ -From cbbcd56e090a59d0eaa4e35ed0efb24d6dd1003e Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:23:24 +0800 -Subject: [PATCH] spapr_pci: add spapr msi read method - -fix CVE-2020-15469 - -Add spapr msi mmio read method to avoid NULL pointer dereference -issue. - -Reported-by: Lei Sun -Acked-by: David Gibson -Reviewed-by: Li Qiang -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/ppc/spapr_pci.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c -index 9003fe9010..1571e049ab 100644 ---- a/hw/ppc/spapr_pci.c -+++ b/hw/ppc/spapr_pci.c -@@ -50,6 +50,7 @@ - #include "sysemu/kvm.h" - #include "sysemu/hostmem.h" - #include "sysemu/numa.h" -+#include "qemu/log.h" - - /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ - #define RTAS_QUERY_FN 0 -@@ -743,6 +744,12 @@ static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin) - return route; - } - -+static uint64_t spapr_msi_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); -+ return 0; -+} -+ - /* - * MSI/MSIX memory region implementation. - * The handler handles both MSI and MSIX. -@@ -760,8 +767,10 @@ static void spapr_msi_write(void *opaque, hwaddr addr, - } - - static const MemoryRegionOps spapr_msi_ops = { -- /* There is no .read as the read result is undefined by PCI spec */ -- .read = NULL, -+ /* .read result is undefined by PCI spec -+ * define .read method to avoid assert failure in memory_region_init_io -+ */ -+ .read = spapr_msi_read, - .write = spapr_msi_write, - .endianness = DEVICE_LITTLE_ENDIAN - }; --- -2.27.0 - diff --git a/sphinx-change-default-language-to-en.patch b/sphinx-change-default-language-to-en.patch new file mode 100644 index 0000000000000000000000000000000000000000..77f2b2af213566c273c942fe6d9f18b56c352d3e --- /dev/null +++ b/sphinx-change-default-language-to-en.patch @@ -0,0 +1,38 @@ +From a6861159f23833f878be833e2c0c37060ac14513 Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:57:47 -0800 +Subject: [PATCH] sphinx: change default language to 'en' + +cherry picked from commit ba1a6723f58640ba281bc952abc255e97c70bad5 + +Fixes the following Sphinx warning (treated as error) starting +with 5.0 release: + +Warning, treated as error: +Invalid configuration value found: 'language = None'. Update your configuration to a valid langauge code. Falling back to 'en' (English). + +Signed-off-by: Martin Liska +Message-id: e91e51ee-48ac-437e-6467-98b56ee40042@suse.cz +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Wanghe Xiao +--- + docs/conf.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/conf.py b/docs/conf.py +index 763e7d2434..84b593e12a 100644 +--- a/docs/conf.py ++++ b/docs/conf.py +@@ -120,7 +120,7 @@ + # + # This is also used if you do content translation via gettext catalogs. + # Usually you set "language" from the command line for these cases. +-language = None ++language = 'en' + + # List of patterns, relative to source directory, that match files and + # directories to ignore when looking for source files. +-- +2.27.0 + diff --git a/ssi-Fix-bad-printf-format-specifiers.patch b/ssi-Fix-bad-printf-format-specifiers.patch deleted file mode 100644 index 811a14da46a4e55ca324209309774973b563b70c..0000000000000000000000000000000000000000 --- a/ssi-Fix-bad-printf-format-specifiers.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 073457a45eaccd2beac3c94c53a449b8f683501e Mon Sep 17 00:00:00 2001 -From: AlexChen -Date: Wed, 4 Nov 2020 18:22:45 +0800 -Subject: [PATCH] ssi: Fix bad printf format specifiers - -We should use printf format specifier "%u" instead of "%d" for -argument of type "unsigned int". - -Reported-by: Euler Robot -Signed-off-by: Alex Chen -Reviewed-by: Alistair Francis -Message-id: 5FA280F5.8060902@huawei.com -Signed-off-by: Peter Maydell -(cherry-picked from commit 9df0a97298) ---- - hw/ssi/imx_spi.c | 2 +- - hw/ssi/xilinx_spi.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c -index 5cec9b5d05..0b3052bdf9 100644 ---- a/hw/ssi/imx_spi.c -+++ b/hw/ssi/imx_spi.c -@@ -52,7 +52,7 @@ static const char *imx_spi_reg_name(uint32_t reg) - case ECSPI_MSGDATA: - return "ECSPI_MSGDATA"; - default: -- sprintf(unknown, "%d ?", reg); -+ sprintf(unknown, "%u ?", reg); - return unknown; - } - } -diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c -index 1379cb164b..d2b69d027a 100644 ---- a/hw/ssi/xilinx_spi.c -+++ b/hw/ssi/xilinx_spi.c -@@ -139,7 +139,7 @@ static void xlx_spi_update_irq(XilinxSPI *s) - irq chain unless things really changed. */ - if (pending != s->irqline) { - s->irqline = pending; -- DB_PRINT("irq_change of state %d ISR:%x IER:%X\n", -+ DB_PRINT("irq_change of state %u ISR:%x IER:%X\n", - pending, s->regs[R_IPISR], s->regs[R_IPIER]); - qemu_set_irq(s->irq, pending); - } --- -2.27.0 - diff --git a/sw_64-Add-sw64-architecture-support.patch b/sw_64-Add-sw64-architecture-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..4bffadfbd69453b5c58bc32e821ed88148d809e1 --- /dev/null +++ b/sw_64-Add-sw64-architecture-support.patch @@ -0,0 +1,18277 @@ +From d74713d8e656e8d0f7a5200122119802e639ff49 Mon Sep 17 00:00:00 2001 +From: Lu Feifei +Date: Mon, 14 Mar 2022 11:04:02 +0800 +Subject: [PATCH] sw_64: Add sw64 architecture support + +Signed-off-by: Lu Feifei +--- + configs/devices/sw64-softmmu/default.mak | 10 + + configs/targets/sw64-softmmu.mak | 8 + + configure | 7 + + disas.c | 2 + + disas/meson.build | 1 + + disas/sw64.c | 1242 +++++++ + hw/Kconfig | 1 + + hw/meson.build | 1 + + hw/rtc/sun4v-rtc.c | 11 + + hw/sw64/Kconfig | 11 + + hw/sw64/Makefile.objs | 1 + + hw/sw64/core.h | 25 + + hw/sw64/core3.c | 182 ++ + hw/sw64/core3_board.c | 493 +++ + hw/sw64/meson.build | 10 + + hw/sw64/sw64_iommu.c | 567 ++++ + hw/sw64/trace-events | 3 + + include/disas/dis-asm.h | 4 + + include/elf.h | 44 + + include/hw/sw64/sw64_iommu.h | 105 + + include/qemu/atomic.h | 2 + + include/qemu/timer.h | 10 + + include/sysemu/arch_init.h | 1 + + linux-headers/asm-sw64/kvm.h | 122 + + linux-headers/asm-sw64/unistd.h | 380 +++ + linux-user/meson.build | 1 + + linux-user/sw64/cpu_loop.c | 108 + + linux-user/sw64/signal.c | 273 ++ + linux-user/sw64/sockbits.h | 1 + + linux-user/sw64/syscall_nr.h | 471 +++ + linux-user/sw64/target_cpu.h | 38 + + linux-user/sw64/target_elf.h | 14 + + linux-user/sw64/target_fcntl.h | 11 + + linux-user/sw64/target_signal.h | 98 + + linux-user/sw64/target_structs.h | 47 + + linux-user/sw64/target_syscall.h | 121 + + linux-user/sw64/termbits.h | 265 ++ + meson.build | 12 +- + pc-bios/core3-hmcode | Bin 0 -> 225904 bytes + pc-bios/core3-reset | Bin 0 -> 5032 bytes + pc-bios/core4-hmcode | Bin 0 -> 243040 bytes + pc-bios/meson.build | 3 + + pc-bios/uefi-bios-sw | Bin 0 -> 3145728 bytes + qapi/machine.json | 2 +- + softmmu/qdev-monitor.c | 3 +- + target/Kconfig | 1 + + target/meson.build | 1 + + target/sw64/Kconfig | 2 + + target/sw64/Makefile.objs | 4 + + target/sw64/cpu-param.h | 24 + + target/sw64/cpu-qom.h | 47 + + target/sw64/cpu.c | 457 +++ + target/sw64/cpu.h | 406 +++ + target/sw64/exception.c | 76 + + target/sw64/float_helper.c | 846 +++++ + target/sw64/helper.c | 349 ++ + target/sw64/helper.h | 127 + + target/sw64/int_helper.c | 118 + + target/sw64/kvm.c | 215 ++ + target/sw64/kvm_sw64.h | 47 + + target/sw64/machine.c | 18 + + target/sw64/meson.build | 19 + + target/sw64/profile.c | 2342 +++++++++++++ + target/sw64/profile.h | 541 +++ + target/sw64/simd_helper.c | 1058 ++++++ + target/sw64/translate.c | 3798 ++++++++++++++++++++++ + target/sw64/translate.h | 60 + + tcg/sw64/tcg-target-con-set.h | 39 + + tcg/sw64/tcg-target-con-str.h | 28 + + tcg/sw64/tcg-target.c.inc | 2109 ++++++++++++ + tcg/sw64/tcg-target.h | 123 + + tcg/sw64/tcg-target.opc.h | 15 + + 72 files changed, 17578 insertions(+), 3 deletions(-) + create mode 100644 configs/devices/sw64-softmmu/default.mak + create mode 100644 configs/targets/sw64-softmmu.mak + create mode 100755 disas/sw64.c + create mode 100644 hw/sw64/Kconfig + create mode 100644 hw/sw64/Makefile.objs + create mode 100644 hw/sw64/core.h + create mode 100644 hw/sw64/core3.c + create mode 100644 hw/sw64/core3_board.c + create mode 100644 hw/sw64/meson.build + create mode 100644 hw/sw64/sw64_iommu.c + create mode 100644 hw/sw64/trace-events + create mode 100644 include/hw/sw64/sw64_iommu.h + create mode 100644 linux-headers/asm-sw64/kvm.h + create mode 100644 linux-headers/asm-sw64/unistd.h + create mode 100644 linux-user/sw64/cpu_loop.c + create mode 100644 linux-user/sw64/signal.c + create mode 100644 linux-user/sw64/sockbits.h + create mode 100644 linux-user/sw64/syscall_nr.h + create mode 100644 linux-user/sw64/target_cpu.h + create mode 100644 linux-user/sw64/target_elf.h + create mode 100644 linux-user/sw64/target_fcntl.h + create mode 100644 linux-user/sw64/target_signal.h + create mode 100644 linux-user/sw64/target_structs.h + create mode 100644 linux-user/sw64/target_syscall.h + create mode 100644 linux-user/sw64/termbits.h + create mode 100755 pc-bios/core3-hmcode + create mode 100755 pc-bios/core3-reset + create mode 100755 pc-bios/core4-hmcode + create mode 100755 pc-bios/uefi-bios-sw + create mode 100644 target/sw64/Kconfig + create mode 100644 target/sw64/Makefile.objs + create mode 100644 target/sw64/cpu-param.h + create mode 100644 target/sw64/cpu-qom.h + create mode 100644 target/sw64/cpu.c + create mode 100644 target/sw64/cpu.h + create mode 100644 target/sw64/exception.c + create mode 100644 target/sw64/float_helper.c + create mode 100644 target/sw64/helper.c + create mode 100644 target/sw64/helper.h + create mode 100644 target/sw64/int_helper.c + create mode 100644 target/sw64/kvm.c + create mode 100644 target/sw64/kvm_sw64.h + create mode 100644 target/sw64/machine.c + create mode 100644 target/sw64/meson.build + create mode 100644 target/sw64/profile.c + create mode 100644 target/sw64/profile.h + create mode 100644 target/sw64/simd_helper.c + create mode 100644 target/sw64/translate.c + create mode 100644 target/sw64/translate.h + create mode 100755 tcg/sw64/tcg-target-con-set.h + create mode 100755 tcg/sw64/tcg-target-con-str.h + create mode 100755 tcg/sw64/tcg-target.c.inc + create mode 100755 tcg/sw64/tcg-target.h + create mode 100755 tcg/sw64/tcg-target.opc.h + +diff --git a/configs/devices/sw64-softmmu/default.mak b/configs/devices/sw64-softmmu/default.mak +new file mode 100644 +index 0000000000..0b4d56b43e +--- /dev/null ++++ b/configs/devices/sw64-softmmu/default.mak +@@ -0,0 +1,10 @@ ++# Default configuration for sw64-softmmu ++ ++# Uncomment the following lines to disable these optional devices: ++# ++#CONFIG_PCI_DEVICES=n ++#CONFIG_TEST_DEVICES=n ++ ++# Boards: ++# ++CONFIG_CORE3=y +diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak +new file mode 100644 +index 0000000000..37cc2e05a6 +--- /dev/null ++++ b/configs/targets/sw64-softmmu.mak +@@ -0,0 +1,8 @@ ++# Default configuration for sw64-softmmu ++ ++# Boards: ++# ++TARGET_ARCH=sw64 ++TARGET_BASE_ARCH=sw64 ++TARGET_ABI_DIR=sw64 ++TARGET_SUPPORTS_MTTCG=y +diff --git a/configure b/configure +index 48c21775f3..9569d7a3d0 100755 +--- a/configure ++++ b/configure +@@ -612,6 +612,9 @@ case "$cpu" in + sparc|sun4[cdmuv]) + cpu="sparc" + ;; ++ sw_64) ++ cpu="sw64" ++ ;; + *) + # This will result in either an error or falling back to TCI later + ARCH=unknown +@@ -3268,6 +3271,10 @@ alpha) + # Ensure there's only a single GP + QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" + ;; ++sw*) ++ # Ensure there's only a single GP ++ QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" ++;; + esac + + if test "$gprof" = "yes" ; then +diff --git a/disas.c b/disas.c +index 3dab4482d1..897de1d9a9 100644 +--- a/disas.c ++++ b/disas.c +@@ -207,6 +207,8 @@ static void initialize_debug_host(CPUDebug *s) + s->info.cap_insn_split = 6; + #elif defined(__hppa__) + s->info.print_insn = print_insn_hppa; ++#elif defined(__sw_64__) ++ s->info.print_insn = print_insn_sw_64; + #endif + } + +diff --git a/disas/meson.build b/disas/meson.build +index 449f99e1de..5c5daa69a7 100644 +--- a/disas/meson.build ++++ b/disas/meson.build +@@ -20,4 +20,5 @@ common_ss.add(when: 'CONFIG_S390_DIS', if_true: files('s390.c')) + common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) + common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) + common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c')) ++common_ss.add(when: 'CONFIG_SW64_DIS', if_true: files('sw64.c')) + common_ss.add(when: capstone, if_true: files('capstone.c')) +diff --git a/disas/sw64.c b/disas/sw64.c +new file mode 100755 +index 0000000000..c5bd578e07 +--- /dev/null ++++ b/disas/sw64.c +@@ -0,0 +1,1242 @@ ++/* ++ * sw_64-dis.c -- Disassemble Sw_64 CORE3 instructions ++ * ++ * This file is part of libopcodes. ++ * ++ * This library 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 3, or (at your option) ++ * any later version. ++ * ++ * It 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 file; see the file COPYING. If not, write to the Free ++ * Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ */ ++ ++#include "qemu/osdep.h" ++#include "disas/dis-asm.h" ++ ++#undef MAX ++ ++struct sw_64_opcode { ++ /* The opcode name. */ ++ const char *name; ++ ++ /* The opcode itself. Those bits which will be filled in with ++ operands are zeroes. */ ++ unsigned opcode; ++ ++ /* The opcode mask. This is used by the disassembler. This is a ++ mask containing ones indicating those bits which must match the ++ opcode field, and zeroes indicating those bits which need not ++ match (and are presumably filled in by operands). */ ++ unsigned mask; ++ ++ /* One bit flags for the opcode. These are primarily used to ++ indicate specific processors and environments support the ++ instructions. The defined values are listed below. */ ++ unsigned flags; ++ ++ /* An array of operand codes. Each code is an index into the ++ operand table. They appear in the order which the operands must ++ appear in assembly code, and are terminated by a zero. */ ++ unsigned char operands[5]; ++}; ++ ++/* The table itself is sorted by major opcode number, and is otherwise ++ in the order in which the disassembler should consider ++ instructions. */ ++extern const struct sw_64_opcode sw_64_opcodes[]; ++extern const unsigned sw_64_num_opcodes; ++ ++/* Values defined for the flags field of a struct sw_64_opcode. */ ++ ++/* CPU Availability */ ++#define SW_OPCODE_BASE 0x0001 /* Base architecture insns. */ ++#define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ ++#define SW_LITOP(i) (((i) >> 26) & 0x3D) ++ ++#define SW_OPCODE_NOHM (~(SW_OPCODE_BASE|SW_OPCODE_CORE3)) ++ ++/* A macro to extract the major opcode from an instruction. */ ++#define SW_OP(i) (((i) >> 26) & 0x3F) ++ ++/* The total number of major opcodes. */ ++#define SW_NOPS 0x40 ++ ++/* The operands table is an array of struct sw_64_operand. */ ++ ++struct sw_64_operand { ++ /* The number of bits in the operand. */ ++ unsigned int bits : 5; ++ ++ /* How far the operand is left shifted in the instruction. */ ++ unsigned int shift : 5; ++ ++ /* The default relocation type for this operand. */ ++ signed int default_reloc : 16; ++ ++ /* One bit syntax flags. */ ++ unsigned int flags : 16; ++ ++ /* Insertion function. This is used by the assembler. To insert an ++ operand value into an instruction, check this field. ++ ++ If it is NULL, execute ++ i |= (op & ((1 << o->bits) - 1)) << o->shift; ++ (i is the instruction which we are filling in, o is a pointer to ++ this structure, and op is the opcode value; this assumes twos ++ complement arithmetic). ++ ++ If this field is not NULL, then simply call it with the ++ instruction and the operand value. It will return the new value ++ of the instruction. If the ERRMSG argument is not NULL, then if ++ the operand value is illegal, *ERRMSG will be set to a warning ++ string (the operand will be inserted in any case). If the ++ operand value is legal, *ERRMSG will be unchanged (most operands ++ can accept any value). */ ++ unsigned (*insert) (unsigned instruction, int op, const char **errmsg); ++ ++ /* Extraction function. This is used by the disassembler. To ++ extract this operand type from an instruction, check this field. ++ ++ If it is NULL, compute ++ op = ((i) >> o->shift) & ((1 << o->bits) - 1); ++ if ((o->flags & SW_OPERAND_SIGNED) != 0 ++ && (op & (1 << (o->bits - 1))) != 0) ++ op -= 1 << o->bits; ++ (i is the instruction, o is a pointer to this structure, and op ++ is the result; this assumes twos complement arithmetic). ++ ++ If this field is not NULL, then simply call it with the ++ instruction value. It will return the value of the operand. If ++ the INVALID argument is not NULL, *INVALID will be set to ++ non-zero if this operand type can not actually be extracted from ++ this operand (i.e., the instruction does not match). If the ++ operand is valid, *INVALID will not be changed. */ ++ int (*extract) (unsigned instruction, int *invalid); ++}; ++ ++/* Elements in the table are retrieved by indexing with values from ++ the operands field of the sw_64_opcodes table. */ ++ ++extern const struct sw_64_operand sw_64_operands[]; ++extern const unsigned sw_64_num_operands; ++/* Values defined for the flags field of a struct sw_64_operand. */ ++ ++/* Mask for selecting the type for typecheck purposes */ ++#define SW_OPERAND_TYPECHECK_MASK \ ++ (SW_OPERAND_PARENS | SW_OPERAND_COMMA | SW_OPERAND_IR | \ ++ SW_OPERAND_FPR | SW_OPERAND_RELATIVE | SW_OPERAND_SIGNED | \ ++ SW_OPERAND_UNSIGNED) ++ ++/* This operand does not actually exist in the assembler input. This ++ is used to support extended mnemonics, for which two operands fields ++ are identical. The assembler should call the insert function with ++ any op value. The disassembler should call the extract function, ++ ignore the return value, and check the value placed in the invalid ++ argument. */ ++#define SW_OPERAND_FAKE 01 ++ ++/* The operand should be wrapped in parentheses rather than separated ++ from the previous by a comma. This is used for the load and store ++ instructions which want their operands to look like "Ra,disp(Rb)". */ ++#define SW_OPERAND_PARENS 02 ++ ++/* Used in combination with PARENS, this supresses the supression of ++ the comma. This is used for "jmp Ra,(Rb),hint". */ ++#define SW_OPERAND_COMMA 04 ++ ++/* This operand names an integer register. */ ++#define SW_OPERAND_IR 010 ++ ++/* This operand names a floating point register. */ ++#define SW_OPERAND_FPR 020 ++ ++/* This operand is a relative branch displacement. The disassembler ++ prints these symbolically if possible. */ ++#define SW_OPERAND_RELATIVE 040 ++ ++/* This operand takes signed values. */ ++#define SW_OPERAND_SIGNED 0100 ++ ++/* This operand takes unsigned values. This exists primarily so that ++ a flags value of 0 can be treated as end-of-arguments. */ ++#define SW_OPERAND_UNSIGNED 0200 ++ ++/* Supress overflow detection on this field. This is used for hints. */ ++#define SW_OPERAND_NOOVERFLOW 0400 ++ ++/* Mask for optional argument default value. */ ++#define SW_OPERAND_OPTIONAL_MASK 07000 ++ ++/* This operand defaults to zero. This is used for jump hints. */ ++#define SW_OPERAND_DEFAULT_ZERO 01000 ++ ++/* This operand should default to the first (real) operand and is used ++ in conjunction with SW_OPERAND_OPTIONAL. This allows ++ "and $0,3,$0" to be written as "and $0,3", etc. I don't like ++ it, but it's what DEC does. */ ++#define SW_OPERAND_DEFAULT_FIRST 02000 ++ ++/* Similarly, this operand should default to the second (real) operand. ++ This allows "negl $0" instead of "negl $0,$0". */ ++#define SW_OPERAND_DEFAULT_SECOND 04000 ++ ++/* Register common names */ ++ ++#define SW_REG_V0 0 ++#define SW_REG_T0 1 ++#define SW_REG_T1 2 ++#define SW_REG_T2 3 ++#define SW_REG_T3 4 ++#define SW_REG_T4 5 ++#define SW_REG_T5 6 ++#define SW_REG_T6 7 ++#define SW_REG_T7 8 ++#define SW_REG_S0 9 ++#define SW_REG_S1 10 ++#define SW_REG_S2 11 ++#define SW_REG_S3 12 ++#define SW_REG_S4 13 ++#define SW_REG_S5 14 ++#define SW_REG_FP 15 ++#define SW_REG_A0 16 ++#define SW_REG_A1 17 ++#define SW_REG_A2 18 ++#define SW_REG_A3 19 ++#define SW_REG_A4 20 ++#define SW_REG_A5 21 ++#define SW_REG_T8 22 ++#define SW_REG_T9 23 ++#define SW_REG_T10 24 ++#define SW_REG_T11 25 ++#define SW_REG_RA 26 ++#define SW_REG_PV 27 ++#define SW_REG_T12 27 ++#define SW_REG_AT 28 ++#define SW_REG_GP 29 ++#define SW_REG_SP 30 ++#define SW_REG_ZERO 31 ++ ++enum bfd_reloc_code_real { ++ BFD_RELOC_23_PCREL_S2, ++ BFD_RELOC_SW_64_HINT ++}; ++ ++static unsigned insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (((insn >> 21) & 0x1f) << 16); ++} ++ ++static int extract_rba(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++/* The same for the RC field. */ ++static unsigned insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | ((insn >> 21) & 0x1f); ++} ++ ++static unsigned insert_rdc(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | ((insn >> 5) & 0x1f); ++} ++ ++static int extract_rdc(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 5) & 0x1f) != (insn & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++static int extract_rca(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 21) & 0x1f) != (insn & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++/* Fake arguments in which the registers must be set to ZERO. */ ++static unsigned insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (31 << 21); ++} ++ ++static int extract_za(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++static unsigned insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (31 << 16); ++} ++ ++static int extract_zb(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++static unsigned insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | 31; ++} ++ ++static int extract_zc(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && (insn & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++ ++/* The displacement field of a Branch format insn. */ ++ ++static unsigned insert_bdisp(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "branch operand unaligned"; ++ return insn | ((value / 4) & 0x1FFFFF); ++} ++ ++static int extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); ++} ++ ++static unsigned insert_bdisp26(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "branch operand unaligned"; ++ return insn | ((value / 4) & 0x3FFFFFF); ++} ++ ++static int extract_bdisp26(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x3FFFFFF) ^ 0x2000000) - 0x2000000); ++} ++ ++/* The hint field of a JMP/JSR insn. */ ++/* sw use 16 bits hint disp. */ ++static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "jump hint unaligned"; ++ return insn | ((value / 4) & 0xFFFF); ++} ++ ++static int extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0xFFFF) ^ 0x8000) - 0x8000); ++} ++ ++/* The hint field of an CORE3 HW_JMP/JSR insn. */ ++ ++static unsigned insert_sw4hwjhint(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "jump hint unaligned"; ++ return insn | ((value / 4) & 0x1FFF); ++} ++ ++static int extract_sw4hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); ++} ++ ++/* The operands table. */ ++ ++const struct sw_64_operand sw_64_operands[] = { ++ /* The fields are bits, shift, insert, extract, flags */ ++ /* The zero index is used to indicate end-of-list */ ++#define UNUSED 0 ++ { 0, 0, 0, 0, 0, 0 }, ++ ++ /* The plain integer register fields. */ ++#define RA (UNUSED + 1) ++ { 5, 21, 0, SW_OPERAND_IR, 0, 0 }, ++#define RB (RA + 1) ++ { 5, 16, 0, SW_OPERAND_IR, 0, 0 }, ++#define RC (RB + 1) ++ { 5, 0, 0, SW_OPERAND_IR, 0, 0 }, ++ ++ /* The plain fp register fields. */ ++#define FA (RC + 1) ++ { 5, 21, 0, SW_OPERAND_FPR, 0, 0 }, ++#define FB (FA + 1) ++ { 5, 16, 0, SW_OPERAND_FPR, 0, 0 }, ++#define FC (FB + 1) ++ { 5, 0, 0, SW_OPERAND_FPR, 0, 0 }, ++ ++ /* The integer registers when they are ZERO. */ ++#define ZA (FC + 1) ++ { 5, 21, 0, SW_OPERAND_FAKE, insert_za, extract_za }, ++#define ZB (ZA + 1) ++ { 5, 16, 0, SW_OPERAND_FAKE, insert_zb, extract_zb }, ++#define ZC (ZB + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_zc, extract_zc }, ++ ++ /* The RB field when it needs parentheses. */ ++#define PRB (ZC + 1) ++ { 5, 16, 0, SW_OPERAND_IR | SW_OPERAND_PARENS, 0, 0 }, ++ ++ /* The RB field when it needs parentheses _and_ a preceding comma. */ ++#define CPRB (PRB + 1) ++ { 5, 16, 0, ++ SW_OPERAND_IR | SW_OPERAND_PARENS | SW_OPERAND_COMMA, 0, 0 }, ++ ++ /* The RB field when it must be the same as the RA field. */ ++#define RBA (CPRB + 1) ++ { 5, 16, 0, SW_OPERAND_FAKE, insert_rba, extract_rba }, ++ ++ /* The RC field when it must be the same as the RB field. */ ++#define RCA (RBA + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_rca, extract_rca }, ++ ++#define RDC (RCA + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_rdc, extract_rdc }, ++ ++ /* The RC field when it can *default* to RA. */ ++#define DRC1 (RDC + 1) ++ { 5, 0, 0, ++ SW_OPERAND_IR | SW_OPERAND_DEFAULT_FIRST, 0, 0 }, ++ ++ /* The RC field when it can *default* to RB. */ ++#define DRC2 (DRC1 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_IR | SW_OPERAND_DEFAULT_SECOND, 0, 0 }, ++ ++ /* The FC field when it can *default* to RA. */ ++#define DFC1 (DRC2 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_FPR | SW_OPERAND_DEFAULT_FIRST, 0, 0 }, ++ ++ /* The FC field when it can *default* to RB. */ ++#define DFC2 (DFC1 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_FPR | SW_OPERAND_DEFAULT_SECOND, 0, 0 }, ++ ++ /* The unsigned 8-bit literal of Operate format insns. */ ++#define LIT (DFC2 + 1) ++ { 8, 13, -LIT, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* The signed 16-bit displacement of Memory format insns. From here ++ we can't tell what relocation should be used, so don't use a default. */ ++#define MDISP (LIT + 1) ++ { 16, 0, -MDISP, SW_OPERAND_SIGNED, 0, 0 }, ++ ++ /* The signed "23-bit" aligned displacement of Branch format insns. */ ++#define BDISP (MDISP + 1) ++ { 21, 0, BFD_RELOC_23_PCREL_S2, ++ SW_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, ++ ++ /* The 26-bit hmcode function for sys_call and sys_call / b. */ ++#define HMFN (BDISP + 1) ++ { 25, 0, -HMFN, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* sw jsr/ret insntructions has no function bits. */ ++ /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint. */ ++#define JMPHINT (HMFN + 1) ++ { 16, 0, BFD_RELOC_SW_64_HINT, ++ SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, ++ insert_jhint, extract_jhint }, ++ ++ /* The optional hint to RET/JSR_COROUTINE. */ ++#define RETHINT (JMPHINT + 1) ++ { 16, 0, -RETHINT, ++ SW_OPERAND_UNSIGNED | SW_OPERAND_DEFAULT_ZERO, 0, 0 }, ++ ++ /* The 12-bit displacement for the core3 hw_{ld,st} (pal1b/pal1f) insns. */ ++#define HWDISP (RETHINT + 1) ++ { 12, 0, -HWDISP, SW_OPERAND_SIGNED, 0, 0 }, ++ ++ /* The 16-bit combined index/scoreboard mask for the core3 ++ hw_m[ft]pr (pal19/pal1d) insns. */ ++#define HWINDEX (HWDISP + 1) ++ { 16, 0, -HWINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* The 13-bit branch hint for the core3 hw_jmp/jsr (pal1e) insn. */ ++#define HWJMPHINT (HWINDEX + 1) ++ { 8, 0, -HWJMPHINT, ++ SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, ++ insert_sw4hwjhint, extract_sw4hwjhint }, ++ ++ /* for the third operand of ternary operands integer insn. */ ++#define R3 (HWJMPHINT + 1) ++ { 5, 5, 0, SW_OPERAND_IR, 0, 0 }, ++ /* The plain fp register fields */ ++#define F3 (R3 + 1) ++ { 5, 5, 0, SW_OPERAND_FPR, 0, 0 }, ++ /* sw simd settle instruction lit */ ++#define FMALIT (F3 + 1) ++ { 5, 5, -FMALIT, SW_OPERAND_UNSIGNED, 0, 0 }, //V1.1 ++#define LMDISP (FMALIT + 1) ++ { 15, 0, -LMDISP, SW_OPERAND_UNSIGNED, 0, 0 }, ++#define RPIINDEX (LMDISP + 1) ++ { 8, 0, -RPIINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, ++#define ATMDISP (RPIINDEX + 1) ++ { 12, 0, -ATMDISP, SW_OPERAND_SIGNED, 0, 0 }, ++#define DISP13 (ATMDISP + 1) ++ { 13, 13, -DISP13, SW_OPERAND_SIGNED, 0, 0}, ++#define BDISP26 (DISP13 + 1) ++ { 26, 0, 222, ++ SW_OPERAND_RELATIVE, insert_bdisp26, extract_bdisp26 }, ++#define DPFTH (BDISP26 + 1) ++ { 5, 21, -DPFTH, SW_OPERAND_UNSIGNED, 0, 0} ++}; ++ ++const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_operands); ++ ++/* Macros used to form opcodes. */ ++ ++/* The main opcode. */ ++#define OP(x) (((x) & 0x3F) << 26) ++#define OP_MASK 0xFC000000 ++ ++/* Branch format instructions. */ ++#define BRA_(oo) OP(oo) ++#define BRA_MASK OP_MASK ++#define BRA(oo) BRA_(oo), BRA_MASK ++ ++#ifdef HUANGLM20171113 ++/* Floating point format instructions. */ ++#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5)) ++#define FP_MASK (OP_MASK | 0xFFE0) ++#define FP(oo,fff) FP_(oo,fff), FP_MASK ++ ++#else ++/* Floating point format instructions. */ ++#define FP_(oo,fff) (OP(oo) | (((fff) & 0xFF) << 5)) ++#define FP_MASK (OP_MASK | 0x1FE0) ++#define FP(oo,fff) FP_(oo,fff), FP_MASK ++ ++#define FMA_(oo,fff) (OP(oo) | (((fff) & 0x3F) << 10 )) ++#define FMA_MASK (OP_MASK | 0xFC00) ++#define FMA(oo,fff) FMA_(oo,fff), FMA_MASK ++#endif ++ ++/* Memory format instructions. */ ++#define MEM_(oo) OP(oo) ++#define MEM_MASK OP_MASK ++#define MEM(oo) MEM_(oo), MEM_MASK ++ ++/* Memory/Func Code format instructions. */ ++#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF)) ++#define MFC_MASK (OP_MASK | 0xFFFF) ++#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK ++ ++/* Memory/Branch format instructions. */ ++#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14)) ++#define MBR_MASK (OP_MASK | 0xC000) ++#define MBR(oo,h) MBR_(oo,h), MBR_MASK ++ ++/* Now sw Operate format instructions is different with SW1. */ ++#define OPR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) ++#define OPRL_(oo,ff) (OPR_((oo), (ff)) ) ++#define OPR_MASK (OP_MASK | 0x1FE0) ++#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK ++#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK ++ ++/* sw ternary operands Operate format instructions. */ ++#define TOPR_(oo,ff) (OP(oo) | (((ff) & 0x07) << 10)) ++#define TOPRL_(oo,ff) (TOPR_((oo), (ff))) ++#define TOPR_MASK (OP_MASK | 0x1C00) ++#define TOPR(oo,ff) TOPR_(oo,ff), TOPR_MASK ++#define TOPRL(oo,ff) TOPRL_(oo,ff), TOPR_MASK ++ ++/* sw atom instructions. */ ++#define ATMEM_(oo,h) (OP(oo) | (((h) & 0xF) << 12)) ++#define ATMEM_MASK (OP_MASK | 0xF000) ++#define ATMEM(oo,h) ATMEM_(oo,h), ATMEM_MASK ++ ++/* sw privilege instructions. */ ++#define PRIRET_(oo,h) (OP(oo) | (((h) & 0x1) << 20)) ++#define PRIRET_MASK (OP_MASK | 0x100000) ++#define PRIRET(oo,h) PRIRET_(oo,h), PRIRET_MASK ++ ++/* sw rpi_rcsr,rpi_wcsr. */ ++#define CSR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 8)) ++#define CSR_MASK (OP_MASK | 0xFF00) ++#define CSR(oo,ff) CSR_(oo,ff), CSR_MASK ++ ++#define PCD_(oo,ff) (OP(oo) | (ff << 25)) ++#define PCD_MASK OP_MASK ++#define PCD(oo,ff) PCD_(oo,ff), PCD_MASK ++ ++/* Hardware memory (hw_{ld,st}) instructions. */ ++#define HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) ++#define HWMEM_MASK (OP_MASK | 0xF000) ++#define HWMEM(oo,f) HWMEM_(oo,f), HWMEM_MASK ++ ++#define LOGX_(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10)) ++#define LOGX_MASK (0xF0000000) ++#define LOGX(oo,ff) LOGX_(oo,ff), LOGX_MASK ++ ++/* Abbreviations for instruction subsets. */ ++#define BASE SW_OPCODE_BASE ++#define CORE3 SW_OPCODE_CORE3 ++ ++/* Common combinations of arguments. */ ++#define ARG_NONE { 0 } ++#define ARG_BRA { RA, BDISP } ++#define ARG_FBRA { FA, BDISP } ++#define ARG_FP { FA, FB, DFC1 } ++#define ARG_FPZ1 { ZA, FB, DFC1 } ++#define ARG_MEM { RA, MDISP, PRB } ++#define ARG_FMEM { FA, MDISP, PRB } ++#define ARG_OPR { RA, RB, DRC1 } ++ ++#define ARG_OPRCAS { RA, RB, RC } ++ ++#define ARG_OPRL { RA, LIT, DRC1 } ++#define ARG_OPRZ1 { ZA, RB, DRC1 } ++#define ARG_OPRLZ1 { ZA, LIT, RC } ++#define ARG_PCD { HMFN } ++#define ARG_HWMEM { RA, HWDISP, PRB } ++#define ARG_FPL { FA,LIT, DFC1 } ++#define ARG_FMA { FA,FB,F3, DFC1 } ++#define ARG_PREFETCH { ZA, MDISP, PRB } ++#define ARG_TOPR { RA, RB,R3, DRC1 } ++#define ARG_TOPRL { RA, LIT, R3,DRC1 } ++#define ARG_FMAL { FA,FB,FMALIT, DFC1 } ++#define ARG_ATMEM { RA, ATMDISP, PRB } ++#define ARG_VUAMEM { FA, ATMDISP, PRB } ++#define ARG_OPRLZ3 { RA, LIT, ZC } ++ ++#define ARG_DISP13 {DISP13, RC} ++ ++/* The opcode table. ++ ++ The format of the opcode table is: ++ ++ NAME OPCODE MASK { OPERANDS } ++ ++ NAME is the name of the instruction. ++ ++ OPCODE is the instruction opcode. ++ ++ MASK is the opcode mask; this is used to tell the disassembler ++ which bits in the actual opcode must match OPCODE. ++ ++ OPERANDS is the list of operands. ++ ++ The preceding macros merge the text of the OPCODE and MASK fields. ++ ++ The disassembler reads the table in order and prints the first ++ instruction which matches, so this table is sorted to put more ++ specific instructions before more general instructions. ++ ++ Otherwise, it is sorted by major opcode and minor function code. ++ */ ++ ++const struct sw_64_opcode sw_64_opcodes[] = { ++ { "sys_call/b", PCD(0x00,0x00), BASE, ARG_PCD }, ++ { "sys_call", PCD(0x00,0x01), BASE, ARG_PCD }, ++ ++ { "call", MEM(0x01), BASE, { RA, CPRB, JMPHINT } }, ++ { "ret", MEM(0x02), BASE, { RA, CPRB, RETHINT } }, ++ { "jmp", MEM(0x03), BASE, { RA, CPRB, JMPHINT } }, ++ { "br", BRA(0x04), BASE, { ZA, BDISP } }, ++ { "br", BRA(0x04), BASE, ARG_BRA }, ++ { "bsr", BRA(0x05), BASE, ARG_BRA }, ++ { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, ++ { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, ++ { "rtc", MFC(0x06,0x0020), BASE, { RA, ZB } }, ++ { "rtc", MFC(0x06,0x0020), BASE, { RA, RB } }, ++ { "rcid", MFC(0x06,0x0040), BASE, { RA , ZB} }, ++ { "halt", MFC(0x06,0x0080), BASE, { ZA, ZB } }, ++ { "rd_f", MFC(0x06,0x1000), CORE3, { RA, ZB } }, ++ { "wr_f", MFC(0x06,0x1020), CORE3, { RA, ZB } }, ++ { "rtid", MFC(0x06,0x1040), BASE, { RA } }, ++ { "pri_rcsr", CSR(0x06,0xFE), CORE3, { RA, RPIINDEX ,ZB } }, ++ { "pri_wcsr", CSR(0x06,0xFF), CORE3, { RA, RPIINDEX ,ZB } }, ++ { "pri_ret", PRIRET(0x07,0x0), BASE, { RA } }, ++ { "pri_ret/b", PRIRET(0x07,0x1), BASE, { RA } }, ++ { "lldw", ATMEM(0x08,0x0), BASE, ARG_ATMEM }, ++ { "lldl", ATMEM(0x08,0x1), BASE, ARG_ATMEM }, ++ { "ldw_inc", ATMEM(0x08,0x2), CORE3, ARG_ATMEM }, ++ { "ldl_inc", ATMEM(0x08,0x3), CORE3, ARG_ATMEM }, ++ { "ldw_dec", ATMEM(0x08,0x4), CORE3, ARG_ATMEM }, ++ { "ldl_dec", ATMEM(0x08,0x5), CORE3, ARG_ATMEM }, ++ { "ldw_set", ATMEM(0x08,0x6), CORE3, ARG_ATMEM }, ++ { "ldl_set", ATMEM(0x08,0x7), CORE3, ARG_ATMEM }, ++ { "lstw", ATMEM(0x08,0x8), BASE, ARG_ATMEM }, ++ { "lstl", ATMEM(0x08,0x9), BASE, ARG_ATMEM }, ++ { "ldw_nc", ATMEM(0x08,0xA), BASE, ARG_ATMEM }, ++ { "ldl_nc", ATMEM(0x08,0xB), BASE, ARG_ATMEM }, ++ { "ldd_nc", ATMEM(0x08,0xC), BASE, ARG_VUAMEM }, ++ { "stw_nc", ATMEM(0x08,0xD), BASE, ARG_ATMEM }, ++ { "stl_nc", ATMEM(0x08,0xE), BASE, ARG_ATMEM }, ++ { "std_nc", ATMEM(0x08,0xF), BASE, ARG_VUAMEM }, ++ { "fillcs", MEM(0x09), BASE, ARG_PREFETCH }, ++ { "ldwe", MEM(0x09), BASE, ARG_FMEM }, ++ { "e_fillcs", MEM(0x0A), BASE, ARG_PREFETCH }, ++ { "ldse", MEM(0x0A), BASE, ARG_FMEM }, ++ { "fillcs_e", MEM(0x0B), BASE, ARG_PREFETCH }, ++ { "ldde", MEM(0x0B), BASE, ARG_FMEM }, ++ { "vlds", MEM(0x0C), BASE, ARG_FMEM }, ++ { "vldd", MEM(0x0D), BASE, ARG_FMEM }, ++ { "vsts", MEM(0x0E), BASE, ARG_FMEM }, ++ { "vstd", MEM(0x0F), BASE, ARG_FMEM }, ++ { "addw", OPR(0x10,0x00), BASE, ARG_OPR }, ++ { "addw", OPRL(0x12,0x00), BASE, ARG_OPRL }, ++ { "subw", OPR(0x10,0x01), BASE, ARG_OPR }, ++ { "subw", OPRL(0x12,0x01), BASE, ARG_OPRL }, ++ { "s4addw", OPR(0x10,0x02), BASE, ARG_OPR }, ++ { "s4addw", OPRL(0x12,0x02), BASE, ARG_OPRL }, ++ { "s4subw", OPR(0x10,0x03), BASE, ARG_OPR }, ++ { "s4subw", OPRL(0x12,0x03), BASE, ARG_OPRL }, ++ { "s8addw", OPR(0x10,0x04), BASE, ARG_OPR }, ++ { "s8addw", OPRL(0x12,0x04), BASE, ARG_OPRL }, ++ { "s8subw", OPR(0x10,0x05), BASE, ARG_OPR }, ++ { "s8subw", OPRL(0x12,0x05), BASE, ARG_OPRL }, ++ { "addl", OPR(0x10,0x08), BASE, ARG_OPR }, ++ { "addl", OPRL(0x12,0x08), BASE, ARG_OPRL }, ++ { "subl", OPR(0x10,0x09), BASE, ARG_OPR }, ++ { "subl", OPRL(0x12,0x09), BASE, ARG_OPRL }, ++ { "s4addl", OPR(0x10,0x0A), BASE, ARG_OPR }, ++ { "s4addl", OPRL(0x12,0x0A), BASE, ARG_OPRL }, ++ { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR }, ++ { "s4subl", OPRL(0x12,0x0B), BASE, ARG_OPRL }, ++ { "s8addl", OPR(0x10,0x0C), BASE, ARG_OPR }, ++ { "s8addl", OPRL(0x12,0x0C), BASE, ARG_OPRL }, ++ { "s8subl", OPR(0x10,0x0D), BASE, ARG_OPR }, ++ { "s8subl", OPRL(0x12,0x0D), BASE, ARG_OPRL }, ++ { "mulw", OPR(0x10,0x10), BASE, ARG_OPR }, ++ { "mulw", OPRL(0x12,0x10), BASE, ARG_OPRL }, ++ { "mull", OPR(0x10,0x18), BASE, ARG_OPR }, ++ { "mull", OPRL(0x12,0x18), BASE, ARG_OPRL }, ++ { "umulh", OPR(0x10,0x19), BASE, ARG_OPR }, ++ { "umulh", OPRL(0x12,0x19), BASE, ARG_OPRL }, ++ { "cmpeq", OPR(0x10,0x28), BASE, ARG_OPR }, ++ { "cmpeq", OPRL(0x12,0x28), BASE, ARG_OPRL }, ++ { "cmplt", OPR(0x10,0x29), BASE, ARG_OPR }, ++ { "cmplt", OPRL(0x12,0x29), BASE, ARG_OPRL }, ++ { "cmple", OPR(0x10,0x2A), BASE, ARG_OPR }, ++ { "cmple", OPRL(0x12,0x2A), BASE, ARG_OPRL }, ++ { "cmpult", OPR(0x10,0x2B), BASE, ARG_OPR }, ++ { "cmpult", OPRL(0x12,0x2B), BASE, ARG_OPRL }, ++ { "cmpule", OPR(0x10,0x2C), BASE, ARG_OPR }, ++ { "cmpule", OPRL(0x12,0x2C), BASE, ARG_OPRL }, ++ ++ { "and", OPR(0x10,0x38), BASE, ARG_OPR }, ++ { "and", OPRL(0x12,0x38),BASE, ARG_OPRL }, ++ { "bic", OPR(0x10,0x39), BASE, ARG_OPR }, ++ { "bic", OPRL(0x12,0x39),BASE, ARG_OPRL }, ++ { "bis", OPR(0x10,0x3A), BASE, ARG_OPR }, ++ { "bis", OPRL(0x12,0x3A),BASE, ARG_OPRL }, ++ { "ornot", OPR(0x10,0x3B), BASE, ARG_OPR }, ++ { "ornot", OPRL(0x12,0x3B),BASE, ARG_OPRL }, ++ { "xor", OPR(0x10,0x3C), BASE, ARG_OPR }, ++ { "xor", OPRL(0x12,0x3C),BASE, ARG_OPRL }, ++ { "eqv", OPR(0x10,0x3D), BASE, ARG_OPR }, ++ { "eqv", OPRL(0x12,0x3D),BASE, ARG_OPRL }, ++ { "inslb", OPR(0x10,0x40), BASE, ARG_OPR }, ++ { "inslb", OPRL(0x12,0x40),BASE, ARG_OPRL }, ++ { "inslh", OPR(0x10,0x41), BASE, ARG_OPR }, ++ { "inslh", OPRL(0x12,0x41),BASE, ARG_OPRL }, ++ { "inslw", OPR(0x10,0x42), BASE, ARG_OPR }, ++ { "inslw", OPRL(0x12,0x42),BASE, ARG_OPRL }, ++ { "insll", OPR(0x10,0x43), BASE, ARG_OPR }, ++ { "insll", OPRL(0x12,0x43),BASE, ARG_OPRL }, ++ { "inshb", OPR(0x10,0x44), BASE, ARG_OPR }, ++ { "inshb", OPRL(0x12,0x44),BASE, ARG_OPRL }, ++ { "inshh", OPR(0x10,0x45), BASE, ARG_OPR }, ++ { "inshh", OPRL(0x12,0x45),BASE, ARG_OPRL }, ++ { "inshw", OPR(0x10,0x46), BASE, ARG_OPR }, ++ { "inshw", OPRL(0x12,0x46),BASE, ARG_OPRL }, ++ { "inshl", OPR(0x10,0x47), BASE, ARG_OPR }, ++ { "inshl", OPRL(0x12,0x47),BASE, ARG_OPRL }, ++ ++ { "sll", OPR(0x10,0x48), BASE, ARG_OPR }, ++ { "sll", OPRL(0x12,0x48),BASE, ARG_OPRL }, ++ { "srl", OPR(0x10,0x49), BASE, ARG_OPR }, ++ { "srl", OPRL(0x12,0x49),BASE, ARG_OPRL }, ++ { "sra", OPR(0x10,0x4A), BASE, ARG_OPR }, ++ { "sra", OPRL(0x12,0x4A),BASE, ARG_OPRL }, ++ { "extlb", OPR(0x10,0x50), BASE, ARG_OPR }, ++ { "extlb", OPRL(0x12,0x50),BASE, ARG_OPRL }, ++ { "extlh", OPR(0x10,0x51), BASE, ARG_OPR }, ++ { "extlh", OPRL(0x12,0x51),BASE, ARG_OPRL }, ++ { "extlw", OPR(0x10,0x52), BASE, ARG_OPR }, ++ { "extlw", OPRL(0x12,0x52),BASE, ARG_OPRL }, ++ { "extll", OPR(0x10,0x53), BASE, ARG_OPR }, ++ { "extll", OPRL(0x12,0x53),BASE, ARG_OPRL }, ++ { "exthb", OPR(0x10,0x54), BASE, ARG_OPR }, ++ { "exthb", OPRL(0x12,0x54),BASE, ARG_OPRL }, ++ { "exthh", OPR(0x10,0x55), BASE, ARG_OPR }, ++ { "exthh", OPRL(0x12,0x55),BASE, ARG_OPRL }, ++ { "exthw", OPR(0x10,0x56), BASE, ARG_OPR }, ++ { "exthw", OPRL(0x12,0x56),BASE, ARG_OPRL }, ++ { "exthl", OPR(0x10,0x57), BASE, ARG_OPR }, ++ { "exthl", OPRL(0x12,0x57),BASE, ARG_OPRL }, ++ { "ctpop", OPR(0x10,0x58), BASE, ARG_OPRZ1 }, ++ { "ctlz", OPR(0x10,0x59), BASE, ARG_OPRZ1 }, ++ { "cttz", OPR(0x10,0x5A), BASE, ARG_OPRZ1 }, ++ { "masklb", OPR(0x10,0x60), BASE, ARG_OPR }, ++ { "masklb", OPRL(0x12,0x60),BASE, ARG_OPRL }, ++ { "masklh", OPR(0x10,0x61), BASE, ARG_OPR }, ++ { "masklh", OPRL(0x12,0x61),BASE, ARG_OPRL }, ++ { "masklw", OPR(0x10,0x62), BASE, ARG_OPR }, ++ { "masklw", OPRL(0x12,0x62),BASE, ARG_OPRL }, ++ { "maskll", OPR(0x10,0x63), BASE, ARG_OPR }, ++ { "maskll", OPRL(0x12,0x63),BASE, ARG_OPRL }, ++ { "maskhb", OPR(0x10,0x64), BASE, ARG_OPR }, ++ { "maskhb", OPRL(0x12,0x64),BASE, ARG_OPRL }, ++ { "maskhh", OPR(0x10,0x65), BASE, ARG_OPR }, ++ { "maskhh", OPRL(0x12,0x65),BASE, ARG_OPRL }, ++ { "maskhw", OPR(0x10,0x66), BASE, ARG_OPR }, ++ { "maskhw", OPRL(0x12,0x66),BASE, ARG_OPRL }, ++ { "maskhl", OPR(0x10,0x67), BASE, ARG_OPR }, ++ { "maskhl", OPRL(0x12,0x67),BASE, ARG_OPRL }, ++ { "zap", OPR(0x10,0x68), BASE, ARG_OPR }, ++ { "zap", OPRL(0x12,0x68),BASE, ARG_OPRL }, ++ { "zapnot", OPR(0x10,0x69), BASE, ARG_OPR }, ++ { "zapnot", OPRL(0x12,0x69),BASE, ARG_OPRL }, ++ { "sextb", OPR(0x10,0x6A), BASE, ARG_OPRZ1}, ++ { "sextb", OPRL(0x12,0x6A),BASE, ARG_OPRLZ1 }, ++ { "sexth", OPR(0x10,0x6B), BASE, ARG_OPRZ1 }, ++ { "sexth", OPRL(0x12,0x6B),BASE, ARG_OPRLZ1 }, ++ { "cmpgeb", OPR(0x10,0x6C), BASE, ARG_OPR }, ++ { "cmpgeb", OPRL(0x12,0x6C),BASE, ARG_OPRL }, ++ { "fimovs", OPR(0x10,0x70), BASE, { FA, ZB, RC } }, ++ { "fimovd", OPR(0x10,0x78), BASE, { FA, ZB, RC } }, ++ { "seleq", TOPR(0x11,0x0), BASE, ARG_TOPR }, ++ { "seleq", TOPRL(0x13,0x0),BASE, ARG_TOPRL }, ++ { "selge", TOPR(0x11,0x1), BASE, ARG_TOPR }, ++ { "selge", TOPRL(0x13,0x1),BASE, ARG_TOPRL }, ++ { "selgt", TOPR(0x11,0x2), BASE, ARG_TOPR }, ++ { "selgt", TOPRL(0x13,0x2),BASE, ARG_TOPRL }, ++ { "selle", TOPR(0x11,0x3), BASE, ARG_TOPR }, ++ { "selle", TOPRL(0x13,0x3),BASE, ARG_TOPRL }, ++ { "sellt", TOPR(0x11,0x4), BASE, ARG_TOPR }, ++ { "sellt", TOPRL(0x13,0x4),BASE, ARG_TOPRL }, ++ { "selne", TOPR(0x11,0x5), BASE, ARG_TOPR }, ++ { "selne", TOPRL(0x13,0x5),BASE, ARG_TOPRL }, ++ { "sellbc", TOPR(0x11,0x6), BASE, ARG_TOPR }, ++ { "sellbc", TOPRL(0x13,0x6),BASE, ARG_TOPRL }, ++ { "sellbs", TOPR(0x11,0x7), BASE, ARG_TOPR }, ++ { "sellbs", TOPRL(0x13,0x7),BASE, ARG_TOPRL }, ++ { "vlog", LOGX(0x14,0x00), BASE, ARG_FMA }, ++ ++ { "fadds", FP(0x18,0x00), BASE, ARG_FP }, ++ { "faddd", FP(0x18,0x01), BASE, ARG_FP }, ++ { "fsubs", FP(0x18,0x02), BASE, ARG_FP }, ++ { "fsubd", FP(0x18,0x03), BASE, ARG_FP }, ++ { "fmuls", FP(0x18,0x04), BASE, ARG_FP }, ++ { "fmuld", FP(0x18,0x05), BASE, ARG_FP }, ++ { "fdivs", FP(0x18,0x06), BASE, ARG_FP }, ++ { "fdivd", FP(0x18,0x07), BASE, ARG_FP }, ++ { "fsqrts", FP(0x18,0x08), BASE, ARG_FPZ1 }, ++ { "fsqrtd", FP(0x18,0x09), BASE, ARG_FPZ1 }, ++ { "fcmpeq", FP(0x18,0x10), BASE, ARG_FP }, ++ { "fcmple", FP(0x18,0x11), BASE, ARG_FP }, ++ { "fcmplt", FP(0x18,0x12), BASE, ARG_FP }, ++ { "fcmpun", FP(0x18,0x13), BASE, ARG_FP }, ++ ++ { "fcvtsd", FP(0x18,0x20), BASE, ARG_FPZ1 }, ++ { "fcvtds", FP(0x18,0x21), BASE, ARG_FPZ1 }, ++ { "fcvtdl_g", FP(0x18,0x22), BASE, ARG_FPZ1 }, ++ { "fcvtdl_p", FP(0x18,0x23), BASE, ARG_FPZ1 }, ++ { "fcvtdl_z", FP(0x18,0x24), BASE, ARG_FPZ1 }, ++ { "fcvtdl_n", FP(0x18,0x25), BASE, ARG_FPZ1 }, ++ { "fcvtdl", FP(0x18,0x27), BASE, ARG_FPZ1 }, ++ { "fcvtwl", FP(0x18,0x28), BASE, ARG_FPZ1 }, ++ { "fcvtlw", FP(0x18,0x29), BASE, ARG_FPZ1 }, ++ { "fcvtls", FP(0x18,0x2d), BASE, ARG_FPZ1 }, ++ { "fcvtld", FP(0x18,0x2f), BASE, ARG_FPZ1 }, ++ { "fcpys", FP(0x18,0x30), BASE, ARG_FP }, ++ { "fcpyse", FP(0x18,0x31), BASE, ARG_FP }, ++ { "fcpysn", FP(0x18,0x32), BASE, ARG_FP }, ++ { "ifmovs", FP(0x18,0x40), BASE, { RA, ZB, FC } }, ++ { "ifmovd", FP(0x18,0x41), BASE, { RA, ZB, FC } }, ++ { "rfpcr", FP(0x18,0x50), BASE, { FA, RBA, RCA } }, ++ { "wfpcr", FP(0x18,0x51), BASE, { FA, RBA, RCA } }, ++ { "setfpec0", FP(0x18,0x54), BASE, ARG_NONE }, ++ { "setfpec1", FP(0x18,0x55), BASE, ARG_NONE }, ++ { "setfpec2", FP(0x18,0x56), BASE, ARG_NONE }, ++ { "setfpec3", FP(0x18,0x57), BASE, ARG_NONE }, ++ { "fmas", FMA(0x19,0x00), BASE, ARG_FMA }, ++ { "fmad", FMA(0x19,0x01), BASE, ARG_FMA }, ++ { "fmss", FMA(0x19,0x02), BASE, ARG_FMA }, ++ { "fmsd", FMA(0x19,0x03), BASE, ARG_FMA }, ++ { "fnmas", FMA(0x19,0x04), BASE, ARG_FMA }, ++ { "fnmad", FMA(0x19,0x05), BASE, ARG_FMA }, ++ { "fnmss", FMA(0x19,0x06), BASE, ARG_FMA }, ++ { "fnmsd", FMA(0x19,0x07), BASE, ARG_FMA }, ++ { "fseleq", FMA(0x19,0x10), BASE, ARG_FMA }, ++ { "fselne", FMA(0x19,0x11), BASE, ARG_FMA }, ++ { "fsellt", FMA(0x19,0x12), BASE, ARG_FMA }, ++ { "fselle", FMA(0x19,0x13), BASE, ARG_FMA }, ++ { "fselgt", FMA(0x19,0x14), BASE, ARG_FMA }, ++ { "fselge", FMA(0x19,0x15), BASE, ARG_FMA }, ++ { "vaddw", FP(0x1A,0x00), BASE, ARG_FP }, ++ { "vaddw", FP(0x1A,0x20), BASE, ARG_FPL }, ++ { "vsubw", FP(0x1A,0x01), BASE, ARG_FP }, ++ { "vsubw", FP(0x1A,0x21), BASE, ARG_FPL }, ++ { "vcmpgew", FP(0x1A,0x02), BASE, ARG_FP }, ++ { "vcmpgew", FP(0x1A,0x22), BASE, ARG_FPL }, ++ { "vcmpeqw", FP(0x1A,0x03), BASE, ARG_FP }, ++ { "vcmpeqw", FP(0x1A,0x23), BASE, ARG_FPL }, ++ { "vcmplew", FP(0x1A,0x04), BASE, ARG_FP }, ++ { "vcmplew", FP(0x1A,0x24), BASE, ARG_FPL }, ++ { "vcmpltw", FP(0x1A,0x05), BASE, ARG_FP }, ++ { "vcmpltw", FP(0x1A,0x25), BASE, ARG_FPL }, ++ { "vcmpulew", FP(0x1A,0x06), BASE, ARG_FP }, ++ { "vcmpulew", FP(0x1A,0x26), BASE, ARG_FPL }, ++ { "vcmpultw", FP(0x1A,0x07), BASE, ARG_FP }, ++ { "vcmpultw", FP(0x1A,0x27), BASE, ARG_FPL }, ++ ++ { "vsllw", FP(0x1A,0x08), BASE, ARG_FP }, ++ { "vsllw", FP(0x1A,0x28), BASE, ARG_FPL }, ++ { "vsrlw", FP(0x1A,0x09), BASE, ARG_FP }, ++ { "vsrlw", FP(0x1A,0x29), BASE, ARG_FPL }, ++ { "vsraw", FP(0x1A,0x0A), BASE, ARG_FP }, ++ { "vsraw", FP(0x1A,0x2A), BASE, ARG_FPL }, ++ { "vrolw", FP(0x1A,0x0B), BASE, ARG_FP }, ++ { "vrolw", FP(0x1A,0x2B), BASE, ARG_FPL }, ++ { "sllow", FP(0x1A,0x0C), BASE, ARG_FP }, ++ { "sllow", FP(0x1A,0x2C), BASE, ARG_FPL }, ++ { "srlow", FP(0x1A,0x0D), BASE, ARG_FP }, ++ { "srlow", FP(0x1A,0x2D), BASE, ARG_FPL }, ++ { "vaddl", FP(0x1A,0x0E), BASE, ARG_FP }, ++ { "vaddl", FP(0x1A,0x2E), BASE, ARG_FPL }, ++ { "vsubl", FP(0x1A,0x0F), BASE, ARG_FP }, ++ { "vsubl", FP(0x1A,0x2F), BASE, ARG_FPL }, ++ { "ctpopow", FP(0x1A,0x18), BASE, { FA, ZB, DFC1 } }, ++ { "ctlzow", FP(0x1A,0x19), BASE, { FA, ZB, DFC1 } }, ++ { "vucaddw", FP(0x1A,0x40), BASE, ARG_FP }, ++ { "vucaddw", FP(0x1A,0x60), BASE, ARG_FPL }, ++ { "vucsubw", FP(0x1A,0x41), BASE, ARG_FP }, ++ { "vucsubw", FP(0x1A,0x61), BASE, ARG_FPL }, ++ { "vucaddh", FP(0x1A,0x42), BASE, ARG_FP }, ++ { "vucaddh", FP(0x1A,0x62), BASE, ARG_FPL }, ++ { "vucsubh", FP(0x1A,0x43), BASE, ARG_FP }, ++ { "vucsubh", FP(0x1A,0x63), BASE, ARG_FPL }, ++ { "vucaddb", FP(0x1A,0x44), BASE, ARG_FP }, ++ { "vucaddb", FP(0x1A,0x64), BASE, ARG_FPL }, ++ { "vucsubb", FP(0x1A,0x45), BASE, ARG_FP }, ++ { "vucsubb", FP(0x1A,0x65), BASE, ARG_FPL }, ++ { "vadds", FP(0x1A,0x80), BASE, ARG_FP }, ++ { "vaddd", FP(0x1A,0x81), BASE, ARG_FP }, ++ { "vsubs", FP(0x1A,0x82), BASE, ARG_FP }, ++ { "vsubd", FP(0x1A,0x83), BASE, ARG_FP }, ++ { "vmuls", FP(0x1A,0x84), BASE, ARG_FP }, ++ { "vmuld", FP(0x1A,0x85), BASE, ARG_FP }, ++ { "vdivs", FP(0x1A,0x86), BASE, ARG_FP }, ++ { "vdivd", FP(0x1A,0x87), BASE, ARG_FP }, ++ { "vsqrts", FP(0x1A,0x88), BASE, ARG_FPZ1 }, ++ { "vsqrtd", FP(0x1A,0x89), BASE, ARG_FPZ1 }, ++ { "vfcmpeq", FP(0x1A,0x8C), BASE, ARG_FP }, ++ { "vfcmple", FP(0x1A,0x8D), BASE, ARG_FP }, ++ { "vfcmplt", FP(0x1A,0x8E), BASE, ARG_FP }, ++ { "vfcmpun", FP(0x1A,0x8F), BASE, ARG_FP }, ++ { "vcpys", FP(0x1A,0x90), BASE, ARG_FP }, ++ { "vcpyse", FP(0x1A,0x91), BASE, ARG_FP }, ++ { "vcpysn", FP(0x1A,0x92), BASE, ARG_FP }, ++ { "vmas", FMA(0x1B,0x00), BASE, ARG_FMA }, ++ { "vmad", FMA(0x1B,0x01), BASE, ARG_FMA }, ++ { "vmss", FMA(0x1B,0x02), BASE, ARG_FMA }, ++ { "vmsd", FMA(0x1B,0x03), BASE, ARG_FMA }, ++ { "vnmas", FMA(0x1B,0x04), BASE, ARG_FMA }, ++ { "vnmad", FMA(0x1B,0x05), BASE, ARG_FMA }, ++ { "vnmss", FMA(0x1B,0x06), BASE, ARG_FMA }, ++ { "vnmsd", FMA(0x1B,0x07), BASE, ARG_FMA }, ++ { "vfseleq", FMA(0x1B,0x10), BASE, ARG_FMA }, ++ { "vfsellt", FMA(0x1B,0x12), BASE, ARG_FMA }, ++ { "vfselle", FMA(0x1B,0x13), BASE, ARG_FMA }, ++ { "vseleqw", FMA(0x1B,0x18), BASE, ARG_FMA }, ++ { "vseleqw", FMA(0x1B,0x38), BASE, ARG_FMAL }, ++ { "vsellbcw", FMA(0x1B,0x19), BASE, ARG_FMA }, ++ { "vsellbcw", FMA(0x1B,0x39), BASE, ARG_FMAL }, ++ { "vselltw", FMA(0x1B,0x1A), BASE, ARG_FMA }, ++ { "vselltw", FMA(0x1B,0x3A), BASE, ARG_FMAL }, ++ { "vsellew", FMA(0x1B,0x1B), BASE, ARG_FMA }, ++ { "vsellew", FMA(0x1B,0x3B), BASE, ARG_FMAL }, ++ { "vinsw", FMA(0x1B,0x20), BASE, ARG_FMAL }, ++ { "vinsf", FMA(0x1B,0x21), BASE, ARG_FMAL }, ++ { "vextw", FMA(0x1B,0x22), BASE, { FA, FMALIT, DFC1 }}, ++ { "vextf", FMA(0x1B,0x23), BASE, { FA, FMALIT, DFC1 }}, ++ { "vcpyw", FMA(0x1B,0x24), BASE, { FA, DFC1 }}, ++ { "vcpyf", FMA(0x1B,0x25), BASE, { FA, DFC1 }}, ++ { "vconw", FMA(0x1B,0x26), BASE, ARG_FMA }, ++ { "vshfw", FMA(0x1B,0x27), BASE, ARG_FMA }, ++ { "vcons", FMA(0x1B,0x28), BASE, ARG_FMA }, ++ { "vcond", FMA(0x1B,0x29), BASE, ARG_FMA }, ++ { "vldw_u", ATMEM(0x1C,0x0), BASE, ARG_VUAMEM }, ++ { "vstw_u", ATMEM(0x1C,0x1), BASE, ARG_VUAMEM }, ++ { "vlds_u", ATMEM(0x1C,0x2), BASE, ARG_VUAMEM }, ++ { "vsts_u", ATMEM(0x1C,0x3), BASE, ARG_VUAMEM }, ++ { "vldd_u", ATMEM(0x1C,0x4), BASE, ARG_VUAMEM }, ++ { "vstd_u", ATMEM(0x1C,0x5), BASE, ARG_VUAMEM }, ++ { "vstw_ul", ATMEM(0x1C,0x8), BASE, ARG_VUAMEM }, ++ { "vstw_uh", ATMEM(0x1C,0x9), BASE, ARG_VUAMEM }, ++ { "vsts_ul", ATMEM(0x1C,0xA), BASE, ARG_VUAMEM }, ++ { "vsts_uh", ATMEM(0x1C,0xB), BASE, ARG_VUAMEM }, ++ { "vstd_ul", ATMEM(0x1C,0xC), BASE, ARG_VUAMEM }, ++ { "vstd_uh", ATMEM(0x1C,0xD), BASE, ARG_VUAMEM }, ++ { "vldd_nc", ATMEM(0x1C,0xE), BASE, ARG_VUAMEM }, ++ { "vstd_nc", ATMEM(0x1C,0xF), BASE, ARG_VUAMEM }, ++ ++ { "flushd", MEM(0x20), BASE, ARG_PREFETCH }, ++ { "ldbu", MEM(0x20), BASE, ARG_MEM }, ++ { "evictdg", MEM(0x21), BASE, ARG_PREFETCH }, ++ { "ldhu", MEM(0x21), BASE, ARG_MEM }, ++ { "s_fillcs", MEM(0x22), BASE, ARG_PREFETCH }, ++ { "ldw", MEM(0x22), BASE, ARG_MEM }, ++ { "s_fillde", MEM(0x23), BASE, ARG_PREFETCH }, ++ { "ldl", MEM(0x23), BASE, ARG_MEM }, ++ { "evictdl", MEM(0x24), BASE, ARG_PREFETCH }, ++ { "ldl_u", MEM(0x24), BASE, ARG_MEM }, ++ { "pri_ldw/p", HWMEM(0x25,0x0), BASE, ARG_HWMEM }, ++ { "pri_ldw/v", HWMEM(0x25,0x8), BASE, ARG_HWMEM }, ++ { "pri_ldl/p", HWMEM(0x25,0x1), BASE, ARG_HWMEM }, ++ { "pri_ldl/v", HWMEM(0x25,0x9), BASE, ARG_HWMEM }, ++ { "fillde", MEM(0x26), BASE, ARG_PREFETCH }, ++ { "flds", MEM(0x26), BASE, ARG_FMEM }, ++ { "fillde_e", MEM(0x27), BASE, ARG_PREFETCH }, ++ { "fldd", MEM(0x27), BASE, ARG_FMEM }, ++ ++ { "stb", MEM(0x28), BASE, ARG_MEM }, ++ { "sth", MEM(0x29), BASE, ARG_MEM }, ++ { "stw", MEM(0x2A), BASE, ARG_MEM }, ++ { "stl", MEM(0x2B), BASE, ARG_MEM }, ++ { "stl_u", MEM(0x2C), BASE, ARG_MEM }, ++ { "pri_stw/p", HWMEM(0x2D,0x0), BASE, ARG_HWMEM }, ++ { "pri_stw/v", HWMEM(0x2D,0x8), BASE, ARG_HWMEM }, ++ { "pri_stl/p", HWMEM(0x2D,0x1), BASE, ARG_HWMEM }, ++ { "pri_stl/v", HWMEM(0x2D,0x9), BASE, ARG_HWMEM }, ++ { "fsts", MEM(0x2E), BASE, ARG_FMEM }, ++ { "fstd", MEM(0x2F), BASE, ARG_FMEM }, ++ { "beq", BRA(0x30), BASE, ARG_BRA }, ++ { "bne", BRA(0x31), BASE, ARG_BRA }, ++ { "blt", BRA(0x32), BASE, ARG_BRA }, ++ { "ble", BRA(0x33), BASE, ARG_BRA }, ++ { "bgt", BRA(0x34), BASE, ARG_BRA }, ++ { "bge", BRA(0x35), BASE, ARG_BRA }, ++ { "blbc", BRA(0x36), BASE, ARG_BRA }, ++ { "blbs", BRA(0x37), BASE, ARG_BRA }, ++ ++ { "fbeq", BRA(0x38), BASE, ARG_FBRA }, ++ { "fbne", BRA(0x39), BASE, ARG_FBRA }, ++ { "fblt", BRA(0x3A), BASE, ARG_FBRA }, ++ { "fble", BRA(0x3B), BASE, ARG_FBRA }, ++ { "fbgt", BRA(0x3C), BASE, ARG_FBRA }, ++ { "fbge", BRA(0x3D), BASE, ARG_FBRA }, ++ { "ldi", MEM(0x3E), BASE, ARG_MEM }, ++ { "ldih", MEM(0x3F), BASE, ARG_MEM }, ++}; ++ ++const unsigned sw_64_num_opcodes = sizeof(sw_64_opcodes) / sizeof(*sw_64_opcodes); ++ ++/* OSF register names. */ ++ ++static const char * const osf_regnames[64] = { ++ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", ++ "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", ++ "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", ++ "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", ++ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", ++ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", ++ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", ++ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" ++}; ++ ++/* VMS register names. */ ++ ++static const char * const vms_regnames[64] = { ++ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", ++ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", ++ "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", ++ "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", ++ "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", ++ "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", ++ "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", ++ "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" ++}; ++ ++int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) ++{ ++ static const struct sw_64_opcode *opcode_index[SW_NOPS + 1]; ++ const char * const * regnames; ++ const struct sw_64_opcode *opcode, *opcode_end; ++ const unsigned char *opindex; ++ unsigned insn, op, isa_mask; ++ int need_comma; ++ ++ /* Initialize the majorop table the first time through */ ++ if (!opcode_index[0]) { ++ opcode = sw_64_opcodes; ++ opcode_end = opcode + sw_64_num_opcodes; ++ ++ for (op = 0; op < SW_NOPS; ++op) { ++ opcode_index[op] = opcode; ++ if ((SW_LITOP (opcode->opcode) != 0x10) && (SW_LITOP (opcode->opcode) != 0x11)) { ++ while (opcode < opcode_end && op == SW_OP (opcode->opcode)) ++ ++opcode; ++ } else { ++ while (opcode < opcode_end && op == SW_LITOP (opcode->opcode)) ++ ++opcode; ++ } ++ } ++ opcode_index[op] = opcode; ++ } ++ ++ if (info->flavour == bfd_target_evax_flavour) ++ regnames = vms_regnames; ++ else ++ regnames = osf_regnames; ++ isa_mask = SW_OPCODE_NOHM; ++ switch (info->mach) { ++ case bfd_mach_sw_64_core3: ++ isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE3; ++ break; ++ } ++ ++ /* Read the insn into a host word */ ++ { ++ bfd_byte buffer[4]; ++ int status = (*info->read_memory_func) (memaddr, buffer, 4, info); ++ if (status != 0) { ++ (*info->memory_error_func) (status, memaddr, info); ++ return -1; ++ } ++ insn = bfd_getl32 (buffer); ++ } ++ ++ /* Get the major opcode of the instruction. */ ++ if ((SW_LITOP (insn) == 0x10) || (SW_LITOP (insn) == 0x11)) ++ op = SW_LITOP (insn); ++ else if ((SW_OP(insn) & 0x3C) == 0x14 ) ++ op = 0x14; ++ else ++ op = SW_OP (insn); ++ ++ /* Find the first match in the opcode table. */ ++ opcode_end = opcode_index[op + 1]; ++ for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) { ++ if ((insn ^ opcode->opcode) & opcode->mask) ++ continue; ++ ++ if (!(opcode->flags & isa_mask)) ++ continue; ++ ++ /* Make two passes over the operands. First see if any of them ++ have extraction functions, and, if they do, make sure the ++ instruction is valid. */ ++ { ++ int invalid = 0; ++ for (opindex = opcode->operands; *opindex != 0; opindex++) { ++ const struct sw_64_operand *operand = sw_64_operands + *opindex; ++ if (operand->extract) ++ (*operand->extract) (insn, &invalid); ++ } ++ if (invalid) ++ continue; ++ } ++ ++ /* The instruction is valid. */ ++ goto found; ++ } ++ ++ /* No instruction found */ ++ (*info->fprintf_func) (info->stream, ".long %#08x", insn); ++ ++ return 4; ++ ++found: ++ if (!strncmp("sys_call",opcode->name,8)) { ++ if (insn & (0x1 << 25)) ++ (*info->fprintf_func) (info->stream, "%s", "sys_call"); ++ else ++ (*info->fprintf_func) (info->stream, "%s", "sys_call/b"); ++ } else ++ (*info->fprintf_func) (info->stream, "%s", opcode->name); ++ ++ /* get zz[7:6] and zz[5:0] to form truth for vlog */ ++ if (!strcmp(opcode->name, "vlog")) ++ { ++ unsigned int truth; ++ char tr[4]; ++ truth=(SW_OP(insn) & 3) << 6; ++ truth = truth | ((insn & 0xFC00) >> 10); ++ sprintf(tr,"%x",truth); ++ (*info->fprintf_func) (info->stream, "%s", tr); ++ } ++ if (opcode->operands[0] != 0) ++ (*info->fprintf_func) (info->stream, "\t"); ++ ++ /* Now extract and print the operands. */ ++ need_comma = 0; ++ for (opindex = opcode->operands; *opindex != 0; opindex++) { ++ const struct sw_64_operand *operand = sw_64_operands + *opindex; ++ int value; ++ ++ /* Operands that are marked FAKE are simply ignored. We ++ already made sure that the extract function considered ++ the instruction to be valid. */ ++ if ((operand->flags & SW_OPERAND_FAKE) != 0) ++ continue; ++ ++ /* Extract the value from the instruction. */ ++ if (operand->extract) ++ value = (*operand->extract) (insn, (int *) NULL); ++ else { ++ value = (insn >> operand->shift) & ((1 << operand->bits) - 1); ++ if (operand->flags & SW_OPERAND_SIGNED) { ++ int signbit = 1 << (operand->bits - 1); ++ value = (value ^ signbit) - signbit; ++ } ++ } ++ ++ if (need_comma && ++ ((operand->flags & (SW_OPERAND_PARENS | SW_OPERAND_COMMA)) ++ != SW_OPERAND_PARENS)) { ++ (*info->fprintf_func) (info->stream, ","); ++ } ++ if (operand->flags & SW_OPERAND_PARENS) ++ (*info->fprintf_func) (info->stream, "("); ++ ++ /* Print the operand as directed by the flags. */ ++ if (operand->flags & SW_OPERAND_IR) ++ (*info->fprintf_func) (info->stream, "%s", regnames[value]); ++ else if (operand->flags & SW_OPERAND_FPR) ++ (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); ++ else if (operand->flags & SW_OPERAND_RELATIVE) ++ (*info->print_address_func) (memaddr + 4 + value, info); ++ else if (operand->flags & SW_OPERAND_SIGNED) ++ (*info->fprintf_func) (info->stream, "%d", value); ++ else ++ (*info->fprintf_func) (info->stream, "%#x", value); ++ ++ if (operand->flags & SW_OPERAND_PARENS) ++ (*info->fprintf_func) (info->stream, ")"); ++ need_comma = 1; ++ } ++ ++ return 4; ++} +diff --git a/hw/Kconfig b/hw/Kconfig +index ad20cce0a9..5f3957be0f 100644 +--- a/hw/Kconfig ++++ b/hw/Kconfig +@@ -63,6 +63,7 @@ source sparc/Kconfig + source sparc64/Kconfig + source tricore/Kconfig + source xtensa/Kconfig ++source sw64/Kconfig + + # Symbols used by multiple targets + config TEST_DEVICES +diff --git a/hw/meson.build b/hw/meson.build +index b3366c888e..f39c1f7e70 100644 +--- a/hw/meson.build ++++ b/hw/meson.build +@@ -62,5 +62,6 @@ subdir('s390x') + subdir('sh4') + subdir('sparc') + subdir('sparc64') ++subdir('sw64') + subdir('tricore') + subdir('xtensa') +diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c +index e037acd1b5..58a0cff483 100644 +--- a/hw/rtc/sun4v-rtc.c ++++ b/hw/rtc/sun4v-rtc.c +@@ -32,10 +32,17 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr, + unsigned size) + { + uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; ++#if defined(__sw_64__) ++ if (addr & 4ULL) { ++ /* accessing the high 32 bits */ ++ val >>= 32; ++ } ++#else + if (!(addr & 4ULL)) { + /* accessing the high 32 bits */ + val >>= 32; + } ++#endif + trace_sun4v_rtc_read(addr, val); + return val; + } +@@ -49,7 +56,11 @@ static void sun4v_rtc_write(void *opaque, hwaddr addr, + static const MemoryRegionOps sun4v_rtc_ops = { + .read = sun4v_rtc_read, + .write = sun4v_rtc_write, ++#if defined(__sw_64__) ++ .endianness = DEVICE_LITTLE_ENDIAN, ++#else + .endianness = DEVICE_NATIVE_ENDIAN, ++#endif + }; + + void sun4v_rtc_init(hwaddr addr) +diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig +new file mode 100644 +index 0000000000..2bf19e8234 +--- /dev/null ++++ b/hw/sw64/Kconfig +@@ -0,0 +1,11 @@ ++config CORE3 ++ bool ++ imply PCI_DEVICES ++ imply TEST_DEVICES ++ imply E1000_PCI ++ select PCI_EXPRESS ++ select SUN4V_RTC ++ select VIRTIO_MMIO ++ select SERIAL ++ select IDE_CMD646 ++ select VIRTIO_VGA +diff --git a/hw/sw64/Makefile.objs b/hw/sw64/Makefile.objs +new file mode 100644 +index 0000000000..73add9a91d +--- /dev/null ++++ b/hw/sw64/Makefile.objs +@@ -0,0 +1 @@ ++obj-y += core3.o core3_board.o +diff --git a/hw/sw64/core.h b/hw/sw64/core.h +new file mode 100644 +index 0000000000..4923382229 +--- /dev/null ++++ b/hw/sw64/core.h +@@ -0,0 +1,25 @@ ++#ifndef HW_SW64_SYS_H ++#define HW_SW64_SYS_H ++ ++typedef struct boot_params { ++ unsigned long initrd_size; /* size of initrd */ ++ unsigned long initrd_start; /* logical address of initrd */ ++ unsigned long dtb_start; /* logical address of dtb */ ++ unsigned long efi_systab; /* logical address of EFI system table */ ++ unsigned long efi_memmap; /* logical address of EFI memory map */ ++ unsigned long efi_memmap_size; /* size of EFI memory map */ ++ unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ ++ unsigned long efi_memdesc_version; /* memory descriptor version */ ++ unsigned long cmdline; /* logical address of cmdline */ ++} BOOT_PARAMS; ++ ++void core3_board_init(SW64CPU *cpus[4], MemoryRegion *ram); ++#endif ++ ++#define MAX_CPUS 64 ++ ++#ifdef CONFIG_KVM ++#define MAX_CPUS_CORE3 64 ++#else ++#define MAX_CPUS_CORE3 32 ++#endif +diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c +new file mode 100644 +index 0000000000..dbe4ed6fa1 +--- /dev/null ++++ b/hw/sw64/core3.c +@@ -0,0 +1,182 @@ ++/* ++ * QEMU CORE3 hardware system emulator. ++ * ++ * Copyright (c) 2021 Lu Feifei ++ * ++ * This work is licensed under the GNU GPL license version 2 or later. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qemu/datadir.h" ++#include "cpu.h" ++#include "hw/hw.h" ++#include "elf.h" ++#include "hw/loader.h" ++#include "hw/boards.h" ++#include "qemu/error-report.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" ++#include "sysemu/reset.h" ++#include "hw/ide.h" ++#include "hw/char/serial.h" ++#include "qemu/cutils.h" ++#include "ui/console.h" ++#include "core.h" ++#include "hw/boards.h" ++#include "sysemu/numa.h" ++ ++static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) ++{ ++ return addr &= ~0xffffffff80000000 ; ++} ++ ++static CpuInstanceProperties ++sw64_cpu_index_to_props(MachineState *ms, unsigned cpu_index) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ ++ assert(cpu_index < possible_cpus->len); ++ return possible_cpus->cpus[cpu_index].props; ++} ++ ++static int64_t sw64_get_default_cpu_node_id(const MachineState *ms, int idx) ++{ ++ int nb_numa_nodes = ms->numa_state->num_nodes; ++ return idx % nb_numa_nodes; ++} ++ ++static const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms) ++{ ++ int i; ++ unsigned int max_cpus = ms->smp.max_cpus; ++ ++ if (ms->possible_cpus) { ++ /* ++ * make sure that max_cpus hasn't changed since the first use, i.e. ++ * -smp hasn't been parsed after it ++ */ ++ assert(ms->possible_cpus->len == max_cpus); ++ return ms->possible_cpus; ++ } ++ ++ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + ++ sizeof(CPUArchId) * max_cpus); ++ ms->possible_cpus->len = max_cpus; ++ for (i = 0; i < ms->possible_cpus->len; i++) { ++ ms->possible_cpus->cpus[i].type = ms->cpu_type; ++ ms->possible_cpus->cpus[i].vcpus_count = 1; ++ ms->possible_cpus->cpus[i].arch_id = i; ++ ms->possible_cpus->cpus[i].props.has_thread_id = true; ++ ms->possible_cpus->cpus[i].props.core_id = i; ++ } ++ ++ return ms->possible_cpus; ++} ++ ++static void core3_cpu_reset(void *opaque) ++{ ++ SW64CPU *cpu = opaque; ++ ++ cpu_reset(CPU(cpu)); ++} ++ ++static void core3_init(MachineState *machine) ++{ ++ ram_addr_t ram_size = machine->ram_size; ++ ram_addr_t buf; ++ SW64CPU *cpus[machine->smp.max_cpus]; ++ long i, size; ++ const char *kernel_filename = machine->kernel_filename; ++ const char *kernel_cmdline = machine->kernel_cmdline; ++ char *hmcode_filename; ++ char *uefi_filename; ++ uint64_t hmcode_entry, hmcode_low, hmcode_high; ++ uint64_t kernel_entry, kernel_low, kernel_high; ++ BOOT_PARAMS *core3_boot_params = g_new0(BOOT_PARAMS, 1); ++ uint64_t param_offset; ++ ++ memset(cpus, 0, sizeof(cpus)); ++ ++ for (i = 0; i < machine->smp.cpus; ++i) { ++ cpus[i] = SW64_CPU(cpu_create(machine->cpu_type)); ++ cpus[i]->env.csr[CID] = i; ++ qemu_register_reset(core3_cpu_reset, cpus[i]); ++ } ++ core3_board_init(cpus, machine->ram); ++ if (kvm_enabled()) ++ buf = ram_size; ++ else ++ buf = ram_size | (1UL << 63); ++ ++ rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); ++ ++ param_offset = 0x90B000UL; ++ core3_boot_params->cmdline = param_offset | 0xfff0000000000000UL; ++ rom_add_blob_fixed("core3_boot_params", (core3_boot_params), 0x48, 0x90A100); ++ ++ hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, kvm_enabled() ? "core3-reset":"core3-hmcode"); ++ if (hmcode_filename == NULL) { ++ if (kvm_enabled()) ++ error_report("no core3-reset provided"); ++ else ++ error_report("no core3-hmcode provided"); ++ exit(1); ++ } ++ size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, ++ &hmcode_entry, &hmcode_low, &hmcode_high, NULL, 0, EM_SW64, 0, 0); ++ if (size < 0) { ++ if (kvm_enabled()) ++ error_report("could not load core3-reset: '%s'", hmcode_filename); ++ else ++ error_report("could not load core3-hmcode: '%s'", hmcode_filename); ++ exit(1); ++ } ++ g_free(hmcode_filename); ++ ++ /* Start all cpus at the hmcode RESET entry point. */ ++ for (i = 0; i < machine->smp.cpus; ++i) { ++ cpus[i]->env.pc = hmcode_entry; ++ cpus[i]->env.hm_entry = hmcode_entry; ++ } ++ ++ if (!kernel_filename) { ++ uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "uefi-bios-sw"); ++ load_image_targphys(uefi_filename, 0x2f00000UL, -1); ++ g_free(uefi_filename); ++ } else { ++ /* Load a kernel. */ ++ size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, ++ &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_SW64, 0, 0); ++ if (size < 0) { ++ error_report("could not load kernel '%s'", kernel_filename); ++ exit(1); ++ } ++ cpus[0]->env.trap_arg1 = kernel_entry; ++ if (kernel_cmdline) ++ pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); ++ } ++} ++ ++static void board_reset(MachineState *state) ++{ ++ qemu_devices_reset(); ++} ++ ++static void core3_machine_init(MachineClass *mc) ++{ ++ mc->desc = "core3 BOARD"; ++ mc->init = core3_init; ++ mc->block_default_type = IF_IDE; ++ mc->max_cpus = MAX_CPUS_CORE3; ++ mc->is_default = 0; ++ mc->reset = board_reset; ++ mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; ++ mc->cpu_index_to_instance_props = sw64_cpu_index_to_props; ++ mc->default_cpu_type = SW64_CPU_TYPE_NAME("core3"); ++ mc->default_ram_id = "ram"; ++ mc->get_default_cpu_node_id = sw64_get_default_cpu_node_id; ++} ++ ++DEFINE_MACHINE("core3", core3_machine_init) +diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c +new file mode 100644 +index 0000000000..7853e01edb +--- /dev/null ++++ b/hw/sw64/core3_board.c +@@ -0,0 +1,493 @@ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "cpu.h" ++#include "core.h" ++#include "hw/hw.h" ++#include "hw/boards.h" ++#include "sysemu/sysemu.h" ++#include "exec/address-spaces.h" ++#include "hw/pci/pci_host.h" ++#include "hw/pci/pci.h" ++#include "hw/char/serial.h" ++#include "hw/irq.h" ++#include "net/net.h" ++#include "hw/usb.h" ++#include "hw/ide/pci.h" ++#include "hw/ide/ahci.h" ++#include "sysemu/numa.h" ++#include "sysemu/kvm.h" ++#include "hw/rtc/sun4v-rtc.h" ++#include "hw/pci/msi.h" ++#include "hw/sw64/sw64_iommu.h" ++ ++#define TYPE_SWBOARD_PCI_HOST_BRIDGE "core_board-pcihost" ++#define SWBOARD_PCI_HOST_BRIDGE(obj) \ ++ OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) ++ ++#define MAX_IDE_BUS 2 ++#define SW_PIN_TO_IRQ 16 ++ ++typedef struct SWBoard { ++ SW64CPU *cpu[MAX_CPUS_CORE3]; ++} SWBoard; ++ ++typedef struct BoardState { ++ PCIHostState parent_obj; ++ ++ SWBoard sboard; ++ uint64_t expire_time; ++} BoardState; ++ ++typedef struct TimerState { ++ void *opaque; ++ int order; ++} TimerState; ++ ++#ifndef CONFIG_KVM ++static void swboard_alarm_timer(void *opaque) ++{ ++ TimerState *ts = (TimerState *)((uintptr_t)opaque); ++ BoardState *bs = (BoardState *)((uintptr_t)ts->opaque); ++ ++ int cpu = ts->order; ++ cpu_interrupt(CPU(bs->sboard.cpu[cpu]), CPU_INTERRUPT_TIMER); ++} ++#endif ++ ++static PCIINTxRoute sw_route_intx_pin_to_irq(void *opaque, int pin) ++{ ++ PCIINTxRoute route; ++ ++ route.mode = PCI_INTX_ENABLED; ++ route.irq = SW_PIN_TO_IRQ; ++ return route; ++} ++ ++static uint64_t convert_bit(int n) ++{ ++ uint64_t ret = (1UL << n) - 1; ++ ++ if (n == 64) ++ ret = 0xffffffffffffffffUL; ++ return ret; ++} ++ ++static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ uint64_t ret = 0; ++ switch (addr) { ++ case 0x0000: ++ /* CG_ONLINE */ ++ { ++ int i; ++ for (i = 0; i < smp_cpus; i = i + 4) ++ ret |= (1UL << i); ++ } ++ break; ++ /*IO_START*/ ++ case 0x1300: ++ ret = 0x1; ++ break; ++ case 0x3780: ++ /* MC_ONLINE */ ++ ret = convert_bit(smp_cpus); ++ break; ++ case 0x0900: ++ /* CPUID */ ++ ret = 0; ++ break; ++ case 0x1180: ++ /* LONGTIME */ ++ ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; ++ break; ++ case 0x4900: ++ /* MC_CONFIG */ ++ break; ++ case 0x0780: ++ /* CORE_ONLINE */ ++ ret = convert_bit(smp_cpus); ++ break; ++ case 0x0680: ++ /* INIT_CTL */ ++ ret = 0x000003AE00000D28; ++ break; ++ default: ++ fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); ++ return -1; ++ } ++ return ret; ++} ++ ++static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) ++{ ++#ifndef CONFIG_KVM ++#ifdef CONFIG_DUMP_PRINTK ++ uint64_t print_addr; ++ uint32_t len; ++ int i; ++ ++ if (addr == 0x40000) { ++ print_addr = val & 0x7fffffff; ++ len = (uint32_t)(val >> 32); ++ uint8_t *buf; ++ buf = malloc(len + 10); ++ memset(buf, 0, len + 10); ++ cpu_physical_memory_rw(print_addr, buf, len, 0); ++ for (i = 0; i < len; i++) ++ printf("%c", buf[i]); ++ ++ free(buf); ++ return; ++ } ++#endif ++#endif ++} ++ ++static const MemoryRegionOps mcu_ops = { ++ .read = mcu_read, ++ .write = mcu_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t ret = 0; ++#ifndef CONFIG_KVM ++ switch (addr) { ++ case 0x180: ++ /* LONGTIME */ ++ ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 32; ++ break; ++ } ++#endif ++ return ret; ++} ++ ++static void intpu_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++#ifndef CONFIG_KVM ++ BoardState *bs = (BoardState *)opaque; ++ SW64CPU *cpu; ++ switch (addr) { ++ case 0x00: ++ val &= 0x1f; ++ cpu = bs->sboard.cpu[val]; ++ cpu->env.csr[II_REQ] = 0x100000; ++ cpu_interrupt(CPU(cpu),CPU_INTERRUPT_IIMAIL); ++ break; ++ default: ++ fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); ++ break; ++ } ++#endif ++} ++ ++static const MemoryRegionOps intpu_ops = { ++ .read = intpu_read, ++ .write = intpu_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++}; ++ ++static MemTxResult msi_read(void *opaque, hwaddr addr, ++ uint64_t *data, unsigned size, ++ MemTxAttrs attrs) ++{ ++ return MEMTX_OK; ++} ++ ++MemTxResult msi_write(void *opaque, hwaddr addr, ++ uint64_t value, unsigned size, ++ MemTxAttrs attrs) ++{ ++#ifdef CONFIG_KVM ++ int ret = 0; ++ MSIMessage msg = {}; ++ ++ msg.address = (uint64_t) addr + 0x8000fee00000; ++ msg.data = (uint32_t) value; ++ ++ ret = kvm_irqchip_send_msi(kvm_state, msg); ++ if (ret < 0) { ++ fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", ++ strerror(-ret)); ++ } ++#endif ++ return MEMTX_OK; ++} ++ ++static const MemoryRegionOps msi_ops = { ++ .read_with_attrs = msi_read, ++ .write_with_attrs = msi_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ return 1; ++} ++ ++static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) ++{ ++} ++ ++const MemoryRegionOps core3_pci_ignore_ops = { ++ .read = ignore_read, ++ .write = ignore_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t config_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ PCIBus *b = opaque; ++ uint32_t trans_addr = 0; ++ trans_addr |= ((addr >> 16) & 0xffff) << 8; ++ trans_addr |= (addr & 0xff); ++ return pci_data_read(b, trans_addr, size); ++} ++ ++static void config_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ PCIBus *b = opaque; ++ uint32_t trans_addr = 0; ++ trans_addr |= ((addr >> 16) & 0xffff) << 8; ++ trans_addr |= (addr & 0xff); ++ pci_data_write(b, trans_addr, val, size); ++} ++ ++const MemoryRegionOps core3_pci_config_ops = { ++ .read = config_read, ++ .write = config_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static void cpu_irq_change(SW64CPU *cpu, uint64_t req) ++{ ++ if (cpu != NULL) { ++ CPUState *cs = CPU(cpu); ++ if (req) ++ cpu_interrupt(cs, CPU_INTERRUPT_HARD); ++ else ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); ++ } ++} ++ ++static void swboard_set_irq(void *opaque, int irq, int level) ++{ ++ BoardState *bs = opaque; ++ SW64CPU *cpu; ++ int i; ++ ++ if (kvm_enabled()) { ++ if (level == 0) ++ return; ++ kvm_set_irq(kvm_state, irq, level); ++ return; ++ } ++ ++ for (i = 0; i < 1; i++) { ++ cpu = bs->sboard.cpu[i]; ++ if (cpu != NULL) { ++ CPUState *cs = CPU(cpu); ++ if (level) ++ cpu_interrupt(cs, CPU_INTERRUPT_PCIE); ++ else ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_PCIE); ++ } ++ } ++} ++ ++static int swboard_map_irq(PCIDevice *d, int irq_num) ++{ ++ /* In fact,the return value is the interrupt type passed to kernel, ++ * so it must keep same with the type in do_entInt in kernel. ++ */ ++ return 16; ++} ++ ++static void serial_set_irq(void *opaque, int irq, int level) ++{ ++ BoardState *bs = (BoardState *)opaque; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ int i; ++ if (level == 0) ++ return; ++ if (kvm_enabled()) { ++ kvm_set_irq(kvm_state, irq, level); ++ return; ++ } ++ for (i = 0; i < smp_cpus; i++) { ++ if (bs->sboard.cpu[i]) ++ cpu_irq_change(bs->sboard.cpu[i], 1); ++ } ++} ++ ++void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) ++{ ++ DeviceState *dev; ++ BoardState *bs; ++#ifndef CONFIG_KVM ++ TimerState *ts; ++#endif ++ MemoryRegion *io_mcu = g_new(MemoryRegion, 1); ++ MemoryRegion *io_intpu = g_new(MemoryRegion, 1); ++ MemoryRegion *msi_ep = g_new(MemoryRegion, 1); ++ qemu_irq serial_irq; ++ uint64_t MB = 1024 * 1024; ++ MemoryRegion *mem_ep = g_new(MemoryRegion, 1); ++ MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); ++ MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); ++ MemoryRegion *io_ep = g_new(MemoryRegion, 1); ++ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ ++ PCIBus *b; ++ PCIHostState *phb; ++ uint64_t GB = 1024 * MB; ++ ++ int i; ++ dev = qdev_new(TYPE_SWBOARD_PCI_HOST_BRIDGE); ++ phb = PCI_HOST_BRIDGE(dev); ++ bs = SWBOARD_PCI_HOST_BRIDGE(dev); ++ ++#ifdef CONFIG_KVM ++ if (kvm_has_gsi_routing()) ++ msi_nonbroken = true; ++#endif ++ ++ for (i = 0; i < smp_cpus; ++i) { ++ if (cpus[i] == NULL) ++ continue; ++ bs->sboard.cpu[i] = cpus[i]; ++#ifndef CONFIG_KVM ++ ts = g_new(TimerState, 1); ++ ts->opaque = (void *) ((uintptr_t)bs); ++ ts->order = i; ++ cpus[i]->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &swboard_alarm_timer, ts); ++#endif ++ } ++ memory_region_add_subregion(get_system_memory(), 0, ram); ++ ++ memory_region_init_io(io_mcu, NULL, &mcu_ops, bs, "io_mcu", 16 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x803000000000ULL, io_mcu); ++ ++ memory_region_init_io(io_intpu, NULL, &intpu_ops, bs, "io_intpu", 1 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x802a00000000ULL, ++ io_intpu); ++ ++ memory_region_init_io(msi_ep, NULL, &msi_ops, bs, "msi_ep", 1 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x8000fee00000ULL, msi_ep); ++ ++ memory_region_init(mem_ep, OBJECT(bs), "pci0-mem", 0x890000000000ULL); ++ memory_region_add_subregion(get_system_memory(), 0x880000000000ULL, mem_ep); ++ ++ memory_region_init_alias(mem_ep64, NULL, "mem_ep64", mem_ep, 0x888000000000ULL, 1ULL << 39); ++ memory_region_add_subregion(get_system_memory(), 0x888000000000ULL, mem_ep64); ++ ++ memory_region_init_io(io_ep, OBJECT(bs), &core3_pci_ignore_ops, NULL, ++ "pci0-io-ep", 4 * GB); ++ ++ memory_region_add_subregion(get_system_memory(), 0x880100000000ULL, io_ep); ++ b = pci_register_root_bus(dev, "pcie.0", swboard_set_irq, swboard_map_irq, bs, ++ mem_ep, io_ep, 0, 537, TYPE_PCIE_BUS); ++ phb->bus = b; ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ++ pci_bus_set_route_irq_fn(b, sw_route_intx_pin_to_irq); ++ memory_region_init_io(conf_piu0, OBJECT(bs), &core3_pci_config_ops, b, ++ "pci0-ep-conf-io", 4 * GB); ++ memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, ++ conf_piu0); ++#ifdef SW64_VT_IOMMU ++ sw64_vt_iommu_init(b); ++#endif ++ for (i = 0; i < nb_nics; i++) { ++ pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); ++ } ++ ++ pci_vga_init(b); ++#define MAX_SATA_PORTS 6 ++ PCIDevice *ahci; ++ DriveInfo *hd[MAX_SATA_PORTS]; ++ ahci = pci_create_simple_multifunction(b, PCI_DEVFN(0x1f, 0), true, ++ TYPE_ICH9_AHCI); ++ g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); ++ ide_drive_get(hd, ahci_get_num_ports(ahci)); ++ ahci_ide_create_devs(ahci, hd); ++ ++ serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); ++ if (serial_hd(0)) { ++ serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, ++ serial_irq, (1843200 >> 4), serial_hd(0), ++ DEVICE_LITTLE_ENDIAN); ++ } ++ pci_create_simple(phb->bus, -1, "nec-usb-xhci"); ++ sun4v_rtc_init(0x804910000000ULL); ++} ++ ++static const TypeInfo swboard_pcihost_info = { ++ .name = TYPE_SWBOARD_PCI_HOST_BRIDGE, ++ .parent = TYPE_PCI_HOST_BRIDGE, ++ .instance_size = sizeof(BoardState), ++}; ++ ++static void swboard_register_types(void) ++{ ++ type_register_static(&swboard_pcihost_info); ++} ++ ++type_init(swboard_register_types) +diff --git a/hw/sw64/meson.build b/hw/sw64/meson.build +new file mode 100644 +index 0000000000..8abb18222a +--- /dev/null ++++ b/hw/sw64/meson.build +@@ -0,0 +1,10 @@ ++sw64_ss = ss.source_set() ++ ++sw64_ss.add(files('sw64_iommu.c')) ++ ++sw64_ss.add(when: 'CONFIG_CORE3', if_true: files( ++ 'core3.c', ++ 'core3_board.c', ++)) ++ ++hw_arch += {'sw64': sw64_ss} +diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c +new file mode 100644 +index 0000000000..8ded65f213 +--- /dev/null ++++ b/hw/sw64/sw64_iommu.c +@@ -0,0 +1,567 @@ ++/* ++ * QEMU sw64 IOMMU emulation ++ * ++ * Copyright (c) 2021 Lu Feifei ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "exec/address-spaces.h" ++#include "qemu/log.h" ++#include "qapi/error.h" ++#include "hw/sw64/sw64_iommu.h" ++#include "sysemu/kvm.h" ++ ++#define IOMMU_PAGE_SHIFT 13 ++#define IOMMU_PAGE_SIZE_8K (1ULL << IOMMU_PAGE_SHIFT) ++#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) ++#define IOMMU_IOVA_SHIFT 16 ++#define SW64IOMMU_PTIOTLB_MAX_SIZE 256 ++ ++static MemTxResult swvt_msi_read(void *opaque, hwaddr addr, ++ uint64_t *data, unsigned size, MemTxAttrs attrs) ++{ ++ return MEMTX_OK; ++} ++ ++static MemTxResult swvt_msi_write(void *opaque, hwaddr addr, ++ uint64_t value, unsigned size, ++ MemTxAttrs attrs) ++{ ++ MemTxResult ret; ++ ++ ret = msi_write(opaque, addr, value, size, attrs); ++ ++ return ret; ++} ++ ++static const MemoryRegionOps swvt_msi_ops = { ++ .read_with_attrs = swvt_msi_read, ++ .write_with_attrs = swvt_msi_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn) ++{ ++ uintptr_t key = (uintptr_t)bus; ++ SWVTBus *swvt_bus = g_hash_table_lookup(s->swvtbus_as_by_busptr, &key); ++ SWVTAddressSpace *swvt_dev_as; ++ char name[128]; ++ ++ if (!swvt_bus) { ++ uintptr_t *new_key = g_malloc(sizeof(*new_key)); ++ *new_key = (uintptr_t)bus; ++ /* No corresponding free() */ ++ swvt_bus = g_malloc0(sizeof(SWVTBus) + sizeof(SWVTAddressSpace *) * \ ++ PCI_DEVFN_MAX); ++ swvt_bus->bus = bus; ++ g_hash_table_insert(s->swvtbus_as_by_busptr, new_key, swvt_bus); ++ } ++ swvt_dev_as = swvt_bus->dev_as[devfn]; ++ if (!swvt_dev_as) { ++ snprintf(name, sizeof(name), "sw64_iommu_devfn_%d", devfn); ++ swvt_bus->dev_as[devfn] = swvt_dev_as = g_malloc0(sizeof(SWVTAddressSpace)); ++ ++ swvt_dev_as->bus = bus; ++ swvt_dev_as->devfn = (uint8_t)devfn; ++ swvt_dev_as->iommu_state = s; ++ ++ memory_region_init_iommu(&swvt_dev_as->iommu, sizeof(swvt_dev_as->iommu), ++ TYPE_SW64_IOMMU_MEMORY_REGION, OBJECT(s), ++ "sw64_iommu_dmar", ++ 1UL << 32); ++ memory_region_init_io(&swvt_dev_as->msi, OBJECT(s), ++ &swvt_msi_ops, s, "sw_msi", 1 * 1024 * 1024); ++ memory_region_init(&swvt_dev_as->root, OBJECT(s), ++ "swvt_root", UINT64_MAX); ++ memory_region_add_subregion_overlap(&swvt_dev_as->root, ++ 0x8000fee00000ULL, ++ &swvt_dev_as->msi, 64); ++ address_space_init(&swvt_dev_as->as, &swvt_dev_as->root, name); ++ memory_region_add_subregion_overlap(&swvt_dev_as->root, 0, ++ MEMORY_REGION(&swvt_dev_as->iommu), ++ 1); ++ } ++ ++ memory_region_set_enabled(MEMORY_REGION(&swvt_dev_as->iommu), true); ++ ++ return swvt_dev_as; ++} ++ ++/** ++ * get_pte - Get the content of a page table entry located at ++ * @base_addr[@index] ++ */ ++static int get_pte(dma_addr_t baseaddr, uint64_t *pte) ++{ ++ int ret; ++ ++ /* TODO: guarantee 64-bit single-copy atomicity */ ++ ret = dma_memory_read(&address_space_memory, baseaddr, ++ (uint8_t *)pte, sizeof(*pte)); ++ ++ if (ret != MEMTX_OK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static bool swvt_do_iommu_translate(SWVTAddressSpace *swvt_as, PCIBus *bus, ++ uint8_t devfn, hwaddr addr, IOMMUTLBEntry *entry) ++{ ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ uint8_t bus_num = pci_bus_num(bus); ++ unsigned long dtbbaseaddr, dtbbasecond; ++ unsigned long pdebaseaddr, ptebaseaddr; ++ unsigned long pte; ++ uint16_t source_id; ++ SW64DTIOTLBEntry *dtcached_entry = NULL; ++ SW64DTIOTLBKey dtkey, *new_key; ++ ++ dtcached_entry = g_hash_table_lookup(s->dtiotlb, &dtkey); ++ ++ if (unlikely(!dtcached_entry)) { ++ dtbbaseaddr = s->dtbr + (bus_num << 3); ++ ++ if (get_pte(dtbbaseaddr, &pte)) ++ goto error; ++ ++ dtbbasecond = (pte & (~(SW_IOMMU_ENTRY_VALID))) + (devfn << 3); ++ if (get_pte(dtbbasecond, &pte)) ++ goto error; ++ ++ source_id = ((bus_num & 0xffUL) << 8) | (devfn & 0xffUL); ++ dtcached_entry = g_new0(SW64DTIOTLBEntry, 1); ++ dtcached_entry->ptbase_addr = pte & (~(SW_IOMMU_ENTRY_VALID)); ++ dtcached_entry->source_id = source_id; ++ ++ new_key = g_new0(SW64DTIOTLBKey, 1); ++ new_key->source_id = source_id; ++ ++ g_hash_table_insert(s->dtiotlb, new_key, dtcached_entry); ++ } ++ ++ pdebaseaddr = dtcached_entry->ptbase_addr; ++ pdebaseaddr += ((addr >> 23) & SW_IOMMU_LEVEL1_OFFSET) << 3; ++ ++ if (get_pte(pdebaseaddr, &pte)) ++ goto error; ++ ++ ptebaseaddr = pte & (~(SW_IOMMU_ENTRY_VALID)); ++ ptebaseaddr += ((addr >> IOMMU_PAGE_SHIFT) & SW_IOMMU_LEVEL2_OFFSET) << 3; ++ ++ if (get_pte(ptebaseaddr, &pte)) ++ goto error; ++ ++ pte &= ~(SW_IOMMU_ENTRY_VALID | SW_IOMMU_GRN | SW_IOMMU_ENABLE); ++ entry->translated_addr = pte; ++ entry->addr_mask = IOMMU_PAGE_SIZE_8K - 1; ++ ++ return 0; ++ ++error: ++ entry->perm = IOMMU_NONE; ++ return -EINVAL; ++} ++ ++static void swvt_ptiotlb_inv_all(SW64IOMMUState *s) ++{ ++ g_hash_table_remove_all(s->ptiotlb); ++} ++ ++static void swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, ++ hwaddr addr, IOMMUTLBEntry *entry) ++{ ++ SW64PTIOTLBKey ptkey; ++ ++ ptkey.source_id = source_id; ++ ptkey.iova = addr; ++ ++ entry = g_hash_table_lookup(s->ptiotlb, &ptkey); ++} ++ ++static IOMMUTLBEntry sw64_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, ++ IOMMUAccessFlags flag, int iommu_idx) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ IOMMUTLBEntry *cached_entry = NULL; ++ IOMMUTLBEntry entry = { ++ .target_as = &address_space_memory, ++ .iova = addr, ++ .translated_addr = addr, ++ .addr_mask = ~(hwaddr)0, ++ .perm = IOMMU_NONE, ++ }; ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t source_id; ++ SW64PTIOTLBKey *new_ptkey; ++ hwaddr aligned_addr; ++ ++ source_id = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ qemu_mutex_lock(&s->iommu_lock); ++ ++ aligned_addr = addr & IOMMU_PAGE_MASK_8K; ++ ++ swvt_lookup_ptiotlb(s, aligned_addr, source_id, cached_entry); ++ ++ if (cached_entry) ++ goto out; ++ ++ if (g_hash_table_size(s->ptiotlb) >= SW64IOMMU_PTIOTLB_MAX_SIZE) { ++ swvt_ptiotlb_inv_all(s); ++ } ++ ++ cached_entry = g_new0(IOMMUTLBEntry, 1); ++ ++ if (swvt_do_iommu_translate(swvt_as, swvt_as->bus, swvt_as->devfn, ++ addr, cached_entry)) { ++ g_free(cached_entry); ++ qemu_mutex_unlock(&s->iommu_lock); ++ printf("%s: detected translation failure " ++ "(busnum=%d, devfn=%#x, iova=%#lx.\n", ++ __func__, pci_bus_num(swvt_as->bus), swvt_as->devfn, ++ entry.iova); ++ entry.iova = 0; ++ entry.translated_addr = 0; ++ entry.addr_mask = 0; ++ entry.perm = IOMMU_NONE; ++ ++ return entry; ++ } else { ++ new_ptkey = g_new0(SW64PTIOTLBKey, 1); ++ new_ptkey->source_id = source_id; ++ new_ptkey->iova = aligned_addr; ++ g_hash_table_insert(s->ptiotlb, new_ptkey, cached_entry); ++ } ++ ++out: ++ qemu_mutex_unlock(&s->iommu_lock); ++ entry.perm = flag; ++ entry.translated_addr = cached_entry->translated_addr + ++ (addr & (IOMMU_PAGE_SIZE_8K - 1)); ++ entry.addr_mask = cached_entry->addr_mask; ++ ++ return entry; ++} ++ ++static void swvt_ptiotlb_inv_iova(SW64IOMMUState *s, uint16_t source_id, dma_addr_t iova) ++{ ++ SW64PTIOTLBKey key = {.source_id = source_id, .iova = iova}; ++ ++ qemu_mutex_lock(&s->iommu_lock); ++ g_hash_table_remove(s->ptiotlb, &key); ++ qemu_mutex_unlock(&s->iommu_lock); ++} ++ ++void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ SWVTAddressSpace *swvt_as; ++ IOMMUNotifier *n; ++ uint16_t source_id; ++ dma_addr_t iova; ++ IOMMUTLBEvent event; ++ ++ source_id = val & 0xffff; ++ iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; ++ ++ swvt_ptiotlb_inv_iova(s, source_id, iova); ++ ++ QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ if (as_sourceid == source_id) { ++ IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { ++ event.type = IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.iova = iova & IOMMU_PAGE_MASK_8K; ++ event.entry.translated_addr = 0; ++ event.entry.perm = IOMMU_NONE; ++ event.entry.addr_mask = IOMMU_PAGE_SIZE_8K - 1; ++ ++ memory_region_notify_iommu(&swvt_as->iommu, 0, event); ++ } ++ } ++ } ++} ++ ++/* Unmap the whole range in the notifier's scope. */ ++static void swvt_address_space_unmap(SWVTAddressSpace *as, IOMMUNotifier *n) ++{ ++ IOMMUTLBEvent event; ++ hwaddr size; ++ hwaddr start = n->start; ++ hwaddr end = n->end; ++ ++ assert(start <= end); ++ size = end - start; ++ ++ event.entry.target_as = &address_space_memory; ++ /* Adjust iova for the size */ ++ event.entry.iova = n->start & ~(size - 1); ++ /* This field is meaningless for unmap */ ++ event.entry.translated_addr = 0; ++ event.entry.perm = IOMMU_NONE; ++ event.entry.addr_mask = size - 1; ++ ++ memory_region_notify_iommu_one(n, &event); ++} ++ ++void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ SWVTAddressSpace *swvt_as; ++ IOMMUNotifier *n; ++ uint16_t source_id; ++ dma_addr_t iova; ++ IOMMUTLBEvent event; ++ int ret; ++ ++ source_id = val & 0xffff; ++ iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; ++ ++ swvt_ptiotlb_inv_iova(s, source_id, iova); ++ ++ QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ if (as_sourceid == source_id) { ++ IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { ++ event.type = IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.iova = iova & IOMMU_PAGE_MASK_8K; ++ event.entry.perm = IOMMU_RW; ++ ++ ret = swvt_do_iommu_translate(swvt_as, swvt_as->bus, ++ swvt_as->devfn, iova, &event.entry); ++ if (ret) ++ goto out; ++ ++ memory_region_notify_iommu(&swvt_as->iommu, 0, event); ++ } ++ } ++ } ++out: ++ return; ++} ++ ++void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ int map_flag; ++ ++ map_flag = val >> 36; ++ ++ if (map_flag) ++ swvt_address_space_map_iova(s, val & 0xfffffffff); ++ else ++ swvt_address_space_unmap_iova(s, val); ++ ++ return; ++} ++ ++static AddressSpace *sw64_dma_iommu(PCIBus *bus, void *opaque, int devfn) ++{ ++ SW64IOMMUState *s = opaque; ++ SWVTAddressSpace *swvt_as; ++ ++ assert(0 <= devfn && devfn < PCI_DEVFN_MAX); ++ ++ swvt_as = iommu_find_add_as(s, bus, devfn); ++ return &swvt_as->as; ++} ++ ++static uint64_t piu0_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t ret = 0; ++ switch (addr) { ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static void piu0_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ SW64IOMMUState *s = (SW64IOMMUState *)opaque; ++ ++ switch (addr) { ++ case 0xb000: ++ /* DTBaseAddr */ ++ s->dtbr = val; ++ break; ++ case 0xb280: ++ /* PTLB_FlushVAddr */ ++ swvt_address_space_invalidate_iova(s, val); ++ break; ++ default: ++ break; ++ } ++} ++ ++const MemoryRegionOps core3_pci_piu0_ops = { ++ .read = piu0_read, ++ .write = piu0_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++void sw64_vt_iommu_init(PCIBus *b) ++{ ++ DeviceState *dev_iommu; ++ SW64IOMMUState *s; ++ MemoryRegion *io_piu0 = g_new(MemoryRegion, 1); ++ ++ dev_iommu = qdev_new(TYPE_SW64_IOMMU); ++ s = SW64_IOMMU(dev_iommu); ++ ++ s->pci_bus = b; ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev_iommu), &error_fatal); ++ ++ pci_setup_iommu(b, sw64_dma_iommu, dev_iommu); ++ ++ memory_region_init_io(io_piu0, OBJECT(s), &core3_pci_piu0_ops, s, ++ "pci0-piu0-io", 4 * 1024 * 1024); ++ memory_region_add_subregion(get_system_memory(), 0x880200000000ULL, ++ io_piu0); ++} ++ ++static int swvt_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, ++ IOMMUNotifierFlag old, ++ IOMMUNotifierFlag new, ++ Error **errp) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ ++ /* Update per-address-space notifier flags */ ++ swvt_as->notifier_flags = new; ++ ++ if (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { ++ error_setg(errp, "swvt does not support dev-iotlb yet"); ++ return -EINVAL; ++ } ++ ++ if (old == IOMMU_NOTIFIER_NONE) { ++ QLIST_INSERT_HEAD(&s->swvt_as_with_notifiers, swvt_as, next); ++ } else if (new == IOMMU_NOTIFIER_NONE) { ++ QLIST_REMOVE(swvt_as, next); ++ } ++ return 0; ++} ++ ++static void swvt_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu_mr, SWVTAddressSpace, iommu); ++ ++ /* ++ * The replay can be triggered by either a invalidation or a newly ++ * created entry. No matter what, we release existing mappings ++ * (it means flushing caches for UNMAP-only registers). ++ */ ++ swvt_address_space_unmap(swvt_as, n); ++} ++ ++/* GHashTable functions */ ++static gboolean swvt_uint64_equal(gconstpointer v1, gconstpointer v2) ++{ ++ return *((const uint64_t *)v1) == *((const uint64_t *)v2); ++} ++ ++static guint swvt_uint64_hash(gconstpointer v) ++{ ++ return (guint)*(const uint64_t *)v; ++} ++ ++static void iommu_realize(DeviceState *d, Error **errp) ++{ ++ SW64IOMMUState *s = SW64_IOMMU(d); ++ ++ QLIST_INIT(&s->swvt_as_with_notifiers); ++ qemu_mutex_init(&s->iommu_lock); ++ ++ s->dtiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, ++ g_free, g_free); ++ s->ptiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, ++ g_free, g_free); ++ ++ s->swvtbus_as_by_busptr = g_hash_table_new(NULL, NULL); ++} ++ ++static void iommu_reset(DeviceState *d) ++{ ++} ++ ++static void sw64_iommu_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->reset = iommu_reset; ++ dc->realize = iommu_realize; ++} ++ ++static void sw64_iommu_memory_region_class_init(ObjectClass *klass, void *data) ++{ ++ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); ++ ++ imrc->translate = sw64_translate_iommu; ++ imrc->notify_flag_changed = swvt_iommu_notify_flag_changed; ++ imrc->replay = swvt_iommu_replay; ++} ++ ++static const TypeInfo sw64_iommu_info = { ++ .name = TYPE_SW64_IOMMU, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(SW64IOMMUState), ++ .class_init = sw64_iommu_class_init, ++ .class_size = sizeof(SW64IOMMUClass), ++}; ++ ++static const TypeInfo sw64_iommu_memory_region_info = { ++ .parent = TYPE_IOMMU_MEMORY_REGION, ++ .name = TYPE_SW64_IOMMU_MEMORY_REGION, ++ .class_init = sw64_iommu_memory_region_class_init, ++}; ++ ++static void sw64_iommu_register_types(void) ++{ ++ type_register_static(&sw64_iommu_info); ++ type_register_static(&sw64_iommu_memory_region_info); ++} ++ ++type_init(sw64_iommu_register_types) +diff --git a/hw/sw64/trace-events b/hw/sw64/trace-events +new file mode 100644 +index 0000000000..1aa744c984 +--- /dev/null ++++ b/hw/sw64/trace-events +@@ -0,0 +1,3 @@ ++# See docs/devel/tracing.rst for syntax documentation. ++ ++# pci.c +diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h +index 08e1beec85..4590bcc968 100644 +--- a/include/disas/dis-asm.h ++++ b/include/disas/dis-asm.h +@@ -191,6 +191,9 @@ enum bfd_architecture + #define bfd_mach_alpha_ev4 0x10 + #define bfd_mach_alpha_ev5 0x20 + #define bfd_mach_alpha_ev6 0x30 ++ bfd_arch_sw_64, /* Dec Sw_64 */ ++#define bfd_mach_sw_64 1 ++#define bfd_mach_sw_64_core3 1621 + bfd_arch_arm, /* Advanced Risc Machines ARM */ + #define bfd_mach_arm_unknown 0 + #define bfd_mach_arm_2 1 +@@ -429,6 +432,7 @@ int print_insn_h8500 (bfd_vma, disassemble_info*); + int print_insn_arm_a64 (bfd_vma, disassemble_info*); + int print_insn_alpha (bfd_vma, disassemble_info*); + disassembler_ftype arc_get_disassembler (int, int); ++int print_insn_sw_64 (bfd_vma, disassemble_info*); + int print_insn_arm (bfd_vma, disassemble_info*); + int print_insn_sparc (bfd_vma, disassemble_info*); + int print_insn_big_a29k (bfd_vma, disassemble_info*); +diff --git a/include/elf.h b/include/elf.h +index 811bf4a1cb..79c188b62f 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -207,6 +207,8 @@ typedef struct mips_elf_abiflags_v0 { + + #define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */ + ++#define EM_SW64 0x9916 /* SW64 */ ++ + /* This is the info that is needed to parse the dynamic section of the file */ + #define DT_NULL 0 + #define DT_NEEDED 1 +@@ -1417,6 +1419,48 @@ typedef struct { + #define EF_RISCV_RVE 0x0008 + #define EF_RISCV_TSO 0x0010 + ++/* ++ SW_64 ELF relocation types ++ */ ++#define EM_SW_64 0x9916 ++#define R_SW_64_NONE 0 /* No reloc */ ++#define R_SW_64_REFLONG 1 /* Direct 32 bit */ ++#define R_SW_64_REFQUAD 2 /* Direct 64 bit */ ++#define R_SW_64_GPREL32 3 /* GP relative 32 bit */ ++#define R_SW_64_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_SW_64_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_SW_64_GPDISP 6 /* Add displacement to GP */ ++#define R_SW_64_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_SW_64_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_SW_64_SREL16 9 /* PC relative 16 bit */ ++#define R_SW_64_SREL32 10 /* PC relative 32 bit */ ++#define R_SW_64_SREL64 11 /* PC relative 64 bit */ ++#define R_SW_64_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_SW_64_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_SW_64_GPREL16 19 /* GP relative 16 bit */ ++#define R_SW_64_COPY 24 /* Copy symbol at runtime */ ++#define R_SW_64_GLOB_DAT 25 /* Create GOT entry */ ++#define R_SW_64_JMP_SLOT 26 /* Create PLT entry */ ++#define R_SW_64_RELATIVE 27 /* Adjust by program base */ ++#define R_SW_64_TLS_GD_HI 28 ++#define R_SW_64_TLSGD 29 ++#define R_SW_64_TLS_LDM 30 ++#define R_SW_64_DTPMOD64 31 ++#define R_SW_64_GOTDTPREL 32 ++#define R_SW_64_DTPREL64 33 ++#define R_SW_64_DTPRELHI 34 ++#define R_SW_64_DTPRELLO 35 ++#define R_SW_64_DTPREL16 36 ++#define R_SW_64_GOTTPREL 37 ++#define R_SW_64_TPREL64 38 ++#define R_SW_64_TPRELHI 39 ++#define R_SW_64_TPRELLO 40 ++#define R_SW_64_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_SW_64_NUM 46 ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++#define SHF_SW_64_GPREL 0x10000000 ++ + typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +diff --git a/include/hw/sw64/sw64_iommu.h b/include/hw/sw64/sw64_iommu.h +new file mode 100644 +index 0000000000..7191876083 +--- /dev/null ++++ b/include/hw/sw64/sw64_iommu.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2021-2025 Wuxi Institute of Advanced Technology ++ * Written by Lu Feifei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ */ ++ ++#ifndef HW_SW64_IOMMU_H ++#define HW_SW64_IOMMU_H ++ ++#include "hw/sysbus.h" ++#include "hw/pci/pci.h" ++ ++#define TYPE_SW64_IOMMU_MEMORY_REGION "sw64-iommu-memory-region" ++#define SW_IOMMU_ENTRY_VALID ((1UL) << 63) ++#define SW_IOMMU_LEVEL1_OFFSET 0x1ff ++#define SW_IOMMU_LEVEL2_OFFSET 0x3ff ++#define SW_IOMMU_ENABLE 3 ++#define SW_IOMMU_GRN ((0UL) << 4) ++#define SWVT_PCI_BUS_MAX 256 ++ ++typedef struct SW64IOMMUClass SW64IOMMUClass; ++typedef struct SW64IOMMUState SW64IOMMUState; ++typedef struct SWVTAddressSpace SWVTAddressSpace; ++typedef struct SW64DTIOTLBKey SW64DTIOTLBKey; ++typedef struct SW64PTIOTLBKey SW64PTIOTLBKey; ++typedef struct SW64DTIOTLBEntry SW64DTIOTLBEntry; ++typedef struct SWVTBus SWVTBus; ++ ++struct SW64DTIOTLBEntry { ++ uint16_t source_id; ++ unsigned long ptbase_addr; ++}; ++ ++struct SW64DTIOTLBKey { ++ uint16_t source_id; ++}; ++ ++struct SW64PTIOTLBKey { ++ uint16_t source_id; ++ dma_addr_t iova; ++}; ++ ++struct SWVTAddressSpace { ++ PCIBus *bus; ++ uint8_t devfn; ++ AddressSpace as; ++ IOMMUMemoryRegion iommu; ++ MemoryRegion root; ++ MemoryRegion msi; /* Interrupt region: 0xfeeXXXXX */ ++ SW64IOMMUState *iommu_state; ++ QLIST_ENTRY(SWVTAddressSpace) next; ++ /* Superset of notifier flags that this address space has */ ++ IOMMUNotifierFlag notifier_flags; ++}; ++ ++struct SWVTBus { ++ PCIBus* bus; /* A reference to the bus to provide translation for */ ++ SWVTAddressSpace *dev_as[0]; /* A table of SWVTAddressSpace objects indexed by devfn */ ++}; ++ ++struct SW64IOMMUState { ++ SysBusDevice busdev; ++ dma_addr_t dtbr; /* Current root table pointer */ ++ GHashTable *dtiotlb; /* IOTLB for device table */ ++ GHashTable *ptiotlb; /* IOTLB for page table */ ++ ++ GHashTable *swvtbus_as_by_busptr; ++ /* list of registered notifiers */ ++ QLIST_HEAD(, SWVTAddressSpace) swvt_as_with_notifiers; ++ ++ PCIBus *pci_bus; ++ QemuMutex iommu_lock; ++}; ++ ++struct SW64IOMMUClass { ++ SysBusDeviceClass parent; ++ DeviceRealize realize; ++}; ++ ++#define TYPE_SW64_IOMMU "sw64-iommu" ++#define SW64_IOMMU(obj) \ ++ OBJECT_CHECK(SW64IOMMUState, (obj), TYPE_SW64_IOMMU) ++#define SW64_IOMMU_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(SW64IOMMUClass, (klass), TYPE_SW64_IOMMU) ++#define SW64_IOMMU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64IOMMUClass, (obj), TYPE_SW64_IOMMU) ++extern void sw64_vt_iommu_init(PCIBus *b); ++extern void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val); ++extern void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val); ++extern void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val); ++extern SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn); ++extern MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, ++ MemTxAttrs attrs); ++#endif +diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h +index 112a29910b..6141122308 100644 +--- a/include/qemu/atomic.h ++++ b/include/qemu/atomic.h +@@ -85,6 +85,8 @@ + #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) + #elif defined(__alpha__) + #define smp_read_barrier_depends() asm volatile("mb":::"memory") ++#elif defined(__sw_64__) ++#define smp_read_barrier_depends() asm volatile("memb":::"memory") + #else + #define smp_read_barrier_depends() barrier() + #endif +diff --git a/include/qemu/timer.h b/include/qemu/timer.h +index d263fad9a4..e6d442abee 100644 +--- a/include/qemu/timer.h ++++ b/include/qemu/timer.h +@@ -1007,6 +1007,16 @@ static inline int64_t cpu_get_host_ticks(void) + return cur - ofs; + } + ++#elif defined(__sw_64__) ++ ++static inline int64_t cpu_get_host_ticks(void) ++{ ++ uint64_t cc; ++ ++ asm volatile("rtc %0" : "=r"(cc)); ++ return cc; ++} ++ + #else + /* The host CPU doesn't have an easily accessible cycle counter. + Just return a monotonically increasing value. This will be +diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h +index 70c579560a..1cf27baa7c 100644 +--- a/include/sysemu/arch_init.h ++++ b/include/sysemu/arch_init.h +@@ -24,6 +24,7 @@ enum { + QEMU_ARCH_RX = (1 << 20), + QEMU_ARCH_AVR = (1 << 21), + QEMU_ARCH_HEXAGON = (1 << 22), ++ QEMU_ARCH_SW64 = (1 << 23), + }; + + extern const uint32_t arch_type; +diff --git a/linux-headers/asm-sw64/kvm.h b/linux-headers/asm-sw64/kvm.h +new file mode 100644 +index 0000000000..b0ce2ca346 +--- /dev/null ++++ b/linux-headers/asm-sw64/kvm.h +@@ -0,0 +1,122 @@ ++#ifndef __LINUX_KVM_SW64_H ++#define __LINUX_KVM_SW64_H ++ ++#include ++/* ++ * for KVM_GET_REGS and KVM_SET_REGS ++ */ ++struct kvm_regs { ++ unsigned long r0; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++ ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long r15; ++ ++ unsigned long r19; ++ unsigned long r20; ++ unsigned long r21; ++ unsigned long r22; ++ ++ unsigned long r23; ++ unsigned long r24; ++ unsigned long r25; ++ unsigned long r26; ++ ++ unsigned long r27; ++ unsigned long r28; ++ unsigned long __padding0; ++ unsigned long fpcr; ++ ++ unsigned long fp[124]; ++ /* These are saved by hmcode: */ ++ unsigned long ps; ++ unsigned long pc; ++ unsigned long gp; ++ unsigned long r16; ++ unsigned long r17; ++ unsigned long r18; ++}; ++ ++struct vcpucb { ++ unsigned long go_flag; ++ unsigned long pcbb; ++ unsigned long ksp; ++ unsigned long usp; ++ unsigned long kgp; ++ unsigned long ent_arith; ++ unsigned long ent_if; ++ unsigned long ent_int; ++ unsigned long ent_mm; ++ unsigned long ent_sys; ++ unsigned long ent_una; ++ unsigned long stack_pc; ++ unsigned long new_a0; ++ unsigned long new_a1; ++ unsigned long new_a2; ++ unsigned long whami; ++ unsigned long csr_save; ++ unsigned long wakeup_magic; ++ unsigned long host_vcpucb; ++ unsigned long upcr; ++ unsigned long vpcr; ++ unsigned long dtb_pcr; ++ unsigned long guest_ksp; ++ unsigned long guest_usp; ++ unsigned long vcpu_irq_disabled; ++ unsigned long vcpu_irq; ++ unsigned long ptbr; ++ unsigned long int_stat0; ++ unsigned long int_stat1; ++ unsigned long int_stat2; ++ unsigned long int_stat3; ++ unsigned long reset_entry; ++ unsigned long pvcpu; ++ unsigned long exit_reason; ++ unsigned long ipaddr; ++ unsigned long vcpu_irq_vector; ++}; ++ ++/* ++ * for KVM_GET_FPU and KVM_SET_FPU ++ */ ++struct kvm_fpu { ++}; ++ ++/* ++ * KVM SW_64 specific structures and definitions ++ */ ++struct kvm_debug_exit_arch { ++}; ++ ++/* for KVM_SET_GUEST_DEBUG */ ++struct kvm_guest_debug_arch { ++}; ++ ++/* definition of registers in kvm_run */ ++struct kvm_sync_regs { ++}; ++ ++/* dummy definition */ ++struct kvm_sregs { ++}; ++ ++#define KVM_SW64_VCPU_INIT _IO(KVMIO, 0xba) ++#define KVM_SW64_USE_SLAVE _IO(KVMIO, 0xbb) ++#define KVM_SW64_GET_VCB _IO(KVMIO, 0xbc) ++#define KVM_SW64_SET_VCB _IO(KVMIO, 0xbd) ++ ++#endif /* __LINUX_KVM_SW64_H */ +diff --git a/linux-headers/asm-sw64/unistd.h b/linux-headers/asm-sw64/unistd.h +new file mode 100644 +index 0000000000..affe297e73 +--- /dev/null ++++ b/linux-headers/asm-sw64/unistd.h +@@ -0,0 +1,380 @@ ++#ifndef _UAPI_ASM_SW64_UNISTD_64_H ++#define _UAPI_ASM_SW64_UNISTD_64_H ++ ++#define __NR_exit 1 ++#define __NR_fork 2 ++#define __NR_read 3 ++#define __NR_write 4 ++#define __NR_close 6 ++#define __NR_osf_wait4 7 ++#define __NR_link 9 ++#define __NR_unlink 10 ++#define __NR_chdir 12 ++#define __NR_fchdir 13 ++#define __NR_mknod 14 ++#define __NR_chmod 15 ++#define __NR_chown 16 ++#define __NR_brk 17 ++#define __NR_lseek 19 ++#define __NR_getxpid 20 ++#define __NR_osf_mount 21 ++#define __NR_umount2 22 ++#define __NR_setuid 23 ++#define __NR_getxuid 24 ++#define __NR_ptrace 26 ++#define __NR_access 33 ++#define __NR_sync 36 ++#define __NR_kill 37 ++#define __NR_setpgid 39 ++#define __NR_dup 41 ++#define __NR_pipe 42 ++#define __NR_osf_set_program_attributes 43 ++#define __NR_open 45 ++#define __NR_getxgid 47 ++#define __NR_osf_sigprocmask 48 ++#define __NR_acct 51 ++#define __NR_sigpending 52 ++#define __NR_ioctl 54 ++#define __NR_symlink 57 ++#define __NR_readlink 58 ++#define __NR_execve 59 ++#define __NR_umask 60 ++#define __NR_chroot 61 ++#define __NR_getpgrp 63 ++#define __NR_getpagesize 64 ++#define __NR_vfork 66 ++#define __NR_stat 67 ++#define __NR_lstat 68 ++#define __NR_mmap 71 ++#define __NR_munmap 73 ++#define __NR_mprotect 74 ++#define __NR_madvise 75 ++#define __NR_vhangup 76 ++#define __NR_getgroups 79 ++#define __NR_setgroups 80 ++#define __NR_setpgrp 82 ++#define __NR_osf_setitimer 83 ++#define __NR_osf_getitimer 86 ++#define __NR_gethostname 87 ++#define __NR_sethostname 88 ++#define __NR_getdtablesize 89 ++#define __NR_dup2 90 ++#define __NR_fstat 91 ++#define __NR_fcntl 92 ++#define __NR_osf_select 93 ++#define __NR_poll 94 ++#define __NR_fsync 95 ++#define __NR_setpriority 96 ++#define __NR_socket 97 ++#define __NR_connect 98 ++#define __NR_accept 99 ++#define __NR_getpriority 100 ++#define __NR_send 101 ++#define __NR_recv 102 ++#define __NR_sigreturn 103 ++#define __NR_bind 104 ++#define __NR_setsockopt 105 ++#define __NR_listen 106 ++#define __NR_sigsuspend 111 ++#define __NR_osf_sigstack 112 ++#define __NR_recvmsg 113 ++#define __NR_sendmsg 114 ++#define __NR_osf_gettimeofday 116 ++#define __NR_osf_getrusage 117 ++#define __NR_getsockopt 118 ++#define __NR_socketcall 119 ++#define __NR_readv 120 ++#define __NR_writev 121 ++#define __NR_osf_settimeofday 122 ++#define __NR_fchown 123 ++#define __NR_fchmod 124 ++#define __NR_recvfrom 125 ++#define __NR_setreuid 126 ++#define __NR_setregid 127 ++#define __NR_rename 128 ++#define __NR_truncate 129 ++#define __NR_ftruncate 130 ++#define __NR_flock 131 ++#define __NR_setgid 132 ++#define __NR_sendto 133 ++#define __NR_shutdown 134 ++#define __NR_socketpair 135 ++#define __NR_mkdir 136 ++#define __NR_rmdir 137 ++#define __NR_osf_utimes 138 ++#define __NR_getpeername 141 ++#define __NR_getrlimit 144 ++#define __NR_setrlimit 145 ++#define __NR_setsid 147 ++#define __NR_quotactl 148 ++#define __NR_getsockname 150 ++#define __NR_sigaction 156 ++#define __NR_osf_getdirentries 159 ++#define __NR_osf_statfs 160 ++#define __NR_osf_fstatfs 161 ++#define __NR_osf_getdomainname 165 ++#define __NR_setdomainname 166 ++#define __NR_bpf 170 ++#define __NR_userfaultfd 171 ++#define __NR_membarrier 172 ++#define __NR_mlock2 173 ++#define __NR_getpid 174 ++#define __NR_getppid 175 ++#define __NR_getuid 176 ++#define __NR_geteuid 177 ++#define __NR_getgid 178 ++#define __NR_getegid 179 ++#define __NR_osf_swapon 199 ++#define __NR_msgctl 200 ++#define __NR_msgget 201 ++#define __NR_msgrcv 202 ++#define __NR_msgsnd 203 ++#define __NR_semctl 204 ++#define __NR_semget 205 ++#define __NR_semop 206 ++#define __NR_osf_utsname 207 ++#define __NR_lchown 208 ++#define __NR_shmat 209 ++#define __NR_shmctl 210 ++#define __NR_shmdt 211 ++#define __NR_shmget 212 ++#define __NR_msync 217 ++#define __NR_osf_stat 224 ++#define __NR_osf_lstat 225 ++#define __NR_osf_fstat 226 ++#define __NR_osf_statfs64 227 ++#define __NR_osf_fstatfs64 228 ++#define __NR_statfs64 229 ++#define __NR_fstatfs64 230 ++#define __NR_getpgid 233 ++#define __NR_getsid 234 ++#define __NR_sigaltstack 235 ++#define __NR_osf_sysinfo 241 ++#define __NR_osf_proplist_syscall 244 ++#define __NR_osf_usleep_thread 251 ++#define __NR_sysfs 254 ++#define __NR_osf_getsysinfo 256 ++#define __NR_osf_setsysinfo 257 ++#define __NR_bdflush 300 ++#define __NR_sethae 301 ++#define __NR_mount 302 ++#define __NR_old_adjtimex 303 ++#define __NR_swapoff 304 ++#define __NR_getdents 305 ++#define __NR_create_module 306 ++#define __NR_init_module 307 ++#define __NR_delete_module 308 ++#define __NR_get_kernel_syms 309 ++#define __NR_syslog 310 ++#define __NR_reboot 311 ++#define __NR_clone 312 ++#define __NR_uselib 313 ++#define __NR_mlock 314 ++#define __NR_munlock 315 ++#define __NR_mlockall 316 ++#define __NR_munlockall 317 ++#define __NR_sysinfo 318 ++#define __NR__sysctl 319 ++#define __NR_oldumount 321 ++#define __NR_swapon 322 ++#define __NR_times 323 ++#define __NR_personality 324 ++#define __NR_setfsuid 325 ++#define __NR_setfsgid 326 ++#define __NR_ustat 327 ++#define __NR_statfs 328 ++#define __NR_fstatfs 329 ++#define __NR_sched_setparam 330 ++#define __NR_sched_getparam 331 ++#define __NR_sched_setscheduler 332 ++#define __NR_sched_getscheduler 333 ++#define __NR_sched_yield 334 ++#define __NR_sched_get_priority_max 335 ++#define __NR_sched_get_priority_min 336 ++#define __NR_sched_rr_get_interval 337 ++#define __NR_afs_syscall 338 ++#define __NR_uname 339 ++#define __NR_nanosleep 340 ++#define __NR_mremap 341 ++#define __NR_nfsservctl 342 ++#define __NR_setresuid 343 ++#define __NR_getresuid 344 ++#define __NR_pciconfig_read 345 ++#define __NR_pciconfig_write 346 ++#define __NR_query_module 347 ++#define __NR_prctl 348 ++#define __NR_pread64 349 ++#define __NR_pwrite64 350 ++#define __NR_rt_sigreturn 351 ++#define __NR_rt_sigaction 352 ++#define __NR_rt_sigprocmask 353 ++#define __NR_rt_sigpending 354 ++#define __NR_rt_sigtimedwait 355 ++#define __NR_rt_sigqueueinfo 356 ++#define __NR_rt_sigsuspend 357 ++#define __NR_select 358 ++#define __NR_gettimeofday 359 ++#define __NR_settimeofday 360 ++#define __NR_getitimer 361 ++#define __NR_setitimer 362 ++#define __NR_utimes 363 ++#define __NR_getrusage 364 ++#define __NR_wait4 365 ++#define __NR_adjtimex 366 ++#define __NR_getcwd 367 ++#define __NR_capget 368 ++#define __NR_capset 369 ++#define __NR_sendfile 370 ++#define __NR_setresgid 371 ++#define __NR_getresgid 372 ++#define __NR_dipc 373 ++#define __NR_pivot_root 374 ++#define __NR_mincore 375 ++#define __NR_pciconfig_iobase 376 ++#define __NR_getdents64 377 ++#define __NR_gettid 378 ++#define __NR_readahead 379 ++#define __NR_tkill 381 ++#define __NR_setxattr 382 ++#define __NR_lsetxattr 383 ++#define __NR_fsetxattr 384 ++#define __NR_getxattr 385 ++#define __NR_lgetxattr 386 ++#define __NR_fgetxattr 387 ++#define __NR_listxattr 388 ++#define __NR_llistxattr 389 ++#define __NR_flistxattr 390 ++#define __NR_removexattr 391 ++#define __NR_lremovexattr 392 ++#define __NR_fremovexattr 393 ++#define __NR_futex 394 ++#define __NR_sched_setaffinity 395 ++#define __NR_sched_getaffinity 396 ++#define __NR_tuxcall 397 ++#define __NR_io_setup 398 ++#define __NR_io_destroy 399 ++#define __NR_io_getevents 400 ++#define __NR_io_submit 401 ++#define __NR_io_cancel 402 ++#define __NR_io_pgetevents 403 ++#define __NR_rseq 404 ++#define __NR_exit_group 405 ++#define __NR_lookup_dcookie 406 ++#define __NR_epoll_create 407 ++#define __NR_epoll_ctl 408 ++#define __NR_epoll_wait 409 ++#define __NR_remap_file_pages 410 ++#define __NR_set_tid_address 411 ++#define __NR_restart_syscall 412 ++#define __NR_fadvise64 413 ++#define __NR_timer_create 414 ++#define __NR_timer_settime 415 ++#define __NR_timer_gettime 416 ++#define __NR_timer_getoverrun 417 ++#define __NR_timer_delete 418 ++#define __NR_clock_settime 419 ++#define __NR_clock_gettime 420 ++#define __NR_clock_getres 421 ++#define __NR_clock_nanosleep 422 ++#define __NR_semtimedop 423 ++#define __NR_tgkill 424 ++#define __NR_stat64 425 ++#define __NR_lstat64 426 ++#define __NR_fstat64 427 ++#define __NR_vserver 428 ++#define __NR_mbind 429 ++#define __NR_get_mempolicy 430 ++#define __NR_set_mempolicy 431 ++#define __NR_mq_open 432 ++#define __NR_mq_unlink 433 ++#define __NR_mq_timedsend 434 ++#define __NR_mq_timedreceive 435 ++#define __NR_mq_notify 436 ++#define __NR_mq_getsetattr 437 ++#define __NR_waitid 438 ++#define __NR_add_key 439 ++#define __NR_request_key 440 ++#define __NR_keyctl 441 ++#define __NR_ioprio_set 442 ++#define __NR_ioprio_get 443 ++#define __NR_inotify_init 444 ++#define __NR_inotify_add_watch 445 ++#define __NR_inotify_rm_watch 446 ++#define __NR_fdatasync 447 ++#define __NR_kexec_load 448 ++#define __NR_migrate_pages 449 ++#define __NR_openat 450 ++#define __NR_mkdirat 451 ++#define __NR_mknodat 452 ++#define __NR_fchownat 453 ++#define __NR_futimesat 454 ++#define __NR_fstatat64 455 ++#define __NR_unlinkat 456 ++#define __NR_renameat 457 ++#define __NR_linkat 458 ++#define __NR_symlinkat 459 ++#define __NR_readlinkat 460 ++#define __NR_fchmodat 461 ++#define __NR_faccessat 462 ++#define __NR_pselect6 463 ++#define __NR_ppoll 464 ++#define __NR_unshare 465 ++#define __NR_set_robust_list 466 ++#define __NR_get_robust_list 467 ++#define __NR_splice 468 ++#define __NR_sync_file_range 469 ++#define __NR_tee 470 ++#define __NR_vmsplice 471 ++#define __NR_move_pages 472 ++#define __NR_getcpu 473 ++#define __NR_epoll_pwait 474 ++#define __NR_utimensat 475 ++#define __NR_signalfd 476 ++#define __NR_timerfd 477 ++#define __NR_eventfd 478 ++#define __NR_recvmmsg 479 ++#define __NR_fallocate 480 ++#define __NR_timerfd_create 481 ++#define __NR_timerfd_settime 482 ++#define __NR_timerfd_gettime 483 ++#define __NR_signalfd4 484 ++#define __NR_eventfd2 485 ++#define __NR_epoll_create1 486 ++#define __NR_dup3 487 ++#define __NR_pipe2 488 ++#define __NR_inotify_init1 489 ++#define __NR_preadv 490 ++#define __NR_pwritev 491 ++#define __NR_rt_tgsigqueueinfo 492 ++#define __NR_perf_event_open 493 ++#define __NR_fanotify_init 494 ++#define __NR_fanotify_mark 495 ++#define __NR_prlimit64 496 ++#define __NR_name_to_handle_at 497 ++#define __NR_open_by_handle_at 498 ++#define __NR_clock_adjtime 499 ++#define __NR_syncfs 500 ++#define __NR_setns 501 ++#define __NR_accept4 502 ++#define __NR_sendmmsg 503 ++#define __NR_process_vm_readv 504 ++#define __NR_process_vm_writev 505 ++#define __NR_kcmp 506 ++#define __NR_finit_module 507 ++#define __NR_sched_setattr 508 ++#define __NR_sched_getattr 509 ++#define __NR_renameat2 510 ++#define __NR_getrandom 511 ++#define __NR_memfd_create 512 ++#define __NR_execveat 513 ++#define __NR_seccomp 514 ++#define __NR_copy_file_range 515 ++#define __NR_preadv2 516 ++#define __NR_pwritev2 517 ++#define __NR_statx 518 ++ ++#ifdef __KERNEL__ ++#define __NR_syscalls 519 ++#endif ++ ++#endif /* _UAPI_ASM_SW64_UNISTD_64_H */ +diff --git a/linux-user/meson.build b/linux-user/meson.build +index bf62c13e37..4f4196ed13 100644 +--- a/linux-user/meson.build ++++ b/linux-user/meson.build +@@ -37,5 +37,6 @@ subdir('ppc') + subdir('s390x') + subdir('sh4') + subdir('sparc') ++subdir('sw64') + subdir('x86_64') + subdir('xtensa') +diff --git a/linux-user/sw64/cpu_loop.c b/linux-user/sw64/cpu_loop.c +new file mode 100644 +index 0000000000..3f2fde0fba +--- /dev/null ++++ b/linux-user/sw64/cpu_loop.c +@@ -0,0 +1,108 @@ ++/* ++ * qemu user cpu loop ++ * ++ * Copyright (c) 2003-2008 Fabrice Bellard ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "cpu_loop-common.h" ++ ++void cpu_loop(CPUSW64State *env) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ int trapnr; ++ target_siginfo_t info; ++ abi_long sysret; ++ ++ while (1) { ++ cpu_exec_start(cs); ++ trapnr = cpu_exec(cs); ++ cpu_exec_end(cs); ++ process_queued_cpu_work(cs); ++ ++ switch (trapnr) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL SW64 insn at line %d!", __LINE__); ++ case EXCP_CALL_SYS: ++ switch (env->error_code) { ++ case 0x83: ++ /* CALLSYS */ ++ trapnr = env->ir[IDX_V0]; ++ sysret = do_syscall(env, trapnr, ++ env->ir[IDX_A0], env->ir[IDX_A1], ++ env->ir[IDX_A2], env->ir[IDX_A3], ++ env->ir[IDX_A4], env->ir[IDX_A5], ++ 0, 0); ++ if (sysret == -TARGET_ERESTARTSYS) { ++ env->pc -= 4; ++ break; ++ } ++ if (sysret == -TARGET_QEMU_ESIGRETURN) { ++ break; ++ } ++ /* Syscall writes 0 to V0 to bypass error check, similar ++ to how this is handled internal to Linux kernel. ++ (Ab)use trapnr temporarily as boolean indicating error. */ ++ trapnr = (env->ir[IDX_V0] != 0 && sysret < 0); ++ env->ir[IDX_V0] = (trapnr ? -sysret : sysret); ++ env->ir[IDX_A3] = trapnr; ++ break; ++ default: ++ printf("UNDO sys_call %lx\n", env->error_code); ++ exit(-1); ++ } ++ break; ++ case EXCP_MMFAULT: ++ info.si_signo = TARGET_SIGSEGV; ++ info.si_errno = 0; ++ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ++ ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); ++ info._sifields._sigfault._addr = env->trap_arg0; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_ARITH: ++ info.si_signo = TARGET_SIGFPE; ++ info.si_errno = 0; ++ info.si_code = TARGET_FPE_FLTINV; ++ info._sifields._sigfault._addr = env->pc; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_INTERRUPT: ++ /* just indicate that signals should be handled asap */ ++ break; ++ default: ++ cpu_abort(cs, "UNDO"); ++ } ++ process_pending_signals (env); ++ ++ /* Most of the traps imply a transition through HMcode, which ++ implies an REI instruction has been executed. Which means ++ that RX and LOCK_ADDR should be cleared. But there are a ++ few exceptions for traps internal to QEMU. */ ++ } ++} ++ ++void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) ++{ ++ int i; ++ ++ for(i = 0; i < 28; i++) { ++ env->ir[i] = ((abi_ulong *)regs)[i]; ++ } ++ env->ir[IDX_SP] = regs->usp; ++ env->pc = regs->pc; ++} +diff --git a/linux-user/sw64/signal.c b/linux-user/sw64/signal.c +new file mode 100644 +index 0000000000..5822e808d3 +--- /dev/null ++++ b/linux-user/sw64/signal.c +@@ -0,0 +1,273 @@ ++/* ++ * Emulation of Linux signals ++ * ++ * Copyright (c) 2003 Fabrice Bellard ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "signal-common.h" ++#include "linux-user/trace.h" ++ ++struct target_sigcontext { ++ abi_long sc_onstack; ++ abi_long sc_mask; ++ abi_long sc_pc; ++ abi_long sc_ps; ++ abi_long sc_regs[32]; ++ abi_long sc_ownedfp; ++ abi_long sc_fpregs[32]; ++ abi_ulong sc_fpcr; ++ abi_ulong sc_fp_control; ++ abi_ulong sc_reserved1; ++ abi_ulong sc_reserved2; ++ abi_ulong sc_ssize; ++ abi_ulong sc_sbase; ++ abi_ulong sc_traparg_a0; ++ abi_ulong sc_traparg_a1; ++ abi_ulong sc_traparg_a2; ++ abi_ulong sc_fp_trap_pc; ++ abi_ulong sc_fp_trigger_sum; ++ abi_ulong sc_fp_trigger_inst; ++}; ++ ++struct target_ucontext { ++ abi_ulong tuc_flags; ++ abi_ulong tuc_link; ++ abi_ulong tuc_osf_sigmask; ++ target_stack_t tuc_stack; ++ struct target_sigcontext tuc_mcontext; ++ target_sigset_t tuc_sigmask; ++}; ++ ++struct target_sigframe { ++ struct target_sigcontext sc; ++ unsigned int retcode[3]; ++}; ++ ++struct target_rt_sigframe { ++ target_siginfo_t info; ++ struct target_ucontext uc; ++ unsigned int retcode[3]; ++}; ++ ++#define INSN_MOV_R30_R16 0x47fe0410 ++#define INSN_LDI_R0 0x201f0000 ++#define INSN_CALLSYS 0x00000083 ++ ++static void setup_sigcontext(struct target_sigcontext *sc, CPUSW64State *env, ++ abi_ulong frame_addr, target_sigset_t *set) ++{ ++ int i; ++ ++ __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); ++ __put_user(set->sig[0], &sc->sc_mask); ++ __put_user(env->pc, &sc->sc_pc); ++ __put_user(8, &sc->sc_ps); ++ ++ for (i = 0; i < 31; ++i) { ++ __put_user(env->ir[i], &sc->sc_regs[i]); ++ } ++ __put_user(0, &sc->sc_regs[31]); ++ ++ for (i = 0; i < 31; ++i) { ++ __put_user(env->fr[i], &sc->sc_fpregs[i]); ++ } ++ __put_user(0, &sc->sc_fpregs[31]); ++ __put_user(cpu_sw64_load_fpcr(env), &sc->sc_fpcr); ++ ++ __put_user(0, &sc->sc_traparg_a0); /* FIXME */ ++ __put_user(0, &sc->sc_traparg_a1); /* FIXME */ ++ __put_user(0, &sc->sc_traparg_a2); /* FIXME */ ++} ++ ++static void restore_sigcontext(CPUSW64State *env, ++ struct target_sigcontext *sc) ++{ ++ uint64_t fpcr; ++ int i; ++ ++ __get_user(env->pc, &sc->sc_pc); ++ ++ for (i = 0; i < 31; ++i) { ++ __get_user(env->ir[i], &sc->sc_regs[i]); ++ } ++ for (i = 0; i < 31; ++i) { ++ __get_user(env->fr[i], &sc->sc_fpregs[i]); ++ } ++ ++ __get_user(fpcr, &sc->sc_fpcr); ++ cpu_sw64_store_fpcr(env, fpcr); ++} ++ ++static inline abi_ulong get_sigframe(struct target_sigaction *sa, ++ CPUSW64State *env, ++ unsigned long framesize) ++{ ++ abi_ulong sp; ++ ++ sp = target_sigsp(get_sp_from_cpustate(env), sa); ++ ++ return (sp - framesize) & -32; ++} ++ ++void setup_frame(int sig, struct target_sigaction *ka, ++ target_sigset_t *set, CPUSW64State *env) ++{ ++ abi_ulong frame_addr, r26; ++ struct target_sigframe *frame; ++ int err = 0; ++ ++ frame_addr = get_sigframe(ka, env, sizeof(*frame)); ++ trace_user_setup_frame(env, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { ++ goto give_sigsegv; ++ } ++ ++ setup_sigcontext(&frame->sc, env, frame_addr, set); ++ ++ if (ka->sa_restorer) { ++ r26 = ka->sa_restorer; ++ } else { ++ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, ++ &frame->retcode[1]); ++ __put_user(INSN_CALLSYS, &frame->retcode[2]); ++ /* imb() */ ++ r26 = frame_addr + offsetof(struct target_sigframe, retcode); ++ } ++ ++ unlock_user_struct(frame, frame_addr, 1); ++ ++ if (err) { ++give_sigsegv: ++ force_sigsegv(sig); ++ return; ++ } ++ ++ env->ir[IDX_RA] = r26; ++ env->ir[IDX_PV] = env->pc = ka->_sa_handler; ++ env->ir[IDX_A0] = sig; ++ env->ir[IDX_A1] = 0; ++ env->ir[IDX_A2] = frame_addr + offsetof(struct target_sigframe, sc); ++ env->ir[IDX_SP] = frame_addr; ++} ++ ++void setup_rt_frame(int sig, struct target_sigaction *ka, ++ target_siginfo_t *info, ++ target_sigset_t *set, CPUSW64State *env) ++{ ++ abi_ulong frame_addr, r26; ++ struct target_rt_sigframe *frame; ++ int i, err = 0; ++ ++ frame_addr = get_sigframe(ka, env, sizeof(*frame)); ++ trace_user_setup_rt_frame(env, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { ++ goto give_sigsegv; ++ } ++ ++ tswap_siginfo(&frame->info, info); ++ ++ __put_user(0, &frame->uc.tuc_flags); ++ __put_user(0, &frame->uc.tuc_link); ++ __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); ++ ++ target_save_altstack(&frame->uc.tuc_stack, env); ++ ++ setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); ++ for (i = 0; i < TARGET_NSIG_WORDS; ++i) { ++ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); ++ } ++ ++ if (ka->sa_restorer) { ++ r26 = ka->sa_restorer; ++ } else { ++ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, ++ &frame->retcode[1]); ++ __put_user(INSN_CALLSYS, &frame->retcode[2]); ++ r26 = frame_addr + offsetof(struct target_sigframe, retcode); ++ } ++ ++ if (err) { ++give_sigsegv: ++ force_sigsegv(sig); ++ return; ++ } ++ ++ env->ir[IDX_RA] = r26; ++ env->ir[IDX_PV] = env->pc = ka->_sa_handler; ++ env->ir[IDX_A0] = sig; ++ env->ir[IDX_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); ++ env->ir[IDX_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); ++ env->ir[IDX_SP] = frame_addr; ++} ++ ++long do_sigreturn(CPUSW64State *env) ++{ ++ struct target_sigcontext *sc; ++ abi_ulong sc_addr = env->ir[IDX_A0]; ++ target_sigset_t target_set; ++ sigset_t set; ++ ++ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { ++ goto badframe; ++ } ++ ++ target_sigemptyset(&target_set); ++ __get_user(target_set.sig[0], &sc->sc_mask); ++ ++ target_to_host_sigset_internal(&set, &target_set); ++ set_sigmask(&set); ++ ++ restore_sigcontext(env, sc); ++ unlock_user_struct(sc, sc_addr, 0); ++ return -TARGET_QEMU_ESIGRETURN; ++ ++badframe: ++ force_sig(TARGET_SIGSEGV); ++ return -TARGET_QEMU_ESIGRETURN; ++} ++ ++long do_rt_sigreturn(CPUSW64State *env) ++{ ++ abi_ulong frame_addr = env->ir[IDX_A0]; ++ struct target_rt_sigframe *frame; ++ sigset_t set; ++ ++ trace_user_do_rt_sigreturn(env, frame_addr); ++ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { ++ goto badframe; ++ } ++ target_to_host_sigset(&set, &frame->uc.tuc_sigmask); ++ set_sigmask(&set); ++ ++ restore_sigcontext(env, &frame->uc.tuc_mcontext); ++ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, ++ uc.tuc_stack), ++ 0, env->ir[IDX_SP]) == -EFAULT) { ++ goto badframe; ++ } ++ ++ unlock_user_struct(frame, frame_addr, 0); ++ return -TARGET_QEMU_ESIGRETURN; ++ ++ ++badframe: ++ unlock_user_struct(frame, frame_addr, 0); ++ force_sig(TARGET_SIGSEGV); ++ return -TARGET_QEMU_ESIGRETURN; ++} +diff --git a/linux-user/sw64/sockbits.h b/linux-user/sw64/sockbits.h +new file mode 100644 +index 0000000000..0e4c8f012d +--- /dev/null ++++ b/linux-user/sw64/sockbits.h +@@ -0,0 +1 @@ ++#include "../generic/sockbits.h" +diff --git a/linux-user/sw64/syscall_nr.h b/linux-user/sw64/syscall_nr.h +new file mode 100644 +index 0000000000..91737af322 +--- /dev/null ++++ b/linux-user/sw64/syscall_nr.h +@@ -0,0 +1,471 @@ ++/* ++ * This file contains the system call numbers. ++ */ ++#define TARGET_NR_osf_syscall 0 /* not implemented */ ++#define TARGET_NR_exit 1 ++#define TARGET_NR_fork 2 ++#define TARGET_NR_read 3 ++#define TARGET_NR_write 4 ++#define TARGET_NR_osf_old_open 5 /* not implemented */ ++#define TARGET_NR_close 6 ++#define TARGET_NR_osf_wait4 7 ++#define TARGET_NR_osf_old_creat 8 /* not implemented */ ++#define TARGET_NR_link 9 ++#define TARGET_NR_unlink 10 ++#define TARGET_NR_osf_execve 11 /* not implemented */ ++#define TARGET_NR_chdir 12 ++#define TARGET_NR_fchdir 13 ++#define TARGET_NR_mknod 14 ++#define TARGET_NR_chmod 15 ++#define TARGET_NR_chown 16 ++#define TARGET_NR_brk 17 ++#define TARGET_NR_osf_getfsstat 18 /* not implemented */ ++#define TARGET_NR_lseek 19 ++#define TARGET_NR_getxpid 20 ++#define TARGET_NR_osf_mount 21 ++#define TARGET_NR_umount 22 ++#define TARGET_NR_setuid 23 ++#define TARGET_NR_getxuid 24 ++#define TARGET_NR_exec_with_loader 25 /* not implemented */ ++#define TARGET_NR_ptrace 26 ++#define TARGET_NR_osf_nrecvmsg 27 /* not implemented */ ++#define TARGET_NR_osf_nsendmsg 28 /* not implemented */ ++#define TARGET_NR_osf_nrecvfrom 29 /* not implemented */ ++#define TARGET_NR_osf_naccept 30 /* not implemented */ ++#define TARGET_NR_osf_ngetpeername 31 /* not implemented */ ++#define TARGET_NR_osf_ngetsockname 32 /* not implemented */ ++#define TARGET_NR_access 33 ++#define TARGET_NR_osf_chflags 34 /* not implemented */ ++#define TARGET_NR_osf_fchflags 35 /* not implemented */ ++#define TARGET_NR_sync 36 ++#define TARGET_NR_kill 37 ++#define TARGET_NR_osf_old_stat 38 /* not implemented */ ++#define TARGET_NR_setpgid 39 ++#define TARGET_NR_osf_old_lstat 40 /* not implemented */ ++#define TARGET_NR_dup 41 ++#define TARGET_NR_pipe 42 ++#define TARGET_NR_osf_set_program_attributes 43 ++#define TARGET_NR_osf_profil 44 /* not implemented */ ++#define TARGET_NR_open 45 ++#define TARGET_NR_osf_old_sigaction 46 /* not implemented */ ++#define TARGET_NR_getxgid 47 ++#define TARGET_NR_osf_sigprocmask 48 ++#define TARGET_NR_osf_getlogin 49 /* not implemented */ ++#define TARGET_NR_osf_setlogin 50 /* not implemented */ ++#define TARGET_NR_acct 51 ++#define TARGET_NR_sigpending 52 ++ ++#define TARGET_NR_ioctl 54 ++#define TARGET_NR_osf_reboot 55 /* not implemented */ ++#define TARGET_NR_osf_revoke 56 /* not implemented */ ++#define TARGET_NR_symlink 57 ++#define TARGET_NR_readlink 58 ++#define TARGET_NR_execve 59 ++#define TARGET_NR_umask 60 ++#define TARGET_NR_chroot 61 ++#define TARGET_NR_osf_old_fstat 62 /* not implemented */ ++#define TARGET_NR_getpgrp 63 ++#define TARGET_NR_getpagesize 64 ++#define TARGET_NR_osf_mremap 65 /* not implemented */ ++#define TARGET_NR_vfork 66 ++#define TARGET_NR_stat 67 ++#define TARGET_NR_lstat 68 ++#define TARGET_NR_osf_sbrk 69 /* not implemented */ ++#define TARGET_NR_osf_sstk 70 /* not implemented */ ++#define TARGET_NR_mmap 71 /* OSF/1 mmap is superset of Linux */ ++#define TARGET_NR_osf_old_vadvise 72 /* not implemented */ ++#define TARGET_NR_munmap 73 ++#define TARGET_NR_mprotect 74 ++#define TARGET_NR_madvise 75 ++#define TARGET_NR_vhangup 76 ++#define TARGET_NR_osf_kmodcall 77 /* not implemented */ ++#define TARGET_NR_osf_mincore 78 /* not implemented */ ++#define TARGET_NR_getgroups 79 ++#define TARGET_NR_setgroups 80 ++#define TARGET_NR_osf_old_getpgrp 81 /* not implemented */ ++#define TARGET_NR_setpgrp 82 /* BSD alias for setpgid */ ++#define TARGET_NR_osf_setitimer 83 ++#define TARGET_NR_osf_old_wait 84 /* not implemented */ ++#define TARGET_NR_osf_table 85 /* not implemented */ ++#define TARGET_NR_osf_getitimer 86 ++#define TARGET_NR_gethostname 87 ++#define TARGET_NR_sethostname 88 ++#define TARGET_NR_getdtablesize 89 ++#define TARGET_NR_dup2 90 ++#define TARGET_NR_fstat 91 ++#define TARGET_NR_fcntl 92 ++#define TARGET_NR_osf_select 93 ++#define TARGET_NR_poll 94 ++#define TARGET_NR_fsync 95 ++#define TARGET_NR_setpriority 96 ++#define TARGET_NR_socket 97 ++#define TARGET_NR_connect 98 ++#define TARGET_NR_accept 99 ++#define TARGET_NR_getpriority 100 ++#define TARGET_NR_send 101 ++#define TARGET_NR_recv 102 ++#define TARGET_NR_sigreturn 103 ++#define TARGET_NR_bind 104 ++#define TARGET_NR_setsockopt 105 ++#define TARGET_NR_listen 106 ++#define TARGET_NR_osf_plock 107 /* not implemented */ ++#define TARGET_NR_osf_old_sigvec 108 /* not implemented */ ++#define TARGET_NR_osf_old_sigblock 109 /* not implemented */ ++#define TARGET_NR_osf_old_sigsetmask 110 /* not implemented */ ++#define TARGET_NR_sigsuspend 111 ++#define TARGET_NR_osf_sigstack 112 ++#define TARGET_NR_recvmsg 113 ++#define TARGET_NR_sendmsg 114 ++#define TARGET_NR_osf_old_vtrace 115 /* not implemented */ ++#define TARGET_NR_osf_gettimeofday 116 ++#define TARGET_NR_osf_getrusage 117 ++#define TARGET_NR_getsockopt 118 ++ ++#define TARGET_NR_readv 120 ++#define TARGET_NR_writev 121 ++#define TARGET_NR_osf_settimeofday 122 ++#define TARGET_NR_fchown 123 ++#define TARGET_NR_fchmod 124 ++#define TARGET_NR_recvfrom 125 ++#define TARGET_NR_setreuid 126 ++#define TARGET_NR_setregid 127 ++#define TARGET_NR_rename 128 ++#define TARGET_NR_truncate 129 ++#define TARGET_NR_ftruncate 130 ++#define TARGET_NR_flock 131 ++#define TARGET_NR_setgid 132 ++#define TARGET_NR_sendto 133 ++#define TARGET_NR_shutdown 134 ++#define TARGET_NR_socketpair 135 ++#define TARGET_NR_mkdir 136 ++#define TARGET_NR_rmdir 137 ++#define TARGET_NR_osf_utimes 138 ++#define TARGET_NR_osf_old_sigreturn 139 /* not implemented */ ++#define TARGET_NR_osf_adjtime 140 /* not implemented */ ++#define TARGET_NR_getpeername 141 ++#define TARGET_NR_osf_gethostid 142 /* not implemented */ ++#define TARGET_NR_osf_sethostid 143 /* not implemented */ ++#define TARGET_NR_getrlimit 144 ++#define TARGET_NR_setrlimit 145 ++#define TARGET_NR_osf_old_killpg 146 /* not implemented */ ++#define TARGET_NR_setsid 147 ++#define TARGET_NR_quotactl 148 ++#define TARGET_NR_osf_oldquota 149 /* not implemented */ ++#define TARGET_NR_getsockname 150 ++ ++#define TARGET_NR_osf_pid_block 153 /* not implemented */ ++#define TARGET_NR_osf_pid_unblock 154 /* not implemented */ ++ ++#define TARGET_NR_sigaction 156 ++#define TARGET_NR_osf_sigwaitprim 157 /* not implemented */ ++#define TARGET_NR_osf_nfssvc 158 /* not implemented */ ++#define TARGET_NR_osf_getdirentries 159 ++#define TARGET_NR_osf_statfs 160 ++#define TARGET_NR_osf_fstatfs 161 ++ ++#define TARGET_NR_osf_asynch_daemon 163 /* not implemented */ ++#define TARGET_NR_osf_getfh 164 /* not implemented */ ++#define TARGET_NR_osf_getdomainname 165 ++#define TARGET_NR_setdomainname 166 ++ ++#define TARGET_NR_osf_exportfs 169 /* not implemented */ ++ ++#define TARGET_NR_osf_alt_plock 181 /* not implemented */ ++ ++#define TARGET_NR_osf_getmnt 184 /* not implemented */ ++ ++#define TARGET_NR_osf_alt_sigpending 187 /* not implemented */ ++#define TARGET_NR_osf_alt_setsid 188 /* not implemented */ ++ ++#define TARGET_NR_osf_swapon 199 ++#define TARGET_NR_msgctl 200 ++#define TARGET_NR_msgget 201 ++#define TARGET_NR_msgrcv 202 ++#define TARGET_NR_msgsnd 203 ++#define TARGET_NR_semctl 204 ++#define TARGET_NR_semget 205 ++#define TARGET_NR_semop 206 ++#define TARGET_NR_osf_utsname 207 ++#define TARGET_NR_lchown 208 ++#define TARGET_NR_osf_shmat 209 ++#define TARGET_NR_shmctl 210 ++#define TARGET_NR_shmdt 211 ++#define TARGET_NR_shmget 212 ++#define TARGET_NR_osf_mvalid 213 /* not implemented */ ++#define TARGET_NR_osf_getaddressconf 214 /* not implemented */ ++#define TARGET_NR_osf_msleep 215 /* not implemented */ ++#define TARGET_NR_osf_mwakeup 216 /* not implemented */ ++#define TARGET_NR_msync 217 ++#define TARGET_NR_osf_signal 218 /* not implemented */ ++#define TARGET_NR_osf_utc_gettime 219 /* not implemented */ ++#define TARGET_NR_osf_utc_adjtime 220 /* not implemented */ ++ ++#define TARGET_NR_osf_security 222 /* not implemented */ ++#define TARGET_NR_osf_kloadcall 223 /* not implemented */ ++ ++#define TARGET_NR_osf_stat 224 ++#define TARGET_NR_osf_lstat 225 ++#define TARGET_NR_osf_fstat 226 ++#define TARGET_NR_osf_statfs64 227 ++#define TARGET_NR_osf_fstatfs64 228 ++ ++#define TARGET_NR_getpgid 233 ++#define TARGET_NR_getsid 234 ++#define TARGET_NR_sigaltstack 235 ++#define TARGET_NR_osf_waitid 236 /* not implemented */ ++#define TARGET_NR_osf_priocntlset 237 /* not implemented */ ++#define TARGET_NR_osf_sigsendset 238 /* not implemented */ ++#define TARGET_NR_osf_set_speculative 239 /* not implemented */ ++#define TARGET_NR_osf_msfs_syscall 240 /* not implemented */ ++#define TARGET_NR_osf_sysinfo 241 ++#define TARGET_NR_osf_uadmin 242 /* not implemented */ ++#define TARGET_NR_osf_fuser 243 /* not implemented */ ++#define TARGET_NR_osf_proplist_syscall 244 ++#define TARGET_NR_osf_ntp_adjtime 245 /* not implemented */ ++#define TARGET_NR_osf_ntp_gettime 246 /* not implemented */ ++#define TARGET_NR_osf_pathconf 247 /* not implemented */ ++#define TARGET_NR_osf_fpathconf 248 /* not implemented */ ++ ++#define TARGET_NR_osf_uswitch 250 /* not implemented */ ++#define TARGET_NR_osf_usleep_thread 251 ++#define TARGET_NR_osf_audcntl 252 /* not implemented */ ++#define TARGET_NR_osf_audgen 253 /* not implemented */ ++#define TARGET_NR_sysfs 254 ++#define TARGET_NR_osf_subsys_info 255 /* not implemented */ ++#define TARGET_NR_osf_getsysinfo 256 ++#define TARGET_NR_osf_setsysinfo 257 ++#define TARGET_NR_osf_afs_syscall 258 /* not implemented */ ++#define TARGET_NR_osf_swapctl 259 /* not implemented */ ++#define TARGET_NR_osf_memcntl 260 /* not implemented */ ++#define TARGET_NR_osf_fdatasync 261 /* not implemented */ ++ ++/* ++ * Ignore legacy syscalls that we don't use. ++ */ ++#define TARGET_IGNORE_alarm ++#define TARGET_IGNORE_creat ++#define TARGET_IGNORE_getegid ++#define TARGET_IGNORE_geteuid ++#define TARGET_IGNORE_getgid ++#define TARGET_IGNORE_getpid ++#define TARGET_IGNORE_getppid ++#define TARGET_IGNORE_getuid ++#define TARGET_IGNORE_pause ++#define TARGET_IGNORE_time ++#define TARGET_IGNORE_utime ++#define TARGET_IGNORE_umount2 ++ ++/* ++ * Linux-specific system calls begin at 300 ++ */ ++#define TARGET_NR_bdflush 300 ++#define TARGET_NR_sethae 301 ++#define TARGET_NR_mount 302 ++#define TARGET_NR_old_adjtimex 303 ++#define TARGET_NR_swapoff 304 ++#define TARGET_NR_getdents 305 ++#define TARGET_NR_create_module 306 ++#define TARGET_NR_init_module 307 ++#define TARGET_NR_delete_module 308 ++#define TARGET_NR_get_kernel_syms 309 ++#define TARGET_NR_syslog 310 ++#define TARGET_NR_reboot 311 ++#define TARGET_NR_clone 312 ++#define TARGET_NR_uselib 313 ++#define TARGET_NR_mlock 314 ++#define TARGET_NR_munlock 315 ++#define TARGET_NR_mlockall 316 ++#define TARGET_NR_munlockall 317 ++#define TARGET_NR_sysinfo 318 ++#define TARGET_NR__sysctl 319 ++/* 320 was sysTARGETidle. */ ++#define TARGET_NR_oldumount 321 ++#define TARGET_NR_swapon 322 ++#define TARGET_NR_times 323 ++#define TARGET_NR_personality 324 ++#define TARGET_NR_setfsuid 325 ++#define TARGET_NR_setfsgid 326 ++#define TARGET_NR_ustat 327 ++#define TARGET_NR_statfs 328 ++#define TARGET_NR_fstatfs 329 ++#define TARGET_NR_sched_setparam 330 ++#define TARGET_NR_sched_getparam 331 ++#define TARGET_NR_sched_setscheduler 332 ++#define TARGET_NR_sched_getscheduler 333 ++#define TARGET_NR_sched_yield 334 ++#define TARGET_NR_sched_get_priority_max 335 ++#define TARGET_NR_sched_get_priority_min 336 ++#define TARGET_NR_sched_rr_get_interval 337 ++#define TARGET_NR_afs_syscall 338 ++#define TARGET_NR_uname 339 ++#define TARGET_NR_nanosleep 340 ++#define TARGET_NR_mremap 341 ++#define TARGET_NR_nfsservctl 342 ++#define TARGET_NR_setresuid 343 ++#define TARGET_NR_getresuid 344 ++#define TARGET_NR_pciconfig_read 345 ++#define TARGET_NR_pciconfig_write 346 ++#define TARGET_NR_query_module 347 ++#define TARGET_NR_prctl 348 ++#define TARGET_NR_pread64 349 ++#define TARGET_NR_pwrite64 350 ++#define TARGET_NR_rt_sigreturn 351 ++#define TARGET_NR_rt_sigaction 352 ++#define TARGET_NR_rt_sigprocmask 353 ++#define TARGET_NR_rt_sigpending 354 ++#define TARGET_NR_rt_sigtimedwait 355 ++#define TARGET_NR_rt_sigqueueinfo 356 ++#define TARGET_NR_rt_sigsuspend 357 ++#define TARGET_NR_select 358 ++#define TARGET_NR_gettimeofday 359 ++#define TARGET_NR_settimeofday 360 ++#define TARGET_NR_getitimer 361 ++#define TARGET_NR_setitimer 362 ++#define TARGET_NR_utimes 363 ++#define TARGET_NR_getrusage 364 ++#define TARGET_NR_wait4 365 ++#define TARGET_NR_adjtimex 366 ++#define TARGET_NR_getcwd 367 ++#define TARGET_NR_capget 368 ++#define TARGET_NR_capset 369 ++#define TARGET_NR_sendfile 370 ++#define TARGET_NR_setresgid 371 ++#define TARGET_NR_getresgid 372 ++#define TARGET_NR_dipc 373 ++#define TARGET_NR_pivot_root 374 ++#define TARGET_NR_mincore 375 ++#define TARGET_NR_pciconfig_iobase 376 ++#define TARGET_NR_getdents64 377 ++#define TARGET_NR_gettid 378 ++#define TARGET_NR_readahead 379 ++/* 380 is unused */ ++#define TARGET_NR_tkill 381 ++#define TARGET_NR_setxattr 382 ++#define TARGET_NR_lsetxattr 383 ++#define TARGET_NR_fsetxattr 384 ++#define TARGET_NR_getxattr 385 ++#define TARGET_NR_lgetxattr 386 ++#define TARGET_NR_fgetxattr 387 ++#define TARGET_NR_listxattr 388 ++#define TARGET_NR_llistxattr 389 ++#define TARGET_NR_flistxattr 390 ++#define TARGET_NR_removexattr 391 ++#define TARGET_NR_lremovexattr 392 ++#define TARGET_NR_fremovexattr 393 ++#define TARGET_NR_futex 394 ++#define TARGET_NR_sched_setaffinity 395 ++#define TARGET_NR_sched_getaffinity 396 ++#define TARGET_NR_tuxcall 397 ++#define TARGET_NR_io_setup 398 ++#define TARGET_NR_io_destroy 399 ++#define TARGET_NR_io_getevents 400 ++#define TARGET_NR_io_submit 401 ++#define TARGET_NR_io_cancel 402 ++#define TARGET_NR_exit_group 405 ++#define TARGET_NR_lookup_dcookie 406 ++#define TARGET_NR_epoll_create 407 ++#define TARGET_NR_epoll_ctl 408 ++#define TARGET_NR_epoll_wait 409 ++/* Feb 2007: These three sysTARGETepoll defines shouldn't be here but culling ++ * them would break userspace apps ... we'll kill them off in 2010 :) */ ++#define TARGET_NR_sys_epoll_create TARGET_NR_epoll_create ++#define TARGET_NR_sys_epoll_ctl TARGET_NR_epoll_ctl ++#define TARGET_NR_sys_epoll_wait TARGET_NR_epoll_wait ++#define TARGET_NR_remap_file_pages 410 ++#define TARGET_NR_set_tid_address 411 ++#define TARGET_NR_restart_syscall 412 ++#define TARGET_NR_fadvise64 413 ++#define TARGET_NR_timer_create 414 ++#define TARGET_NR_timer_settime 415 ++#define TARGET_NR_timer_gettime 416 ++#define TARGET_NR_timer_getoverrun 417 ++#define TARGET_NR_timer_delete 418 ++#define TARGET_NR_clock_settime 419 ++#define TARGET_NR_clock_gettime 420 ++#define TARGET_NR_clock_getres 421 ++#define TARGET_NR_clock_nanosleep 422 ++#define TARGET_NR_semtimedop 423 ++#define TARGET_NR_tgkill 424 ++#define TARGET_NR_stat64 425 ++#define TARGET_NR_lstat64 426 ++#define TARGET_NR_fstat64 427 ++#define TARGET_NR_vserver 428 ++#define TARGET_NR_mbind 429 ++#define TARGET_NR_get_mempolicy 430 ++#define TARGET_NR_set_mempolicy 431 ++#define TARGET_NR_mq_open 432 ++#define TARGET_NR_mq_unlink 433 ++#define TARGET_NR_mq_timedsend 434 ++#define TARGET_NR_mq_timedreceive 435 ++#define TARGET_NR_mq_notify 436 ++#define TARGET_NR_mq_getsetattr 437 ++#define TARGET_NR_waitid 438 ++#define TARGET_NR_add_key 439 ++#define TARGET_NR_request_key 440 ++#define TARGET_NR_keyctl 441 ++#define TARGET_NR_ioprio_set 442 ++#define TARGET_NR_ioprio_get 443 ++#define TARGET_NR_inotify_init 444 ++#define TARGET_NR_inotify_add_watch 445 ++#define TARGET_NR_inotify_rm_watch 446 ++#define TARGET_NR_fdatasync 447 ++#define TARGET_NR_kexec_load 448 ++#define TARGET_NR_migrate_pages 449 ++#define TARGET_NR_openat 450 ++#define TARGET_NR_mkdirat 451 ++#define TARGET_NR_mknodat 452 ++#define TARGET_NR_fchownat 453 ++#define TARGET_NR_futimesat 454 ++#define TARGET_NR_fstatat64 455 ++#define TARGET_NR_unlinkat 456 ++#define TARGET_NR_renameat 457 ++#define TARGET_NR_linkat 458 ++#define TARGET_NR_symlinkat 459 ++#define TARGET_NR_readlinkat 460 ++#define TARGET_NR_fchmodat 461 ++#define TARGET_NR_faccessat 462 ++#define TARGET_NR_pselect6 463 ++#define TARGET_NR_ppoll 464 ++#define TARGET_NR_unshare 465 ++#define TARGET_NR_set_robust_list 466 ++#define TARGET_NR_get_robust_list 467 ++#define TARGET_NR_splice 468 ++#define TARGET_NR_sync_file_range 469 ++#define TARGET_NR_tee 470 ++#define TARGET_NR_vmsplice 471 ++#define TARGET_NR_move_pages 472 ++#define TARGET_NR_getcpu 473 ++#define TARGET_NR_epoll_pwait 474 ++#define TARGET_NR_utimensat 475 ++#define TARGET_NR_signalfd 476 ++#define TARGET_NR_timerfd 477 ++#define TARGET_NR_eventfd 478 ++#define TARGET_NR_recvmmsg 479 ++#define TARGET_NR_fallocate 480 ++#define TARGET_NR_timerfd_create 481 ++#define TARGET_NR_timerfd_settime 482 ++#define TARGET_NR_timerfd_gettime 483 ++#define TARGET_NR_signalfd4 484 ++#define TARGET_NR_eventfd2 485 ++#define TARGET_NR_epoll_create1 486 ++#define TARGET_NR_dup3 487 ++#define TARGET_NR_pipe2 488 ++#define TARGET_NR_inotify_init1 489 ++#define TARGET_NR_preadv 490 ++#define TARGET_NR_pwritev 491 ++#define TARGET_NR_rt_tgsigqueueinfo 492 ++#define TARGET_NR_perf_event_open 493 ++#define TARGET_NR_fanotify_init 494 ++#define TARGET_NR_fanotify_mark 495 ++#define TARGET_NR_prlimit64 496 ++#define TARGET_NR_name_to_handle_at 497 ++#define TARGET_NR_open_by_handle_at 498 ++#define TARGET_NR_clock_adjtime 499 ++#define TARGET_NR_syncfs 500 ++#define TARGET_NR_setns 501 ++#define TARGET_NR_accept4 502 ++#define TARGET_NR_sendmmsg 503 ++#define TARGET_NR_process_vm_readv 504 ++#define TARGET_NR_process_vm_writev 505 ++#define TARGET_NR_sw_slave_rwperfmons 506 ++#define TARGET_NR_sys_get_vmflags 507 +diff --git a/linux-user/sw64/target_cpu.h b/linux-user/sw64/target_cpu.h +new file mode 100644 +index 0000000000..1b87c8ba6d +--- /dev/null ++++ b/linux-user/sw64/target_cpu.h +@@ -0,0 +1,38 @@ ++/* ++ * SW64 specific CPU ABI and functions for linux-user ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++#ifndef SW64_TARGET_CPU_H ++#define SW64_TARGET_CPU_H ++ ++static inline void cpu_clone_regs(CPUSW64State *env, target_ulong newsp) ++{ ++ if (newsp) { ++ env->ir[IDX_SP] = newsp; ++ } ++ env->ir[IDX_V0] = 0; ++ env->ir[IDX_A3] = 0; ++} ++ ++static inline void cpu_set_tls(CPUSW64State *env, target_ulong newtls) ++{ ++ env->unique = newtls; ++} ++ ++static inline abi_ulong get_sp_from_cpustate(CPUSW64State *state) ++{ ++ return state->ir[IDX_SP]; ++} ++#endif +diff --git a/linux-user/sw64/target_elf.h b/linux-user/sw64/target_elf.h +new file mode 100644 +index 0000000000..be48b6dee3 +--- /dev/null ++++ b/linux-user/sw64/target_elf.h +@@ -0,0 +1,14 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation, or (at your option) any ++ * later version. See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW64_TARGET_ELF_H ++#define SW64_TARGET_ELF_H ++static inline const char *cpu_get_model(uint32_t eflags) ++{ ++ return "any"; ++} ++#endif +diff --git a/linux-user/sw64/target_fcntl.h b/linux-user/sw64/target_fcntl.h +new file mode 100644 +index 0000000000..9721e3de39 +--- /dev/null ++++ b/linux-user/sw64/target_fcntl.h +@@ -0,0 +1,11 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation, or (at your option) any ++ * later version. See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW64_TARGET_FCNTL_H ++#define sw64_TARGET_FCNTL_H ++#include "../generic/fcntl.h" ++#endif +diff --git a/linux-user/sw64/target_signal.h b/linux-user/sw64/target_signal.h +new file mode 100644 +index 0000000000..6393a7542f +--- /dev/null ++++ b/linux-user/sw64/target_signal.h +@@ -0,0 +1,98 @@ ++#ifndef SW64_TARGET_SIGNAL_H ++#define SW64_TARGET_SIGNAL_H ++ ++#include "cpu.h" ++ ++#define TARGET_SIGHUP 1 ++#define TARGET_SIGINT 2 ++#define TARGET_SIGQUIT 3 ++#define TARGET_SIGILL 4 ++#define TARGET_SIGTRAP 5 ++#define TARGET_SIGABRT 6 ++#define TARGET_SIGSTKFLT 7 /* actually SIGEMT */ ++#define TARGET_SIGFPE 8 ++#define TARGET_SIGKILL 9 ++#define TARGET_SIGBUS 10 ++#define TARGET_SIGSEGV 11 ++#define TARGET_SIGSYS 12 ++#define TARGET_SIGPIPE 13 ++#define TARGET_SIGALRM 14 ++#define TARGET_SIGTERM 15 ++#define TARGET_SIGURG 16 ++#define TARGET_SIGSTOP 17 ++#define TARGET_SIGTSTP 18 ++#define TARGET_SIGCONT 19 ++#define TARGET_SIGCHLD 20 ++#define TARGET_SIGTTIN 21 ++#define TARGET_SIGTTOU 22 ++#define TARGET_SIGIO 23 ++#define TARGET_SIGXCPU 24 ++#define TARGET_SIGXFSZ 25 ++#define TARGET_SIGVTALRM 26 ++#define TARGET_SIGPROF 27 ++#define TARGET_SIGWINCH 28 ++#define TARGET_SIGPWR 29 /* actually SIGINFO */ ++#define TARGET_SIGUSR1 30 ++#define TARGET_SIGUSR2 31 ++#define TARGET_SIGRTMIN 32 ++ ++#define TARGET_SIG_BLOCK 1 ++#define TARGET_SIG_UNBLOCK 2 ++#define TARGET_SIG_SETMASK 3 ++ ++/* this struct defines a stack used during syscall handling */ ++ ++typedef struct target_sigaltstack { ++ abi_ulong ss_sp; ++ int32_t ss_flags; ++ int32_t dummy; ++ abi_ulong ss_size; ++} target_stack_t; ++ ++ ++/* ++ * sigaltstack controls ++ */ ++#define TARGET_SS_ONSTACK 1 ++#define TARGET_SS_DISABLE 2 ++ ++#define TARGET_SA_ONSTACK 0x00000001 ++#define TARGET_SA_RESTART 0x00000002 ++#define TARGET_SA_NOCLDSTOP 0x00000004 ++#define TARGET_SA_NODEFER 0x00000008 ++#define TARGET_SA_RESETHAND 0x00000010 ++#define TARGET_SA_NOCLDWAIT 0x00000020 /* not supported yet */ ++#define TARGET_SA_SIGINFO 0x00000040 ++ ++#define TARGET_MINSIGSTKSZ 4096 ++#define TARGET_SIGSTKSZ 16384 ++ ++/* From . */ ++#define TARGET_GEN_INTOVF -1 /* integer overflow */ ++#define TARGET_GEN_INTDIV -2 /* integer division by zero */ ++#define TARGET_GEN_FLTOVF -3 /* fp overflow */ ++#define TARGET_GEN_FLTDIV -4 /* fp division by zero */ ++#define TARGET_GEN_FLTUND -5 /* fp underflow */ ++#define TARGET_GEN_FLTINV -6 /* invalid fp operand */ ++#define TARGET_GEN_FLTINE -7 /* inexact fp operand */ ++#define TARGET_GEN_DECOVF -8 /* decimal overflow (for COBOL??) */ ++#define TARGET_GEN_DECDIV -9 /* decimal division by zero */ ++#define TARGET_GEN_DECINV -10 /* invalid decimal operand */ ++#define TARGET_GEN_ROPRAND -11 /* reserved operand */ ++#define TARGET_GEN_ASSERTERR -12 /* assertion error */ ++#define TARGET_GEN_NULPTRERR -13 /* null pointer error */ ++#define TARGET_GEN_STKOVF -14 /* stack overflow */ ++#define TARGET_GEN_STRLENERR -15 /* string length error */ ++#define TARGET_GEN_SUBSTRERR -16 /* substring error */ ++#define TARGET_GEN_RANGERR -17 /* range error */ ++#define TARGET_GEN_SUBRNG -18 ++#define TARGET_GEN_SUBRNG1 -19 ++#define TARGET_GEN_SUBRNG2 -20 ++#define TARGET_GEN_SUBRNG3 -21 ++#define TARGET_GEN_SUBRNG4 -22 ++#define TARGET_GEN_SUBRNG5 -23 ++#define TARGET_GEN_SUBRNG6 -24 ++#define TARGET_GEN_SUBRNG7 -25 ++ ++#define TARGET_ARCH_HAS_SETUP_FRAME ++#endif /* SW64_TARGET_SIGNAL_H */ +diff --git a/linux-user/sw64/target_structs.h b/linux-user/sw64/target_structs.h +new file mode 100644 +index 0000000000..7c13dc4bac +--- /dev/null ++++ b/linux-user/sw64/target_structs.h +@@ -0,0 +1,47 @@ ++/* ++ * SW64 specific structures for linux-user ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ */ ++#ifndef SW64_TARGET_STRUCTS_H ++#define SW64_TARGET_STRUCTS_H ++ ++/* TODO: Maybe it should be update. now it's different from other arch */ ++struct target_ipc_perm { ++ abi_int __key; /* Key. */ ++ abi_uint uid; /* Owner's user ID. */ ++ abi_uint gid; /* Owner's group ID. */ ++ abi_uint cuid; /* Creator's user ID. */ ++ abi_uint cgid; /* Creator's group ID. */ ++ abi_uint mode; /* Read/write permission. */ ++ abi_ushort __seq; /* Sequence number. */ ++ abi_ushort __pad1; ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++struct target_shmid_ds { ++ struct target_ipc_perm shm_perm; /* operation permission struct */ ++ abi_long shm_segsz; /* size of segment in bytes */ ++ abi_ulong shm_atime; /* time of last shmat() */ ++ abi_ulong shm_dtime; /* time of last shmdt() */ ++ abi_ulong shm_ctime; /* time of last change by shmctl() */ ++ abi_int shm_cpid; /* pid of creator */ ++ abi_int shm_lpid; /* pid of last shmop */ ++ abi_ulong shm_nattch; /* number of current attaches */ ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++#endif +diff --git a/linux-user/sw64/target_syscall.h b/linux-user/sw64/target_syscall.h +new file mode 100644 +index 0000000000..c901ae95d8 +--- /dev/null ++++ b/linux-user/sw64/target_syscall.h +@@ -0,0 +1,121 @@ ++#ifndef SW64_TARGET_SYSCALL_H ++#define SW64_TARGET_SYSCALL_H ++ ++/* TODO */ ++struct target_pt_regs { ++ abi_ulong r0; ++ abi_ulong r1; ++ abi_ulong r2; ++ abi_ulong r3; ++ abi_ulong r4; ++ abi_ulong r5; ++ abi_ulong r6; ++ abi_ulong r7; ++ abi_ulong r8; ++ abi_ulong r19; ++ abi_ulong r20; ++ abi_ulong r21; ++ abi_ulong r22; ++ abi_ulong r23; ++ abi_ulong r24; ++ abi_ulong r25; ++ abi_ulong r26; ++ abi_ulong r27; ++ abi_ulong r28; ++ abi_ulong hae; ++/* JRP - These are the values provided to a0-a2 by HMcode */ ++ abi_ulong trap_a0; ++ abi_ulong trap_a1; ++ abi_ulong trap_a2; ++/* These are saved by HMcode: */ ++ abi_ulong ps; ++ abi_ulong pc; ++ abi_ulong gp; ++ abi_ulong r16; ++ abi_ulong r17; ++ abi_ulong r18; ++}; ++ ++#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 ++#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 ++ ++ ++#define UNAME_MACHINE "sw64" ++#define UNAME_MINIMUM_RELEASE "2.6.32" ++#undef TARGET_EOPNOTSUPP ++#define TARGET_EOPNOTSUPP 45 /* Operation not supported on transport endpoint */ ++#define SWCR_STATUS_INV0 (1UL<<17) ++#define SWCR_STATUS_DZE0 (1UL<<18) ++#define SWCR_STATUS_OVF0 (1UL<<19) ++#define SWCR_STATUS_UNF0 (1UL<<20) ++#define SWCR_STATUS_INE0 (1UL<<21) ++#define SWCR_STATUS_DNO0 (1UL<<22) ++ ++#define SWCR_STATUS_MASK0 (SWCR_STATUS_INV0 | SWCR_STATUS_DZE0 | \ ++ SWCR_STATUS_OVF0 | SWCR_STATUS_UNF0 | \ ++ SWCR_STATUS_INE0 | SWCR_STATUS_DNO0) ++ ++#define SWCR_STATUS0_TO_EXCSUM_SHIFT 16 ++ ++#define SWCR_STATUS_INV1 (1UL<<23) ++#define SWCR_STATUS_DZE1 (1UL<<24) ++#define SWCR_STATUS_OVF1 (1UL<<25) ++#define SWCR_STATUS_UNF1 (1UL<<26) ++#define SWCR_STATUS_INE1 (1UL<<27) ++#define SWCR_STATUS_DNO1 (1UL<<28) ++ ++#define SWCR_STATUS_MASK1 (SWCR_STATUS_INV1 | SWCR_STATUS_DZE1 | \ ++ SWCR_STATUS_OVF1 | SWCR_STATUS_UNF1 | \ ++ SWCR_STATUS_INE1 | SWCR_STATUS_DNO1) ++ ++#define SWCR_STATUS1_TO_EXCSUM_SHIFT 22 ++#define SWCR_STATUS_INV2 (1UL<<34) ++#define SWCR_STATUS_DZE2 (1UL<<35) ++#define SWCR_STATUS_OVF2 (1UL<<36) ++#define SWCR_STATUS_UNF2 (1UL<<37) ++#define SWCR_STATUS_INE2 (1UL<<38) ++#define SWCR_STATUS_DNO2 (1UL<<39) ++ ++#define SWCR_STATUS_MASK2 (SWCR_STATUS_INV2 | SWCR_STATUS_DZE2 | \ ++ SWCR_STATUS_OVF2 | SWCR_STATUS_UNF2 | \ ++ SWCR_STATUS_INE2 | SWCR_STATUS_DNO2) ++#define SWCR_STATUS_INV3 (1UL<<40) ++#define SWCR_STATUS_DZE3 (1UL<<41) ++#define SWCR_STATUS_OVF3 (1UL<<42) ++#define SWCR_STATUS_UNF3 (1UL<<43) ++#define SWCR_STATUS_INE3 (1UL<<44) ++#define SWCR_STATUS_DNO3 (1UL<<45) ++ ++#define SWCR_STATUS_MASK3 (SWCR_STATUS_INV3 | SWCR_STATUS_DZE3 | \ ++ SWCR_STATUS_OVF3 | SWCR_STATUS_UNF3 | \ ++ SWCR_STATUS_INE3 | SWCR_STATUS_DNO3) ++#define SWCR_TRAP_ENABLE_INV (1UL<<1) /* invalid op */ ++#define SWCR_TRAP_ENABLE_DZE (1UL<<2) /* division by zero */ ++#define SWCR_TRAP_ENABLE_OVF (1UL<<3) /* overflow */ ++#define SWCR_TRAP_ENABLE_UNF (1UL<<4) /* underflow */ ++#define SWCR_TRAP_ENABLE_INE (1UL<<5) /* inexact */ ++#define SWCR_TRAP_ENABLE_DNO (1UL<<6) /* denorm */ ++#define SWCR_TRAP_ENABLE_MASK (SWCR_TRAP_ENABLE_INV | SWCR_TRAP_ENABLE_DZE | \ ++ SWCR_TRAP_ENABLE_OVF | SWCR_TRAP_ENABLE_UNF | \ ++ SWCR_TRAP_ENABLE_INE | SWCR_TRAP_ENABLE_DNO) ++ ++/* Denorm and Underflow flushing */ ++#define SWCR_MAP_DMZ (1UL<<12) /* Map denorm inputs to zero */ ++#define SWCR_MAP_UMZ (1UL<<13) /* Map underflowed outputs to zero */ ++ ++#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) ++ ++/* status bits coming from fpcr: */ ++#define SWCR_STATUS_INV (1UL<<17) ++#define SWCR_STATUS_DZE (1UL<<18) ++#define SWCR_STATUS_OVF (1UL<<19) ++#define SWCR_STATUS_UNF (1UL<<20) ++#define SWCR_STATUS_INE (1UL<<21) ++#define SWCR_STATUS_DNO (1UL<<22) ++ ++#define SWCR_STATUS_MASK (SWCR_STATUS_INV | SWCR_STATUS_DZE | \ ++ SWCR_STATUS_OVF | SWCR_STATUS_UNF | \ ++ SWCR_STATUS_INE | SWCR_STATUS_DNO) ++#define TARGET_GSI_IEEE_FP_CONTROL 45 ++#define TARGET_SSI_IEEE_FP_CONTROL 14 ++#endif +diff --git a/linux-user/sw64/termbits.h b/linux-user/sw64/termbits.h +new file mode 100644 +index 0000000000..37dd77120c +--- /dev/null ++++ b/linux-user/sw64/termbits.h +@@ -0,0 +1,265 @@ ++typedef unsigned char target_cc_t; ++typedef unsigned int target_speed_t; ++typedef unsigned int target_tcflag_t; ++ ++#define TARGET_NCCS 19 ++struct target_termios { ++ target_tcflag_t c_iflag; /* input mode flags */ ++ target_tcflag_t c_oflag; /* output mode flags */ ++ target_tcflag_t c_cflag; /* control mode flags */ ++ target_tcflag_t c_lflag; /* local mode flags */ ++ target_cc_t c_cc[TARGET_NCCS]; /* control characters */ ++ target_cc_t c_line; /* line discipline (== c_cc[19]) */ ++ target_speed_t c_ispeed; /* input speed */ ++ target_speed_t c_ospeed; /* output speed */ ++}; ++ ++/* c_cc characters */ ++#define TARGET_VEOF 0 ++#define TARGET_VEOL 1 ++#define TARGET_VEOL2 2 ++#define TARGET_VERASE 3 ++#define TARGET_VWERASE 4 ++#define TARGET_VKILL 5 ++#define TARGET_VREPRINT 6 ++#define TARGET_VSWTC 7 ++#define TARGET_VINTR 8 ++#define TARGET_VQUIT 9 ++#define TARGET_VSUSP 10 ++#define TARGET_VSTART 12 ++#define TARGET_VSTOP 13 ++#define TARGET_VLNEXT 14 ++#define TARGET_VDISCARD 15 ++#define TARGET_VMIN 16 ++#define TARGET_VTIME 17 ++ ++/* c_iflag bits */ ++#define TARGET_IGNBRK 0000001 ++#define TARGET_BRKINT 0000002 ++#define TARGET_IGNPAR 0000004 ++#define TARGET_PARMRK 0000010 ++#define TARGET_INPCK 0000020 ++#define TARGET_ISTRIP 0000040 ++#define TARGET_INLCR 0000100 ++#define TARGET_IGNCR 0000200 ++#define TARGET_ICRNL 0000400 ++#define TARGET_IXON 0001000 ++#define TARGET_IXOFF 0002000 ++#define TARGET_IXANY 0004000 ++#define TARGET_IUCLC 0010000 ++#define TARGET_IMAXBEL 0020000 ++#define TARGET_IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define TARGET_OPOST 0000001 ++#define TARGET_ONLCR 0000002 ++#define TARGET_OLCUC 0000004 ++ ++#define TARGET_OCRNL 0000010 ++#define TARGET_ONOCR 0000020 ++#define TARGET_ONLRET 0000040 ++ ++#define TARGET_OFILL 00000100 ++#define TARGET_OFDEL 00000200 ++#define TARGET_NLDLY 00001400 ++#define TARGET_NL0 00000000 ++#define TARGET_NL1 00000400 ++#define TARGET_NL2 00001000 ++#define TARGET_NL3 00001400 ++#define TARGET_TABDLY 00006000 ++#define TARGET_TAB0 00000000 ++#define TARGET_TAB1 00002000 ++#define TARGET_TAB2 00004000 ++#define TARGET_TAB3 00006000 ++#define TARGET_CRDLY 00030000 ++#define TARGET_CR0 00000000 ++#define TARGET_CR1 00010000 ++#define TARGET_CR2 00020000 ++#define TARGET_CR3 00030000 ++#define TARGET_FFDLY 00040000 ++#define TARGET_FF0 00000000 ++#define TARGET_FF1 00040000 ++#define TARGET_BSDLY 00100000 ++#define TARGET_BS0 00000000 ++#define TARGET_BS1 00100000 ++#define TARGET_VTDLY 00200000 ++#define TARGET_VT0 00000000 ++#define TARGET_VT1 00200000 ++#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ ++ ++/* c_cflag bit meaning */ ++#define TARGET_CBAUD 0000037 ++#define TARGET_B0 0000000 /* hang up */ ++#define TARGET_B50 0000001 ++#define TARGET_B75 0000002 ++#define TARGET_B110 0000003 ++#define TARGET_B134 0000004 ++#define TARGET_B150 0000005 ++#define TARGET_B200 0000006 ++#define TARGET_B300 0000007 ++#define TARGET_B600 0000010 ++#define TARGET_B1200 0000011 ++#define TARGET_B1800 0000012 ++#define TARGET_B2400 0000013 ++#define TARGET_B4800 0000014 ++#define TARGET_B9600 0000015 ++#define TARGET_B19200 0000016 ++#define TARGET_B38400 0000017 ++#define TARGET_EXTA B19200 ++#define TARGET_EXTB B38400 ++#define TARGET_CBAUDEX 0000000 ++#define TARGET_B57600 00020 ++#define TARGET_B115200 00021 ++#define TARGET_B230400 00022 ++#define TARGET_B460800 00023 ++#define TARGET_B500000 00024 ++#define TARGET_B576000 00025 ++#define TARGET_B921600 00026 ++#define TARGET_B1000000 00027 ++#define TARGET_B1152000 00030 ++#define TARGET_B1500000 00031 ++#define TARGET_B2000000 00032 ++#define TARGET_B2500000 00033 ++#define TARGET_B3000000 00034 ++#define TARGET_B3500000 00035 ++#define TARGET_B4000000 00036 ++ ++#define TARGET_CSIZE 00001400 ++#define TARGET_CS5 00000000 ++#define TARGET_CS6 00000400 ++#define TARGET_CS7 00001000 ++#define TARGET_CS8 00001400 ++ ++#define TARGET_CSTOPB 00002000 ++#define TARGET_CREAD 00004000 ++#define TARGET_PARENB 00010000 ++#define TARGET_PARODD 00020000 ++#define TARGET_HUPCL 00040000 ++ ++#define TARGET_CLOCAL 00100000 ++#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define TARGET_CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define TARGET_ISIG 0x00000080 ++#define TARGET_ICANON 0x00000100 ++#define TARGET_XCASE 0x00004000 ++#define TARGET_ECHO 0x00000008 ++#define TARGET_ECHOE 0x00000002 ++#define TARGET_ECHOK 0x00000004 ++#define TARGET_ECHONL 0x00000010 ++#define TARGET_NOFLSH 0x80000000 ++#define TARGET_TOSTOP 0x00400000 ++#define TARGET_ECHOCTL 0x00000040 ++#define TARGET_ECHOPRT 0x00000020 ++#define TARGET_ECHOKE 0x00000001 ++#define TARGET_FLUSHO 0x00800000 ++#define TARGET_PENDIN 0x20000000 ++#define TARGET_IEXTEN 0x00000400 ++ ++#define TARGET_FIOCLEX TARGET_IO('f', 1) ++#define TARGET_FIONCLEX TARGET_IO('f', 2) ++#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) ++#define TARGET_FIONBIO TARGET_IOW('f', 126, int) ++#define TARGET_FIONREAD TARGET_IOR('f', 127, int) ++#define TARGET_TIOCINQ FIONREAD ++#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) ++ ++#define TARGET_TIOCGETP TARGET_IOR('t', 8, struct target_sgttyb) ++#define TARGET_TIOCSETP TARGET_IOW('t', 9, struct target_sgttyb) ++#define TARGET_TIOCSETN TARGET_IOW('t', 10, struct target_sgttyb) /* TIOCSETP wo flush */ ++ ++#define TARGET_TIOCSETC TARGET_IOW('t', 17, struct target_tchars) ++#define TARGET_TIOCGETC TARGET_IOR('t', 18, struct target_tchars) ++#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) ++#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) ++#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) ++#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) ++ ++#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) ++#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) ++#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) ++#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) ++ ++#define TARGET_TCSBRK TARGET_IO('t', 29) ++#define TARGET_TCXONC TARGET_IO('t', 30) ++#define TARGET_TCFLSH TARGET_IO('t', 31) ++ ++#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) ++#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) ++#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ ++#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ ++#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ ++ ++#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) ++#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) ++#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) ++#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) ++ ++#define TARGET_TIOCEXCL 0x540C ++#define TARGET_TIOCNXCL 0x540D ++#define TARGET_TIOCSCTTY 0x540E ++ ++#define TARGET_TIOCSTI 0x5412 ++#define TARGET_TIOCMGET 0x5415 ++#define TARGET_TIOCMBIS 0x5416 ++#define TARGET_TIOCMBIC 0x5417 ++#define TARGET_TIOCMSET 0x5418 ++# define TARGET_TIOCM_LE 0x001 ++# define TARGET_TIOCM_DTR 0x002 ++# define TARGET_TIOCM_RTS 0x004 ++# define TARGET_TIOCM_ST 0x008 ++# define TARGET_TIOCM_SR 0x010 ++# define TARGET_TIOCM_CTS 0x020 ++# define TARGET_TIOCM_CAR 0x040 ++# define TARGET_TIOCM_RNG 0x080 ++# define TARGET_TIOCM_DSR 0x100 ++# define TARGET_TIOCM_CD TIOCM_CAR ++# define TARGET_TIOCM_RI TIOCM_RNG ++# define TARGET_TIOCM_OUT1 0x2000 ++# define TARGET_TIOCM_OUT2 0x4000 ++# define TARGET_TIOCM_LOOP 0x8000 ++ ++#define TARGET_TIOCGSOFTCAR 0x5419 ++#define TARGET_TIOCSSOFTCAR 0x541A ++#define TARGET_TIOCLINUX 0x541C ++#define TARGET_TIOCCONS 0x541D ++#define TARGET_TIOCGSERIAL 0x541E ++#define TARGET_TIOCSSERIAL 0x541F ++#define TARGET_TIOCPKT 0x5420 ++# define TARGET_TIOCPKT_DATA 0 ++# define TARGET_TIOCPKT_FLUSHREAD 1 ++# define TARGET_TIOCPKT_FLUSHWRITE 2 ++# define TARGET_TIOCPKT_STOP 4 ++# define TARGET_TIOCPKT_START 8 ++# define TARGET_TIOCPKT_NOSTOP 16 ++# define TARGET_TIOCPKT_DOSTOP 32 ++ ++ ++#define TARGET_TIOCNOTTY 0x5422 ++#define TARGET_TIOCSETD 0x5423 ++#define TARGET_TIOCGETD 0x5424 ++#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) /* Lock/unlock Pty */ ++#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) /* Safely open the slave */ ++ ++#define TARGET_TIOCSERCONFIG 0x5453 ++#define TARGET_TIOCSERGWILD 0x5454 ++#define TARGET_TIOCSERSWILD 0x5455 ++#define TARGET_TIOCGLCKTRMIOS 0x5456 ++#define TARGET_TIOCSLCKTRMIOS 0x5457 ++#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ ++ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ ++#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ ++#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +diff --git a/meson.build b/meson.build +index 96de1a6ef9..d0bbceffe1 100644 +--- a/meson.build ++++ b/meson.build +@@ -56,7 +56,7 @@ python = import('python').find_installation() + + supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] + supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', +- 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] ++ 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'sw64'] + + cpu = host_machine.cpu_family() + +@@ -65,6 +65,10 @@ if cpu in ['riscv32', 'riscv64'] + cpu = 'riscv' + endif + ++if cpu == 'sw_64' ++ cpu = 'sw64' ++endif ++ + targetos = host_machine.system() + + if cpu in ['x86', 'x86_64'] +@@ -77,6 +81,8 @@ elif cpu in ['ppc', 'ppc64'] + kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] + elif cpu in ['mips', 'mips64'] + kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] ++elif cpu == 'sw64' ++ kvm_targets = ['sw64-softmmu'] + else + kvm_targets = [] + endif +@@ -359,6 +365,8 @@ if not get_option('tcg').disabled() + tcg_arch = 'i386' + elif config_host['ARCH'] == 'ppc64' + tcg_arch = 'ppc' ++ elif config_host['ARCH'] in ['sw64'] ++ tcg_arch = 'sw64' + endif + add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, + language: ['c', 'cpp', 'objc']) +@@ -1814,6 +1822,7 @@ disassemblers = { + 'sh4' : ['CONFIG_SH4_DIS'], + 'sparc' : ['CONFIG_SPARC_DIS'], + 'xtensa' : ['CONFIG_XTENSA_DIS'], ++ 'sw64' : ['CONFIG_SW64_DIS'], + } + if link_language == 'cpp' + disassemblers += { +@@ -2466,6 +2475,7 @@ if have_system + 'hw/sparc', + 'hw/sparc64', + 'hw/ssi', ++ 'hw/sw64', + 'hw/timer', + 'hw/tpm', + 'hw/usb', +diff --git a/pc-bios/meson.build b/pc-bios/meson.build +index b40ff3f2bd..05e9065ad6 100644 +--- a/pc-bios/meson.build ++++ b/pc-bios/meson.build +@@ -38,6 +38,9 @@ blobs = files( + 'vgabios-ramfb.bin', + 'vgabios-bochs-display.bin', + 'vgabios-ati.bin', ++ 'uefi-bios-sw', ++ 'core3-reset', ++ 'core3-hmcode', + 'openbios-sparc32', + 'openbios-sparc64', + 'openbios-ppc', +diff --git a/qapi/machine.json b/qapi/machine.json +index 6822cafe2e..6ed8488255 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -29,7 +29,7 @@ + # Since: 3.0 + ## + { 'enum' : 'SysEmuTarget', +- 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', ++ 'data' : [ 'aarch64', 'alpha', 'sw64', 'arm', 'avr', 'cris', 'hppa', 'i386', + 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', + 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', + 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 05e1d88d99..142352b24e 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -61,7 +61,8 @@ typedef struct QDevAlias + QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ + QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ + QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ +- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) ++ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ ++ QEMU_ARCH_SW64) + #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) + #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) + +diff --git a/target/Kconfig b/target/Kconfig +index ae7f24fc66..a8d6cb1e97 100644 +--- a/target/Kconfig ++++ b/target/Kconfig +@@ -17,3 +17,4 @@ source sh4/Kconfig + source sparc/Kconfig + source tricore/Kconfig + source xtensa/Kconfig ++source sw64/Kconfig +diff --git a/target/meson.build b/target/meson.build +index 2f6940255e..ec6bc97331 100644 +--- a/target/meson.build ++++ b/target/meson.build +@@ -16,5 +16,6 @@ subdir('rx') + subdir('s390x') + subdir('sh4') + subdir('sparc') ++subdir('sw64') + subdir('tricore') + subdir('xtensa') +diff --git a/target/sw64/Kconfig b/target/sw64/Kconfig +new file mode 100644 +index 0000000000..ad50b9677e +--- /dev/null ++++ b/target/sw64/Kconfig +@@ -0,0 +1,2 @@ ++config SW64 ++ bool +diff --git a/target/sw64/Makefile.objs b/target/sw64/Makefile.objs +new file mode 100644 +index 0000000000..1e549d141c +--- /dev/null ++++ b/target/sw64/Makefile.objs +@@ -0,0 +1,4 @@ ++obj-$(CONFIG_SOFTMMU) += machine.o ++obj-y += cpu.o translate.o profile.o helper.o ++obj-y += int_helper.o float_helper.o simd_helper.o helper.o exception.o ++obj-$(CONFIG_KVM) += kvm.o +diff --git a/target/sw64/cpu-param.h b/target/sw64/cpu-param.h +new file mode 100644 +index 0000000000..978a3cd572 +--- /dev/null ++++ b/target/sw64/cpu-param.h +@@ -0,0 +1,24 @@ ++/* ++ * SW64 cpu parameters for qemu. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ */ ++ ++#ifndef SW64_CPU_PARAM_H ++#define SW64_CPU_PARAM_H 1 ++ ++#define TARGET_LONG_BITS 64 /* if use th-1 ,TARGET_PAGE_BITS is 12 */ ++#define TARGET_PAGE_BITS 13 ++ ++#ifdef CONFIG_USER_ONLY ++#define TARGET_VIRT_ADDR_SPACE_BITS 64 ++#else ++#define TARGET_PHYS_ADDR_SPACE_BITS 48 ++#define TARGET_VIRT_ADDR_SPACE_BITS 64 ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++#define NB_MMU_MODES 4 ++#endif ++ ++#endif +diff --git a/target/sw64/cpu-qom.h b/target/sw64/cpu-qom.h +new file mode 100644 +index 0000000000..b093c2bec8 +--- /dev/null ++++ b/target/sw64/cpu-qom.h +@@ -0,0 +1,47 @@ ++/* ++ * QEMU SW64 CPU ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * 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. ++ * ++ */ ++#ifndef QEMU_SW64_CPU_QOM ++#define QEMU_SW64_CPU_QOM ++ ++#include "hw/core/cpu.h" ++ ++#define TYPE_SW64_CPU "sw64-cpu" ++ ++#define SW64_CPU_CLASS(kclass) \ ++ OBJECT_CLASS_CHECK(SW64CPUClass, (kclass), TYPE_SW64_CPU) ++#define SW64_CPU(obj) \ ++ OBJECT_CHECK(SW64CPU, (obj), TYPE_SW64_CPU) ++#define SW64_CPU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64CPUClass, (obj), TYPE_SW64_CPU) ++ ++/** ++ * SW64CPUClass: ++ * @parent_realize: The parent class' realize handler. ++ * @parent_reset: The parent class' reset handler. ++ * ++ * An SW64 CPU model. ++ */ ++typedef struct SW64CPUClass { ++ /* private */ ++ CPUClass parent_class; ++ /* public */ ++ DeviceRealize parent_realize; ++ DeviceReset parent_reset; ++} SW64CPUClass; ++ ++typedef struct SW64CPU SW64CPU; ++#endif +diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c +new file mode 100644 +index 0000000000..89c21850e1 +--- /dev/null ++++ b/target/sw64/cpu.c +@@ -0,0 +1,457 @@ ++/* ++ * QEMU SW64 CPU ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qemu/qemu-print.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "sysemu/kvm.h" ++#include "disas/dis-asm.h" ++#include "kvm_sw64.h" ++#include "sysemu/reset.h" ++#include "hw/qdev-properties.h" ++ ++ ++static void sw64_cpu_set_pc(CPUState *cs, vaddr value) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ ++ cpu->env.pc = value; ++} ++ ++static void sw64_cpu_dump_state(CPUState *cs, FILE *f, int flags) ++{ ++#ifndef CONFIG_KVM ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ int i; ++ ++ static const char ireg_names[31][4] = { ++ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", ++ "s2", "s3", "s4", "s5", "fp", "a0", "a1", "a2", "a3", "a4", "a5", ++ "t8", "t9", "t10", "t11", "ra", "t12", "at", "gp", "sp"}; ++ static const char freg_names[128][4] = { ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", ++ "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", ++ "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", ++ "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", ++ "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", ++ "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", ++ "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", ++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", ++ "f26", "f27", "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", ++ "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", ++ "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", ++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; ++ qemu_fprintf(f, "PC=%016" PRIx64 " SP=%016" PRIx64 "\n", env->pc, ++ env->ir[IDX_SP]); ++ for (i = 0; i < 31; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, ireg_names[i], env->ir[i]); ++ if ((i % 4) == 3) { ++ qemu_fprintf(f, "\n"); ++ } else { ++ qemu_fprintf(f, " "); ++ } ++ } ++ qemu_fprintf(f, "\n"); ++#ifndef CONFIG_USER_ONLY ++ static const char sreg_names[10][4] = {"p1", "p2", "p4", "p5", "p6", ++ "p7", "p20", "p21", "p22", "p23"}; ++ for (i = 0; i < 10; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, sreg_names[i], env->sr[i]); ++ if ((i % 4) == 3) { ++ qemu_fprintf(f, "\n"); ++ } else { ++ qemu_fprintf(f, " "); ++ } ++ } ++ qemu_fprintf(f, "\n"); ++#endif ++ for (i = 0; i < 32; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, freg_names[i + 96], env->fr[i + 96]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i + 64]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i + 32]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i]); ++ qemu_fprintf(f, "\n"); ++ } ++ qemu_fprintf(f, "\n"); ++#endif ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void sw64_machine_cpu_reset(void *opaque) ++{ ++ SW64CPU *cpu = opaque; ++ ++ cpu_reset(CPU(cpu)); ++} ++#endif ++ ++static void sw64_cpu_realizefn(DeviceState *dev, Error **errp) ++{ ++ CPUState *cs = CPU(dev); ++ SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); ++ Error *local_err = NULL; ++ ++ cpu_exec_realizefn(cs, &local_err); ++ if (local_err != NULL) { ++ error_propagate(errp, local_err); ++ return; ++ } ++#ifndef CONFIG_USER_ONLY ++ qemu_register_reset(sw64_machine_cpu_reset, cs); ++#endif ++ ++ qemu_init_vcpu(cs); ++ ++ scc->parent_realize(dev, errp); ++} ++ ++static void sw64_cpu_disas_set_info(CPUState *cs, disassemble_info *info) ++{ ++ info->mach = bfd_mach_sw_64_core3; ++ info->print_insn = print_insn_sw_64; ++} ++ ++#include "fpu/softfloat.h" ++ ++static void core3_init(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ CPUSW64State *env = cs->env_ptr; ++#ifdef CONFIG_USER_ONLY ++ env->fpcr = 0x680e800000000000; ++ parallel_cpus = true; ++#endif ++ set_feature(env, SW64_FEATURE_CORE3); ++} ++ ++static ObjectClass *sw64_cpu_class_by_name(const char *cpu_model) ++{ ++ ObjectClass *oc; ++ char *typename; ++ char **cpuname; ++ ++ cpuname = g_strsplit(cpu_model, ",", 1); ++ typename = g_strdup_printf(SW64_CPU_TYPE_NAME("%s"), cpu_model); ++ ++ oc = object_class_by_name(typename); ++ g_strfreev(cpuname); ++ g_free(typename); ++ ++ if (oc && object_class_dynamic_cast(oc, TYPE_SW64_CPU) && ++ !object_class_is_abstract(oc)) { ++ return oc; ++ } ++ return NULL; ++} ++ ++bool sw64_cpu_has_work(CPUState *cs) ++{ ++ /* If CPU has gotten into asleep(halt), then it may be ++ * wake up by hard interrupt, timer, ii, mail or mchk. ++ */ ++ return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER | ++ CPU_INTERRUPT_IIMAIL | CPU_INTERRUPT_MCHK); ++} ++ ++static void sw64_cpu_initfn(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ SW64CPU *cpu = SW64_CPU(obj); ++ CPUSW64State *env = &cpu->env; ++ ++ cpu_set_cpustate_pointers(cpu); ++ ++ cs->env_ptr = env; ++#ifndef CONFIG_USER_ONLY ++ env->flags = ENV_FLAG_HM_MODE; ++#else ++ env->flags = ENV_FLAG_PS_USER; ++#endif ++ tlb_flush(cs); ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void sw64_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, ++ unsigned size, MMUAccessType access_type, ++ int mmu_idx, MemTxAttrs attrs, ++ MemTxResult response, uintptr_t retaddr) ++{ ++#ifdef DEBUG_TRANS ++ if (retaddr) { ++ cpu_restore_state(cs, retaddr, true); ++ } ++ fprintf(stderr, "PC = %lx, Wrong IO addr. Hwaddr = %lx, vaddr = %lx, access_type = %d\n", ++ env->pc, physaddr, addr, access_type); ++#endif ++} ++#endif ++ ++#define a0(func) (((func & 0xFF) >> 6) & 0x1) ++#define a1(func) ((((func & 0xFF) >> 6) & 0x2) >> 1) ++ ++#define t(func) ((a0(func) ^ a1(func)) & 0x1) ++#define b0(func) (t(func) | a0(func)) ++#define b1(func) ((~t(func) & 1) | a1(func)) ++ ++#define START_SYS_CALL_ADDR(func) \ ++ (b1(func) << 14) | (b0(func) << 13) | ((func & 0x3F) << 7) ++ ++static void sw64_cpu_do_interrupt(CPUState *cs) ++{ ++ int i = cs->exception_index; ++ ++ cs->exception_index = -1; ++#if !defined(CONFIG_USER_ONLY) ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ switch (i) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL INSN"); ++ break; ++ case EXCP_CALL_SYS: ++ i = START_SYS_CALL_ADDR(env->error_code); ++ if (i <= 0x3F) { ++ i += 0x4000; ++ } else if (i >= 0x40 && i <= 0x7F) { ++ i += 0x2000; ++ } else if (i >= 0x80 && i <= 0x8F) { ++ i += 0x6000; ++ } ++ break; ++ case EXCP_ARITH: ++ env->error_code = -1; ++ env->csr[EXC_PC] = env->pc - 4; ++ env->csr[EXC_SUM] = 1; ++ i = 0xB80; ++ break; ++ case EXCP_UNALIGN: ++ i = 0xB00; ++ env->csr[EXC_PC] = env->pc - 4; ++ break; ++ case EXCP_CLK_INTERRUPT: ++ case EXCP_DEV_INTERRUPT: ++ i = 0xE80; ++ break; ++ case EXCP_MMFAULT: ++ i = 0x980; ++ env->csr[EXC_PC] = env->pc; ++ break; ++ case EXCP_IIMAIL: ++ env->csr[EXC_PC] = env->pc; ++ i = 0xE00; ++ break; ++ default: ++ break; ++ } ++ env->pc = env->hm_entry + i; ++ env->flags = ENV_FLAG_HM_MODE; ++#else ++ switch (i) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL INSN"); ++ break; ++ case EXCP_CALL_SYS: ++ default: ++ break; ++ } ++#endif ++} ++ ++#ifndef CONFIG_USER_ONLY ++static bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ int idx = -1; ++ /* We never take interrupts while in Hardmode. */ ++ if (env->flags & ENV_FLAG_HM_MODE) ++ return false; ++ ++ if (interrupt_request & CPU_INTERRUPT_IIMAIL) { ++ idx = EXCP_IIMAIL; ++ env->csr[INT_STAT] |= 1UL << 6; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_IIMAIL; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_TIMER) { ++ idx = EXCP_CLK_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 4; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_HARD) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 12; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_HARD; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_PCIE) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 1; ++ env->csr[INT_PCI_INT] = 0x10; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; ++ goto done; ++ } ++ ++done: ++ if (idx >= 0) { ++ cs->exception_index = idx; ++ env->error_code = 0; ++ env->csr[EXC_PC] = env->pc; ++ sw64_cpu_do_interrupt(cs); ++ return true; ++ } ++ return false; ++} ++#endif ++ ++static void sw64_cpu_reset(DeviceState *dev) ++{ ++ CPUState *s = CPU(dev); ++ SW64CPU *cpu = SW64_CPU(s); ++ SW64CPUClass *scc = SW64_CPU_GET_CLASS(cpu); ++ ++ scc->parent_reset(dev); ++ ++#ifndef CONFIG_USER_ONLY ++ if (kvm_enabled()) { ++ kvm_sw64_reset_vcpu(cpu); ++ } ++#endif ++} ++ ++static Property sw64_cpu_properties[] = { ++#ifdef CONFIG_USER_ONLY ++ /* apic_id = 0 by default for *-user, see commit 9886e834 */ ++ DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0), ++#else ++ DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0xFFFFFFFF), ++#endif ++ DEFINE_PROP_END_OF_LIST() ++}; ++ ++#ifndef CONFIG_USER_ONLY ++#include "hw/core/sysemu-cpu-ops.h" ++ ++static const struct SysemuCPUOps sw64_sysemu_ops = { ++ .get_phys_page_debug = sw64_cpu_get_phys_page_debug, ++}; ++#endif ++ ++#include "hw/core/tcg-cpu-ops.h" ++ ++static const struct TCGCPUOps sw64_tcg_ops = { ++#ifdef CONFIG_TCG ++ .initialize = sw64_translate_init, ++ .tlb_fill = sw64_cpu_tlb_fill, ++#endif /* CONFIG_TCG */ ++ ++#if !defined(CONFIG_USER_ONLY) ++ .do_unaligned_access = sw64_cpu_do_unaligned_access, ++ .cpu_exec_interrupt = sw64_cpu_exec_interrupt, ++ .do_transaction_failed = sw64_cpu_do_transaction_failed, ++#endif /* !CONFIG_USER_ONLY */ ++ .do_interrupt = sw64_cpu_do_interrupt, ++}; ++ ++static void sw64_cpu_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ CPUClass *cc = CPU_CLASS(oc); ++ SW64CPUClass *scc = SW64_CPU_CLASS(oc); ++ ++ device_class_set_parent_realize(dc, sw64_cpu_realizefn, ++ &scc->parent_realize); ++ device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); ++ device_class_set_props(dc, sw64_cpu_properties); ++ ++ cc->class_by_name = sw64_cpu_class_by_name; ++ dc->vmsd = &vmstate_sw64_cpu; ++ cc->has_work = sw64_cpu_has_work; ++ cc->set_pc = sw64_cpu_set_pc; ++ cc->disas_set_info = sw64_cpu_disas_set_info; ++ cc->dump_state = sw64_cpu_dump_state; ++ cc->tcg_ops = &sw64_tcg_ops; ++#ifndef CONFIG_USER_ONLY ++ cc->sysemu_ops = &sw64_sysemu_ops; ++#endif ++} ++ ++static const SW64CPUInfo sw64_cpus[] = ++{ ++ { ++ .name = "core3", ++ .initfn = core3_init, ++ }, ++ { ++ .name = NULL ++ }, ++}; ++ ++static void cpu_register(const SW64CPUInfo *info) ++{ ++ TypeInfo type_info = { ++ .parent = TYPE_SW64_CPU, ++ .instance_size = sizeof(SW64CPU), ++ .instance_init = info->initfn, ++ .class_size = sizeof(SW64CPUClass), ++ .class_init = info->class_init, ++ }; ++ ++ type_info.name = g_strdup_printf("%s-" TYPE_SW64_CPU, info->name); ++ type_register(&type_info); ++ g_free((void*)type_info.name); ++} ++ ++static const TypeInfo sw64_cpu_type_info = { ++ .name = TYPE_SW64_CPU, ++ .parent = TYPE_CPU, ++ .instance_size = sizeof(SW64CPU), ++ .instance_init = sw64_cpu_initfn, ++ .abstract = true, ++ .class_size = sizeof(SW64CPUClass), ++ .class_init = sw64_cpu_class_init, ++}; ++ ++static void sw64_cpu_register_types(void) ++{ ++ const SW64CPUInfo *info = sw64_cpus; ++ ++ type_register_static(&sw64_cpu_type_info); ++ ++ while (info->name) { ++ cpu_register(info); ++ info++; ++ } ++} ++ ++type_init(sw64_cpu_register_types) +diff --git a/target/sw64/cpu.h b/target/sw64/cpu.h +new file mode 100644 +index 0000000000..5a490e2b4a +--- /dev/null ++++ b/target/sw64/cpu.h +@@ -0,0 +1,406 @@ ++/* ++ * SW64 emulation cpu definitions for qemu. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ */ ++#ifndef SW64_CPU_H ++#define SW64_CPU_H ++ ++#include "cpu-qom.h" ++#include "fpu/softfloat.h" ++#include "profile.h" ++ ++/* QEMU addressing/paging config */ ++#define TARGET_PAGE_BITS 13 ++#define TARGET_LONG_BITS 64 ++#define TARGET_LEVEL_BITS 10 ++//#define ALIGNED_ONLY ++ ++#include "exec/cpu-defs.h" ++ ++/* FIXME: LOCKFIX */ ++#define SW64_FIXLOCK 1 ++ ++/* swcore processors have a weak memory model */ ++#define TCG_GUEST_DEFAULT_MO (0) ++ ++#define SOFTMMU 1 ++ ++#ifndef CONFIG_USER_ONLY ++#define MMU_MODE0_SUFFIX _phys ++#define MMU_MODE3_SUFFIX _user ++#define MMU_MODE2_SUFFIX _kernel ++#endif ++#define MMU_PHYS_IDX 0 ++#define MMU_KERNEL_IDX 2 ++#define MMU_USER_IDX 3 ++ ++/* FIXME:Bits 4 and 5 are the mmu mode. The VMS hmcode uses all 4 modes; ++ The Unix hmcode only uses bit 4. */ ++#define PS_USER_MODE 8u ++ ++#define ENV_FLAG_HM_SHIFT 0 ++#define ENV_FLAG_PS_SHIFT 8 ++#define ENV_FLAG_FEN_SHIFT 24 ++ ++#define ENV_FLAG_HM_MODE (1u << ENV_FLAG_HM_SHIFT) ++#define ENV_FLAG_PS_USER (PS_USER_MODE << ENV_FLAG_PS_SHIFT) ++#define ENV_FLAG_FEN (1u << ENV_FLAG_FEN_SHIFT) ++ ++#define MCU_CLOCK 25000000 ++ ++typedef struct CPUSW64State CPUSW64State; ++typedef CPUSW64State CPUArchState; ++typedef SW64CPU ArchCPU; ++ ++struct CPUSW64State { ++ uint64_t ir[32]; ++ uint64_t fr[128]; ++ uint64_t pc; ++ bool is_slave; ++ ++ uint64_t csr[0x100]; ++ uint64_t fpcr; ++ uint64_t fpcr_exc_enable; ++ uint8_t fpcr_round_mode; ++ uint8_t fpcr_flush_to_zero; ++ ++ float_status fp_status; ++ ++ uint64_t hm_entry; ++ ++#if !defined(CONFIG_USER_ONLY) ++ uint64_t sr[10]; /* shadow regs 1,2,4-7,20-23 */ ++#endif ++ ++ uint32_t flags; ++ uint64_t error_code; ++ uint64_t unique; ++ uint64_t lock_addr; ++ uint64_t lock_valid; ++ uint64_t lock_flag; ++ uint64_t lock_success; ++#ifdef SW64_FIXLOCK ++ uint64_t lock_value; ++#endif ++ ++ uint64_t trap_arg0; ++ uint64_t trap_arg1; ++ uint64_t trap_arg2; ++ ++ uint64_t features; ++ uint64_t insn_count[537]; ++ ++ /* reserve for slave */ ++ uint64_t ca[4]; ++ uint64_t scala_gpr[64]; ++ uint64_t vec_gpr[224]; ++ uint64_t fpcr_base; ++ uint64_t fpcr_ext; ++ uint64_t pendding_flag; ++ uint64_t pendding_status; ++ uint64_t synr_pendding_status; ++ uint64_t sync_pendding_status; ++ uint8_t vlenma_idxa; ++ uint8_t stable; ++}; ++#define SW64_FEATURE_CORE3 0x2 ++ ++static inline void set_feature(CPUSW64State *env, int feature) ++{ ++ env->features |= feature; ++} ++ ++/** ++ * SW64CPU: ++ * @env: #CPUSW64State ++ * ++ * An SW64 CPU ++ */ ++struct SW64CPU { ++ /*< private >*/ ++ CPUState parent_obj; ++ /*< public >*/ ++ CPUNegativeOffsetState neg; ++ CPUSW64State env; ++ ++ uint64_t k_regs[158]; ++ uint64_t k_vcb[36]; ++ QEMUTimer *alarm_timer; ++ target_ulong irq; ++ uint32_t cid; ++}; ++ ++enum { ++ IDX_V0 = 0, ++ IDX_T0 = 1, ++ IDX_T1 = 2, ++ IDX_T2 = 3, ++ IDX_T3 = 4, ++ IDX_T4 = 5, ++ IDX_T5 = 6, ++ IDX_T6 = 7, ++ IDX_T7 = 8, ++ IDX_S0 = 9, ++ IDX_S1 = 10, ++ IDX_S2 = 11, ++ IDX_S3 = 12, ++ IDX_S4 = 13, ++ IDX_S5 = 14, ++ IDX_S6 = 15, ++ IDX_FP = IDX_S6, ++ IDX_A0 = 16, ++ IDX_A1 = 17, ++ IDX_A2 = 18, ++ IDX_A3 = 19, ++ IDX_A4 = 20, ++ IDX_A5 = 21, ++ IDX_T8 = 22, ++ IDX_T9 = 23, ++ IDX_T10 = 24, ++ IDX_T11 = 25, ++ IDX_RA = 26, ++ IDX_T12 = 27, ++ IDX_PV = IDX_T12, ++ IDX_AT = 28, ++ IDX_GP = 29, ++ IDX_SP = 30, ++ IDX_ZERO = 31, ++}; ++ ++enum { ++ MM_K_TNV = 0x0, ++ MM_K_ACV = 0x1, ++ MM_K_FOR = 0x2, ++ MM_K_FOE = 0x3, ++ MM_K_FOW = 0x4 ++}; ++ ++enum { ++ PTE_VALID = 0x0001, ++ PTE_FOR = 0x0002, /* used for page protection (fault on read) */ ++ PTE_FOW = 0x0004, /* used for page protection (fault on write) */ ++ PTE_FOE = 0x0008, ++ PTE_KS = 0x0010, ++ PTE_PSE = 0x0040, ++ PTE_GH = 0x0060, ++ PTE_HRE = 0x0100, ++ PTE_VRE = 0x0200, ++ PTE_KRE = 0x0400, ++ PTE_URE = 0x0800, ++ PTE_HWE = 0x1000, ++ PTE_VWE = 0x2000, ++ PTE_KWE = 0x4000, ++ PTE_UWE = 0x8000 ++}; ++ ++static inline int cpu_mmu_index(CPUSW64State *env, bool ifetch) ++{ ++ int ret = env->flags & ENV_FLAG_PS_USER ? MMU_USER_IDX : MMU_KERNEL_IDX; ++ if (env->flags & ENV_FLAG_HM_MODE) { ++ ret = MMU_PHYS_IDX; ++ } ++ return ret; ++} ++ ++static inline SW64CPU *sw64_env_get_cpu(CPUSW64State *env) ++{ ++ return container_of(env, SW64CPU, env); ++} ++ ++#define ENV_GET_CPU(e) CPU(sw64_env_get_cpu(e)) ++#define ENV_OFFSET offsetof(SW64CPU, env) ++ ++#define cpu_init(cpu_model) cpu_generic_init(TYPE_SW64_CPU, cpu_model) ++ ++#define SW64_CPU_TYPE_SUFFIX "-" TYPE_SW64_CPU ++#define SW64_CPU_TYPE_NAME(name) (name SW64_CPU_TYPE_SUFFIX) ++int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr); ++uint64_t sw64_ldl_phys(CPUState *cs, hwaddr addr); ++hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr); ++void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val); ++uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr); ++void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val); ++uint64_t cpu_sw64_load_fpcr(CPUSW64State *env); ++void cpu_sw64_store_fpcr(CPUSW64State *env, uint64_t val); ++void sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, ++ MMUAccessType access_type, int mmu_idx, ++ uintptr_t retaddr) QEMU_NORETURN; ++bool sw64_cpu_has_work(CPUState *cs); ++extern struct VMStateDescription vmstate_sw64_cpu; ++ ++/* SW64-specific interrupt pending bits */ ++#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 ++#define CPU_INTERRUPT_IIMAIL CPU_INTERRUPT_TGT_EXT_1 ++#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 ++#define CPU_INTERRUPT_PCIE CPU_INTERRUPT_TGT_EXT_3 ++#define CPU_INTERRUPT_WAKEUP CPU_INTERRUPT_TGT_EXT_3 ++#define CPU_INTERRUPT_SLAVE CPU_INTERRUPT_TGT_EXT_4 ++ ++#define cpu_signal_handler cpu_sw64_signal_handler ++#define CPU_RESOLVING_TYPE TYPE_SW64_CPU ++ ++#define SWCSR(x, y) x = y ++enum { ++ SWCSR(ITB_TAG, 0x0), ++ SWCSR(ITB_PTE, 0x1), ++ SWCSR(ITB_IA, 0x2), ++ SWCSR(ITB_IV, 0x3), ++ SWCSR(ITB_IVP, 0x4), ++ SWCSR(ITB_IU, 0x5), ++ SWCSR(ITB_IS, 0x6), ++ SWCSR(EXC_SUM, 0xd), ++ SWCSR(EXC_PC, 0xe), ++ SWCSR(DS_STAT, 0x48), ++ SWCSR(CID, 0xc4), ++ SWCSR(TID, 0xc7), ++ ++ SWCSR(DTB_TAG, 0x40), ++ SWCSR(DTB_PTE, 0x41), ++ SWCSR(DTB_IA, 0x42), ++ SWCSR(DTB_IV, 0x43), ++ SWCSR(DTB_IVP, 0x44), ++ SWCSR(DTB_IU, 0x45), ++ SWCSR(DTB_IS, 0x46), ++ SWCSR(II_REQ, 0x82), ++ ++ SWCSR(PTBR, 0x8), ++ SWCSR(PRI_BASE, 0x10), ++ SWCSR(TIMER_CTL, 0x2a), ++ SWCSR(INT_STAT, 0x30), ++ SWCSR(INT_CLR, 0x31), ++ SWCSR(IER, 0x32), ++ SWCSR(INT_PCI_INT, 0x33), ++ SWCSR(DVA, 0x4e), ++}; ++ ++#include "exec/cpu-all.h" ++static inline void cpu_get_tb_cpu_state(CPUSW64State *env, target_ulong *pc, ++ target_ulong *cs_base, uint32_t *pflags) ++{ ++ *pc = env->pc; ++ *cs_base = 0; ++ *pflags = env->flags; ++} ++ ++void sw64_translate_init(void); ++ ++enum { ++ EXCP_NONE, ++ EXCP_HALT, ++ EXCP_IIMAIL, ++ EXCP_OPCDEC, ++ EXCP_CALL_SYS, ++ EXCP_ARITH, ++ EXCP_UNALIGN, ++#ifdef SOFTMMU ++ EXCP_MMFAULT, ++#else ++ EXCP_DTBD, ++ EXCP_DTBS_U, ++ EXCP_DTBS_K, ++ EXCP_ITB_U, ++ EXCP_ITB_K, ++#endif ++ EXCP_CLK_INTERRUPT, ++ EXCP_DEV_INTERRUPT, ++ EXCP_SLAVE, ++}; ++ ++#define CSR_SHIFT_AND_MASK(name, func, shift, bits) \ ++ name##_##func##_S = shift, \ ++ name##_##func##_V = bits, \ ++ name##_##func##_M = (1UL << bits) - 1 ++ ++#define FPCR_MASK(name) ((uint64_t)FPCR_##name##_M << FPCR_##name##_S) ++/* FPCR */ ++enum { ++ CSR_SHIFT_AND_MASK(FPCR, EXC_CTL, 0, 2), ++ CSR_SHIFT_AND_MASK(FPCR, EXC_CTL_WEN, 2, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV0, 3, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INV3, 4, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO0, 5, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF3, 6, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF3, 7, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE3, 8, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO1, 9, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV1, 10, 10), ++ CSR_SHIFT_AND_MASK(FPCR, INV2, 20, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO2, 21, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF2, 22, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF2, 23, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE2, 24, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO3, 25, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV2, 26, 10), ++ CSR_SHIFT_AND_MASK(FPCR, INV1, 36, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO4, 37, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF1, 38, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF1, 39, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE1, 40, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO5, 41, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV3, 42, 6), ++ CSR_SHIFT_AND_MASK(FPCR, DNZ, 48, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INVD, 49, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DZED, 50, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVFD, 51, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INV0, 52, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DZE0, 53, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF0, 54, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF0, 55, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE0, 56, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVI0, 57, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DYN, 58, 2), ++ CSR_SHIFT_AND_MASK(FPCR, UNDZ, 60, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNFD, 61, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INED, 62, 1), ++ CSR_SHIFT_AND_MASK(FPCR, SUM, 63, 1), ++}; ++ ++/* Arithmetic exception (entArith) constants. */ ++#define EXC_M_SWC 1 /* Software completion */ ++#define EXC_M_INV 2 /* Invalid operation */ ++#define EXC_M_DZE 4 /* Division by zero */ ++#define EXC_M_OVF 8 /* Overflow */ ++#define EXC_M_UNF 16 /* Underflow */ ++#define EXC_M_INE 32 /* Inexact result */ ++#define EXC_M_IOV 64 /* Integer Overflow */ ++#define EXC_M_DNO 128 /* Denomal operation */ ++ ++void QEMU_NORETURN dynamic_excp(CPUSW64State *env, uintptr_t retaddr, int excp, ++ int error); ++void QEMU_NORETURN arith_excp(CPUSW64State *env, uintptr_t retaddr, int exc, ++ uint64_t mask); ++ ++#define DEBUG_ARCH ++#ifdef DEBUG_ARCH ++#define arch_assert(x) \ ++ do { \ ++ g_assert(x); /*fprintf(stderr, "+6b %d\n", __LINE__); */ \ ++ } while (0) ++#else ++#define arch_assert(x) ++#endif ++ ++typedef struct SW64CPUInfo { ++ const char *name; ++ void (*initfn)(Object *obj); ++ void (*class_init)(ObjectClass *oc, void *data); ++} SW64CPUInfo; ++#define test_feature(env, x) (env->features & (x)) ++ ++/* Slave */ ++#endif +diff --git a/target/sw64/exception.c b/target/sw64/exception.c +new file mode 100644 +index 0000000000..a2df1cd329 +--- /dev/null ++++ b/target/sw64/exception.c +@@ -0,0 +1,76 @@ ++#include "qemu/osdep.h" ++#include "qemu/timer.h" ++ ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "fpu/softfloat.h" ++#include "exec/helper-proto.h" ++#include "hw/core/cpu.h" ++ ++#ifndef CONFIG_USER_ONLY ++void QEMU_NORETURN sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, ++ MMUAccessType access_type, ++ int mmu_idx, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ uint32_t insn = 0; ++ ++ if (retaddr) { ++ cpu_restore_state(cs, retaddr, true); ++ } ++ ++ fprintf(stderr, "Error %s addr = %lx\n", __func__, addr); ++ env->csr[DVA] = addr; ++ ++ env->csr[EXC_SUM] = ((insn >> 21) & 31) << 8; /* opcode */ ++ env->csr[DS_STAT] = (insn >> 26) << 4; /* dest regno */ ++ cs->exception_index = EXCP_UNALIGN; ++ env->error_code = 0; ++ cpu_loop_exit(cs); ++} ++ ++#endif ++ ++/* This should only be called from translate, via gen_excp. ++ We expect that ENV->PC has already been updated. */ ++void QEMU_NORETURN helper_excp(CPUSW64State *env, int excp, int error) ++{ ++ SW64CPU *cpu = sw64_env_get_cpu(env); ++ CPUState *cs = CPU(cpu); ++ ++ cs->exception_index = excp; ++ env->error_code = error; ++ cpu_loop_exit(cs); ++} ++ ++/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */ ++void QEMU_NORETURN dynamic_excp(CPUSW64State *env, uintptr_t retaddr, int excp, ++ int error) ++{ ++ SW64CPU *cpu = sw64_env_get_cpu(env); ++ CPUState *cs = CPU(cpu); ++ ++ cs->exception_index = excp; ++ env->error_code = error; ++ if (retaddr) { ++ /* FIXME: Not jump to another tb, but jump to next insn emu */ ++ cpu_restore_state(cs, retaddr, true); ++ /* Floating-point exceptions (our only users) point to the next PC. */ ++ env->pc += 4; ++ } ++ cpu_loop_exit(cs); ++} ++ ++void QEMU_NORETURN arith_excp(CPUSW64State *env, uintptr_t retaddr, int exc, ++ uint64_t mask) ++{ ++ env->csr[EXC_SUM] = exc; ++ dynamic_excp(env, retaddr, EXCP_ARITH, 0); ++} ++ ++ ++void helper_trace_mem(CPUSW64State *env, uint64_t addr, uint64_t val) ++{ ++ /* printf("pc = %lx: Access mem addr =%lx, val = %lx\n", env->pc, addr,val); */ ++} +diff --git a/target/sw64/float_helper.c b/target/sw64/float_helper.c +new file mode 100644 +index 0000000000..ad1c3cce48 +--- /dev/null ++++ b/target/sw64/float_helper.c +@@ -0,0 +1,846 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++#include "fpu/softfloat.h" ++ ++static inline uint32_t extractFloat16Frac(float16 a) ++{ ++ return float16_val(a) & 0x3ff; ++} ++ ++/*---------------------------------------------------------------------------- ++| Returns the exponent bits of the half-precision floating-point value `a'. ++*----------------------------------------------------------------------------*/ ++ ++static inline int extractFloat16Exp(float16 a) ++{ ++ return (float16_val(a) >> 10) & 0x1f; ++} ++ ++/*---------------------------------------------------------------------------- ++| Returns the sign bit of the single-precision floating-point value `a'. ++*----------------------------------------------------------------------------*/ ++ ++static inline uint8_t extractFloat16Sign(float16 a) ++{ ++ return float16_val(a) >> 15; ++} ++ ++#define FP_STATUS (env->fp_status) ++ ++#define CONVERT_BIT(X, SRC, DST) \ ++ (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X)&SRC) * (DST / SRC)) ++ ++static uint64_t soft_to_errcode_exc(CPUSW64State *env) ++{ ++ uint8_t exc = get_float_exception_flags(&FP_STATUS); ++ ++ if (unlikely(exc)) { ++ set_float_exception_flags(0, &FP_STATUS); ++ } ++ return exc; ++} ++ ++static inline uint64_t float32_to_s_int(uint32_t fi) ++{ ++ uint32_t frac = fi & 0x7fffff; ++ uint32_t sign = (fi >> 31) & 1; ++ uint32_t exp_msb = (fi >> 30) & 1; ++ uint32_t exp_low = (fi >> 23) & 0x7f; ++ uint32_t exp; ++ ++ exp = (exp_msb << 10) | exp_low; ++ if (exp_msb) { ++ if (exp_low == 0x7f) { ++ exp = 0x7ff; ++ } ++ } else { ++ if (exp_low != 0x00) { ++ exp |= 0x380; ++ } ++ } ++ ++ return (((uint64_t)sign << 63) | ((uint64_t)exp << 52) | ++ ((uint64_t)frac << 29)); ++} ++ ++static inline uint64_t float32_to_s(float32 fa) ++{ ++ CPU_FloatU a; ++ a.f = fa; ++ return float32_to_s_int(a.l); ++} ++static inline uint32_t s_to_float32_int(uint64_t a) ++{ ++ return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); ++} ++ ++static inline float32 s_to_float32(uint64_t a) ++{ ++ CPU_FloatU r; ++ r.l = s_to_float32_int(a); ++ return r.f; ++} ++ ++uint32_t helper_s_to_memory(uint64_t a) ++{ ++ return s_to_float32(a); ++} ++ ++uint64_t helper_memory_to_s(uint32_t a) ++{ ++ return float32_to_s(a); ++} ++ ++uint64_t helper_fcvtls(CPUSW64State *env, uint64_t a) ++{ ++ float32 fr = int64_to_float32(a, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fcvtld(CPUSW64State *env, uint64_t a) ++{ ++ float64 fr = int64_to_float64(a, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++ return (uint64_t)fr; ++} ++ ++static uint64_t do_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ uint64_t frac, ret = 0; ++ uint32_t exp, sign, exc = 0; ++ int shift; ++ ++ sign = (a >> 63); ++ exp = (uint32_t)(a >> 52) & 0x7ff; ++ frac = a & 0xfffffffffffffull; ++ ++ if (exp == 0) { ++ if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { ++ goto do_underflow; ++ } ++ } else if (exp == 0x7ff) { ++ exc = float_flag_invalid; ++ } else { ++ /* Restore implicit bit. */ ++ frac |= 0x10000000000000ull; ++ ++ shift = exp - 1023 - 52; ++ if (shift >= 0) { ++ /* In this case the number is so large that we must shift ++ the fraction left. There is no rounding to do. */ ++ if (shift < 64) { ++ ret = frac << shift; ++ } ++ /* Check for overflow. Note the special case of -0x1p63. */ ++ if (shift >= 11 && a != 0xC3E0000000000000ull) { ++ exc = float_flag_inexact; ++ } ++ } else { ++ uint64_t round; ++ ++ /* In this case the number is smaller than the fraction as ++ represented by the 52 bit number. Here we must think ++ about rounding the result. Handle this by shifting the ++ fractional part of the number into the high bits of ROUND. ++ This will let us efficiently handle round-to-nearest. */ ++ shift = -shift; ++ if (shift < 63) { ++ ret = frac >> shift; ++ round = frac << (64 - shift); ++ } else { ++ /* The exponent is so small we shift out everything. ++ Leave a sticky bit for proper rounding below. */ ++ do_underflow: ++ round = 1; ++ } ++ ++ if (round) { ++ exc = float_flag_inexact; ++ switch (roundmode) { ++ case float_round_nearest_even: ++ if (round == (1ull << 63)) { ++ /* Fraction is exactly 0.5; round to even. */ ++ ret += (ret & 1); ++ } else if (round > (1ull << 63)) { ++ ret += 1; ++ } ++ break; ++ case float_round_to_zero: ++ break; ++ case float_round_up: ++ ret += 1 - sign; ++ break; ++ case float_round_down: ++ ret += sign; ++ break; ++ } ++ } ++ } ++ if (sign) { ++ ret = -ret; ++ } ++ } ++ env->error_code = exc; ++ ++ return ret; ++} ++ ++/* TODO: */ ++uint64_t helper_fris(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ uint64_t ir; ++ float32 fr; ++ ++ if (roundmode == 5) ++ roundmode = env->fpcr_round_mode; ++ ir = do_fcvtdl(env, a, roundmode); ++ fr = int64_to_float32(ir, &FP_STATUS); ++ return float32_to_s(fr); ++} ++ ++/* TODO: */ ++uint64_t helper_frid(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ if (roundmode == 5) ++ roundmode = env->fpcr_round_mode; ++ return int64_to_float64(do_fcvtdl(env, a, roundmode), &FP_STATUS); ++} ++ ++uint64_t helper_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ return do_fcvtdl(env, a, roundmode); ++} ++ ++uint64_t helper_fcvtdl_dyn(CPUSW64State *env, uint64_t a) ++{ ++ uint64_t roundmode = (uint64_t)(env->fpcr_round_mode); ++ return do_fcvtdl(env, a, roundmode); ++} ++ ++uint64_t helper_fcvtsd(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa; ++ float64 fr; ++ ++ fa = s_to_float32(a); ++ fr = float32_to_float64(fa, &FP_STATUS); ++ ++ return fr; ++} ++ ++uint64_t helper_fcvtds(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa; ++ ++ fa = float64_to_float32((float64)a, &FP_STATUS); ++ ++ return float32_to_s(fa); ++} ++ ++uint64_t helper_fcvtwl(CPUSW64State *env, uint64_t a) ++{ ++ int32_t ret; ++ ret = (a >> 29) & 0x3fffffff; ++ ret |= ((a >> 62) & 0x3) << 30; ++ return (uint64_t)(int64_t)ret; //int32_t to int64_t as Sign-Extend ++} ++ ++uint64_t helper_fcvtlw(CPUSW64State *env, uint64_t a) ++{ ++ uint64_t ret; ++ ret = (a & 0x3fffffff) << 29; ++ ret |= ((a >> 30) & 0x3) << 62; ++ return ret; ++} ++ ++uint64_t helper_fadds(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_add(fa, fb, &FP_STATUS); ++ ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fb + *(float*)&fa; ++#endif ++ return float32_to_s(fr); ++} ++ ++/* Input handing without software completion. Trap for all ++ non-finite numbers. */ ++uint64_t helper_faddd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_add(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fb + *(double*)&fa; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fsubs(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_sub(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa - *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fsubd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_sub(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa - *(double*)&fb; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fmuls(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_mul(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa * *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmuld(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_mul(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa * *(double*)&fb; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fdivs(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_div(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa / *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fdivd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_div(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa / *(double*)&fb; ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_frecs(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = int64_to_float32(1, &FP_STATUS); ++#if 1 ++ fr = float32_div(fb, fa, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fb / *(float*)&fa; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_frecd(CPUSW64State *env, uint64_t a) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = int64_to_float64(1, &FP_STATUS); ++#if 1 ++ fr = float64_div(fb, fa, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fb / *(double*)&fa; ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fsqrts(CPUSW64State *env, uint64_t b) ++{ ++ float32 fb, fr; ++#if 1 ++ fb = s_to_float32(b); ++ fr = float32_sqrt(fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++#include ++ *(double*)&fr = sqrt(*(double*)&b); ++#endif ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fsqrt(CPUSW64State *env, uint64_t b) ++{ ++ float64 fr; ++ ++#if 1 ++ fr = float64_sqrt(b, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++#include ++ *(double*)&fr = sqrt(*(double*)&b); ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++ ++uint64_t helper_fmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ ++ fr = float32_muladd(fa, fb, fc, 0, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ ++ fr = float64_muladd(a, b, c, 0, &FP_STATUS); ++ ++ return fr; ++} ++ ++ ++uint64_t helper_fmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ ++ fr = float32_muladd(fa, fb, fc, float_muladd_negate_c, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ ++ fr = float64_muladd(a, b, c, float_muladd_negate_c, &FP_STATUS); ++ ++ return fr; ++} ++ ++ ++uint64_t helper_fnmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ int flag = float_muladd_negate_product; ++ ++ fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fnmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ int flag = float_muladd_negate_product; ++ ++ fr = float64_muladd(a, b, c, flag, &FP_STATUS); ++ ++ return fr; ++} ++ ++uint64_t helper_fnmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ int flag = float_muladd_negate_product | float_muladd_negate_c; ++ ++ fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fnmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ int flag = float_muladd_negate_product | float_muladd_negate_c; ++ ++ fr = float64_muladd(a, b, c, flag, &FP_STATUS); ++ ++ return fr; ++} ++uint64_t helper_load_fpcr(CPUSW64State *env) ++{ ++ return cpu_sw64_load_fpcr(env); ++} ++ ++static void update_fpcr_status_mask(CPUSW64State *env) ++{ ++ uint64_t t = 0; ++ ++ /* Don't mask the inv excp: ++ * EXC_CTL1 = 1 ++ * EXC_CTL1 = 0, input denormal, DNZ=0 ++ * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 ++ */ ++ if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { ++ if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { ++ t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); ++ } else { ++ t |= EXC_M_INE; ++ } ++ } else { ++ /* INV and DNO mask */ ++ if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; ++ if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; ++ if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; ++ if (env->fpcr & FPCR_MASK(UNFD)) { ++ t |= EXC_M_UNF; ++ } ++ if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; ++ if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; ++ } ++ ++ env->fpcr_exc_enable = t; ++} ++ ++void helper_store_fpcr(CPUSW64State *env, uint64_t val) ++{ ++ uint64_t fpcr = val; ++ uint8_t ret; ++ ++ switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { ++ case 0x0: ++ ret = float_round_to_zero; ++ break; ++ case 0x1: ++ ret = float_round_down; ++ break; ++ case 0x2: ++ ret = float_round_nearest_even; ++ break; ++ case 0x3: ++ ret = float_round_up; ++ break; ++ default: ++ ret = float_round_nearest_even; ++ break; ++ } ++ ++ env->fpcr_round_mode = ret; ++ ++ env->fp_status.float_rounding_mode = ret; ++ ++ env->fpcr_flush_to_zero = ++ (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); ++ env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; ++ ++ /* FIXME: Now the DNZ flag does not work int C3A. */ ++ //set_flush_inputs_to_zero((val & FPCR_MASK(DNZ)) != 0? 1 : 0, &FP_STATUS); ++ ++ val &= ~0x3UL; ++ val |= env->fpcr & 0x3UL; ++ env->fpcr = val; ++ update_fpcr_status_mask(env); ++} ++ ++void helper_setfpcrx(CPUSW64State *env, uint64_t val) ++{ ++ if (env->fpcr & FPCR_MASK(EXC_CTL_WEN)) { ++ env->fpcr &= ~3UL; ++ env->fpcr |= val & 0x3; ++ update_fpcr_status_mask(env); ++ } ++} ++#ifndef CONFIG_USER_ONLY ++static uint32_t soft_to_exc_type(uint64_t exc) ++{ ++ uint32_t ret = 0; ++ ++ if (unlikely(exc)) { ++ ret |= CONVERT_BIT(exc, float_flag_invalid, EXC_M_INV); ++ ret |= CONVERT_BIT(exc, float_flag_divbyzero, EXC_M_DZE); ++ ret |= CONVERT_BIT(exc, float_flag_overflow, EXC_M_OVF); ++ ret |= CONVERT_BIT(exc, float_flag_underflow, EXC_M_UNF); ++ ret |= CONVERT_BIT(exc, float_flag_inexact, EXC_M_INE); ++ } ++ ++ return ret; ++} ++static void fp_exc_raise1(CPUSW64State *env, uintptr_t retaddr, uint64_t exc, ++ uint32_t regno) ++{ ++ if (!likely(exc)) ++ return; ++ arith_excp(env, retaddr, exc, 1ull << regno); ++} ++ ++void helper_fp_exc_raise(CPUSW64State *env, uint32_t regno) ++{ ++ uint64_t exc = env->error_code; ++ uint32_t exc_type = soft_to_exc_type(exc); ++ ++ if (exc_type) { ++ exc_type &= ~(env->fpcr_exc_enable); ++ if (exc_type) fp_exc_raise1(env, GETPC(), exc_type | EXC_M_SWC, regno); ++ } ++} ++#endif ++ ++void helper_ieee_input(CPUSW64State *env, uint64_t val) ++{ ++#ifndef CONFIG_USER_ONLY ++ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; ++ uint64_t frac = val & 0xfffffffffffffull; ++ ++ if (exp == 0x7ff) { ++ /* Infinity or NaN. */ ++ uint32_t exc_type = EXC_M_INV; ++ ++ if (exc_type) { ++ exc_type &= ~(env->fpcr_exc_enable); ++ if (exc_type) ++ fp_exc_raise1(env, GETPC(), exc_type | EXC_M_SWC, 32); ++ } ++ } ++#endif ++} ++ ++void helper_ieee_input_s(CPUSW64State *env, uint64_t val) ++{ ++ if (unlikely(2 * val - 1 < 0x1fffffffffffffull) && ++ !env->fp_status.flush_inputs_to_zero) { ++ } ++} ++ ++static inline float64 t_to_float64(uint64_t a) ++{ ++ /* Memory format is the same as float64 */ ++ CPU_DoubleU r; ++ r.ll = a; ++ return r.d; ++} ++ ++uint64_t helper_fcmpun(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpeq(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_eq_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmple(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_le_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmplt(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_lt_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpge(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_le_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpgt(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ fa = t_to_float64(a); ++ fb = t_to_float64(b); ++ ++ if (float64_lt_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpge_s(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ /* Make sure va and vb is s float. */ ++ fa = float32_to_float64(s_to_float32(a), &FP_STATUS); ++ fb = float32_to_float64(s_to_float32(b), &FP_STATUS); ++ ++ if (float64_le_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmple_s(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ /* Make sure va and vb is s float. */ ++ fa = float32_to_float64(s_to_float32(a), &FP_STATUS); ++ fb = float32_to_float64(s_to_float32(b), &FP_STATUS); ++ ++ if (float64_le_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++void helper_vfcvtsh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint64_t temp = 0; ++ int i; ++ for (i = 0; i < 4; i++) { ++ temp |= (uint64_t)float32_to_float16(s_to_float32(env->fr[ra + i * 32]), ++ 1, &FP_STATUS) ++ << (i * 16); ++ } ++ for (i = 0; i < 4; i++) { ++ if (i == (vc & 0x3)) { ++ env->fr[rd + i * 32] = temp; ++ } else { ++ env->fr[rd + i * 32] = env->fr[rb + i * 32]; ++ } ++ } ++} ++ ++void helper_vfcvths(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint64_t temp; ++ int i; ++ ++ temp = env->fr[ra + 32 * (vc & 0x3)]; ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = float32_to_s( ++ float16_to_float32((temp >> (i * 16)) & 0xffffUL, 1, &FP_STATUS)); ++ } ++} +diff --git a/target/sw64/helper.c b/target/sw64/helper.c +new file mode 100644 +index 0000000000..0cc0af7087 +--- /dev/null ++++ b/target/sw64/helper.c +@@ -0,0 +1,349 @@ ++/* ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/timer.h" ++ ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "fpu/softfloat.h" ++#include "exec/helper-proto.h" ++#include "hw/core/cpu.h" ++#include "exec/memattrs.h" ++ ++#if defined(CONFIG_USER_ONLY) ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ ++ cs->exception_index = EXCP_MMFAULT; ++ cpu->env.trap_arg0 = address; ++ cpu_loop_exit_restore(cs, retaddr); ++} ++#else ++static target_ulong ldq_phys_clear(CPUState *cs, target_ulong phys) ++{ ++ return ldq_phys(cs->as, phys & ~(3UL)); ++} ++ ++static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, ++ int prot_need, int mmu_idx, target_ulong *pphys, ++ int *pprot) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ target_ulong phys = 0; ++ int prot = 0; ++ int ret = MM_K_ACV; ++ target_ulong L1pte, L2pte, L3pte, L4pte; ++ target_ulong pt, index, pte_pfn_s; ++ ++ if (((addr >> 28) & 0xffffffff8) == 0xffffffff8) { ++ phys = (~(0xffffffff80000000)) & addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ ret = -1; ++ goto exit; ++ } else if (((addr >> 32) & 0xfffff000) == 0xfffff000) { ++ goto do_pgmiss; ++ } else if (((addr >> 52) & 0xfff) == 0xfff) { ++ phys = (~(0xfff0000000000000)) & addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ ret = -1; ++ goto exit; ++ } ++do_pgmiss: ++ pte_pfn_s = 28; ++ pt = env->csr[PTBR]; ++ index = (addr >> (TARGET_PAGE_BITS + 3 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L1pte = ldq_phys_clear(cs, pt + index * 8); ++ if ((L1pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L1pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L1pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ pt = L1pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> (TARGET_PAGE_BITS + 2 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L2pte = ldq_phys_clear(cs, pt + index * 8); ++ ++ if ((L2pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L2pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L2pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ ++ pt = L2pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> (TARGET_PAGE_BITS + 1 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L3pte = ldq_phys_clear(cs, pt + index * 8); ++ ++ if ((L3pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L3pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L3pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ ++ pt = L3pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> TARGET_PAGE_BITS) & ((1 << TARGET_LEVEL_BITS)-1); ++ L4pte = ldq_phys_clear(cs, pt + index * 8); ++ if ((L4pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4 ++#error page bits out of date ++#endif ++ ++ /* Check access violations. */ ++ if ((L4pte & PTE_FOR) == 0) { ++ prot |= PAGE_READ | PAGE_EXEC; ++ } ++ if ((L4pte & PTE_FOW) == 0) { ++ prot |= PAGE_WRITE; ++ } ++ ++ /* Check fault-on-operation violations. */ ++ prot &= ~(L4pte >> 1); ++ ++ phys = (L4pte >> pte_pfn_s << TARGET_PAGE_BITS); ++ ++ if (unlikely((prot & prot_need) == 0)) { ++ ret = (prot_need & PAGE_EXEC ++ ? MM_K_FOE ++ : prot_need & PAGE_WRITE ++ ? MM_K_FOW ++ : prot_need & PAGE_READ ? MM_K_FOR : -1); ++ goto exit; ++ } ++ ++ ret = -1; ++exit: ++ *pphys = phys; ++ *pprot = prot; ++ return ret; ++} ++ ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ target_ulong phys; ++ int prot, fail; ++ ++ if (mmu_idx == MMU_PHYS_IDX) { ++ phys = address; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ fail = 0; ++ if ((address >> 52) & 1) goto do_pgmiss; ++ goto done; ++ } ++ ++do_pgmiss: ++ fail = get_sw64_physical_address(env, address, 1 << access_type, mmu_idx, &phys, &prot); ++ if (unlikely(fail >= 0)) { ++ if (probe) { ++ return false; ++ } ++ cs->exception_index = EXCP_MMFAULT; ++ if (access_type == 2) { ++ env->csr[DS_STAT] = fail; ++ env->csr[DVA] = address & ~(3UL); ++ } else { ++ env->csr[DS_STAT] = fail | (((unsigned long)access_type + 1) << 3); ++ env->csr[DVA] = address; ++ } ++ env->error_code = access_type; ++ cpu_loop_exit_restore(cs, retaddr); ++ } ++done: ++ tlb_set_page(cs, address & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, prot, ++ mmu_idx, TARGET_PAGE_SIZE); ++ return true; ++} ++ ++hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ target_ulong phys; ++ int prot, fail; ++ int mmu_index = cpu_mmu_index(env, 0); ++ if (mmu_index == MMU_PHYS_IDX) { ++ phys = addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ fail = -1; ++ if ((addr >> 52) & 1) goto do_pgmiss; ++ goto done; ++ } ++do_pgmiss: ++ fail = get_sw64_physical_address(&cpu->env, addr, 1, mmu_index, &phys, &prot); ++done: ++ return (fail >= 0 ? -1 : phys); ++} ++#endif ++ ++static void update_fpcr_status_mask(CPUSW64State* env) { ++ uint64_t t = 0; ++ ++ /* Don't mask the inv excp: ++ * EXC_CTL1 = 1 ++ * EXC_CTL1 = 0, input denormal, DNZ=0 ++ * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 ++ */ ++ if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { ++ if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { ++ t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); ++ } else { ++ t |= EXC_M_INE; ++ } ++ } else { ++ /* INV and DNO mask */ ++ if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; ++ if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; ++ if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; ++ if (env->fpcr & FPCR_MASK(UNFD)) { ++ t |= EXC_M_UNF; ++ } ++ if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; ++ if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; ++ } ++ ++ env->fpcr_exc_enable = t; ++} ++ ++void cpu_sw64_store_fpcr(CPUSW64State* env, uint64_t val) { ++ uint64_t fpcr = val; ++ uint8_t ret; ++ ++ switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { ++ case 0x0: ++ ret = float_round_to_zero; ++ break; ++ case 0x1: ++ ret = float_round_down; ++ break; ++ case 0x2: ++ ret = float_round_nearest_even; ++ break; ++ case 0x3: ++ ret = float_round_up; ++ break; ++ default: ++ ret = float_round_nearest_even; ++ break; ++ } ++ ++ env->fpcr_round_mode = ret; ++ env->fp_status.float_rounding_mode = ret; ++ ++ env->fpcr_flush_to_zero = ++ (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); ++ env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; ++ ++ val &= ~0x3UL; ++ val |= env->fpcr & 0x3UL; ++ env->fpcr = val; ++ update_fpcr_status_mask(env); ++} ++ ++uint64_t helper_read_csr(CPUSW64State *env, uint64_t index) ++{ ++ if (index == PRI_BASE) ++ return 0x10000; ++ return env->csr[index]; ++} ++ ++uint64_t helper_rtc(void) ++{ ++#ifndef CONFIG_USER_ONLY ++ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) * CPUFREQ_SCALE; ++#else ++ return 0; ++#endif ++} ++ ++void helper_write_csr(CPUSW64State *env, uint64_t index, uint64_t va) ++{ ++ env->csr[index] = va; ++#ifndef CONFIG_USER_ONLY ++ CPUState *cs = &(sw64_env_get_cpu(env)->parent_obj); ++ SW64CPU *cpu = SW64_CPU(cs); ++ if ((index == DTB_IA) || (index == DTB_IV) || (index == DTB_IVP) || ++ (index == DTB_IU) || (index == DTB_IS) || (index == ITB_IA) || ++ (index == ITB_IV) || (index == ITB_IVP) || (index == ITB_IU) || ++ (index == ITB_IS) || (index == PTBR)) { ++ tlb_flush(cs); ++ } ++ if (index == INT_CLR || index == INT_PCI_INT) { ++ env->csr[INT_STAT] &= ~va; ++ } ++ ++ if (index == TIMER_CTL && env->csr[index] == 1) { ++ timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1000000000 / 250); ++ } ++#endif ++} ++ ++uint64_t cpu_sw64_load_fpcr(CPUSW64State *env) ++{ ++ return (uint64_t)env->fpcr; ++} ++ ++void helper_tb_flush(CPUSW64State *env) ++{ ++ tb_flush(CPU(sw64_env_get_cpu(env))); ++} ++ ++void helper_cpustate_update(CPUSW64State *env, uint64_t pc) ++{ ++ switch (pc & 0x3) { ++ case 0x00: ++ env->flags = ENV_FLAG_HM_MODE; ++ break; ++ case 0x01: ++ env->flags &= ~(ENV_FLAG_PS_USER | ENV_FLAG_HM_MODE); ++ break; ++ case 0x02: ++ env->flags &= ~(ENV_FLAG_PS_USER | ENV_FLAG_HM_MODE); ++ break; ++ case 0x03: ++ env->flags = ENV_FLAG_PS_USER; ++ } ++} +diff --git a/target/sw64/helper.h b/target/sw64/helper.h +new file mode 100644 +index 0000000000..7cafa563c2 +--- /dev/null ++++ b/target/sw64/helper.h +@@ -0,0 +1,127 @@ ++ ++DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64) ++DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64) ++DEF_HELPER_FLAGS_2(cmpgeb, TCG_CALL_NO_RWG_SE, i64, i64, i64) ++DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) ++DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_NO_RWG_SE, i64, i32) ++DEF_HELPER_FLAGS_2(fcvtls, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtld, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(fcvtdl, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(fcvtdl_dyn, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(fris, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(frid, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(fcvtsd, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtds, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtwl, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtlw, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_5(vfcvtsh, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vfcvths, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(frecs, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(frecd, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fsqrt, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_4(fmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_0(rtc, TCG_CALL_NO_RWG, i64) ++DEF_HELPER_FLAGS_1(load_fpcr, 0, i64, env) ++DEF_HELPER_FLAGS_2(store_fpcr, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(setfpcrx, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(ieee_input, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(ieee_input_s, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(read_csr, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(write_csr, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_2(cpustate_update, 0, void, env, i64) ++DEF_HELPER_FLAGS_3(trace_mem, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpun, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmple, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmplt, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpge, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpgt, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpge_s, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmple_s, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_4(srlow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(sllow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vlogzz, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vconw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcond, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vshfw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_2(ctlzow, 0, i64, env, i64) ++DEF_HELPER_FLAGS_4(vucaddw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddwi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubwi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddhi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubhi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_3(vstw, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(vsts, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(vstd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(v_print, 0, void, env, i64) ++DEF_HELPER_FLAGS_1(tb_flush, 0, void, env) ++DEF_HELPER_FLAGS_4(vmaxb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vmaxh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vmaxw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(sraow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm4r, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm4key, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm3msw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpueqb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpugtb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpueqbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpugtbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vinsb, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vinsh, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vshfq, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vshfqb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vsm3r, 0, void, env, i64, i64, i64, i64) ++ ++#ifndef CONFIG_USER_ONLY ++DEF_HELPER_FLAGS_2(fp_exc_raise, 0, void, env, i32) ++DEF_HELPER_FLAGS_2(pri_ldw, 0, i64, env, i64) ++DEF_HELPER_FLAGS_3(pri_stw, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_2(pri_ldl, 0, i64, env, i64) ++DEF_HELPER_FLAGS_3(pri_stl, 0, void, env, i64, i64) ++#endif ++ ++DEF_HELPER_3(excp, noreturn, env, int, int) ++//DEF_HELPER_FLAGS_3(faddh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++//DEF_HELPER_FLAGS_3(fsubh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++//DEF_HELPER_FLAGS_3(fmulh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++#ifndef CONFIG_USER_ONLY ++/* Scale factor for core3 cpu freq, ie number of ns per tick. */ ++#define CPUFREQ_SCALE 3 ++#endif ++ ++/* SLAVE FLOAT HELPER. */ +diff --git a/target/sw64/int_helper.c b/target/sw64/int_helper.c +new file mode 100644 +index 0000000000..131182585a +--- /dev/null ++++ b/target/sw64/int_helper.c +@@ -0,0 +1,118 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++#include "qemu/host-utils.h" ++#include "exec/memattrs.h" ++ ++uint64_t helper_zapnot(uint64_t val, uint64_t mskb) ++{ ++ uint64_t mask; ++ ++ mask = -(mskb & 0x01) & 0x00000000000000ffull; ++ mask |= -(mskb & 0x02) & 0x000000000000ff00ull; ++ mask |= -(mskb & 0x04) & 0x0000000000ff0000ull; ++ mask |= -(mskb & 0x08) & 0x00000000ff000000ull; ++ mask |= -(mskb & 0x10) & 0x000000ff00000000ull; ++ mask |= -(mskb & 0x20) & 0x0000ff0000000000ull; ++ mask |= -(mskb & 0x40) & 0x00ff000000000000ull; ++ mask |= -(mskb & 0x80) & 0xff00000000000000ull; ++ ++ return val & mask; ++} ++ ++uint64_t helper_zap(uint64_t val, uint64_t mask) ++{ ++ return helper_zapnot(val, ~mask); ++} ++ ++uint64_t helper_cmpgeb(uint64_t va, uint64_t vb) ++{ ++ int i; ++ uint64_t ret = 0; ++ uint64_t tmp; ++ for (i = 0; i < 64; i += 8) { ++ tmp = ((va >> i) & 0xff) + (~(vb >> i) & 0xff) + 1; ++ ret |= (tmp >> 8) << (i / 8); ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_USER_ONLY ++static inline MemTxAttrs cpu_get_mem_attrs(CPUSW64State *env) ++{ ++ return ((MemTxAttrs) { .secure = 1 }); ++} ++ ++static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) ++{ ++ return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); ++} ++ ++uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ int32_t ret; ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ ret = (int32_t)address_space_ldl(as, addr, attrs, NULL); ++ ++ return (uint64_t)(int64_t)ret; ++} ++ ++void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ address_space_stl(as, addr, (uint32_t)val, attrs, NULL); ++} ++ ++uint64_t sw64_ldl_phys(CPUState *cs, hwaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ return address_space_ldq(as, addr, attrs, NULL); ++} ++ ++void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ address_space_stq(as, addr, val, attrs, NULL); ++} ++ ++uint64_t helper_pri_ldw(CPUSW64State *env, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ return sw64_ldw_phys(cs, hwaddr); ++} ++ ++void helper_pri_stw(CPUSW64State *env, uint64_t val, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ sw64_stw_phys(cs, hwaddr, val); ++} ++ ++uint64_t helper_pri_ldl(CPUSW64State *env, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ return sw64_ldl_phys(cs, hwaddr); ++} ++ ++void helper_pri_stl(CPUSW64State *env, uint64_t val, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ sw64_stl_phys(cs, hwaddr, val); ++} ++#endif +diff --git a/target/sw64/kvm.c b/target/sw64/kvm.c +new file mode 100644 +index 0000000000..fc134c83fb +--- /dev/null ++++ b/target/sw64/kvm.c +@@ -0,0 +1,215 @@ ++/* ++ * SW64 implementation of KVM hooks ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include ++ ++#include "qemu-common.h" ++#include "qemu/timer.h" ++#include "qemu/error-report.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" ++#include "kvm_sw64.h" ++#include "cpu.h" ++#include "exec/memattrs.h" ++#include "exec/address-spaces.h" ++#include "hw/boards.h" ++#include "qemu/log.h" ++ ++#define init_pc 0xffffffff80011000 ++const KVMCapabilityInfo kvm_arch_required_capabilities[] = { ++ KVM_CAP_LAST_INFO ++}; ++/* 50000 jump to bootlader while 2f00000 jump to bios*/ ++int kvm_sw64_vcpu_init(CPUState *cs) ++{ ++ struct kvm_regs *regs; ++ SW64CPU *cpu = SW64_CPU(cs); ++ regs = (struct kvm_regs *)cpu->k_regs; ++ regs->pc = init_pc; ++ return kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); ++} ++ ++static void kvm_sw64_host_cpu_class_init(ObjectClass *oc, void *data) ++{ ++} ++ ++static void kvm_sw64_host_cpu_initfn(Object *obj) ++{ ++} ++ ++ ++static const TypeInfo host_sw64_cpu_type_info = { ++ .name = TYPE_SW64_HOST_CPU, ++ .parent = TYPE_SW64_CPU, ++ .instance_init = kvm_sw64_host_cpu_initfn, ++ .class_init = kvm_sw64_host_cpu_class_init, ++ .class_size = sizeof(SW64HostCPUClass), ++}; ++ ++int kvm_arch_init(MachineState *ms, KVMState *s) ++{ ++ kvm_async_interrupts_allowed = true; ++ ++ type_register_static(&host_sw64_cpu_type_info); ++ ++ return 0; ++} ++ ++/* 50000 jump to bootlader while 2f00000 jump to bios*/ ++void kvm_sw64_reset_vcpu(SW64CPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ struct kvm_regs *regs; ++ int ret; ++ ++ regs = (struct kvm_regs *)cpu->k_regs; ++ regs->pc = init_pc; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); ++ ++ if (ret < 0) { ++ fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); ++ abort(); ++ } ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SW64_VCPU_INIT, NULL); ++ ++ if (ret < 0) { ++ fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); ++ abort(); ++ } ++} ++ ++unsigned long kvm_arch_vcpu_id(CPUState *cpu) ++{ ++ return cpu->cpu_index; ++} ++ ++#include ++int kvm_arch_init_vcpu(CPUState *cs) ++{ ++ int ret; ++ ret = kvm_sw64_vcpu_init(cs); ++ if (ret) { ++ return ret; ++ } ++ return 0; ++} ++ ++int kvm_arch_destroy_vcpu(CPUState *cs) ++{ ++ return 0; ++} ++ ++int kvm_arch_get_registers(CPUState *cs) ++{ ++ int ret; ++ SW64CPU *cpu = SW64_CPU(cs); ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &cpu->k_regs); ++ if (ret < 0) ++ return ret; ++ return kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); ++} ++ ++int kvm_arch_put_registers(CPUState *cs, int level) ++{ ++ int ret; ++ SW64CPU *cpu = SW64_CPU(cs); ++ struct vcpucb *vcb; ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &cpu->k_regs); ++ if (ret < 0) ++ return ret; ++ vcb = (struct vcpucb *)cpu->k_vcb; ++ vcb->whami = kvm_arch_vcpu_id(cs); ++ fprintf(stderr,"vcpu %ld init.\n", vcb->whami); ++ return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); ++} ++ ++int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, ++ int vector, PCIDevice *dev) ++{ ++ return -1; ++} ++ ++int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, ++ uint64_t address, uint32_t data, PCIDevice *dev) ++{ ++ return 0; ++} ++ ++void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) ++{ ++} ++ ++MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) ++{ ++ return MEMTXATTRS_UNSPECIFIED; ++} ++ ++ ++int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ++{ ++ return -1; ++} ++ ++bool kvm_arch_stop_on_emulation_error(CPUState *cs) ++{ ++ return true; ++} ++ ++int kvm_arch_process_async_events(CPUState *cs) ++{ ++ return 0; ++} ++ ++void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg) ++{ ++} ++ ++void kvm_arch_init_irq_routing(KVMState *s) ++{ ++ /* We know at this point that we're using the in-kernel ++ * irqchip, so we can use irqfds, and on x86 we know ++ * we can use msi via irqfd and GSI routing. ++ */ ++ kvm_msi_via_irqfd_allowed = true; ++ kvm_gsi_routing_allowed = true; ++} ++ ++int kvm_arch_irqchip_create(KVMState *s) ++{ ++ return 0; ++} ++ ++int kvm_arch_release_virq_post(int virq) ++{ ++ return -1; ++} ++ ++int kvm_arch_msi_data_to_gsi(uint32_t data) ++{ ++ return -1; ++} ++ ++ ++void kvm_sw64_register_slave(SW64CPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ ++ kvm_vcpu_ioctl(cs, KVM_SW64_USE_SLAVE, NULL); ++} ++ ++bool kvm_arch_cpu_check_are_resettable(void) ++{ ++ return true; ++} +diff --git a/target/sw64/kvm_sw64.h b/target/sw64/kvm_sw64.h +new file mode 100644 +index 0000000000..5ebd4ec6fd +--- /dev/null ++++ b/target/sw64/kvm_sw64.h +@@ -0,0 +1,47 @@ ++/* ++ * QEMU KVM support -- SW64 specific functions. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef QEMU_KVM_SW64_H ++#define QEMU_KVM_SW64_H ++ ++#include "sysemu/kvm.h" ++#include "exec/memory.h" ++#include "qemu/error-report.h" ++ ++/** ++ * kvm_sw64_vcpu_init: ++ * @cs: CPUState ++ * ++ * Initialize (or reinitialize) the VCPU by invoking the ++ * KVM_SW64_VCPU_INIT ioctl with the CPU type and feature ++ * bitmask specified in the CPUState. ++ * ++ * Returns: 0 if success else < 0 error code ++ */ ++int kvm_sw64_vcpu_init(CPUState *cs); ++void kvm_sw64_reset_vcpu(SW64CPU *cpu); ++void kvm_sw64_register_slave(SW64CPU *cpu); ++ ++#define TYPE_SW64_HOST_CPU "host-" TYPE_SW64_CPU ++#define SW64_HOST_CPU_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(SW64HostCPUClass, (klass), TYPE_SW64_HOST_CPU) ++#define SW64_HOST_CPU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64HostCPUClass, (obj), TYPE_SW64_HOST_CPU) ++ ++typedef struct SW64HostCPUClass { ++ /*< private >*/ ++ SW64CPUClass parent_class; ++ /*< public >*/ ++ ++ uint64_t features; ++ uint32_t target; ++ const char *dtb_compatible; ++} SW64HostCPUClass; ++#endif +diff --git a/target/sw64/machine.c b/target/sw64/machine.c +new file mode 100644 +index 0000000000..df18d3faba +--- /dev/null ++++ b/target/sw64/machine.c +@@ -0,0 +1,18 @@ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "cpu.h" ++#include "migration/vmstate.h" ++#include "migration/cpu.h" ++ ++VMStateDescription vmstate_sw64_cpu = { ++ .name = "cpu", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++#ifdef CONFIG_KVM ++ VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 158), ++ VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 36), ++#endif ++ VMSTATE_END_OF_LIST() ++ } ++}; +diff --git a/target/sw64/meson.build b/target/sw64/meson.build +new file mode 100644 +index 0000000000..ee49e45927 +--- /dev/null ++++ b/target/sw64/meson.build +@@ -0,0 +1,19 @@ ++sw64_ss = ss.source_set() ++sw64_ss.add(files( ++ 'cpu.c', ++ 'exception.c', ++ 'float_helper.c', ++ 'helper.c', ++ 'int_helper.c', ++ 'profile.c', ++ 'simd_helper.c', ++ 'translate.c', ++)) ++ ++sw64_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) ++ ++sw64_softmmu_ss = ss.source_set() ++sw64_softmmu_ss.add(files('machine.c')) ++ ++target_arch += {'sw64': sw64_ss} ++target_softmmu_arch += {'sw64': sw64_softmmu_ss} +diff --git a/target/sw64/profile.c b/target/sw64/profile.c +new file mode 100644 +index 0000000000..73fe077234 +--- /dev/null ++++ b/target/sw64/profile.c +@@ -0,0 +1,2342 @@ ++#include "translate.h" ++ ++const char *insn_opc[535] = { ++ "sys_call", "call", "ret", "jmp", "br", "bsr", "memb", "imemb", ++ "wmemb", "rtc", "rcid", "halt", "rd_f", "wr_f", "rtid", ++ "csrws", "csrwc", "pri_rcsr", "pri_wcsr", "pri_ret", "lldw", "lldl", ++ "ldw_inc", "ldl_inc", "ldw_dec", "ldl_dec", "ldw_set", "ldl_set", "lstw", ++ "lstl", "ldw_nc", "ldl_nc", "ldd_nc", "stw_nc", "stl_nc", "std_nc", ++ "ldwe", "ldse", "ldde", "vlds", "vldd", "vsts", "vstd", ++ "fimovs", "fimovd", "addw", "subw", "s4addw", "s4subw", "s8addw", ++ "s8subw", "addl", "subl", "s4addl", "s4subl", "s8addl", "s8subl", ++ "mulw", "divw", "udivw", "remw", "uremw", "mull", "mulh", ++ "divl", "udivl", "reml", "ureml", "addpi", "addpis", "cmpeq", ++ "cmplt", "cmple", "cmpult", "cmpule", "sbt", "cbt", "and", ++ "bic", "bis", "ornot", "xor", "eqv", "inslb", "inslh", ++ "inslw", "insll", "inshb", "inshh", "inshw", "inshl", "slll", ++ "srll", "sral", "roll", "sllw", "srlw", "sraw", "rolw", ++ "extlb", "extlh", "extlw", "extll", "exthb", "exthh", "exthw", ++ "exthl", "ctpop", "ctlz", "cttz", "revbh", "revbw", "revbl", ++ "casw", "casl", "masklb", "masklh", "masklw", "maskll", "maskhb", ++ "maskhh", "maskhw", "maskhl", "zap", "zapnot", "sextb", "sexth", ++ "seleq", "selge", "selgt", "selle", "sellt", "selne", "sellbc", ++ "sellbs", "addwi", "subwi", "s4addwi", "s4subwi", "s8addwi", "s8subwi", ++ "addli", "subli", "s4addli", "s4subli", "s8addli", "s8subli", "mulwi", ++ "divwi", "udivwi", "remwi", "uremwi", "mulli", "mulhi", "divli", ++ "udivli", "remli", "uremli", "addpii", "addpisi", "cmpeqi", "cmplti", ++ "cmplei", "cmpulti", "cmpulei", "sbti", "cbti", "andi", "bici", ++ "bisi", "ornoti", "xori", "eqvi", "inslbi", "inslhi", "inslwi", ++ "inslli", "inshbi", "inshhi", "inshwi", "inshli", "sllli", "srlli", ++ "srali", "rolli", "sllwi", "srlwi", "srawi", "rolwi", "extlbi", ++ "extlhi", "extlwi", "extlli", "exthbi", "exthhi", "exthwi", "exthli", ++ "ctpopi", "ctlzi", "cttzi", "revbhi", "revbwi", "revbli", "caswi", ++ "casli", "masklbi", "masklhi", "masklwi", "masklli", "maskhbi", "maskhhi", ++ "maskhwi", "maskhli", "zapi", "zapnoti", "sextbi", "sexthi", "cmpgebi", ++ "seleqi", "selgei", "selgti", "sellei", "sellti", "selnei", "sellbci", ++ "sellbsi", "vlogzz", "fadds", "faddd", "fsubs", "fsubd", "fmuls", ++ "fmuld", "fdivs", "fdivd", "fsqrts", "fsqrtd", "fcmpeq", "fcmple", ++ "fcmplt", "fcmpun", "fcvtsd", "fcvtds", "fcvtdl_g", "fcvtdl_p", "fcvtdl_z", ++ "fcvtdl_n", "fcvtdl", "fcvtwl", "fcvtlw", "fcvtls", "fcvtld", "fcpys", ++ "fcpyse", "fcpysn", "ifmovs", "ifmovd", "rfpcr", "wfpcr", "setfpec0", ++ "setfpec1", "setfpec2", "setfpec3", "frecs", "frecd", "fris", "fris_g", ++ "fris_p", "fris_z", "fris_n", "frid", "frid_g", "frid_p", "frid_z", ++ "frid_n", "fmas", "fmad", "fmss", "fmsd", "fnmas", "fnmad", ++ "fnmss", "fnmsd", "fseleq", "fselne", "fsellt", "fselle", "fselgt", ++ "fselge", "vaddw", "vaddwi", "vsubw", "vsubwi", "vcmpgew", "vcmpgewi", ++ "vcmpeqw", "vcmpeqwi", "vcmplew", "vcmplewi", "vcmpltw", "vcmpltwi", "vcmpulew", ++ "vcmpulewi", "vcmpultw", "vcmpultwi", "vsllw", "vsllwi", "vsrlw", "vsrlwi", ++ "vsraw", "vsrawi", "vrolw", "vrolwi", "sllow", "sllowi", "srlow", ++ "srlowi", "vaddl", "vaddli", "vsubl", "vsubli", "vsllb", "vsllbi", ++ "vsrlb", "vsrlbi", "vsrab", "vsrabi", "vrolb", "vrolbi", "vsllh", ++ "vsllhi", "vsrlh", "vsrlhi", "vsrah", "vsrahi", "vrolh", "vrolhi", ++ "ctpopow", "ctlzow", "vslll", "vsllli", "vsrll", "vsrlli", "vsral", ++ "vsrali", "vroll", "vrolli", "vmaxb", "vminb", "vucaddw", "vucaddwi", ++ "vucsubw", "vucsubwi", "vucaddh", "vucaddhi", "vucsubh", "vucsubhi", "vucaddb", ++ "vucaddbi", "vucsubb", "vucsubbi", "sraow", "sraowi", "vsumw", "vsuml", ++ "vsm4r", "vbinvw", "vcmpueqb", "vcmpugtb", "vcmpugtbi", "vsm3msw", "vmaxh", ++ "vminh", "vmaxw", "vminw", "vmaxl", "vminl", "vumaxb", "vuminb", ++ "vumaxh", "vuminh", "vumaxw", "vuminw", "vumaxl", "vuminl", "vsm4key", ++ "vadds", "vaddd", "vsubs", "vsubd", "vmuls", "vmuld", "vdivs", ++ "vdivd", "vsqrts", "vsqrtd", "vfcmpeq", "vfcmple", "vfcmplt", "vfcmpun", ++ "vcpys", "vcpyse", "vcpysn", "vsums", "vsumd", "vfcvtsd", "vfcvtds", ++ "vfcvtls", "vfcvtld", "vfcvtdl", "vfcvtdl_g", "vfcvtdl_p", "vfcvtdl_z", "vfcvtdl_n", ++ "vfris", "vfris_g", "vfris_p", "vfris_z", "vfris_n", "vfrid", "vfrid_g", ++ "vfrid_p", "vfrid_z", "vfrid_n", "vfrecs", "vfrecd", "vmaxs", "vmins", ++ "vmaxd", "vmind", "vmas", "vmad", "vmss", "vmsd", "vnmas", ++ "vnmad", "vnmss", "vnmsd", "vfseleq", "vfsellt", "vfselle", "vseleqw", ++ "vseleqwi", "vsellbcw", "vsellbcwi", "vselltw", "vselltwi", "vsellew", "vsellewi", ++ "vinsw", "vinsf", "vextw", "vextf", "vcpyw", "vcpyf", "vconw", ++ "vshfw", "vcons", "vcond", "vinsb", "vinsh", "vinsectlh", "vinsectlw", ++ "vinsectll", "vinsectlb", "vshfq", "vshfqb", "vcpyb", "vcpyh", "vsm3r", ++ "vfcvtsh", "vfcvths", "vldw_u", "vstw_u", "vlds_u", "vsts_u", "vldd_u", ++ "vstd_u", "vstw_ul", "vstw_uh", "vsts_ul", "vsts_uh", "vstd_ul", "vstd_uh", ++ "vldd_nc", "vstd_nc", "lbr", "ldbu_a", "ldhu_a", "ldw_a", "ldl_a", ++ "flds_a", "fldd_a", "stbu_a", "sthu_a", "stw_a", "stl_a", "fsts_a", ++ "fstd_a", "dpfhr", "dpfhw", "ldbu", "ldhu", "ldw", "ldl", ++ "ldl_u", "pri_ldl", "pri_ldw", "flds", "fldd", "stb", "sth", ++ "stw", "stl", "stl_u", "pri_stl", "pri_stw", "fsts", "fstd", ++ "beq", "bne", "blt", "ble", "bgt", "bge", "blbc", ++ "blbs", "fbeq", "fbne", "fblt", "fble", "fbgt", "fbge", ++ "ldih", "ldi", }; ++ ++void insn_profile(DisasContext *ctx, uint32_t insn) ++{ ++ int32_t disp16, disp26 __attribute__((unused)); ++ uint8_t opc; ++ uint16_t fn3, fn4, fn6, fn8, fn11; ++ TCGv count; ++ int index, offs; ++ ++ opc = extract32(insn, 26, 6); ++ ++ fn3 = extract32(insn, 10, 3); ++ fn6 = extract32(insn, 10, 6); ++ fn4 = extract32(insn, 12, 4); ++ fn8 = extract32(insn, 5, 8); ++ fn11 = extract32(insn, 5, 11); ++ ++ disp16 = sextract32(insn, 0, 16); ++ disp26 = sextract32(insn, 0, 26); ++ ++ index = 0; ++ switch (opc) { ++ case 0x00: ++ /* SYS_CALL */ ++ index = SYS_CALL; ++ break; ++ case 0x01: ++ /* CALL */ ++ index = CALL; ++ break; ++ case 0x02: ++ /* RET */ ++ index = RET; ++ break; ++ case 0x03: ++ /* JMP */ ++ index = JMP; ++ break; ++ case 0x04: ++ /* BR */ ++ index = BR; ++ break; ++ case 0x05: ++ /* BSR */ ++ index = BSR; ++ break; ++ case 0x06: ++ switch (disp16) { ++ case 0x0000: ++ /* MEMB */ ++ index = MEMB; ++ break; ++ case 0x0001: ++ /* IMEMB */ ++ index = IMEMB; ++ break; ++ case 0x0002: ++ /* WMEMB */ ++ index = WMEMB; ++ break; ++ case 0x0020: ++ /* RTC */ ++ index = RTC; ++ break; ++ case 0x0040: ++ /* RCID */ ++ index = RCID; ++ break; ++ case 0x0080: ++ /* HALT */ ++ index = HALT; ++ break; ++ case 0x1000: ++ /* RD_F */ ++ index = RD_F; ++ break; ++ case 0x1020: ++ /* WR_F */ ++ index = WR_F; ++ break; ++ case 0x1040: ++ /* RTID */ ++ index = RTID; ++ break; ++ default: ++ if ((disp16 & 0xFF00) == 0xFC00) { ++ /* CSRWS */ ++ index = CSRWS; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFD00) { ++ /* CSRWC */ ++ index = CSRWC; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFE00) { ++ /* PRI_RCSR */ ++ index = PRI_RCSR; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFF00) { ++ /* PRI_WCSR */ ++ index = PRI_WCSR; ++ break; ++ } ++ goto do_invalid; ++ } ++ break; ++ case 0x07: ++ /* PRI_RET */ ++ index = PRI_RET; ++ break; ++ case 0x08: ++ switch (fn4) { ++ case 0x0: ++ /* LLDW */ ++ index = LLDW; ++ break; ++ case 0x1: ++ /* LLDL */ ++ index = LLDL; ++ break; ++ case 0x2: ++ /* LDW_INC */ ++ index = LDW_INC; ++ break; ++ case 0x3: ++ /* LDL_INC */ ++ index = LDL_INC; ++ break; ++ case 0x4: ++ /* LDW_DEC */ ++ index = LDW_DEC; ++ break; ++ case 0x5: ++ /* LDL_DEC */ ++ index = LDL_DEC; ++ break; ++ case 0x6: ++ /* LDW_SET */ ++ index = LDW_SET; ++ break; ++ case 0x7: ++ /* LDL_SET */ ++ index = LDL_SET; ++ break; ++ case 0x8: ++ /* LSTW */ ++ index = LSTW; ++ break; ++ case 0x9: ++ /* LSTL */ ++ index = LSTL; ++ break; ++ case 0xa: ++ /* LDW_NC */ ++ index = LDW_NC; ++ break; ++ case 0xb: ++ /* LDL_NC */ ++ index = LDL_NC; ++ break; ++ case 0xc: ++ /* LDD_NC */ ++ index = LDD_NC; ++ break; ++ case 0xd: ++ /* STW_NC */ ++ index = STW_NC; ++ break; ++ case 0xe: ++ /* STL_NC */ ++ index = STL_NC; ++ break; ++ case 0xf: ++ /* STD_NC */ ++ index = STD_NC; ++ break; ++ default: ++ goto do_invalid; ++ } ++ break; ++ case 0x9: ++ /* LDWE */ ++ index = LDWE; ++ break; ++ case 0x0a: ++ /* LDSE */ ++ index = LDSE; ++ break; ++ case 0x0b: ++ /* LDDE */ ++ index = LDDE; ++ break; ++ case 0x0c: ++ /* VLDS */ ++ index = VLDS; ++ break; ++ case 0x0d: ++ /* VLDD */ ++ index = VLDD; ++ break; ++ case 0x0e: ++ /* VSTS */ ++ index = VSTS; ++ break; ++ case 0x0f: ++ /* VSTD */ ++ index = VSTD; ++ break; ++ case 0x10: ++ if (fn11 == 0x70) { ++ /* FIMOVS */ ++ index = FIMOVS; ++ } else if (fn11 == 0x78) { ++ /* FIMOVD */ ++ index = FIMOVD; ++ } else { ++ switch (fn11 & 0xff) { ++ case 0x00: ++ /* ADDW */ ++ index = ADDW; ++ break; ++ case 0x01: ++ /* SUBW */ ++ index = SUBW; ++ break; ++ case 0x02: ++ /* S4ADDW */ ++ index = S4ADDW; ++ break; ++ case 0x03: ++ /* S4SUBW */ ++ index = S4SUBW; ++ break; ++ case 0x04: ++ /* S8ADDW */ ++ index = S8ADDW; ++ break; ++ case 0x05: ++ /* S8SUBW */ ++ index = S8SUBW; ++ break; ++ ++ case 0x08: ++ /* ADDL */ ++ index = ADDL; ++ break; ++ case 0x09: ++ /* SUBL */ ++ index = SUBL; ++ break; ++ case 0x0a: ++ /* S4ADDL */ ++ index = S4ADDL; ++ break; ++ case 0x0b: ++ /* S4SUBL */ ++ index = S4SUBL; ++ break; ++ case 0x0c: ++ /* S8ADDL */ ++ index = S8ADDL; ++ break; ++ case 0x0d: ++ /* S8SUBL */ ++ index = S8SUBL; ++ break; ++ case 0x10: ++ /* MULW */ ++ index = MULW; ++ break; ++ case 0x11: ++ /* DIVW */ ++ index = DIVW; ++ break; ++ case 0x12: ++ /* UDIVW */ ++ index = UDIVW; ++ break; ++ case 0x13: ++ /* REMW */ ++ index = REMW; ++ break; ++ case 0x14: ++ /* UREMW */ ++ index = UREMW; ++ break; ++ case 0x18: ++ /* MULL */ ++ index = MULL; ++ break; ++ case 0x19: ++ /* MULH */ ++ index = MULH; ++ break; ++ case 0x1A: ++ /* DIVL */ ++ index = DIVL; ++ break; ++ case 0x1B: ++ /* UDIVL */ ++ index = UDIVL; ++ break; ++ case 0x1C: ++ /* REML */ ++ index = REML; ++ break; ++ case 0x1D: ++ /* UREML */ ++ index = UREML; ++ break; ++ case 0x1E: ++ /* ADDPI */ ++ index = ADDPI; ++ break; ++ case 0x1F: ++ /* ADDPIS */ ++ index = ADDPIS; ++ break; ++ case 0x28: ++ /* CMPEQ */ ++ index = CMPEQ; ++ break; ++ case 0x29: ++ /* CMPLT */ ++ index = CMPLT; ++ break; ++ case 0x2a: ++ /* CMPLE */ ++ index = CMPLE; ++ break; ++ case 0x2b: ++ /* CMPULT */ ++ index = CMPULT; ++ break; ++ case 0x2c: ++ /* CMPULE */ ++ index = CMPULE; ++ break; ++ case 0x2D: ++ /* SBT */ ++ index = SBT; ++ break; ++ case 0x2E: ++ /* CBT */ ++ index = CBT; ++ break; ++ case 0x38: ++ /* AND */ ++ index = AND; ++ break; ++ case 0x39: ++ /* BIC */ ++ index = BIC; ++ break; ++ case 0x3a: ++ /* BIS */ ++ index = BIS; ++ break; ++ case 0x3b: ++ /* ORNOT */ ++ index = ORNOT; ++ break; ++ case 0x3c: ++ /* XOR */ ++ index = XOR; ++ break; ++ case 0x3d: ++ /* EQV */ ++ index = EQV; ++ break; ++ case 0x40: ++ /* INSLB */ ++ index = INSLB; ++ break; ++ case 0x41: ++ /* INSLH */ ++ index = INSLH; ++ break; ++ case 0x42: ++ /* INSLW */ ++ index = INSLW; ++ break; ++ case 0x43: ++ /* INSLL */ ++ index = INSLL; ++ break; ++ case 0x44: ++ /* INSHB */ ++ index = INSHB; ++ break; ++ case 0x45: ++ /* INSHH */ ++ index = INSHH; ++ break; ++ case 0x46: ++ /* INSHW */ ++ index = INSHW; ++ break; ++ case 0x47: ++ /* INSHL */ ++ index = INSHL; ++ break; ++ case 0x48: ++ /* SLLL */ ++ index = SLLL; ++ break; ++ case 0x49: ++ /* SRLL */ ++ index = SRLL; ++ break; ++ case 0x4a: ++ /* SRAL */ ++ index = SRAL; ++ break; ++ case 0x4B: ++ /* ROLL */ ++ index = ROLL; ++ break; ++ case 0x4C: ++ /* SLLW */ ++ index = SLLW; ++ break; ++ case 0x4D: ++ /* SRLW */ ++ index = SRLW; ++ break; ++ case 0x4E: ++ /* SRAW */ ++ index = SRAW; ++ break; ++ case 0x4F: ++ /* ROLW */ ++ index = ROLW; ++ break; ++ case 0x50: ++ /* EXTLB */ ++ index = EXTLB; ++ break; ++ case 0x51: ++ /* EXTLH */ ++ index = EXTLH; ++ break; ++ case 0x52: ++ /* EXTLW */ ++ index = EXTLW; ++ break; ++ case 0x53: ++ /* EXTLL */ ++ index = EXTLL; ++ break; ++ case 0x54: ++ /* EXTHB */ ++ index = EXTHB; ++ break; ++ case 0x55: ++ /* EXTHH */ ++ index = EXTHH; ++ break; ++ case 0x56: ++ /* EXTHW */ ++ index = EXTHW; ++ break; ++ case 0x57: ++ /* EXTHL */ ++ index = EXTHL; ++ break; ++ case 0x58: ++ /* CTPOP */ ++ index = CTPOP; ++ break; ++ case 0x59: ++ /* CTLZ */ ++ index = CTLZ; ++ break; ++ case 0x5a: ++ /* CTTZ */ ++ index = CTTZ; ++ break; ++ case 0x5B: ++ /* REVBH */ ++ index = REVBH; ++ break; ++ case 0x5C: ++ /* REVBW */ ++ index = REVBW; ++ break; ++ case 0x5D: ++ /* REVBL */ ++ index = REVBL; ++ break; ++ case 0x5E: ++ /* CASW */ ++ index = CASW; ++ break; ++ case 0x5F: ++ /* CASL */ ++ index = CASL; ++ break; ++ case 0x60: ++ /* MASKLB */ ++ index = MASKLB; ++ break; ++ case 0x61: ++ /* MASKLH */ ++ index = MASKLH; ++ break; ++ case 0x62: ++ /* MASKLW */ ++ index = MASKLW; ++ break; ++ case 0x63: ++ /* MASKLL */ ++ index = MASKLL; ++ break; ++ case 0x64: ++ /* MASKHB */ ++ index = MASKHB; ++ break; ++ case 0x65: ++ /* MASKHH */ ++ index = MASKHH; ++ break; ++ case 0x66: ++ /* MASKHW */ ++ index = MASKHW; ++ break; ++ case 0x67: ++ /* MASKHL */ ++ index = MASKHL; ++ break; ++ case 0x68: ++ /* ZAP */ ++ index = ZAP; ++ break; ++ case 0x69: ++ /* ZAPNOT */ ++ index = ZAPNOT; ++ break; ++ case 0x6a: ++ /* SEXTB */ ++ index = SEXTB; ++ break; ++ case 0x6b: ++ /* SEXTH */ ++ index = SEXTH; ++ break; ++ case 0x6c: ++ /* CMPGEB*/ ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ case 0x11: ++ switch (fn3) { ++ case 0x0: ++ /* SELEQ */ ++ index = SELEQ; ++ break; ++ case 0x1: ++ /* SELGE */ ++ index = SELGE; ++ break; ++ case 0x2: ++ /* SELGT */ ++ index = SELGT; ++ break; ++ case 0x3: ++ /* SELLE */ ++ index = SELLE; ++ break; ++ case 0x4: ++ /* SELLT */ ++ index = SELLT; ++ break; ++ case 0x5: ++ /* SELNE */ ++ index = SELNE; ++ break; ++ case 0x6: ++ /* SELLBC */ ++ index = SELLBC; ++ break; ++ case 0x7: ++ /* SELLBS */ ++ index = SELLBS; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x12: ++ switch (fn8 & 0xff) { ++ case 0x00: ++ /* ADDWI */ ++ index = ADDWI; ++ break; ++ case 0x01: ++ /* SUBWI */ ++ index = SUBWI; ++ break; ++ case 0x02: ++ /* S4ADDWI */ ++ index = S4ADDWI; ++ break; ++ case 0x03: ++ /* S4SUBWI */ ++ index = S4SUBWI; ++ break; ++ case 0x04: ++ /* S8ADDWI */ ++ index = S8ADDWI; ++ break; ++ case 0x05: ++ /* S8SUBWI */ ++ index = S8SUBWI; ++ break; ++ ++ case 0x08: ++ /* ADDLI */ ++ index = ADDLI; ++ break; ++ case 0x09: ++ /* SUBLI */ ++ index = SUBLI; ++ break; ++ case 0x0a: ++ /* S4ADDLI */ ++ index = S4ADDLI; ++ break; ++ case 0x0b: ++ /* S4SUBLI */ ++ index = S4SUBLI; ++ break; ++ case 0x0c: ++ /* S8ADDLI */ ++ index = S8ADDLI; ++ break; ++ case 0x0d: ++ /* S8SUBLI */ ++ index = S8SUBLI; ++ break; ++ case 0x10: ++ /* MULWI */ ++ index = MULWI; ++ break; ++ case 0x11: ++ /* DIVWI */ ++ index = DIVWI; ++ break; ++ case 0x12: ++ /* UDIVWI */ ++ index = UDIVWI; ++ break; ++ case 0x13: ++ /* REMWI */ ++ index = REMWI; ++ break; ++ case 0x14: ++ /* UREMWI */ ++ index = UREMWI; ++ break; ++ case 0x18: ++ /* MULLI */ ++ index = MULLI; ++ break; ++ case 0x19: ++ /* MULHI */ ++ index = MULHI; ++ break; ++ case 0x1A: ++ /* DIVLI */ ++ index = DIVLI; ++ break; ++ case 0x1B: ++ /* UDIVLI */ ++ index = UDIVLI; ++ break; ++ case 0x1C: ++ /* REMLI */ ++ index = REMLI; ++ break; ++ case 0x1D: ++ /* UREMLI */ ++ index = UREMLI; ++ break; ++ case 0x1E: ++ /* ADDPII */ ++ index = ADDPII; ++ break; ++ case 0x1F: ++ /* ADDPISI */ ++ index = ADDPISI; ++ break; ++ case 0x28: ++ /* CMPEQI */ ++ index = CMPEQI; ++ break; ++ case 0x29: ++ /* CMPLTI */ ++ index = CMPLTI; ++ break; ++ case 0x2a: ++ /* CMPLEI */ ++ index = CMPLEI; ++ break; ++ case 0x2b: ++ /* CMPULTI */ ++ index = CMPULTI; ++ break; ++ case 0x2c: ++ /* CMPULEI */ ++ index = CMPULEI; ++ break; ++ case 0x2D: ++ /* SBTI */ ++ index = SBTI; ++ break; ++ case 0x2E: ++ /* CBTI */ ++ index = CBTI; ++ break; ++ case 0x38: ++ /* ANDI */ ++ index = ANDI; ++ break; ++ case 0x39: ++ /* BICI */ ++ index = BICI; ++ break; ++ case 0x3a: ++ /* BISI */ ++ index = BISI; ++ break; ++ case 0x3b: ++ /* ORNOTI */ ++ index = ORNOTI; ++ break; ++ case 0x3c: ++ /* XORI */ ++ index = XORI; ++ break; ++ case 0x3d: ++ /* EQVI */ ++ index = EQVI; ++ break; ++ case 0x40: ++ /* INSLBI */ ++ index = INSLBI; ++ break; ++ case 0x41: ++ /* INSLHI */ ++ index = INSLHI; ++ break; ++ case 0x42: ++ /* INSLWI */ ++ index = INSLWI; ++ break; ++ case 0x43: ++ /* INSLLI */ ++ index = INSLLI; ++ break; ++ case 0x44: ++ /* INSHBI */ ++ index = INSHBI; ++ break; ++ case 0x45: ++ /* INSHHI */ ++ index = INSHHI; ++ break; ++ case 0x46: ++ /* INSHWI */ ++ index = INSHWI; ++ break; ++ case 0x47: ++ /* INSHLI */ ++ index = INSHLI; ++ break; ++ case 0x48: ++ /* SLLLI */ ++ index = SLLLI; ++ break; ++ case 0x49: ++ /* SRLLI */ ++ index = SRLLI; ++ break; ++ case 0x4a: ++ /* SRALI */ ++ index = SRALI; ++ break; ++ case 0x4B: ++ /* ROLLI */ ++ index = ROLLI; ++ break; ++ case 0x4C: ++ /* SLLWI */ ++ index = SLLWI; ++ break; ++ case 0x4D: ++ /* SRLWI */ ++ index = SRLWI; ++ break; ++ case 0x4E: ++ /* SRAWI */ ++ index = SRAWI; ++ break; ++ case 0x4F: ++ /* ROLWI */ ++ index = ROLWI; ++ break; ++ case 0x50: ++ /* EXTLBI */ ++ index = EXTLBI; ++ break; ++ case 0x51: ++ /* EXTLHI */ ++ index = EXTLHI; ++ break; ++ case 0x52: ++ /* EXTLWI */ ++ index = EXTLWI; ++ break; ++ case 0x53: ++ /* EXTLLI */ ++ index = EXTLLI; ++ break; ++ case 0x54: ++ /* EXTHBI */ ++ index = EXTHBI; ++ break; ++ case 0x55: ++ /* EXTHHI */ ++ index = EXTHHI; ++ break; ++ case 0x56: ++ /* EXTHWI */ ++ index = EXTHWI; ++ break; ++ case 0x57: ++ /* EXTHLI */ ++ index = EXTHLI; ++ break; ++ case 0x58: ++ /* CTPOPI */ ++ index = CTPOPI; ++ break; ++ case 0x59: ++ /* CTLZI */ ++ index = CTLZI; ++ break; ++ case 0x5a: ++ /* CTTZI */ ++ index = CTTZI; ++ break; ++ case 0x5B: ++ /* REVBHI */ ++ index = REVBHI; ++ break; ++ case 0x5C: ++ /* REVBWI */ ++ index = REVBWI; ++ break; ++ case 0x5D: ++ /* REVBLI */ ++ index = REVBLI; ++ break; ++ case 0x5E: ++ /* CASWI */ ++ index = CASWI; ++ break; ++ case 0x5F: ++ /* CASLI */ ++ index = CASLI; ++ break; ++ case 0x60: ++ /* MASKLBI */ ++ index = MASKLBI; ++ break; ++ case 0x61: ++ /* MASKLHI */ ++ index = MASKLHI; ++ break; ++ case 0x62: ++ /* MASKLWI */ ++ index = MASKLWI; ++ break; ++ case 0x63: ++ /* MASKLLI */ ++ index = MASKLLI; ++ break; ++ case 0x64: ++ /* MASKHBI */ ++ index = MASKHBI; ++ break; ++ case 0x65: ++ /* MASKHHI */ ++ index = MASKHHI; ++ break; ++ case 0x66: ++ /* MASKHWI */ ++ index = MASKHWI; ++ break; ++ case 0x67: ++ /* MASKHLI */ ++ index = MASKHLI; ++ break; ++ case 0x68: ++ /* ZAPI */ ++ index = ZAPI; ++ break; ++ case 0x69: ++ /* ZAPNOTI */ ++ index = ZAPNOTI; ++ break; ++ case 0x6a: ++ /* SEXTBI */ ++ index = SEXTBI; ++ break; ++ case 0x6b: ++ /* SEXTHI */ ++ index = SEXTHI; ++ break; ++ case 0x6c: ++ /* CMPGEBI */ ++ index = CMPGEBI; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x13: ++ switch (fn3) { ++ case 0x0: ++ /* SELEQI */ ++ index = SELEQI; ++ break; ++ case 0x1: ++ /* SELGEI */ ++ index = SELGEI; ++ break; ++ case 0x2: ++ /* SELGTI */ ++ index = SELGTI; ++ break; ++ case 0x3: ++ /* SELLEI */ ++ index = SELLEI; ++ break; ++ case 0x4: ++ /* SELLTI */ ++ index = SELLTI; ++ break; ++ case 0x5: ++ /* SELNEI */ ++ index = SELNEI; ++ break; ++ case 0x6: ++ /* SELLBCI */ ++ index = SELLBCI; ++ break; ++ case 0x7: ++ /* SELLBSI */ ++ index = SELLBSI; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x14: ++ case 0x15: ++ case 0x16: ++ case 0x17: ++ /* VLOGZZ */ ++ index = VLOGZZ; ++ break; ++ case 0x18: ++ switch (fn8) { ++ case 0x00: ++ /* FADDS */ ++ index = FADDS; ++ break; ++ case 0x01: ++ /* FADDD */ ++ index = FADDD; ++ break; ++ case 0x02: ++ /* FSUBS */ ++ index = FSUBS; ++ break; ++ case 0x03: ++ /* FSUBD */ ++ index = FSUBD; ++ break; ++ case 0x4: ++ /* FMULS */ ++ index = FMULS; ++ break; ++ case 0x05: ++ /* FMULD */ ++ index = FMULD; ++ break; ++ case 0x06: ++ /* FDIVS */ ++ index = FDIVS; ++ break; ++ case 0x07: ++ /* FDIVD */ ++ index = FDIVD; ++ break; ++ case 0x08: ++ /* FSQRTS */ ++ index = FSQRTS; ++ break; ++ case 0x09: ++ /* FSQRTD */ ++ index = FSQRTD; ++ break; ++ case 0x10: ++ /* FCMPEQ */ ++ index = FCMPEQ; ++ break; ++ case 0x11: ++ /* FCMPLE */ ++ index = FCMPLE; ++ break; ++ case 0x12: ++ /* FCMPLT */ ++ index = FCMPLT; ++ break; ++ case 0x13: ++ /* FCMPUN */ ++ index = FCMPUN; ++ break; ++ case 0x20: ++ /* FCVTSD */ ++ index = FCVTSD; ++ break; ++ case 0x21: ++ /* FCVTDS */ ++ index = FCVTDS; ++ break; ++ case 0x22: ++ /* FCVTDL_G */ ++ index = FCVTDL_G; ++ break; ++ case 0x23: ++ /* FCVTDL_P */ ++ index = FCVTDL_P; ++ break; ++ case 0x24: ++ /* FCVTDL_Z */ ++ index = FCVTDL_Z; ++ break; ++ case 0x25: ++ /* FCVTDL_N */ ++ index = FCVTDL_N; ++ break; ++ case 0x27: ++ /* FCVTDL */ ++ index = FCVTDL; ++ break; ++ case 0x28: ++ /* FCVTWL */ ++ index = FCVTWL; ++ break; ++ case 0x29: ++ /* FCVTLW */ ++ index = FCVTLW; ++ break; ++ case 0x2d: ++ /* FCVTLS */ ++ index = FCVTLS; ++ break; ++ case 0x2f: ++ /* FCVTLD */ ++ index = FCVTLD; ++ break; ++ case 0x30: ++ /* FCPYS */ ++ index = FCPYS; ++ break; ++ case 0x31: ++ /* FCPYSE */ ++ index = FCPYSE; ++ break; ++ case 0x32: ++ /* FCPYSN */ ++ index = FCPYSN; ++ break; ++ case 0x40: ++ /* IFMOVS */ ++ index = IFMOVS; ++ break; ++ case 0x41: ++ /* IFMOVD */ ++ index = IFMOVD; ++ break; ++ case 0x50: ++ /* RFPCR */ ++ index = RFPCR; ++ break; ++ case 0x51: ++ /* WFPCR */ ++ index = WFPCR; ++ break; ++ case 0x54: ++ /* SETFPEC0 */ ++ index = SETFPEC0; ++ break; ++ case 0x55: ++ /* SETFPEC1 */ ++ index = SETFPEC1; ++ break; ++ case 0x56: ++ /* SETFPEC2 */ ++ index = SETFPEC2; ++ break; ++ case 0x57: ++ /* SETFPEC3 */ ++ index = SETFPEC3; ++ break; ++ case 0x58: ++ /* FRECS */ ++ index = FRECS; ++ break; ++ case 0x59: ++ /* FRECD */ ++ index = FRECD; ++ break; ++ case 0x5A: ++ /* FRIS */ ++ index = FRIS; ++ break; ++ case 0x5B: ++ /* FRIS_G */ ++ index = FRIS_G; ++ break; ++ case 0x5C: ++ /* FRIS_P */ ++ index = FRIS_P; ++ break; ++ case 0x5D: ++ /* FRIS_Z */ ++ index = FRIS_Z; ++ break; ++ case 0x5F: ++ /* FRIS_N */ ++ index = FRIS_N; ++ break; ++ case 0x60: ++ /* FRID */ ++ index = FRID; ++ break; ++ case 0x61: ++ /* FRID_G */ ++ index = FRID_G; ++ break; ++ case 0x62: ++ /* FRID_P */ ++ index = FRID_P; ++ break; ++ case 0x63: ++ /* FRID_Z */ ++ index = FRID_Z; ++ break; ++ case 0x64: ++ /* FRID_N */ ++ index = FRID_N; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x19: ++ switch (fn6) { ++ case 0x00: ++ /* FMAS */ ++ index = FMAS; ++ break; ++ case 0x01: ++ /* FMAD */ ++ index = FMAD; ++ break; ++ case 0x02: ++ /* FMSS */ ++ index = FMSS; ++ break; ++ case 0x03: ++ /* FMSD */ ++ index = FMSD; ++ break; ++ case 0x04: ++ /* FNMAS */ ++ index = FNMAS; ++ break; ++ case 0x05: ++ /* FNMAD */ ++ index = FNMAD; ++ break; ++ case 0x06: ++ /* FNMSS */ ++ index = FNMSS; ++ break; ++ case 0x07: ++ /* FNMSD */ ++ index = FNMSD; ++ break; ++ case 0x10: ++ /* FSELEQ */ ++ index = FSELEQ; ++ break; ++ case 0x11: ++ /* FSELNE */ ++ index = FSELNE; ++ break; ++ case 0x12: ++ /* FSELLT */ ++ index = FSELLT; ++ break; ++ case 0x13: ++ /* FSELLE */ ++ index = FSELLE; ++ break; ++ case 0x14: ++ /* FSELGT */ ++ index = FSELGT; ++ break; ++ case 0x15: ++ /* FSELGE */ ++ index = FSELGE; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1A: ++ switch (fn8) { ++ case 0x00: ++ /* VADDW */ ++ index = VADDW; ++ break; ++ case 0x20: ++ /* VADDWI */ ++ index = VADDWI; ++ break; ++ case 0x01: ++ /* VSUBW */ ++ index = VSUBW; ++ break; ++ case 0x21: ++ /* VSUBWI */ ++ index = VSUBWI; ++ break; ++ case 0x02: ++ /* VCMPGEW */ ++ index = VCMPGEW; ++ break; ++ case 0x22: ++ /* VCMPGEWI */ ++ index = VCMPGEWI; ++ break; ++ case 0x03: ++ /* VCMPEQW */ ++ index = VCMPEQW; ++ break; ++ case 0x23: ++ /* VCMPEQWI */ ++ index = VCMPEQWI; ++ break; ++ case 0x04: ++ /* VCMPLEW */ ++ index = VCMPLEW; ++ break; ++ case 0x24: ++ /* VCMPLEWI */ ++ index = VCMPLEWI; ++ break; ++ case 0x05: ++ /* VCMPLTW */ ++ index = VCMPLTW; ++ break; ++ case 0x25: ++ /* VCMPLTWI */ ++ index = VCMPLTWI; ++ break; ++ case 0x06: ++ /* VCMPULEW */ ++ index = VCMPULEW; ++ break; ++ case 0x26: ++ /* VCMPULEWI */ ++ index = VCMPULEWI; ++ break; ++ case 0x07: ++ /* VCMPULTW */ ++ index = VCMPULTW; ++ break; ++ case 0x27: ++ /* VCMPULTWI */ ++ index = VCMPULTWI; ++ break; ++ case 0x08: ++ /* VSLLW */ ++ index = VSLLW; ++ break; ++ case 0x28: ++ /* VSLLWI */ ++ index = VSLLWI; ++ break; ++ case 0x09: ++ /* VSRLW */ ++ index = VSRLW; ++ break; ++ case 0x29: ++ /* VSRLWI */ ++ index = VSRLWI; ++ break; ++ case 0x0A: ++ /* VSRAW */ ++ index = VSRAW; ++ break; ++ case 0x2A: ++ /* VSRAWI */ ++ index = VSRAWI; ++ break; ++ case 0x0B: ++ /* VROLW */ ++ index = VROLW; ++ break; ++ case 0x2B: ++ /* VROLWI */ ++ index = VROLWI; ++ break; ++ case 0x0C: ++ /* SLLOW */ ++ index = SLLOW; ++ break; ++ case 0x2C: ++ /* SLLOWI */ ++ index = SLLOWI; ++ break; ++ case 0x0D: ++ /* SRLOW */ ++ index = SRLOW; ++ break; ++ case 0x2D: ++ /* SRLOWI */ ++ index = SRLOWI; ++ break; ++ case 0x0E: ++ /* VADDL */ ++ index = VADDL; ++ break; ++ case 0x2E: ++ /* VADDLI */ ++ index = VADDLI; ++ break; ++ case 0x0F: ++ /* VSUBL */ ++ index = VSUBL; ++ break; ++ case 0x2F: ++ /* VSUBLI */ ++ index = VSUBLI; ++ break; ++ case 0x10: ++ /* VSLLB */ ++ index = VSLLB; ++ break; ++ case 0x30: ++ /* VSLLBI */ ++ index = VSLLBI; ++ break; ++ case 0x11: ++ /* VSRLB */ ++ index = VSRLB; ++ break; ++ case 0x31: ++ /* VSRLBI */ ++ index = VSRLBI; ++ break; ++ case 0x12: ++ /* VSRAB */ ++ index = VSRAB; ++ break; ++ case 0x32: ++ /* VSRABI */ ++ index = VSRABI; ++ break; ++ case 0x13: ++ /* VROLB */ ++ index = VROLB; ++ break; ++ case 0x33: ++ /* VROLBI */ ++ index = VROLBI; ++ break; ++ case 0x14: ++ /* VSLLH */ ++ index = VSLLH; ++ break; ++ case 0x34: ++ /* VSLLHI */ ++ index = VSLLHI; ++ break; ++ case 0x15: ++ /* VSRLH */ ++ index = VSRLH; ++ break; ++ case 0x35: ++ /* VSRLHI */ ++ index = VSRLHI; ++ break; ++ case 0x16: ++ /* VSRAH */ ++ index = VSRAH; ++ break; ++ case 0x36: ++ /* VSRAHI */ ++ index = VSRAHI; ++ break; ++ case 0x17: ++ /* VROLH */ ++ index = VROLH; ++ break; ++ case 0x37: ++ /* VROLHI */ ++ index = VROLHI; ++ break; ++ case 0x18: ++ /* CTPOPOW */ ++ index = CTPOPOW; ++ break; ++ case 0x19: ++ /* CTLZOW */ ++ index = CTLZOW; ++ break; ++ case 0x1A: ++ /* VSLLL */ ++ index = VSLLL; ++ break; ++ case 0x3A: ++ /* VSLLLI */ ++ index = VSLLLI; ++ break; ++ case 0x1B: ++ /* VSRLL */ ++ index = VSRLL; ++ break; ++ case 0x3B: ++ /* VSRLLI */ ++ index = VSRLLI; ++ break; ++ case 0x1C: ++ /* VSRAL */ ++ index = VSRAL; ++ break; ++ case 0x3C: ++ /* VSRALI */ ++ index = VSRALI; ++ break; ++ case 0x1D: ++ /* VROLL */ ++ index = VROLL; ++ break; ++ case 0x3D: ++ /* VROLLI */ ++ index = VROLLI; ++ break; ++ case 0x1E: ++ /* VMAXB */ ++ index = VMAXB; ++ break; ++ case 0x1F: ++ /* VMINB */ ++ index = VMINB; ++ break; ++ case 0x40: ++ /* VUCADDW */ ++ index = VUCADDW; ++ break; ++ case 0x60: ++ /* VUCADDWI */ ++ index = VUCADDWI; ++ break; ++ case 0x41: ++ /* VUCSUBW */ ++ index = VUCSUBW; ++ break; ++ case 0x61: ++ /* VUCSUBWI */ ++ index = VUCSUBWI; ++ break; ++ case 0x42: ++ /* VUCADDH */ ++ index = VUCADDH; ++ break; ++ case 0x62: ++ /* VUCADDHI */ ++ index = VUCADDHI; ++ break; ++ case 0x43: ++ /* VUCSUBH */ ++ index = VUCSUBH; ++ break; ++ case 0x63: ++ /* VUCSUBHI */ ++ index = VUCSUBHI; ++ break; ++ case 0x44: ++ /* VUCADDB */ ++ index = VUCADDB; ++ break; ++ case 0x64: ++ /* VUCADDBI */ ++ index = VUCADDBI; ++ break; ++ case 0x45: ++ /* VUCSUBB */ ++ index = VUCSUBB; ++ break; ++ case 0x65: ++ /* VUCSUBBI */ ++ index = VUCSUBBI; ++ break; ++ case 0x46: ++ /* SRAOW */ ++ index = SRAOW; ++ break; ++ case 0x66: ++ /* SRAOWI */ ++ index = SRAOWI; ++ break; ++ case 0x47: ++ /* VSUMW */ ++ index = VSUMW; ++ break; ++ case 0x48: ++ /* VSUML */ ++ index = VSUML; ++ break; ++ case 0x49: ++ /* VSM4R */ ++ index = VSM4R; ++ break; ++ case 0x4A: ++ /* VBINVW */ ++ index = VBINVW; ++ break; ++ case 0x4B: ++ /* VCMPUEQB */ ++ index = VCMPUEQB; ++ break; ++ case 0x6B: ++ /* VCMPUEQBI*/ ++ break; ++ case 0x4C: ++ /* VCMPUGTB */ ++ index = VCMPUGTB; ++ break; ++ case 0x6C: ++ /* VCMPUGTBI */ ++ index = VCMPUGTBI; ++ break; ++ case 0x4D: ++ /* VSM3MSW */ ++ index = VSM3MSW; ++ break; ++ case 0x50: ++ /* VMAXH */ ++ index = VMAXH; ++ break; ++ case 0x51: ++ /* VMINH */ ++ index = VMINH; ++ break; ++ case 0x52: ++ /* VMAXW */ ++ index = VMAXW; ++ break; ++ case 0x53: ++ /* VMINW */ ++ index = VMINW; ++ break; ++ case 0x54: ++ /* VMAXL */ ++ index = VMAXL; ++ break; ++ case 0x55: ++ /* VMINL */ ++ index = VMINL; ++ break; ++ case 0x56: ++ /* VUMAXB */ ++ index = VUMAXB; ++ break; ++ case 0x57: ++ /* VUMINB */ ++ index = VUMINB; ++ break; ++ case 0x58: ++ /* VUMAXH */ ++ index = VUMAXH; ++ break; ++ case 0x59: ++ /* VUMINH */ ++ index = VUMINH; ++ break; ++ case 0x5A: ++ /* VUMAXW */ ++ index = VUMAXW; ++ break; ++ case 0x5B: ++ /* VUMINW */ ++ index = VUMINW; ++ break; ++ case 0x5C: ++ /* VUMAXL */ ++ index = VUMAXL; ++ break; ++ case 0x5D: ++ /* VUMINL */ ++ index = VUMINL; ++ break; ++ case 0x68: ++ /* VSM4KEY */ ++ index = VSM4KEY; ++ break; ++ case 0x80: ++ /* VADDS */ ++ index = VADDS; ++ break; ++ case 0x81: ++ /* VADDD */ ++ index = VADDD; ++ break; ++ case 0x82: ++ /* VSUBS */ ++ index = VSUBS; ++ break; ++ case 0x83: ++ /* VSUBD */ ++ index = VSUBD; ++ break; ++ case 0x84: ++ /* VMULS */ ++ index = VMULS; ++ break; ++ case 0x85: ++ /* VMULD */ ++ index = VMULD; ++ break; ++ case 0x86: ++ /* VDIVS */ ++ index = VDIVS; ++ break; ++ case 0x87: ++ /* VDIVD */ ++ index = VDIVD; ++ break; ++ case 0x88: ++ /* VSQRTS */ ++ index = VSQRTS; ++ break; ++ case 0x89: ++ /* VSQRTD */ ++ index = VSQRTD; ++ break; ++ case 0x8C: ++ /* VFCMPEQ */ ++ index = VFCMPEQ; ++ break; ++ case 0x8D: ++ /* VFCMPLE */ ++ index = VFCMPLE; ++ break; ++ case 0x8E: ++ /* VFCMPLT */ ++ index = VFCMPLT; ++ break; ++ case 0x8F: ++ /* VFCMPUN */ ++ index = VFCMPUN; ++ break; ++ case 0x90: ++ /* VCPYS */ ++ index = VCPYS; ++ break; ++ case 0x91: ++ /* VCPYSE */ ++ index = VCPYSE; ++ break; ++ case 0x92: ++ /* VCPYSN */ ++ index = VCPYSN; ++ break; ++ case 0x93: ++ /* VSUMS */ ++ index = VSUMS; ++ break; ++ case 0x94: ++ /* VSUMD */ ++ index = VSUMD; ++ break; ++ case 0x95: ++ /* VFCVTSD */ ++ index = VFCVTSD; ++ break; ++ case 0x96: ++ /* VFCVTDS */ ++ index = VFCVTDS; ++ break; ++ case 0x99: ++ /* VFCVTLS */ ++ index = VFCVTLS; ++ break; ++ case 0x9A: ++ /* VFCVTLD */ ++ index = VFCVTLD; ++ break; ++ case 0x9B: ++ /* VFCVTDL */ ++ index = VFCVTDL; ++ break; ++ case 0x9C: ++ /* VFCVTDL_G */ ++ index = VFCVTDL_G; ++ break; ++ case 0x9D: ++ /* VFCVTDL_P */ ++ index = VFCVTDL_P; ++ break; ++ case 0x9E: ++ /* VFCVTDL_Z */ ++ index = VFCVTDL_Z; ++ break; ++ case 0x9F: ++ /* VFCVTDL_N */ ++ index = VFCVTDL_N; ++ break; ++ case 0xA0: ++ /* VFRIS */ ++ index = VFRIS; ++ break; ++ case 0xA1: ++ /* VFRIS_G */ ++ index = VFRIS_G; ++ break; ++ case 0xA2: ++ /* VFRIS_P */ ++ index = VFRIS_P; ++ break; ++ case 0xA3: ++ /* VFRIS_Z */ ++ index = VFRIS_Z; ++ break; ++ case 0xA4: ++ /* VFRIS_N */ ++ index = VFRIS_N; ++ break; ++ case 0xA5: ++ /* VFRID */ ++ index = VFRID; ++ break; ++ case 0xA6: ++ /* VFRID_G */ ++ index = VFRID_G; ++ break; ++ case 0xA7: ++ /* VFRID_P */ ++ index = VFRID_P; ++ break; ++ case 0xA8: ++ /* VFRID_Z */ ++ index = VFRID_Z; ++ break; ++ case 0xA9: ++ /* VFRID_N */ ++ index = VFRID_N; ++ break; ++ case 0xAA: ++ /* VFRECS */ ++ index = VFRECS; ++ break; ++ case 0xAB: ++ /* VFRECD */ ++ index = VFRECD; ++ break; ++ case 0xAC: ++ /* VMAXS */ ++ index = VMAXS; ++ break; ++ case 0xAD: ++ /* VMINS */ ++ index = VMINS; ++ break; ++ case 0xAE: ++ /* VMAXD */ ++ index = VMAXD; ++ break; ++ case 0xAF: ++ /* VMIND */ ++ index = VMIND; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1B: ++ switch (fn6) { ++ case 0x00: ++ /* VMAS */ ++ index = VMAS; ++ break; ++ case 0x01: ++ /* VMAD */ ++ index = VMAD; ++ break; ++ case 0x02: ++ /* VMSS */ ++ index = VMSS; ++ break; ++ case 0x03: ++ /* VMSD */ ++ index = VMSD; ++ break; ++ case 0x04: ++ /* VNMAS */ ++ index = VNMAS; ++ break; ++ case 0x05: ++ /* VNMAD */ ++ index = VNMAD; ++ break; ++ case 0x06: ++ /* VNMSS */ ++ index = VNMSS; ++ break; ++ case 0x07: ++ /* VNMSD */ ++ index = VNMSD; ++ break; ++ case 0x10: ++ /* VFSELEQ */ ++ index = VFSELEQ; ++ break; ++ case 0x12: ++ /* VFSELLT */ ++ index = VFSELLT; ++ break; ++ case 0x13: ++ /* VFSELLE */ ++ index = VFSELLE; ++ break; ++ case 0x18: ++ /* VSELEQW */ ++ index = VSELEQW; ++ break; ++ case 0x38: ++ /* VSELEQWI */ ++ index = VSELEQWI; ++ break; ++ case 0x19: ++ /* VSELLBCW */ ++ index = VSELLBCW; ++ break; ++ case 0x39: ++ /* VSELLBCWI */ ++ index = VSELLBCWI; ++ break; ++ case 0x1A: ++ /* VSELLTW */ ++ index = VSELLTW; ++ break; ++ case 0x3A: ++ /* VSELLTWI */ ++ index = VSELLTWI; ++ break; ++ case 0x1B: ++ /* VSELLEW */ ++ index = VSELLEW; ++ break; ++ case 0x3B: ++ /* VSELLEWI */ ++ index = VSELLEWI; ++ break; ++ case 0x20: ++ /* VINSW */ ++ index = VINSW; ++ break; ++ case 0x21: ++ /* VINSF */ ++ index = VINSF; ++ break; ++ case 0x22: ++ /* VEXTW */ ++ index = VEXTW; ++ break; ++ case 0x23: ++ /* VEXTF */ ++ index = VEXTF; ++ break; ++ case 0x24: ++ /* VCPYW */ ++ index = VCPYW; ++ break; ++ case 0x25: ++ /* VCPYF */ ++ index = VCPYF; ++ break; ++ case 0x26: ++ /* VCONW */ ++ index = VCONW; ++ break; ++ case 0x27: ++ /* VSHFW */ ++ index = VSHFW; ++ break; ++ case 0x28: ++ /* VCONS */ ++ index = VCONS; ++ break; ++ case 0x29: ++ /* VCOND */ ++ index = VCOND; ++ break; ++ case 0x2A: ++ /* VINSB */ ++ index = VINSB; ++ break; ++ case 0x2B: ++ /* VINSH */ ++ index = VINSH; ++ break; ++ case 0x2C: ++ /* VINSECTLH */ ++ index = VINSECTLH; ++ break; ++ case 0x2D: ++ /* VINSECTLW */ ++ index = VINSECTLW; ++ break; ++ case 0x2E: ++ /* VINSECTLL */ ++ index = VINSECTLL; ++ break; ++ case 0x2F: ++ /* VINSECTLB */ ++ index = VINSECTLB; ++ break; ++ case 0x30: ++ /* VSHFQ */ ++ index = VSHFQ; ++ break; ++ case 0x31: ++ /* VSHFQB */ ++ index = VSHFQB; ++ break; ++ case 0x32: ++ /* VCPYB */ ++ index = VCPYB; ++ break; ++ case 0x33: ++ /* VCPYH */ ++ index = VCPYH; ++ break; ++ case 0x34: ++ /* VSM3R */ ++ index = VSM3R; ++ break; ++ case 0x35: ++ /* VFCVTSH */ ++ index = VFCVTSH; ++ break; ++ case 0x36: ++ /* VFCVTHS */ ++ index = VFCVTHS; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1C: ++ switch (fn4) { ++ case 0x0: ++ /* VLDW_U */ ++ index = VLDW_U; ++ break; ++ case 0x1: ++ /* VSTW_U */ ++ index = VSTW_U; ++ break; ++ case 0x2: ++ /* VLDS_U */ ++ index = VLDS_U; ++ break; ++ case 0x3: ++ /* VSTS_U */ ++ index = VSTS_U; ++ break; ++ case 0x4: ++ /* VLDD_U */ ++ index = VLDD_U; ++ break; ++ case 0x5: ++ /* VSTD_U */ ++ index = VSTD_U; ++ break; ++ case 0x8: ++ /* VSTW_UL */ ++ index = VSTW_UL; ++ break; ++ case 0x9: ++ /* VSTW_UH */ ++ index = VSTW_UH; ++ break; ++ case 0xa: ++ /* VSTS_UL */ ++ index = VSTS_UL; ++ break; ++ case 0xb: ++ /* VSTS_UH */ ++ index = VSTS_UH; ++ break; ++ case 0xc: ++ /* VSTD_UL */ ++ index = VSTD_UL; ++ break; ++ case 0xd: ++ /* VSTD_UH */ ++ index = VSTD_UH; ++ break; ++ case 0xe: ++ /* VLDD_NC */ ++ index = VLDD_NC; ++ break; ++ case 0xf: ++ /* VSTD_NC */ ++ index = VSTD_NC; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1D: ++ /* LBR */ ++ index = LBR; ++ break; ++ case 0x1E: ++ switch (fn4) { ++ case 0x0: ++ /* LDBU_A */ ++ index = LDBU_A; ++ break; ++ case 0x1: ++ /* LDHU_A */ ++ index = LDHU_A; ++ break; ++ case 0x2: ++ /* LDW_A */ ++ index = LDW_A; ++ break; ++ case 0x3: ++ /* LDL_A */ ++ index = LDL_A; ++ break; ++ case 0x4: ++ /* FLDS_A */ ++ index = FLDS_A; ++ break; ++ case 0x5: ++ /* FLDD_A */ ++ index = FLDD_A; ++ break; ++ case 0x6: ++ /* STBU_A */ ++ index = STBU_A; ++ break; ++ case 0x7: ++ /* STHU_A */ ++ index = STHU_A; ++ break; ++ case 0x8: ++ /* STW_A */ ++ index = STW_A; ++ break; ++ case 0x9: ++ /* STL_A */ ++ index = STL_A; ++ break; ++ case 0xA: ++ /* FSTS_A */ ++ index = FSTS_A; ++ break; ++ case 0xB: ++ /* FSTD_A */ ++ index = FSTD_A; ++ break; ++ case 0xE: ++ /* DPFHR */ ++ index = DPFHR; ++ break; ++ case 0xF: ++ /* DPFHW */ ++ index = DPFHW; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x20: ++ /* LDBU */ ++ index = LDBU; ++ break; ++ case 0x21: ++ /* LDHU */ ++ index = LDHU; ++ break; ++ case 0x22: ++ /* LDW */ ++ index = LDW; ++ break; ++ case 0x23: ++ /* LDL */ ++ index = LDL; ++ break; ++ case 0x24: ++ /* LDL_U */ ++ index = LDL_U; ++ break; ++ case 0x25: ++ if ((insn >> 12) & 1) { ++ /* PRI_LDL */ ++ index = PRI_LDL; ++ } else { ++ /* PRI_LDW */ ++ index = PRI_LDW; ++ } ++ break; ++ case 0x26: ++ /* FLDS */ ++ index = FLDS; ++ break; ++ case 0x27: ++ /* FLDD */ ++ index = FLDD; ++ break; ++ case 0x28: ++ /* STB */ ++ index = STB; ++ break; ++ case 0x29: ++ /* STH */ ++ index = STH; ++ break; ++ case 0x2a: ++ /* STW */ ++ index = STW; ++ break; ++ case 0x2b: ++ /* STL */ ++ index = STL; ++ break; ++ case 0x2c: ++ /* STL_U */ ++ index = STL_U; ++ break; ++ case 0x2d: ++ if ((insn >> 12) & 1) { ++ /* PRI_STL */ ++ index = PRI_STL; ++ } else { ++ /* PRI_STW */ ++ index = PRI_STW; ++ } ++ break; ++ case 0x2e: ++ /* FSTS */ ++ index = FSTS; ++ break; ++ case 0x2f: ++ /* FSTD */ ++ index = FSTD; ++ break; ++ case 0x30: ++ /* BEQ */ ++ index = BEQ; ++ break; ++ case 0x31: ++ /* BNE */ ++ index = BNE; ++ break; ++ case 0x32: ++ /* BLT */ ++ index = BLT; ++ break; ++ case 0x33: ++ /* BLE */ ++ index = BLE; ++ break; ++ case 0x34: ++ /* BGT */ ++ index = BGT; ++ break; ++ case 0x35: ++ /* BGE */ ++ index = BGE; ++ break; ++ case 0x36: ++ /* BLBC */ ++ index = BLBC; ++ break; ++ case 0x37: ++ /* BLBS */ ++ index = BLBS; ++ break; ++ case 0x38: ++ /* FBEQ */ ++ index = FBEQ; ++ break; ++ case 0x39: ++ /* FBNE */ ++ index = FBNE; ++ break; ++ case 0x3a: ++ /* FBLT */ ++ index = FBLT; ++ break; ++ case 0x3b: ++ /* FBLE */ ++ index = FBLE; ++ break; ++ case 0x3c: ++ /* FBGT */ ++ index = FBGT; ++ break; ++ case 0x3d: ++ /* FBGE */ ++ index = FBGE; ++ break; ++ case 0x3f: ++ /* LDIH */ ++ index = LDIH; ++ break; ++ case 0x3e: ++ /* LDI */ ++ index = LDI; ++ break; ++ default: ++do_invalid: ++ break; ++ } ++ count = tcg_temp_new(); ++ offs = offsetof(CPUSW64State, insn_count[index]); ++ tcg_gen_ld_i64(count, cpu_env, offs); ++ tcg_gen_addi_i64(count, count, 1); ++ tcg_gen_st_i64(count, cpu_env, offs); ++ tcg_temp_free(count); ++} +diff --git a/target/sw64/profile.h b/target/sw64/profile.h +new file mode 100644 +index 0000000000..5aca541ea7 +--- /dev/null ++++ b/target/sw64/profile.h +@@ -0,0 +1,541 @@ ++#ifndef PROFILE_H ++#define PROFILE_H ++#define SYS_CALL 0 ++#define CALL 1 ++#define RET 2 ++#define JMP 3 ++#define BR 4 ++#define BSR 5 ++#define MEMB 6 ++#define IMEMB 7 ++#define WMEMB 8 ++#define RTC 9 ++#define RCID 10 ++#define HALT 11 ++#define RD_F 12 ++#define WR_F 13 ++#define RTID 14 ++#define CSRWS 15 ++#define CSRWC 16 ++#define PRI_RCSR 17 ++#define PRI_WCSR 18 ++#define PRI_RET 19 ++#define LLDW 20 ++#define LLDL 21 ++#define LDW_INC 22 ++#define LDL_INC 23 ++#define LDW_DEC 24 ++#define LDL_DEC 25 ++#define LDW_SET 26 ++#define LDL_SET 27 ++#define LSTW 28 ++#define LSTL 29 ++#define LDW_NC 30 ++#define LDL_NC 31 ++#define LDD_NC 32 ++#define STW_NC 33 ++#define STL_NC 34 ++#define STD_NC 35 ++#define LDWE 36 ++#define LDSE 37 ++#define LDDE 38 ++#define VLDS 39 ++#define VLDD 40 ++#define VSTS 41 ++#define VSTD 42 ++#define FIMOVS 43 ++#define FIMOVD 44 ++#define ADDW 45 ++#define SUBW 46 ++#define S4ADDW 47 ++#define S4SUBW 48 ++#define S8ADDW 49 ++#define S8SUBW 50 ++#define ADDL 51 ++#define SUBL 52 ++#define S4ADDL 53 ++#define S4SUBL 54 ++#define S8ADDL 55 ++#define S8SUBL 56 ++#define MULW 57 ++#define DIVW 58 ++#define UDIVW 59 ++#define REMW 60 ++#define UREMW 61 ++#define MULL 62 ++#define MULH 63 ++#define DIVL 64 ++#define UDIVL 65 ++#define REML 66 ++#define UREML 67 ++#define ADDPI 68 ++#define ADDPIS 69 ++#define CMPEQ 70 ++#define CMPLT 71 ++#define CMPLE 72 ++#define CMPULT 73 ++#define CMPULE 74 ++#define SBT 75 ++#define CBT 76 ++#define AND 77 ++#define BIC 78 ++#define BIS 79 ++#define ORNOT 80 ++#define XOR 81 ++#define EQV 82 ++#define INSLB 83 ++#define INSLH 84 ++#define INSLW 85 ++#define INSLL 86 ++#define INSHB 87 ++#define INSHH 88 ++#define INSHW 89 ++#define INSHL 90 ++#define SLLL 91 ++#define SRLL 92 ++#define SRAL 93 ++#define ROLL 94 ++#define SLLW 95 ++#define SRLW 96 ++#define SRAW 97 ++#define ROLW 98 ++#define EXTLB 99 ++#define EXTLH 100 ++#define EXTLW 101 ++#define EXTLL 102 ++#define EXTHB 103 ++#define EXTHH 104 ++#define EXTHW 105 ++#define EXTHL 106 ++#define CTPOP 107 ++#define CTLZ 108 ++#define CTTZ 109 ++#define REVBH 110 ++#define REVBW 111 ++#define REVBL 112 ++#define CASW 113 ++#define CASL 114 ++#define MASKLB 115 ++#define MASKLH 116 ++#define MASKLW 117 ++#define MASKLL 118 ++#define MASKHB 119 ++#define MASKHH 120 ++#define MASKHW 121 ++#define MASKHL 122 ++#define ZAP 123 ++#define ZAPNOT 124 ++#define SEXTB 125 ++#define SEXTH 126 ++#define SELEQ 127 ++#define SELGE 128 ++#define SELGT 129 ++#define SELLE 130 ++#define SELLT 131 ++#define SELNE 132 ++#define SELLBC 133 ++#define SELLBS 134 ++#define ADDWI 135 ++#define SUBWI 136 ++#define S4ADDWI 137 ++#define S4SUBWI 138 ++#define S8ADDWI 139 ++#define S8SUBWI 140 ++#define ADDLI 141 ++#define SUBLI 142 ++#define S4ADDLI 143 ++#define S4SUBLI 144 ++#define S8ADDLI 145 ++#define S8SUBLI 146 ++#define MULWI 147 ++#define DIVWI 148 ++#define UDIVWI 149 ++#define REMWI 150 ++#define UREMWI 151 ++#define MULLI 152 ++#define MULHI 153 ++#define DIVLI 154 ++#define UDIVLI 155 ++#define REMLI 156 ++#define UREMLI 157 ++#define ADDPII 158 ++#define ADDPISI 159 ++#define CMPEQI 160 ++#define CMPLTI 161 ++#define CMPLEI 162 ++#define CMPULTI 163 ++#define CMPULEI 164 ++#define SBTI 165 ++#define CBTI 166 ++#define ANDI 167 ++#define BICI 168 ++#define BISI 169 ++#define ORNOTI 170 ++#define XORI 171 ++#define EQVI 172 ++#define INSLBI 173 ++#define INSLHI 174 ++#define INSLWI 175 ++#define INSLLI 176 ++#define INSHBI 177 ++#define INSHHI 178 ++#define INSHWI 179 ++#define INSHLI 180 ++#define SLLLI 181 ++#define SRLLI 182 ++#define SRALI 183 ++#define ROLLI 184 ++#define SLLWI 185 ++#define SRLWI 186 ++#define SRAWI 187 ++#define ROLWI 188 ++#define EXTLBI 189 ++#define EXTLHI 190 ++#define EXTLWI 191 ++#define EXTLLI 192 ++#define EXTHBI 193 ++#define EXTHHI 194 ++#define EXTHWI 195 ++#define EXTHLI 196 ++#define CTPOPI 197 ++#define CTLZI 198 ++#define CTTZI 199 ++#define REVBHI 200 ++#define REVBWI 201 ++#define REVBLI 202 ++#define CASWI 203 ++#define CASLI 204 ++#define MASKLBI 205 ++#define MASKLHI 206 ++#define MASKLWI 207 ++#define MASKLLI 208 ++#define MASKHBI 209 ++#define MASKHHI 210 ++#define MASKHWI 211 ++#define MASKHLI 212 ++#define ZAPI 213 ++#define ZAPNOTI 214 ++#define SEXTBI 215 ++#define SEXTHI 216 ++#define CMPGEBI 217 ++#define SELEQI 218 ++#define SELGEI 219 ++#define SELGTI 220 ++#define SELLEI 221 ++#define SELLTI 222 ++#define SELNEI 223 ++#define SELLBCI 224 ++#define SELLBSI 225 ++#define VLOGZZ 226 ++#define FADDS 227 ++#define FADDD 228 ++#define FSUBS 229 ++#define FSUBD 230 ++#define FMULS 231 ++#define FMULD 232 ++#define FDIVS 233 ++#define FDIVD 234 ++#define FSQRTS 235 ++#define FSQRTD 236 ++#define FCMPEQ 237 ++#define FCMPLE 238 ++#define FCMPLT 239 ++#define FCMPUN 240 ++#define FCVTSD 241 ++#define FCVTDS 242 ++#define FCVTDL_G 243 ++#define FCVTDL_P 244 ++#define FCVTDL_Z 245 ++#define FCVTDL_N 246 ++#define FCVTDL 247 ++#define FCVTWL 248 ++#define FCVTLW 249 ++#define FCVTLS 250 ++#define FCVTLD 251 ++#define FCPYS 252 ++#define FCPYSE 253 ++#define FCPYSN 254 ++#define IFMOVS 255 ++#define IFMOVD 256 ++#define RFPCR 257 ++#define WFPCR 258 ++#define SETFPEC0 259 ++#define SETFPEC1 260 ++#define SETFPEC2 261 ++#define SETFPEC3 262 ++#define FRECS 263 ++#define FRECD 264 ++#define FRIS 265 ++#define FRIS_G 266 ++#define FRIS_P 267 ++#define FRIS_Z 268 ++#define FRIS_N 269 ++#define FRID 270 ++#define FRID_G 271 ++#define FRID_P 272 ++#define FRID_Z 273 ++#define FRID_N 274 ++#define FMAS 275 ++#define FMAD 276 ++#define FMSS 277 ++#define FMSD 278 ++#define FNMAS 279 ++#define FNMAD 280 ++#define FNMSS 281 ++#define FNMSD 282 ++#define FSELEQ 283 ++#define FSELNE 284 ++#define FSELLT 285 ++#define FSELLE 286 ++#define FSELGT 287 ++#define FSELGE 288 ++#define VADDW 289 ++#define VADDWI 290 ++#define VSUBW 291 ++#define VSUBWI 292 ++#define VCMPGEW 293 ++#define VCMPGEWI 294 ++#define VCMPEQW 295 ++#define VCMPEQWI 296 ++#define VCMPLEW 297 ++#define VCMPLEWI 298 ++#define VCMPLTW 299 ++#define VCMPLTWI 300 ++#define VCMPULEW 301 ++#define VCMPULEWI 302 ++#define VCMPULTW 303 ++#define VCMPULTWI 304 ++#define VSLLW 305 ++#define VSLLWI 306 ++#define VSRLW 307 ++#define VSRLWI 308 ++#define VSRAW 309 ++#define VSRAWI 310 ++#define VROLW 311 ++#define VROLWI 312 ++#define SLLOW 313 ++#define SLLOWI 314 ++#define SRLOW 315 ++#define SRLOWI 316 ++#define VADDL 317 ++#define VADDLI 318 ++#define VSUBL 319 ++#define VSUBLI 320 ++#define VSLLB 321 ++#define VSLLBI 322 ++#define VSRLB 323 ++#define VSRLBI 324 ++#define VSRAB 325 ++#define VSRABI 326 ++#define VROLB 327 ++#define VROLBI 328 ++#define VSLLH 329 ++#define VSLLHI 330 ++#define VSRLH 331 ++#define VSRLHI 332 ++#define VSRAH 333 ++#define VSRAHI 334 ++#define VROLH 335 ++#define VROLHI 336 ++#define CTPOPOW 337 ++#define CTLZOW 338 ++#define VSLLL 339 ++#define VSLLLI 340 ++#define VSRLL 341 ++#define VSRLLI 342 ++#define VSRAL 343 ++#define VSRALI 344 ++#define VROLL 345 ++#define VROLLI 346 ++#define VMAXB 347 ++#define VMINB 348 ++#define VUCADDW 349 ++#define VUCADDWI 350 ++#define VUCSUBW 351 ++#define VUCSUBWI 352 ++#define VUCADDH 353 ++#define VUCADDHI 354 ++#define VUCSUBH 355 ++#define VUCSUBHI 356 ++#define VUCADDB 357 ++#define VUCADDBI 358 ++#define VUCSUBB 359 ++#define VUCSUBBI 360 ++#define SRAOW 361 ++#define SRAOWI 362 ++#define VSUMW 363 ++#define VSUML 364 ++#define VSM4R 365 ++#define VBINVW 366 ++#define VCMPUEQB 367 ++#define VCMPUGTB 368 ++#define VCMPUGTBI 369 ++#define VSM3MSW 370 ++#define VMAXH 371 ++#define VMINH 372 ++#define VMAXW 373 ++#define VMINW 374 ++#define VMAXL 375 ++#define VMINL 376 ++#define VUMAXB 377 ++#define VUMINB 378 ++#define VUMAXH 379 ++#define VUMINH 380 ++#define VUMAXW 381 ++#define VUMINW 382 ++#define VUMAXL 383 ++#define VUMINL 384 ++#define VSM4KEY 385 ++#define VADDS 386 ++#define VADDD 387 ++#define VSUBS 388 ++#define VSUBD 389 ++#define VMULS 390 ++#define VMULD 391 ++#define VDIVS 392 ++#define VDIVD 393 ++#define VSQRTS 394 ++#define VSQRTD 395 ++#define VFCMPEQ 396 ++#define VFCMPLE 397 ++#define VFCMPLT 398 ++#define VFCMPUN 399 ++#define VCPYS 400 ++#define VCPYSE 401 ++#define VCPYSN 402 ++#define VSUMS 403 ++#define VSUMD 404 ++#define VFCVTSD 405 ++#define VFCVTDS 406 ++#define VFCVTLS 407 ++#define VFCVTLD 408 ++#define VFCVTDL 409 ++#define VFCVTDL_G 410 ++#define VFCVTDL_P 411 ++#define VFCVTDL_Z 412 ++#define VFCVTDL_N 413 ++#define VFRIS 414 ++#define VFRIS_G 415 ++#define VFRIS_P 416 ++#define VFRIS_Z 417 ++#define VFRIS_N 418 ++#define VFRID 419 ++#define VFRID_G 420 ++#define VFRID_P 421 ++#define VFRID_Z 422 ++#define VFRID_N 423 ++#define VFRECS 424 ++#define VFRECD 425 ++#define VMAXS 426 ++#define VMINS 427 ++#define VMAXD 428 ++#define VMIND 429 ++#define VMAS 430 ++#define VMAD 431 ++#define VMSS 432 ++#define VMSD 433 ++#define VNMAS 434 ++#define VNMAD 435 ++#define VNMSS 436 ++#define VNMSD 437 ++#define VFSELEQ 438 ++#define VFSELLT 439 ++#define VFSELLE 440 ++#define VSELEQW 441 ++#define VSELEQWI 442 ++#define VSELLBCW 443 ++#define VSELLBCWI 444 ++#define VSELLTW 445 ++#define VSELLTWI 446 ++#define VSELLEW 447 ++#define VSELLEWI 448 ++#define VINSW 449 ++#define VINSF 450 ++#define VEXTW 451 ++#define VEXTF 452 ++#define VCPYW 453 ++#define VCPYF 454 ++#define VCONW 455 ++#define VSHFW 456 ++#define VCONS 457 ++#define VCOND 458 ++#define VINSB 459 ++#define VINSH 460 ++#define VINSECTLH 461 ++#define VINSECTLW 462 ++#define VINSECTLL 463 ++#define VINSECTLB 464 ++#define VSHFQ 465 ++#define VSHFQB 466 ++#define VCPYB 467 ++#define VCPYH 468 ++#define VSM3R 469 ++#define VFCVTSH 470 ++#define VFCVTHS 471 ++#define VLDW_U 472 ++#define VSTW_U 473 ++#define VLDS_U 474 ++#define VSTS_U 475 ++#define VLDD_U 476 ++#define VSTD_U 477 ++#define VSTW_UL 478 ++#define VSTW_UH 479 ++#define VSTS_UL 480 ++#define VSTS_UH 481 ++#define VSTD_UL 482 ++#define VSTD_UH 483 ++#define VLDD_NC 484 ++#define VSTD_NC 485 ++#define LBR 486 ++#define LDBU_A 487 ++#define LDHU_A 488 ++#define LDW_A 489 ++#define LDL_A 490 ++#define FLDS_A 491 ++#define FLDD_A 492 ++#define STBU_A 493 ++#define STHU_A 494 ++#define STW_A 495 ++#define STL_A 496 ++#define FSTS_A 497 ++#define FSTD_A 498 ++#define DPFHR 499 ++#define DPFHW 500 ++#define LDBU 501 ++#define LDHU 502 ++#define LDW 503 ++#define LDL 504 ++#define LDL_U 505 ++#define PRI_LDL 506 ++#define PRI_LDW 507 ++#define FLDS 508 ++#define FLDD 509 ++#define STB 510 ++#define STH 511 ++#define STW 512 ++#define STL 513 ++#define STL_U 514 ++#define PRI_STL 515 ++#define PRI_STW 516 ++#define FSTS 517 ++#define FSTD 518 ++#define BEQ 519 ++#define BNE 520 ++#define BLT 521 ++#define BLE 522 ++#define BGT 523 ++#define BGE 524 ++#define BLBC 525 ++#define BLBS 526 ++#define FBEQ 527 ++#define FBNE 528 ++#define FBLT 529 ++#define FBLE 530 ++#define FBGT 531 ++#define FBGE 532 ++#define LDIH 533 ++#define LDI 534 ++ ++extern const char *insn_opc[535]; ++ ++#endif +diff --git a/target/sw64/simd_helper.c b/target/sw64/simd_helper.c +new file mode 100644 +index 0000000000..13bd52de3d +--- /dev/null ++++ b/target/sw64/simd_helper.c +@@ -0,0 +1,1058 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++ ++#undef DEBUG_SIMD ++ ++static inline uint8_t *get_element_b(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint8_t*)&env->fr[ra + (index / 8) * 32] + (index % 8); ++} ++ ++static inline uint16_t *get_element_h(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint16_t*)&env->fr[ra + (index / 4) * 32] + (index % 4); ++} ++ ++static inline uint32_t *get_element_w(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint32_t*)&env->fr[ra + (index / 2) * 32] + (index % 2); ++} ++ ++static inline uint64_t *get_element_l(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return &env->fr[ra + index * 32]; ++} ++ ++void helper_srlow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ adden = shift >> 6; ++ shift &= 0x3f; ++#ifdef DEBUG_SIMD ++ printf("right shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 0; (i + adden) < 4; i++) { ++ dest = i * 32 + rc; ++ src = (i + adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] >> shift; ++ if (((i + adden) < 3) && (shift != 0)) ++ env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); ++ } ++ ++ for (; i < 4; i++) { ++ env->fr[rc + i * 32] = 0; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++void helper_sllow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ adden = shift >> 6; ++ shift &= 0x3f; ++#ifdef DEBUG_SIMD ++ printf("left shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 3; (i - adden) >= 0; i--) { ++ dest = i * 32 + rc; ++ src = (i - adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] << shift; ++ if (((i - adden) > 0) && (shift != 0)) ++ env->fr[dest] |= (env->fr[src - 32] >> (64 - shift)); ++ } ++ for (; i >= 0; i--) { ++ env->fr[rc + i * 32] = 0; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++static uint64_t do_logzz(uint64_t va, uint64_t vb, uint64_t vc, uint64_t zz) ++{ ++ int i; ++ uint64_t ret = 0; ++ int index; ++ ++ for (i = 0; i < 64; i++) { ++ index = (((va >> i) & 1) << 2) | (((vb >> i) & 1) << 1) | ((vc >> i) & 1); ++ ret |= ((zz >> index) & 1) << i; ++ } ++ ++ return ret; ++} ++ ++void helper_vlogzz(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t zz) ++{ ++ int i; ++ int ra, rb, rc; ++ ra = args >> 16; ++ rb = (args >> 8) & 0xff; ++ rc = args & 0xff; ++#ifdef DEBUG_SIMD ++ printf("zz = %lx\n", zz); ++ printf("in_fr[%d]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++ printf("in_fr[%d]:", rb); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rb + 32 * i]); ++ } ++ printf("\n"); ++ printf("in_fr[%d]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = do_logzz(env->fr[ra + i * 32], env->fr[rb + i * 32], ++ env->fr[rc + i * 32], zz); ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rd); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rd + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++void helper_v_print(CPUSW64State *env, uint64_t v) ++{ ++ printf("PC[%lx]: fr[%lx]:\n", GETPC(), v); ++} ++ ++void helper_vconw(CPUSW64State *env, uint64_t args, uint64_t rd, ++ uint64_t byte4_len) ++{ ++ int ra, rb; ++ int count; ++ int i; ++ uint32_t *ptr_dst, *ptr_src; ++ uint32_t tmp[8]; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ count = 8 - byte4_len; ++ ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ if (i < count) { ++ ptr_src = get_element_w(env, ra, i + byte4_len); ++ } else { ++ ptr_src = get_element_w(env, rb, i - count); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++void helper_vcond(CPUSW64State *env, uint64_t args, uint64_t rd, ++ uint64_t byte8_len) ++{ ++ int ra, rb; ++ int count; ++ int i; ++ uint64_t *ptr_dst, *ptr_src; ++ uint64_t tmp[8]; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ count = 4 - byte8_len; ++ ++ for (i = 0; i < 4; i++) { ++ if (i < count) { ++ ptr_src = get_element_l(env, ra, i + byte8_len); ++ } else { ++ ptr_src = get_element_l(env, rb, i - count); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 4; i++) { ++ ptr_dst = get_element_l(env, rd, i + byte8_len); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++void helper_vshfw(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t vc) ++{ ++ int ra, rb; ++ int i; ++ uint32_t *ptr_dst, *ptr_src; ++ uint32_t tmp[8]; ++ int flag, idx; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ ++ for (i = 0; i < 8; i++) { ++ flag = (vc >> (i * 4)) & 0x8; ++ idx = (vc >> (i * 4)) & 0x7; ++ if (flag == 0) { ++ ptr_src = get_element_w(env, ra, idx); ++ } else { ++ ptr_src = get_element_w(env, rb, idx); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++uint64_t helper_ctlzow(CPUSW64State *env, uint64_t ra) ++{ ++ int i, j; ++ uint64_t val; ++ uint64_t ctlz = 0; ++ ++ for (j = 3; j >= 0; j--) { ++ val = env->fr[ra + 32 * j]; ++ for (i = 63; i >= 0; i--) { ++ if ((val >> i) & 1) ++ return ctlz << 29; ++ else ++ ctlz++; ++ } ++ } ++ return ctlz << 29; ++} ++ ++void helper_vucaddw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ b = (int)(env->fr[rb + i * 32] & 0xffffffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ b = (int)(env->fr[rb + i * 32] >> 32); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucaddwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ b = (int)vb; ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucsubw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ b = (int)(env->fr[rb + i * 32] & 0xffffffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ b = (int)(env->fr[rb + i * 32] >> 32); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucsubwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ b = (int)vb; ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucaddh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (short)vb; ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (short)vb; ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (int8_t)(vb & 0xff); ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (int8_t)(vb & 0xff); ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++uint64_t helper_vstw(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx, shift; ++ ++ idx = t0 + (t1 / 2) * 32; ++ shift = (t1 % 2) * 32; ++ ++ return (env->fr[idx] >> shift) & 0xffffffffUL; ++} ++ ++uint64_t helper_vsts(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx, val; ++ ++ idx = t0 + t1 * 32; ++ val = env->fr[idx]; ++ ++ return ((val >> 32) & 0xc0000000) | ((val >> 29) & 0x3fffffff); ++} ++ ++uint64_t helper_vstd(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx; ++ ++ idx = t0 + t1 * 32; ++ return env->fr[idx]; ++} ++ ++#define HELPER_VMAX(name, _suffix, type, loop) \ ++ void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ ++ uint64_t rb, uint64_t rc) \ ++ { \ ++ int i; \ ++ type *ptr_dst, *ptr_src_a, *ptr_src_b; \ ++ \ ++ for (i = 0; i < loop; i++) { \ ++ ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ ++ ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ ++ ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ ++ \ ++ if (*ptr_src_a >= *ptr_src_b) { \ ++ *ptr_dst = *ptr_src_a; \ ++ } else { \ ++ *ptr_dst = *ptr_src_b; \ ++ } \ ++ } \ ++ } ++ ++#define HELPER_VMIN(name, _suffix, type, loop) \ ++ void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ ++ uint64_t rb, uint64_t rc) \ ++ { \ ++ int i; \ ++ type *ptr_dst, *ptr_src_a, *ptr_src_b; \ ++ \ ++ for (i = 0; i < loop; i++) { \ ++ ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ ++ ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ ++ ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ ++ \ ++ if (*ptr_src_a <= *ptr_src_b) { \ ++ *ptr_dst = *ptr_src_a; \ ++ } else { \ ++ *ptr_dst = *ptr_src_b; \ ++ } \ ++ } \ ++ } ++ ++HELPER_VMAX(vmax, b, int8_t, 32) ++HELPER_VMIN(vmin, b, int8_t, 32) ++HELPER_VMAX(vmax, h, int16_t, 16) ++HELPER_VMIN(vmin, h, int16_t, 16) ++HELPER_VMAX(vmax, w, int32_t, 8) ++HELPER_VMIN(vmin, w, int32_t, 8) ++HELPER_VMAX(vumax, b, uint8_t, 32) ++HELPER_VMIN(vumin, b, uint8_t, 32) ++HELPER_VMAX(vumax, h, uint16_t, 16) ++HELPER_VMIN(vumin, h, uint16_t, 16) ++HELPER_VMAX(vumax, w, uint32_t, 8) ++HELPER_VMIN(vumin, w, uint32_t, 8) ++ ++void helper_sraow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ uint64_t sign; ++ adden = shift >> 6; ++ shift &= 0x3f; ++ sign = (uint64_t)((int64_t)env->fr[ra + 96] >> 63); ++#ifdef DEBUG_SIMD ++ printf("right shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 0; (i + adden) < 4; i++) { ++ dest = i * 32 + rc; ++ src = (i + adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] >> shift; ++ if (shift != 0) { ++ if (((i + adden) < 3)) ++ env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); ++ else ++ env->fr[dest] |= (sign << (64 - shift)); ++ } ++ } ++ ++ for (; i < 4; i++) { ++ env->fr[rc + i * 32] = sign; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++static uint16_t sm4_sbox[16][16] = { ++ { 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05 }, ++ { 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99 }, ++ { 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62 }, ++ { 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6 }, ++ { 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8 }, ++ { 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35 }, ++ { 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87 }, ++ { 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e }, ++ { 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1 }, ++ { 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3 }, ++ { 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f }, ++ { 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51 }, ++ { 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8 }, ++ { 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0 }, ++ { 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84 }, ++ { 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 } ++}; ++ ++static uint32_t SBOX(uint32_t val) ++{ ++ int ret = 0; ++ int i; ++ int idx_x, idx_y; ++ for (i = 0; i < 4; i++) { ++ idx_x = (val >> (i * 8)) & 0xff; ++ idx_y = idx_x & 0xf; ++ idx_x = idx_x >> 4; ++ ++ ret |= (sm4_sbox[idx_x][idx_y] << (i * 8)); ++ } ++ return ret; ++} ++ ++static uint32_t rotl(uint32_t val, int shift) ++{ ++ uint64_t ret = (uint64_t)val; ++ ret = (ret << (shift & 0x1f)); ++ return (uint32_t)((ret & 0xffffffff) | (ret >> 32)); ++} ++ ++void helper_vsm4r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint32_t W[12], rk[8]; ++ uint32_t temp1, temp2; ++ int i, j; ++ ++ for (i = 0; i < 8; i++) { ++ rk[i] = *get_element_w(env, rb, i); ++ } ++ for (i = 0; i < 2; i++) { ++ for (j = 0; j < 4; j++) { ++ W[j] = *get_element_w(env, ra, i * 4 + j); ++ } ++ for (j = 0; j < 8; j++) { ++ temp1 = W[j + 1] ^ W[j + 2] ^ W[j + 3] ^ rk[j]; ++ temp2 = SBOX(temp1); ++ W[j + 4] = W[j] ^ temp2 ^ rotl(temp2, 2) ^ rotl(temp2, 10) ^ rotl(temp2, 18) ^ rotl(temp2, 24); ++ } ++ ++ for (j = 0; j < 4; j++) { ++ *get_element_w(env, rc, i * 4 + j) = W[8 + j]; ++ } ++ } ++} ++ ++void helper_vcmpueqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_b, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_b = get_element_b(env, rb, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a == *ptr_b) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpugtb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_b, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_b = get_element_b(env, rb, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a > *ptr_b) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpueqbi(CPUSW64State *env, uint64_t ra, uint64_t vb, ++ uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a == vb) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpugtbi(CPUSW64State *env, uint64_t ra, uint64_t vb, ++ uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a > vb) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vsm3msw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint32_t W[24]; ++ uint32_t temp; ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ W[i + 0] = *get_element_w(env, ra, i); ++ W[i + 8] = *get_element_w(env, rb, i); ++ } ++ for (i = 16; i < 24; i++) { ++ temp = W[i - 16] ^ W[i - 9] ^ rotl(W[i - 3], 15); ++ temp = temp ^ rotl(temp, 15) ^ rotl(temp, 23) ^ rotl(W[i - 13], 7) ^ W[i - 6]; ++ W[i] = temp; ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rc, i) = W[16 + i]; ++ } ++} ++ ++static uint32_t selck[4][8] = { ++ {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9}, ++ {0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9}, ++ {0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299}, ++ {0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279} ++}; ++ ++void helper_vsm4key(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ uint32_t K[12], *CK; ++ int i; ++ uint32_t temp1, temp2; ++ ++ for (i = 4; i < 8; i++) { ++ K[i - 4] = *get_element_w(env, ra, i); ++ } ++ CK = selck[vb]; ++ ++ for (i = 0; i < 8; i++) { ++ temp1 = K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]; ++ temp2 = SBOX(temp1); ++ K[i + 4] = K[i] ^ temp2 ^ rotl(temp2, 13) ^ rotl(temp2, 23); ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rc, i) = K[i + 4]; ++ } ++} ++ ++void helper_vinsb(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ ++ for (i = 0; i < 128; i += 32) { ++ env->fr[rd + i] = env->fr[rb + i]; ++ } ++ ++ *get_element_b(env, rd, vc) = (uint8_t)(va & 0xff); ++} ++ ++void helper_vinsh(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ ++ if (vc >= 16) ++ return; ++ ++ for (i = 0; i < 128; i += 32) { ++ env->fr[rd + i] = env->fr[rb + i]; ++ } ++ ++ *get_element_h(env, rd, vc) = (uint16_t)(va & 0xffff); ++} ++ ++void helper_vinsectlh(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint32_t temp[8]; ++ for (i = 0; i < 8; i++) { ++ temp[i] = *get_element_h(env, ra, i) | ((uint32_t)*get_element_h(env, rb, i) << 16); ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rd, i) = temp[i]; ++ } ++} ++void helper_vinsectlw(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint64_t temp[4]; ++ for (i = 0; i < 4; i++) { ++ temp[i] = *get_element_w(env, ra, i) | ((uint64_t)*get_element_w(env, rb, i) << 32); ++ } ++ for (i = 0; i < 4; i++) { ++ *get_element_l(env, rd, i) = temp[i]; ++ } ++} ++ ++void helper_vinsectlb(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint16_t temp[16]; ++ for (i = 0; i < 16; i++) { ++ temp[i] = *get_element_b(env, ra, i) | ((uint16_t)*get_element_b(env, rb, i) << 8); ++ } ++ for (i = 0; i < 16; i++) { ++ *get_element_h(env, rd, i) = temp[i]; ++ } ++} ++ ++void helper_vshfq(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ int idx; ++ uint64_t temp[4]; ++ for (i = 0; i < 2; i++) { ++ idx = ((vc >> (i * 2)) & 1) * 64; ++ if ((vc >> (i * 2 + 1)) & 1) { ++ temp[i * 2] = env->fr[rb + idx]; ++ temp[i * 2 + 1] = env->fr[rb + idx + 32]; ++ } else { ++ temp[i * 2] = env->fr[ra + idx]; ++ temp[i * 2 + 1] = env->fr[ra + idx + 32]; ++ } ++ } ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = temp[i]; ++ } ++} ++ ++void helper_vshfqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rd) ++{ ++ int i; ++ int idx; ++ int vb; ++ uint8_t temp[32]; ++ ++ for (i = 0; i < 16; i++) { ++ vb = *get_element_b(env, rb, i); ++ if (vb >> 7) { ++ temp[i] = 0; ++ } else { ++ idx = vb & 0xf; ++ temp[i] = *get_element_b(env, ra, idx); ++ } ++ vb = *get_element_b(env, rb, i + 16); ++ if (vb >> 7) { ++ temp[i + 16] = 0; ++ } else { ++ idx = vb & 0xf; ++ temp[i + 16] = *get_element_b(env, ra, idx + 16); ++ } ++ } ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = *((uint64_t*)temp + i); ++ } ++} ++ ++void helper_vsm3r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint32_t W[8]; ++ uint32_t A, B, C, D, E, F, G, H, T; ++ int i; ++ uint32_t SS1, SS2, TT1, TT2, P0; ++ ++ if (vc >= 16) ++ return; ++ for (i = 0; i < 8; i++) { ++ W[i] = *get_element_w(env, ra, i); ++ } ++ A = *get_element_w(env, rb, 0); ++ B = *get_element_w(env, rb, 1); ++ C = *get_element_w(env, rb, 2); ++ D = *get_element_w(env, rb, 3); ++ E = *get_element_w(env, rb, 4); ++ F = *get_element_w(env, rb, 5); ++ G = *get_element_w(env, rb, 6); ++ H = *get_element_w(env, rb, 7); ++ ++ if (vc < 4) { ++ T = 0x79cc4519; ++ for (i = 0; i < 4; i++) { ++ SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); ++ SS2 = SS1 ^ rotl(A, 12); ++ TT1 = (A ^ B ^ C) + D + SS2 + (W[i] ^ W[i + 4]); ++ TT2 = (E ^ F ^ G) + H + SS1 + W[i]; ++ ++ P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); ++ ++ H = G; ++ G = rotl(F, 19); ++ F = E; ++ E = P0; ++ D = C; ++ C = rotl(B, 9); ++ B = A; ++ A = TT1; ++ } ++ } else { ++ T = 0x7a879d8a; ++ for (i = 0; i < 4; i++) { ++ SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); ++ SS2 = SS1 ^ rotl(A, 12); ++ TT1 = ((A & B) | (A & C) | (B & C)) + D + SS2 + (W[i] ^ W[i + 4]); ++ TT2 = ((E & F) | ((~E) & G)) + H + SS1 + W[i]; ++ ++ P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); ++ ++ H = G; ++ G = rotl(F, 19); ++ F = E; ++ E = P0; ++ D = C; ++ C = rotl(B, 9); ++ B = A; ++ A = TT1; ++ } ++ } ++ *get_element_w(env, rd, 0) = A; ++ *get_element_w(env, rd, 1) = B; ++ *get_element_w(env, rd, 2) = C; ++ *get_element_w(env, rd, 3) = D; ++ *get_element_w(env, rd, 4) = E; ++ *get_element_w(env, rd, 5) = F; ++ *get_element_w(env, rd, 6) = G; ++ *get_element_w(env, rd, 7) = H; ++} +diff --git a/target/sw64/translate.c b/target/sw64/translate.c +new file mode 100644 +index 0000000000..37b7e89077 +--- /dev/null ++++ b/target/sw64/translate.c +@@ -0,0 +1,3798 @@ ++#include "translate.h" ++#include "tcg/tcg.h" ++#define DEVELOP_SW64 1 ++#ifdef DEVELOP_SW64 ++ ++#define ILLEGAL(x) \ ++ do { \ ++ printf("Illegal SW64 0x%x at line %d!\n", x, __LINE__); \ ++ exit(-1); \ ++ } while (0) ++#endif ++ ++TCGv cpu_pc; ++TCGv cpu_std_ir[31]; ++TCGv cpu_fr[128]; ++TCGv cpu_lock_addr; ++TCGv cpu_lock_flag; ++TCGv cpu_lock_success; ++#ifdef SW64_FIXLOCK ++TCGv cpu_lock_value; ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++TCGv cpu_hm_ir[31]; ++#endif ++ ++#include "exec/gen-icount.h" ++ ++void sw64_translate_init(void) ++{ ++#define DEF_VAR(V) \ ++ { &cpu_##V, #V, offsetof(CPUSW64State, V) } ++ ++ typedef struct { ++ TCGv* var; ++ const char* name; ++ int ofs; ++ } GlobalVar; ++ ++ static const GlobalVar vars[] = { ++ DEF_VAR(pc), DEF_VAR(lock_addr), ++ DEF_VAR(lock_flag), DEF_VAR(lock_success), ++#ifdef SW64_FIXLOCK ++ DEF_VAR(lock_value), ++#endif ++ }; ++ cpu_pc = tcg_global_mem_new_i64(cpu_env, ++ offsetof(CPUSW64State, pc), "PC"); ++ ++#undef DEF_VAR ++ ++ /* Use the symbolic register names that match the disassembler. */ ++ static const char ireg_names[31][4] = { ++ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", ++ "s2", "s3", "s4", "s5", "fp", "a0", "a1", "a2", "a3", "a4", "a5", ++ "t8", "t9", "t10", "t11", "ra", "t12", "at", "gp", "sp"}; ++ ++ static const char freg_names[128][4] = { ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", ++ "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", ++ "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", ++ "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", ++ "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", ++ "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", ++ "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", ++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", ++ "f26", "f27", "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", ++ "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", ++ "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", ++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; ++ ++#ifndef CONFIG_USER_ONLY ++ static const char shadow_names[10][8] = { ++ "hm_p1", "hm_p2", "hm_p4", "hm_p5", "hm_p6", ++ "hm_p7", "hm_p20", "hm_p21", "hm_p22", "hm_p23"}; ++ static const int shadow_index[10] = {1, 2, 4, 5, 6, 7, 20, 21, 22, 23}; ++#endif ++ ++ int i; ++ ++ for (i = 0; i < 31; i++) { ++ cpu_std_ir[i] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, ir[i]), ireg_names[i]); ++ } ++ ++ for (i = 0; i < 128; i++) { ++ cpu_fr[i] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, fr[i]), freg_names[i]); ++ } ++ for (i = 0; i < ARRAY_SIZE(vars); ++i) { ++ const GlobalVar* v = &vars[i]; ++ *v->var = tcg_global_mem_new_i64(cpu_env, v->ofs, v->name); ++ } ++#ifndef CONFIG_USER_ONLY ++ memcpy(cpu_hm_ir, cpu_std_ir, sizeof(cpu_hm_ir)); ++ for (i = 0; i < 10; i++) { ++ int r = shadow_index[i]; ++ cpu_hm_ir[r] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, sr[i]), shadow_names[i]); ++ } ++#endif ++} ++ ++static bool in_superpage(DisasContext* ctx, int64_t addr) ++{ ++ return false; ++} ++ ++bool use_exit_tb(DisasContext* ctx) ++{ ++ return ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ++ ctx->base.singlestep_enabled || singlestep); ++} ++ ++bool use_goto_tb(DisasContext* ctx, uint64_t dest) ++{ ++ /* Suppress goto_tb in the case of single-steping and IO. */ ++ if (unlikely(use_exit_tb(ctx))) { ++ return false; ++ } ++ /* If the destination is in the superpage, the page perms can't change. */ ++ if (in_superpage(ctx, dest)) { ++ return true; ++ } ++/* Check for the dest on the same page as the start of the TB. */ ++#ifndef CONFIG_USER_ONLY ++ return ((ctx->base.tb->pc ^ dest) & TARGET_PAGE_MASK) == 0; ++#else ++ return true; ++#endif ++} ++ ++void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src) ++{ ++ uint64_t mzero = 1ull << 63; ++ ++ switch (cond) { ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ /* For <= or >, the -0.0 value directly compares the way we want. */ ++ tcg_gen_mov_i64(dest, src); ++ break; ++ ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ /* For == or !=, we can simply mask off the sign bit and compare. */ ++ tcg_gen_andi_i64(dest, src, mzero - 1); ++ break; ++ ++ case TCG_COND_GE: ++ case TCG_COND_LT: ++ /* For >= or <, map -0.0 to +0.0 via comparison and mask. */ ++ tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero); ++ tcg_gen_neg_i64(dest, dest); ++ tcg_gen_and_i64(dest, dest, src); ++ break; ++ ++ default: ++ abort(); ++ } ++} ++ ++static TCGv load_zero(DisasContext *ctx) ++{ ++ if (!ctx->zero) { ++ ctx->zero = tcg_const_i64(0); ++ } ++ return ctx->zero; ++} ++ ++static void free_context_temps(DisasContext *ctx) ++{ ++ if (ctx->zero) { ++ tcg_temp_free(ctx->zero); ++ ctx->zero = NULL; ++ } ++} ++ ++static TCGv load_gir(DisasContext *ctx, unsigned reg) ++{ ++ if (likely(reg < 31)) { ++ return ctx->ir[reg]; ++ } else { ++ return load_zero(ctx); ++ } ++} ++ ++static void gen_excp_1(int exception, int error_code) ++{ ++ TCGv_i32 tmp1, tmp2; ++ ++ tmp1 = tcg_const_i32(exception); ++ tmp2 = tcg_const_i32(error_code); ++ gen_helper_excp(cpu_env, tmp1, tmp2); ++ tcg_temp_free_i32(tmp2); ++ tcg_temp_free_i32(tmp1); ++} ++ ++static DisasJumpType gen_excp(DisasContext* ctx, int exception, ++ int error_code) ++{ ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ gen_excp_1(exception, error_code); ++ return DISAS_NORETURN; ++} ++ ++static int i_count = 1; ++ ++static inline DisasJumpType gen_invalid(DisasContext *ctx) ++{ ++ if (i_count == 0) { ++ i_count++; ++ return DISAS_NEXT; ++ } ++ fprintf(stderr, "here %lx\n", ctx->base.pc_next); ++ return gen_excp(ctx, EXCP_OPCDEC, 0); ++} ++ ++static uint64_t zapnot_mask(uint8_t byte_mask) ++{ ++ uint64_t mask = 0; ++ int i; ++ ++ for (i = 0; i < 8; ++i) { ++ if ((byte_mask >> i) & 1) { ++ mask |= 0xffull << (i * 8); ++ } ++ } ++ return mask; ++} ++ ++static void gen_ins_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(tmp, va, zapnot_mask(byte_mask)); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_shl_i64(vc, tmp, shift); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_ins_h(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(tmp, va, zapnot_mask(byte_mask)); ++ ++ tcg_gen_shli_i64(shift, vb, 3); ++ tcg_gen_not_i64(shift, shift); ++ tcg_gen_andi_i64(shift, shift, 0x3f); ++ ++ tcg_gen_shr_i64(vc, tmp, shift); ++ tcg_gen_shri_i64(vc, vc, 1); ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_ext_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_shr_i64(tmp, va, shift); ++ ++ tcg_gen_andi_i64(vc, tmp, zapnot_mask(byte_mask)); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_ext_h(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_movi_i64(tmp, 64); ++ tcg_gen_sub_i64(shift, tmp, shift); ++ tcg_gen_shl_i64(tmp, va, shift); ++ ++ tcg_gen_andi_i64(vc, tmp, zapnot_mask(byte_mask)); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_mask_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv shift = tcg_temp_new(); ++ TCGv mask = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_movi_i64(mask, zapnot_mask(byte_mask)); ++ tcg_gen_shl_i64(mask, mask, shift); ++ ++ tcg_gen_andc_i64(vc, va, mask); ++ ++ tcg_temp_free(mask); ++ tcg_temp_free(shift); ++} ++ ++static void gen_mask_h(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv shift = tcg_temp_new(); ++ TCGv mask = tcg_temp_new(); ++ ++ /* The instruction description is as above, where the byte_mask ++ is shifted left, and then we extract bits <15:8>. This can be ++ emulated with a right-shift on the expanded byte mask. This ++ requires extra care because for an input <2:0> == 0 we need a ++ shift of 64 bits in order to generate a zero. This is done by ++ splitting the shift into two parts, the variable shift - 1 ++ followed by a constant 1 shift. The code we expand below is ++ equivalent to ~(B * 8) & 63. */ ++ ++ tcg_gen_shli_i64(shift, vb, 3); ++ tcg_gen_not_i64(shift, shift); ++ tcg_gen_andi_i64(shift, shift, 0x3f); ++ tcg_gen_movi_i64(mask, zapnot_mask(byte_mask)); ++ tcg_gen_shr_i64(mask, mask, shift); ++ tcg_gen_shri_i64(mask, mask, 1); ++ ++ tcg_gen_andc_i64(vc, va, mask); ++ ++ tcg_temp_free(mask); ++ tcg_temp_free(shift); ++} ++ ++static inline void gen_load_mem( ++ DisasContext *ctx, void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, bool fp, bool clear) ++{ ++ TCGv tmp, addr, va; ++ ++ /* LDQ_U with ra $31 is UNOP. Other various loads are forms of ++ prefetches, which we can treat as nops. No worries about ++ missed exceptions here. */ ++ if (unlikely(ra == 31)) { ++ return; ++ } ++ ++ tmp = tcg_temp_new(); ++ addr = load_gir(ctx, rb); ++ ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (clear) { ++ tcg_gen_andi_i64(tmp, addr, ~0x7UL); ++ addr = tmp; ++ } ++ ++ va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); ++ tcg_gen_qemu_load(va, addr, ctx->mem_idx); ++ ++ tcg_temp_free(tmp); ++} ++ ++static inline void gen_store_mem( ++ DisasContext *ctx, void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, bool fp, bool clear) ++{ ++ TCGv tmp, addr, va; ++ ++ tmp = tcg_temp_new(); ++ addr = load_gir(ctx, rb); ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (clear) { ++ tcg_gen_andi_i64(tmp, addr, ~0x7); ++ addr = tmp; ++ } ++ va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); ++ ++ tcg_gen_qemu_store(va, addr, ctx->mem_idx); ++ gen_helper_trace_mem(cpu_env, addr, va); ++ tcg_temp_free(tmp); ++} ++ ++static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, ++ int32_t disp13, uint16_t fn) ++{ ++ TCGv tmp; ++ ++ switch (fn & 0xff) { ++ case 0x00: ++ /* ADDW */ ++ tcg_gen_add_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x01: ++ /* SUBW */ ++ tcg_gen_sub_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x02: ++ /* S4ADDW */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_add_i64(tmp, tmp, vb); ++ tcg_gen_ext32s_i64(vc, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x03: ++ /* S4SUBW */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_sub_i64(tmp, tmp, vb); ++ tcg_gen_ext32s_i64(vc, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x04: ++ /* S8ADDW */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_add_i64(tmp, tmp, vb); ++ tcg_gen_ext32s_i64(vc, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x05: ++ /* S8SUBW */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_sub_i64(tmp, tmp, vb); ++ tcg_gen_ext32s_i64(vc, tmp); ++ tcg_temp_free(tmp); ++ break; ++ ++ case 0x08: ++ /* ADDL */ ++ tcg_gen_add_i64(vc, va, vb); ++ break; ++ case 0x09: ++ /* SUBL */ ++ tcg_gen_sub_i64(vc, va, vb); ++ break; ++ case 0x0a: ++ /* S4ADDL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_add_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0b: ++ /* S4SUBL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_sub_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0c: ++ /* S8ADDL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_add_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0d: ++ /* S8SUBL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_sub_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x10: ++ /* MULW */ ++ tcg_gen_mul_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x18: ++ /* MULL */ ++ tcg_gen_mul_i64(vc, va, vb); ++ break; ++ case 0x19: ++ /* MULH */ ++ tmp = tcg_temp_new(); ++ tcg_gen_mulu2_i64(tmp, vc, va, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x28: ++ /* CMPEQ */ ++ tcg_gen_setcond_i64(TCG_COND_EQ, vc, va, vb); ++ break; ++ case 0x29: ++ /* CMPLT */ ++ tcg_gen_setcond_i64(TCG_COND_LT, vc, va, vb); ++ break; ++ case 0x2a: ++ /* CMPLE */ ++ tcg_gen_setcond_i64(TCG_COND_LE, vc, va, vb); ++ break; ++ case 0x2b: ++ /* CMPULT */ ++ tcg_gen_setcond_i64(TCG_COND_LTU, vc, va, vb); ++ break; ++ case 0x2c: ++ /* CMPULE */ ++ tcg_gen_setcond_i64(TCG_COND_LEU, vc, va, vb); ++ break; ++ case 0x38: ++ /* AND */ ++ tcg_gen_and_i64(vc, va, vb); ++ break; ++ case 0x39: ++ /* BIC */ ++ tcg_gen_andc_i64(vc, va, vb); ++ break; ++ case 0x3a: ++ /* BIS */ ++ tcg_gen_or_i64(vc, va, vb); ++ break; ++ case 0x3b: ++ /* ORNOT */ ++ tcg_gen_orc_i64(vc, va, vb); ++ break; ++ case 0x3c: ++ /* XOR */ ++ tcg_gen_xor_i64(vc, va, vb); ++ break; ++ case 0x3d: ++ /* EQV */ ++ tcg_gen_eqv_i64(vc, va, vb); ++ break; ++ case 0x40: ++ /* INSLB */ ++ gen_ins_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x41: ++ /* INSLH */ ++ gen_ins_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x42: ++ /* INSLW */ ++ gen_ins_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x43: ++ /* INSLL */ ++ gen_ins_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x44: ++ /* INSHB */ ++ gen_ins_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x45: ++ /* INSHH */ ++ gen_ins_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x46: ++ /* INSHW */ ++ gen_ins_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x47: ++ /* INSHL */ ++ gen_ins_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x48: ++ /* SLL/SLLL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_shl_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x49: ++ /* SRL/SRLL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_shr_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x4a: ++ /* SRA/SRAL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_sar_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x50: ++ /* EXTLB */ ++ gen_ext_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x51: ++ /* EXTLH */ ++ gen_ext_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x52: ++ /* EXTLW */ ++ gen_ext_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x53: ++ /* EXTLL */ ++ gen_ext_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x54: ++ /* EXTHB */ ++ gen_ext_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x55: ++ /* EXTHH */ ++ gen_ext_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x56: ++ /* EXTHW */ ++ gen_ext_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x57: ++ /* EXTHL */ ++ gen_ext_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x58: ++ /* CTPOP */ ++ tcg_gen_ctpop_i64(vc, vb); ++ break; ++ case 0x59: ++ /* CTLZ */ ++ tcg_gen_clzi_i64(vc, vb, 64); ++ break; ++ case 0x5a: ++ /* CTTZ */ ++ tcg_gen_ctzi_i64(vc, vb, 64); ++ break; ++ case 0x60: ++ /* MASKLB */ ++ gen_mask_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x61: ++ /* MASKLH */ ++ gen_mask_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x62: ++ /* MASKLW */ ++ gen_mask_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x63: ++ /* MASKLL */ ++ gen_mask_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x64: ++ /* MASKHB */ ++ gen_mask_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x65: ++ /* MASKHH */ ++ gen_mask_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x66: ++ /* MASKHW */ ++ gen_mask_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x67: ++ /* MASKHL */ ++ gen_mask_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x68: ++ /* ZAP */ ++ gen_helper_zap(vc, va, vb); ++ break; ++ case 0x69: ++ /* ZAPNOT */ ++ gen_helper_zapnot(vc, va, vb); ++ break; ++ case 0x6a: ++ /* SEXTB */ ++ tcg_gen_ext8s_i64(vc, vb); ++ break; ++ case 0x6b: ++ /* SEXTH */ ++ tcg_gen_ext16s_i64(vc, vb); ++ break; ++ case 0x6c: ++ /* CMPGEB*/ ++ gen_helper_cmpgeb(vc, va, vb); ++ break; ++ default: ++ ILLEGAL(fn); ++ } ++} ++ ++static void cal_with_imm_2(DisasContext *ctx, TCGv vc, TCGv va, int64_t disp, ++ uint8_t fn) ++{ ++ TCGv_i64 t0 = tcg_const_i64(disp); ++ cal_with_iregs_2(ctx, vc, va, t0, 0, fn); ++ tcg_temp_free_i64(t0); ++} ++ ++static void cal_with_iregs_3(DisasContext *ctx, TCGv vd, TCGv va, TCGv vb, ++ TCGv vc, uint8_t fn) ++{ ++ TCGv_i64 t0 = tcg_const_i64(0); ++ TCGv_i64 tmp; ++ switch (fn) { ++ case 0x0: ++ /* SELEQ */ ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, va, t0, vb, vc); ++ break; ++ case 0x1: ++ /* SELGE */ ++ tcg_gen_movcond_i64(TCG_COND_GE, vd, va, t0, vb, vc); ++ break; ++ case 0x2: ++ /* SELGT */ ++ tcg_gen_movcond_i64(TCG_COND_GT, vd, va, t0, vb, vc); ++ break; ++ case 0x3: ++ /* SELLE */ ++ tcg_gen_movcond_i64(TCG_COND_LE, vd, va, t0, vb, vc); ++ break; ++ case 0x4: ++ /* SELLT */ ++ tcg_gen_movcond_i64(TCG_COND_LT, vd, va, t0, vb, vc); ++ break; ++ case 0x5: ++ /* SELNE */ ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, va, t0, vb, vc); ++ break; ++ case 0x6: ++ /* SELLBC */ ++ tmp = tcg_temp_new_i64(); ++ tcg_gen_andi_i64(tmp, va, 1); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp, t0, vb, vc); ++ tcg_temp_free_i64(tmp); ++ break; ++ case 0x7: ++ /* SELLBS */ ++ tmp = tcg_temp_new_i64(); ++ tcg_gen_andi_i64(tmp, va, 1); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp, t0, vb, vc); ++ tcg_temp_free_i64(tmp); ++ break; ++ default: ++ ILLEGAL(fn); ++ break; ++ } ++ tcg_temp_free_i64(t0); ++} ++ ++static void cal_with_imm_3(DisasContext *ctx, TCGv vd, TCGv va, int32_t disp, ++ TCGv vc, uint8_t fn) ++{ ++ TCGv_i64 vb = tcg_const_i64(disp); ++ cal_with_iregs_3(ctx, vd, va, vb, vc, fn); ++ tcg_temp_free_i64(vb); ++} ++ ++static DisasJumpType gen_bdirect(DisasContext *ctx, int ra, int32_t disp) ++{ ++ uint64_t dest = ctx->base.pc_next + ((int64_t)disp << 2); ++ if (ra != 31) { ++ tcg_gen_movi_i64(load_gir(ctx, ra), ctx->base.pc_next & (~0x3UL)); ++ } ++ if (disp == 0) { ++ return 0; ++ } else if (use_goto_tb(ctx, dest)) { ++ tcg_gen_goto_tb(0); ++ tcg_gen_movi_i64(cpu_pc, dest); ++ tcg_gen_exit_tb(ctx->base.tb, 0); ++ return DISAS_NORETURN; ++ } else { ++ tcg_gen_movi_i64(cpu_pc, dest); ++ return DISAS_PC_UPDATED; ++ } ++} ++ ++static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond, ++ TCGv cmp, int disp) ++{ ++ uint64_t dest = ctx->base.pc_next + (disp << 2); ++ TCGLabel* lab_true = gen_new_label(); ++ ++ if (use_goto_tb(ctx, dest)) { ++ tcg_gen_brcondi_i64(cond, cmp, 0, lab_true); ++ ++ tcg_gen_goto_tb(0); ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ tcg_gen_exit_tb(ctx->base.tb, 0); ++ ++ gen_set_label(lab_true); ++ tcg_gen_goto_tb(1); ++ tcg_gen_movi_i64(cpu_pc, dest); ++ tcg_gen_exit_tb(ctx->base.tb, 1); ++ ++ return DISAS_NORETURN; ++ } else { ++ TCGv_i64 t = tcg_const_i64(0); ++ TCGv_i64 d = tcg_const_i64(dest); ++ TCGv_i64 p = tcg_const_i64(ctx->base.pc_next); ++ ++ tcg_gen_movcond_i64(cond, cpu_pc, cmp, t, d, p); ++ ++ tcg_temp_free_i64(t); ++ tcg_temp_free_i64(d); ++ tcg_temp_free_i64(p); ++ return DISAS_PC_UPDATED; ++ } ++} ++ ++static DisasJumpType gen_bcond(DisasContext *ctx, TCGCond cond, uint32_t ra, ++ int32_t disp, uint64_t mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ DisasJumpType ret; ++ ++ tcg_gen_andi_i64(tmp, load_gir(ctx, ra), mask); ++ ret = gen_bcond_internal(ctx, cond, tmp, disp); ++ tcg_temp_free(tmp); ++ return ret; ++} ++ ++static DisasJumpType gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, ++ int32_t disp) ++{ ++ TCGv cmp_tmp = tcg_temp_new(); ++ DisasJumpType ret; ++ ++ gen_fold_mzero(cond, cmp_tmp, cpu_fr[ra]); ++ ret = gen_bcond_internal(ctx, cond, cmp_tmp, disp); ++ tcg_temp_free(cmp_tmp); ++ return ret; ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void gen_qemu_pri_ldw(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_ldw(t0, cpu_env, t1); ++} ++ ++static void gen_qemu_pri_stw(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_stw(cpu_env, t0, t1); ++} ++ ++static void gen_qemu_pri_ldl(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_ldl(t0, cpu_env, t1); ++} ++ ++static void gen_qemu_pri_stl(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_stl(cpu_env, t0, t1); ++} ++#endif ++ ++static inline void gen_load_mem_simd( ++ DisasContext *ctx, void (*tcg_gen_qemu_load)(int t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, uint64_t mask) ++{ ++ TCGv tmp, addr; ++ ++ /* LDQ_U with ra $31 is UNOP. Other various loads are forms of ++ prefetches, which we can treat as nops. No worries about ++ missed exceptions here. */ ++ if (unlikely(ra == 31)) ++ return; ++ ++ tmp = tcg_temp_new(); ++ addr = load_gir(ctx, rb); ++ ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ ++ if (mask) { ++ tcg_gen_andi_i64(addr, addr, mask); ++ } ++ ++ tcg_gen_qemu_load(ra, addr, ctx->mem_idx); ++ // FIXME: for debug ++ ++ tcg_temp_free(tmp); ++} ++ ++static inline void gen_store_mem_simd( ++ DisasContext *ctx, void (*tcg_gen_qemu_store)(int t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, uint64_t mask) ++{ ++ TCGv tmp, addr; ++ ++ tmp = tcg_temp_new(); ++ addr = load_gir(ctx, rb); ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (mask) { ++ tcg_gen_andi_i64(addr, addr, mask); ++ } ++ // FIXME: for debug ++ tcg_gen_qemu_store(ra, addr, ctx->mem_idx); ++ ++ tcg_temp_free(tmp); ++} ++ ++static void gen_qemu_ldwe(int t0, TCGv t1, int memidx) ++{ ++ TCGv tmp = tcg_temp_new(); ++ ++ tcg_gen_qemu_ld_i64(tmp, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ tcg_gen_shli_i64(cpu_fr[t0], tmp, 32); ++ tcg_gen_or_i64(cpu_fr[t0], cpu_fr[t0], tmp); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++ ++ tcg_temp_free(tmp); ++} ++ ++static void gen_qemu_vlds(int t0, TCGv t1, int memidx) ++{ ++ int i; ++ TCGv_i32 tmp32 = tcg_temp_new_i32(); ++ ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0], tmp32); ++ tcg_gen_addi_i64(t1, t1, 4); ++ ++ for (i = 1; i < 4; i++) { ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0 + i * 32], tmp32); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ ++ tcg_temp_free_i32(tmp32); ++} ++ ++static void gen_qemu_ldse(int t0, TCGv t1, int memidx) ++{ ++ TCGv_i32 tmp32 = tcg_temp_new_i32(); ++ TCGv tmp64 = tcg_temp_new(); ++ ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0], tmp32); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++ ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++} ++ ++static void gen_qemu_ldde(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_ld_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++} ++ ++static void gen_qemu_vldd(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_ld_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 32], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 64], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 96], t1, memidx, MO_TEQ); ++} ++ ++static void gen_qemu_vsts(int t0, TCGv t1, int memidx) ++{ ++ int i; ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ ++ gen_helper_s_to_memory(tmp, cpu_fr[t0]); ++ tcg_gen_qemu_st_i32(tmp, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ for (i = 1; i < 4; i++) { ++ gen_helper_s_to_memory(tmp, cpu_fr[t0 + 32 * i]); ++ tcg_gen_qemu_st_i32(tmp, t1, memidx, MO_LEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ tcg_temp_free_i32(tmp); ++} ++ ++static void gen_qemu_vstd(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_st_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 32], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 64], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 96], t1, memidx, MO_TEQ); ++} ++ ++static inline void gen_qemu_fsts(TCGv t0, TCGv t1, int flags) ++{ ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp, t0); ++ tcg_gen_qemu_st_i32(tmp, t1, flags, MO_LEUL); ++ tcg_temp_free_i32(tmp); ++} ++ ++static inline void gen_qemu_flds(TCGv t0, TCGv t1, int flags) ++{ ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld_i32(tmp, t1, flags, MO_LEUL); ++ gen_helper_memory_to_s(t0, tmp); ++ tcg_temp_free_i32(tmp); ++} ++ ++static TCGv gen_ieee_input(DisasContext *ctx, int reg, int is_cmp) ++{ ++ TCGv val; ++ ++ if (unlikely(reg == 31)) { ++ val = load_zero(ctx); ++ } else { ++ val = cpu_fr[reg]; ++#ifndef CONFIG_USER_ONLY ++ /* In system mode, raise exceptions for denormals like real ++ hardware. In user mode, proceed as if the OS completion ++ handler is handling the denormal as per spec. */ ++ gen_helper_ieee_input(cpu_env, val); ++#endif ++ } ++ return val; ++} ++ ++static void gen_fp_exc_raise(int rc) ++{ ++#ifndef CONFIG_USER_ONLY ++ TCGv_i32 reg = tcg_const_i32(rc + 32); ++ gen_helper_fp_exc_raise(cpu_env, reg); ++ tcg_temp_free_i32(reg); ++#endif ++} ++ ++static void gen_ieee_arith2(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv), int ra, ++ int rc) ++{ ++ TCGv va, vc; ++ ++ va = gen_ieee_input(ctx, ra, 0); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++static void gen_ieee_arith3(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), int ra, ++ int rb, int rc) ++{ ++ TCGv va, vb, vc; ++ ++ va = gen_ieee_input(ctx, ra, 0); ++ vb = gen_ieee_input(ctx, rb, 0); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va, vb); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++#define IEEE_ARITH2(name) \ ++ static inline void glue(gen_, name)(DisasContext * ctx, int ra, int rc) { \ ++ gen_ieee_arith2(ctx, gen_helper_##name, ra, rc); \ ++ } ++ ++#define IEEE_ARITH3(name) \ ++ static inline void glue(gen_, name)(DisasContext * ctx, int ra, int rb, \ ++ int rc) { \ ++ gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc); \ ++ } ++IEEE_ARITH3(fadds) ++IEEE_ARITH3(faddd) ++IEEE_ARITH3(fsubs) ++IEEE_ARITH3(fsubd) ++IEEE_ARITH3(fmuls) ++IEEE_ARITH3(fmuld) ++IEEE_ARITH3(fdivs) ++IEEE_ARITH3(fdivd) ++IEEE_ARITH2(frecs) ++IEEE_ARITH2(frecd) ++ ++static void gen_ieee_compare(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), int ra, ++ int rb, int rc) ++{ ++ TCGv va, vb, vc; ++ ++ va = gen_ieee_input(ctx, ra, 1); ++ vb = gen_ieee_input(ctx, rb, 1); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va, vb); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++#define IEEE_CMP2(name) \ ++ static inline void glue(gen_, name)(DisasContext *ctx, int ra, int rb, \ ++ int rc) { \ ++ gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc); \ ++ } ++ ++IEEE_CMP2(fcmpun) ++IEEE_CMP2(fcmpeq) ++IEEE_CMP2(fcmplt) ++IEEE_CMP2(fcmple) ++ ++static void gen_fcvtdl(int rb, int rc, uint64_t round_mode) ++{ ++ TCGv tmp64; ++ tmp64 = tcg_temp_new_i64(); ++ tcg_gen_movi_i64(tmp64, round_mode); ++ gen_helper_fcvtdl(cpu_fr[rc], cpu_env, cpu_fr[rb], tmp64); ++ tcg_temp_free(tmp64); ++ gen_fp_exc_raise(rc); ++} ++ ++static void cal_with_fregs_2(DisasContext *ctx, uint8_t rc, uint8_t ra, ++ uint8_t rb, uint8_t fn) ++{ ++ TCGv tmp64; ++ TCGv_i32 tmp32; ++ switch (fn) { ++ case 0x00: ++ /* FADDS */ ++ gen_fadds(ctx, ra, rb, rc); ++ break; ++ case 0x01: ++ /* FADDD */ ++ gen_faddd(ctx, ra, rb, rc); ++ break; ++ case 0x02: ++ /* FSUBS */ ++ gen_fsubs(ctx, ra, rb, rc); ++ break; ++ case 0x03: ++ /* FSUBD */ ++ gen_fsubd(ctx, ra, rb, rc); ++ break; ++ case 0x4: ++ /* FMULS */ ++ gen_fmuls(ctx, ra, rb, rc); ++ break; ++ case 0x05: ++ /* FMULD */ ++ gen_fmuld(ctx, ra, rb, rc); ++ break; ++ case 0x06: ++ /* FDIVS */ ++ gen_fdivs(ctx, ra, rb, rc); ++ break; ++ case 0x07: ++ /* FDIVD */ ++ gen_fdivd(ctx, ra, rb, rc); ++ break; ++ case 0x08: ++ /* FSQRTS */ ++ gen_helper_fsqrts(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x09: ++ /* FSQRTD */ ++ gen_helper_fsqrt(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x10: ++ /* FCMPEQ */ ++ gen_fcmpeq(ctx, ra, rb, rc); ++ break; ++ case 0x11: ++ /* FCMPLE */ ++ gen_fcmple(ctx, ra, rb, rc); ++ break; ++ case 0x12: ++ /* FCMPLT */ ++ gen_fcmplt(ctx, ra, rb, rc); ++ break; ++ case 0x13: ++ /* FCMPUN */ ++ gen_fcmpun(ctx, ra, rb, rc); ++ break; ++ case 0x20: ++ /* FCVTSD */ ++ gen_helper_fcvtsd(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x21: ++ /* FCVTDS */ ++ gen_helper_fcvtds(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x22: ++ /* FCVTDL_G */ ++ gen_fcvtdl(rb, rc, 0); ++ break; ++ case 0x23: ++ /* FCVTDL_P */ ++ gen_fcvtdl(rb, rc, 2); ++ break; ++ case 0x24: ++ /* FCVTDL_Z */ ++ gen_fcvtdl(rb, rc, 3); ++ break; ++ case 0x25: ++ /* FCVTDL_N */ ++ gen_fcvtdl(rb, rc, 1); ++ break; ++ case 0x27: ++ /* FCVTDL */ ++ gen_helper_fcvtdl_dyn(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x28: ++ /* FCVTWL */ ++ gen_helper_fcvtwl(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ tcg_gen_ext32s_i64(cpu_fr[rc], cpu_fr[rc]); ++ break; ++ case 0x29: ++ /* FCVTLW */ ++ gen_helper_fcvtlw(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x2d: ++ /* FCVTLS */ ++ gen_helper_fcvtls(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x2f: ++ /* FCVTLD */ ++ gen_helper_fcvtld(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x30: ++ /* FCPYS */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 63); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x31: ++ /* FCPYSE */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 52); ++ tcg_gen_shli_i64(tmp64, tmp64, 52); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x000fffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x32: ++ /* FCPYSN */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 63); ++ tcg_gen_not_i64(tmp64, tmp64); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x40: ++ /* IFMOVS */ ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ tcg_gen_movi_i64(tmp64, ra); ++ tcg_gen_extrl_i64_i32(tmp32, load_gir(ctx, ra)); ++ gen_helper_memory_to_s(tmp64, tmp32); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64); ++ tcg_gen_movi_i64(tmp64, rc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x41: ++ /* IFMOVD */ ++ tcg_gen_mov_i64(cpu_fr[rc], load_gir(ctx, ra)); ++ break; ++ case 0x50: ++ /* RFPCR */ ++ gen_helper_load_fpcr(cpu_fr[ra], cpu_env); ++ break; ++ case 0x51: ++ /* WFPCR */ ++ gen_helper_store_fpcr(cpu_env, cpu_fr[ra]); ++ break; ++ case 0x54: ++ /* SETFPEC0 */ ++ tmp64 = tcg_const_i64(0); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x55: ++ /* SETFPEC1 */ ++ tmp64 = tcg_const_i64(1); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x56: ++ /* SETFPEC2 */ ++ tmp64 = tcg_const_i64(2); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x57: ++ /* SETFPEC3 */ ++ tmp64 = tcg_const_i64(3); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ default: ++ fprintf(stderr, "Illegal insn func[%x]\n", fn); ++ gen_invalid(ctx); ++ break; ++ } ++} ++ ++static void cal_with_fregs_4(DisasContext *ctx, uint8_t rd, uint8_t ra, ++ uint8_t rb, uint8_t rc, uint8_t fn) ++{ ++ TCGv zero = tcg_const_i64(0); ++ TCGv va, vb, vc, vd, tmp64; ++ ++ va = cpu_fr[ra]; ++ vb = cpu_fr[rb]; ++ vc = cpu_fr[rc]; ++ vd = cpu_fr[rd]; ++ ++ switch (fn) { ++ case 0x00: ++ /* FMAS */ ++ gen_helper_fmas(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x01: ++ /* FMAD */ ++ gen_helper_fmad(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x02: ++ /* FMSS */ ++ gen_helper_fmss(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x03: ++ /* FMSD */ ++ gen_helper_fmsd(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x04: ++ /* FNMAS */ ++ gen_helper_fnmas(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x05: ++ /* FNMAD */ ++ gen_helper_fnmad(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x06: ++ /* FNMSS */ ++ gen_helper_fnmss(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x07: ++ /* FNMSD */ ++ gen_helper_fnmsd(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x10: ++ /* FSELEQ */ ++ // Maybe wrong translation. ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpeq(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x11: ++ /* FSELNE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpeq(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x12: ++ /* FSELLT */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmplt(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x13: ++ /* FSELLE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmple(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x14: ++ /* FSELGT */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpgt(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x15: ++ /* FSELGE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpge(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ default: ++ fprintf(stderr, "Illegal insn func[%x]\n", fn); ++ gen_invalid(ctx); ++ break; ++ } ++ tcg_temp_free(zero); ++} ++static inline void gen_qemu_lldw(TCGv t0, TCGv t1, int flags) ++{ ++ tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LESL); ++ tcg_gen_mov_i64(cpu_lock_addr, t1); ++#ifdef SW64_FIXLOCK ++ tcg_gen_ext32u_i64(cpu_lock_value, t0); ++#endif ++} ++ ++static inline void gen_qemu_lldl(TCGv t0, TCGv t1, int flags) ++{ ++ tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LEQ); ++ tcg_gen_mov_i64(cpu_lock_addr, t1); ++#ifdef SW64_FIXLOCK ++ tcg_gen_mov_i64(cpu_lock_value, t0); ++#endif ++} ++ ++static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, ++ int32_t disp16, int mem_idx, ++ MemOp op) ++{ ++ TCGLabel *lab_fail, *lab_done; ++ TCGv addr; ++ ++ addr = tcg_temp_new_i64(); ++ tcg_gen_addi_i64(addr, load_gir(ctx, rb), disp16); ++ free_context_temps(ctx); ++ ++ lab_fail = gen_new_label(); ++ lab_done = gen_new_label(); ++ tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); ++ tcg_temp_free_i64(addr); ++ tcg_gen_brcondi_i64(TCG_COND_NE, cpu_lock_flag, 0x1, lab_fail); ++#ifdef SW64_FIXLOCK ++ TCGv val = tcg_temp_new_i64(); ++ tcg_gen_atomic_cmpxchg_i64(val, cpu_lock_addr, cpu_lock_value, ++ load_gir(ctx, ra), mem_idx, op); ++ tcg_gen_setcond_i64(TCG_COND_EQ, cpu_lock_success, val, cpu_lock_value); ++ tcg_temp_free_i64(val); ++#else ++ tcg_gen_qemu_st_i64(load_gir(ctx, ra), addr, mem_idx, op); ++#endif ++ ++ tcg_gen_br(lab_done); ++ ++ gen_set_label(lab_fail); ++ tcg_gen_movi_i64(cpu_lock_success, 0); ++ gen_set_label(lab_done); ++ ++ tcg_gen_movi_i64(cpu_lock_flag, 0); ++ tcg_gen_movi_i64(cpu_lock_addr, -1); ++ return DISAS_NEXT; ++} ++ ++static DisasJumpType gen_sys_call(DisasContext *ctx, int syscode) ++{ ++ if (syscode >= 0x80 && syscode <= 0xbf) { ++ switch (syscode) { ++ case 0x86: ++ /* IMB */ ++ /* No-op inside QEMU */ ++ break; ++#ifdef CONFIG_USER_ONLY ++ case 0x9E: ++ /* RDUNIQUE */ ++ tcg_gen_ld_i64(ctx->ir[IDX_V0], cpu_env, ++ offsetof(CPUSW64State, unique)); ++ break; ++ case 0x9F: ++ /* WRUNIQUE */ ++ tcg_gen_st_i64(ctx->ir[IDX_A0], cpu_env, ++ offsetof(CPUSW64State, unique)); ++ break; ++#endif ++ default: ++ goto do_sys_call; ++ } ++ return DISAS_NEXT; ++ } ++do_sys_call: ++#ifdef CONFIG_USER_ONLY ++ return gen_excp(ctx, EXCP_CALL_SYS, syscode); ++#else ++ tcg_gen_movi_i64(cpu_hm_ir[23], ctx->base.pc_next); ++ return gen_excp(ctx, EXCP_CALL_SYS, syscode); ++#endif ++} ++ ++static void read_csr(int idx, TCGv va) ++{ ++ TCGv_i64 tmp = tcg_const_i64(idx); ++ gen_helper_read_csr(va, cpu_env, tmp); ++ tcg_temp_free_i64(tmp); ++} ++ ++static void write_csr(int idx, TCGv va, CPUSW64State *env) ++{ ++ TCGv_i64 tmp = tcg_const_i64(idx); ++ gen_helper_write_csr(cpu_env, tmp, va); ++ tcg_temp_free_i64(tmp); ++} ++ ++static inline void ldx_set(DisasContext *ctx, int ra, int rb, int32_t disp12, ++ bool bype) ++{ ++ TCGv tmp, addr, va, t1; ++ ++ /* LDQ_U with ra $31 is UNOP. Other various loads are forms of ++ prefetches, which we can treat as nops. No worries about ++ missed exceptions here. */ ++ if (unlikely(ra == 31)) { ++ return; ++ } ++ ++ tmp = tcg_temp_new(); ++ t1 = tcg_const_i64(1); ++ addr = load_gir(ctx, rb); ++ ++ tcg_gen_addi_i64(tmp, addr, disp12); ++ addr = tmp; ++ ++ va = load_gir(ctx, ra); ++ if (bype == 0) { ++ tcg_gen_atomic_xchg_i64(va, addr, t1, ctx->mem_idx, MO_TESL); ++ } else { ++ tcg_gen_atomic_xchg_i64(va, addr, t1, ctx->mem_idx, MO_TEQ); ++ } ++ ++ tcg_temp_free(tmp); ++ tcg_temp_free(t1); ++} ++ ++static inline void ldx_xxx(DisasContext *ctx, int ra, int rb, int32_t disp12, ++ bool bype, int64_t val) ++{ ++ TCGv tmp, addr, va, t; ++ ++ /* LDQ_U with ra $31 is UNOP. Other various loads are forms of ++ prefetches, which we can treat as nops. No worries about ++ missed exceptions here. */ ++ if (unlikely(ra == 31)) { ++ return; ++ } ++ ++ tmp = tcg_temp_new(); ++ t = tcg_const_i64(val); ++ addr = load_gir(ctx, rb); ++ ++ tcg_gen_addi_i64(tmp, addr, disp12); ++ addr = tmp; ++ ++ va = load_gir(ctx, ra); ++ if (bype == 0) { ++ tcg_gen_atomic_fetch_add_i64(va, addr, t, ctx->mem_idx, MO_TESL); ++ } else { ++ tcg_gen_atomic_fetch_add_i64(va, addr, t, ctx->mem_idx, MO_TEQ); ++ } ++ ++ tcg_temp_free(tmp); ++ tcg_temp_free(t); ++} ++ ++static void tcg_gen_srlow_i64(int ra, int rc, int rb) ++{ ++ TCGv va, vb, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ vb = cpu_fr[rb]; ++ tcg_gen_shri_i64(shift, vb, 29); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_srlow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_srlowi_i64(int ra, int rc, int disp8) ++{ ++ TCGv va, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ tcg_gen_movi_i64(shift, disp8); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_srlow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_sllow_i64(int ra, int rc, int rb) ++{ ++ TCGv va, vb, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ vb = cpu_fr[rb]; ++ tcg_gen_shri_i64(shift, vb, 29); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_sllow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_sllowi_i64(int ra, int rc, int disp8) ++{ ++ TCGv va, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ tcg_gen_movi_i64(shift, disp8); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_sllow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void gen_qemu_vstw_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[8]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ tmp[4] = tcg_temp_new(); ++ tmp[5] = tcg_temp_new(); ++ tmp[6] = tcg_temp_new(); ++ tmp[7] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x7UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0x1fUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 7; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_subi_i64(t1, t1, 4); ++ tcg_gen_movi_i64(ti, i); ++ if (i % 2) ++ tcg_gen_shli_i64(tmp[i], tmp[i], 32); ++ } ++ tcg_gen_subfi_i64(byte4_len, 8, byte4_len); ++ ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte4_len, cpu_fr[t0 + (i / 2)*32], tmp[i]); ++ if (i % 2) ++ tcg_gen_shri_i64(tmp[i], tmp[i], 32); ++ else ++ tcg_gen_andi_i64(tmp[i], tmp[i], 0xffffffffUL); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 32); ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(addr_end, addr_end, 4); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++ tcg_temp_free(tmp[4]); ++ tcg_temp_free(tmp[5]); ++ tcg_temp_free(tmp[6]); ++ tcg_temp_free(tmp[7]); ++} ++ ++static void gen_qemu_vstw_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[8]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ tmp[4] = tcg_temp_new(); ++ tmp[5] = tcg_temp_new(); ++ tmp[6] = tcg_temp_new(); ++ tmp[7] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x7UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 24); ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ if (i % 2) ++ tcg_gen_shli_i64(tmp[i], tmp[i], 32); ++ } ++ tcg_gen_subfi_i64(byte4_len, 8, byte4_len); ++ ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte4_len, cpu_fr[t0 + (i/2)*32], tmp[i]); ++ if (i % 2) ++ tcg_gen_shri_i64(tmp[i], tmp[i], 32); ++ else ++ tcg_gen_andi_i64(tmp[i], tmp[i], 0xffffffffUL); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 32); ++ for (i = 7; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 4); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++ tcg_temp_free(tmp[4]); ++ tcg_temp_free(tmp[5]); ++ tcg_temp_free(tmp[6]); ++ tcg_temp_free(tmp[7]); ++} ++ ++static void gen_qemu_vsts_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ftmp; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ ftmp = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0xfUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_subi_i64(t1, t1, 4); ++ } ++ tcg_gen_subfi_i64(byte4_len, 4, byte4_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_shri_i64(ti, cpu_fr[t0 + i * 32], 62); ++ tcg_gen_shli_i64(ti, ti, 30); ++ tcg_gen_shri_i64(ftmp, cpu_fr[t0 + i * 32], 29); ++ tcg_gen_andi_i64(ftmp, ftmp, 0x3fffffffUL); ++ tcg_gen_or_i64(ftmp, ftmp, ti); ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte4_len, ftmp, tmp[i]); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 16); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(addr_end, addr_end, 4); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(ftmp); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vsts_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ftmp; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ftmp = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 12); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ tcg_gen_subfi_i64(byte4_len, 4, byte4_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_shri_i64(ti, cpu_fr[t0 + i * 32], 62); ++ tcg_gen_shli_i64(ti, ti, 30); ++ tcg_gen_shri_i64(ftmp, cpu_fr[t0 + i * 32], 29); ++ tcg_gen_andi_i64(ftmp, ftmp, 0x3fffffffUL); ++ tcg_gen_or_i64(ftmp, ftmp, ti); ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte4_len, ftmp, tmp[i]); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 16); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 4); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(ftmp); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vstd_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte8_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte8_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte8_len, t1, 3); ++ tcg_gen_andi_i64(byte8_len, byte8_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x7UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0x1fUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_subi_i64(t1, t1, 8); ++ } ++ tcg_gen_subfi_i64(byte8_len, 4, byte8_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte8_len, cpu_fr[t0 + i*32], tmp[i]); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 32); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(addr_end, addr_end, 8); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte8_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vstd_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte8_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte8_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte8_len, t1, 3); ++ tcg_gen_andi_i64(byte8_len, byte8_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x7UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 24); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ } ++ tcg_gen_subfi_i64(byte8_len, 4, byte8_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte8_len, cpu_fr[t0 + i*32], tmp[i]); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 32); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 8); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEQ); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte8_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void tcg_gen_vcpys_i64(int ra, int rb, int rc) ++{ ++ int i; ++ TCGv tmp64 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 63); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vcpyse_i64(int ra, int rb, int rc) ++{ ++ int i; ++ ++ TCGv tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 52); ++ tcg_gen_shli_i64(tmp64, tmp64, 52); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x000fffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vcpysn_i64(int ra, int rb, int rc) ++{ ++ int i; ++ TCGv tmp64 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 63); ++ tcg_gen_not_i64(tmp64, tmp64); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vlogzz_i64(DisasContext *ctx, int opc, int ra, int rb, ++ int rc, int rd, int fn6) ++{ ++ TCGv zz; ++ TCGv args, vd; ++ zz = tcg_const_i64(((opc & 0x3) << 6) | fn6); ++ args = tcg_const_i64((ra << 16) | (rb << 8) | rc); ++ vd = tcg_const_i64(rd); ++ ++ gen_helper_vlogzz(cpu_env, args, vd, zz); ++ ++ tcg_temp_free(vd); ++ tcg_temp_free(args); ++ tcg_temp_free(zz); ++} ++ ++static void gen_qemu_vcmpxxw_i64(TCGCond cond, int ra, int rb, int rc) ++{ ++ TCGv va, vb, vc, tmp64; ++ int i; ++ ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32s_i64(vb, cpu_fr[rb + i]); ++ } else { ++ tcg_gen_ext32u_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(vb, cpu_fr[rb + i]); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_mov_i64(tmp64, vc); ++ ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_shri_i64(vb, cpu_fr[rb + i], 32); ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_ext32s_i64(vb, vb); ++ } else { ++ tcg_gen_ext32u_i64(va, va); ++ tcg_gen_ext32u_i64(vb, vb); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_shli_i64(vc, vc, 32); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++} ++ ++static void gen_qemu_vcmpxxwi_i64(TCGCond cond, int ra, int rb, int rc) ++{ ++ TCGv va, vb, vc, tmp64; ++ int i; ++ ++ va = tcg_temp_new(); ++ vb = tcg_const_i64(rb); ++ vc = tcg_temp_new(); ++ tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ } else { ++ tcg_gen_ext32u_i64(va, cpu_fr[ra + i]); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_mov_i64(tmp64, vc); ++ ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, va); ++ } else { ++ tcg_gen_ext32u_i64(va, va); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_shli_i64(vc, vc, 32); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++} ++ ++static void gen_qemu_vselxxw(TCGCond cond, int ra, int rb, int rc, int rd, ++ int mask) ++{ ++ int i; ++ ++ TCGv t0 = tcg_const_i64(0); ++ TCGv tmpa = tcg_temp_new(); ++ TCGv tmpb = tcg_temp_new(); ++ TCGv tmpc = tcg_temp_new(); ++ TCGv tmpd = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(tmpa, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(tmpb, cpu_fr[rb + i]); ++ tcg_gen_ext32u_i64(tmpc, cpu_fr[rc + i]); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, mask); ++ tcg_gen_movcond_i64(cond, tmpd, tmpa, t0, tmpb, tmpc); ++ ++ tcg_gen_andi_i64(tmpa, cpu_fr[ra + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpb, cpu_fr[rb + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpc, cpu_fr[rc + i], 0xffffffff00000000UL); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, (uint64_t)mask << 32); ++ tcg_gen_movcond_i64(cond, cpu_fr[rd + i], tmpa, t0, tmpb, tmpc); ++ ++ tcg_gen_or_i64(cpu_fr[rd + i], cpu_fr[rd + i], tmpd); ++ } ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(tmpa); ++ tcg_temp_free(tmpb); ++ tcg_temp_free(tmpc); ++ tcg_temp_free(tmpd); ++} ++ ++static void gen_qemu_vselxxwi(TCGCond cond, int ra, int rb, int disp8, int rd, ++ int mask) ++{ ++ int i; ++ ++ TCGv t0 = tcg_const_i64(0); ++ TCGv tmpa = tcg_temp_new(); ++ TCGv tmpb = tcg_temp_new(); ++ TCGv tmpc_0 = tcg_temp_new(); ++ TCGv tmpc_1 = tcg_temp_new(); ++ TCGv tmpd = tcg_temp_new(); ++ ++ tcg_gen_movi_i64(tmpc_0, (uint64_t)(((uint64_t)disp8))); ++ tcg_gen_movi_i64(tmpc_1, (uint64_t)(((uint64_t)disp8 << 32))); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(tmpa, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(tmpb, cpu_fr[rb + i]); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, mask); ++ tcg_gen_movcond_i64(cond, tmpd, tmpa, t0, tmpb, tmpc_0); ++ ++ tcg_gen_andi_i64(tmpa, cpu_fr[ra + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpb, cpu_fr[rb + i], 0xffffffff00000000UL); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, (uint64_t)mask << 32); ++ tcg_gen_movcond_i64(cond, cpu_fr[rd + i], tmpa, t0, tmpb, tmpc_1); ++ ++ tcg_gen_or_i64(cpu_fr[rd + i], cpu_fr[rd + i], tmpd); ++ } ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(tmpa); ++ tcg_temp_free(tmpb); ++ tcg_temp_free(tmpc_0); ++ tcg_temp_free(tmpc_1); ++ tcg_temp_free(tmpd); ++} ++ ++DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu) ++{ ++ int32_t disp5, disp8, disp12, disp13, disp16, disp21, disp26 __attribute__((unused)); ++ uint8_t opc, ra, rb, rc, rd; ++ uint16_t fn3, fn4, fn6, fn8, fn11; ++ int32_t i; ++ TCGv va, vb, vc, vd; ++ TCGv_i32 tmp32; ++ TCGv_i64 tmp64, tmp64_0, tmp64_1, shift; ++ TCGv_i32 tmpa, tmpb, tmpc; ++ DisasJumpType ret; ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ ++ opc = extract32(insn, 26, 6); ++ ra = extract32(insn, 21, 5); ++ rb = extract32(insn, 16, 5); ++ rc = extract32(insn, 0, 5); ++ rd = extract32(insn, 5, 5); ++ ++ fn3 = extract32(insn, 10, 3); ++ fn6 = extract32(insn, 10, 6); ++ fn4 = extract32(insn, 12, 4); ++ fn8 = extract32(insn, 5, 8); ++ fn11 = extract32(insn, 5, 11); ++ ++ disp5 = extract32(insn, 5, 5); ++ disp8 = extract32(insn, 13, 8); ++ disp12 = sextract32(insn, 0, 12); ++ disp13 = sextract32(insn, 13, 13); ++ disp16 = sextract32(insn, 0, 16); ++ disp21 = sextract32(insn, 0, 21); ++ disp26 = sextract32(insn, 0, 26); ++ ++ ret = DISAS_NEXT; ++ insn_profile(ctx, insn); ++ ++ switch (opc) { ++ case 0x00: ++ /* SYS_CALL */ ++ ret = gen_sys_call(ctx, insn & 0x1ffffff); ++ break; ++ case 0x01: ++ /* CALL */ ++ case 0x02: ++ /* RET */ ++ case 0x03: ++ /* JMP */ ++ vb = load_gir(ctx, rb); ++ tcg_gen_addi_i64(cpu_pc, vb, ctx->base.pc_next & 0x3); ++ if (ra != 31) { ++ tcg_gen_movi_i64(load_gir(ctx, ra), ctx->base.pc_next & (~3UL)); ++ } ++ ret = DISAS_PC_UPDATED; ++ break; ++ case 0x04: ++ /* BR */ ++ case 0x05: ++ /* BSR */ ++ ret = gen_bdirect(ctx, ra, disp21); ++ break; ++ case 0x06: ++ switch (disp16) { ++ case 0x0000: ++ /* MEMB */ ++ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); ++ break; ++ case 0x0001: ++ /* IMEMB */ ++ /* No achievement in Qemu*/ ++ break; ++ case 0x0020: ++ /* RTC */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ gen_helper_rtc(va); ++ break; ++ case 0x0040: ++ /* RCID */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(0xc4, va); ++ break; ++ case 0x0080: ++ /* HALT */ ++#ifndef CONFIG_USER_ONLY ++ { ++ tmp32 = tcg_const_i32(1); ++ tcg_gen_st_i32( ++ tmp32, cpu_env, ++ -offsetof(SW64CPU, env) + offsetof(CPUState, halted)); ++ tcg_temp_free_i32(tmp32); ++ } ++ ret = gen_excp(ctx, EXCP_HALTED, 0); ++#endif ++ break; ++ case 0x1000: ++ /* RD_F */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ tcg_gen_mov_i64(va, cpu_lock_success); ++ break; ++ case 0x1020: ++ /* WR_F */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ tcg_gen_andi_i64(cpu_lock_flag, va, 0x1); ++ break; ++ case 0x1040: ++ /* RTID */ ++ if (unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(0xc7, va); ++ break; ++ default: ++ if ((disp16 & 0xFF00) == 0xFE00) { ++ /* PRI_RCSR */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(disp16 & 0xff, va); ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFF00) { ++ /* PRI_WCSR */ ++ va = load_gir(ctx, ra); ++ write_csr(disp16 & 0xff, va, ctx->env); ++ break; ++ } ++ goto do_invalid; ++ } ++ break; ++ case 0x07: ++ /* PRI_RET */ ++ va = load_gir(ctx, ra); ++ tcg_gen_mov_i64(cpu_pc, va); ++ gen_helper_cpustate_update(cpu_env, va); ++ ret = DISAS_PC_UPDATED_NOCHAIN; ++ break; ++ case 0x08: ++ switch (fn4) { ++ case 0x0: ++ /* LLDW */ ++ gen_load_mem(ctx, &gen_qemu_lldw, ra, rb, disp12, 0, 0); ++ break; ++ case 0x1: ++ /* LLDL */ ++ gen_load_mem(ctx, &gen_qemu_lldl, ra, rb, disp12, 0, 0); ++ break; ++ case 0x2: ++ /* LDW_INC */ ++ ldx_xxx(ctx, ra, rb, disp12, 0, 1); ++ break; ++ case 0x3: ++ /* LDL_INC */ ++ ldx_xxx(ctx, ra, rb, disp12, 1, 1); ++ break; ++ case 0x4: ++ /* LDW_DEC */ ++ ldx_xxx(ctx, ra, rb, disp12, 0, -1); ++ break; ++ case 0x5: ++ /* LDL_DEC */ ++ ldx_xxx(ctx, ra, rb, disp12, 1, -1); ++ break; ++ case 0x6: ++ /* LDW_SET */ ++ ldx_set(ctx, ra, rb, disp12, 0); ++ break; ++ case 0x7: ++ /* LDL_SET */ ++ ldx_set(ctx, ra, rb, disp12, 1); ++ break; ++ case 0x8: ++ /* LSTW */ ++ ret = gen_store_conditional(ctx, ra, rb, disp12, ++ ctx->mem_idx, MO_LEUL); ++ break; ++ case 0x9: ++ /* LSTL */ ++ ret = gen_store_conditional(ctx, ra, rb, disp12, ++ ctx->mem_idx, MO_LEQ); ++ break; ++ case 0xa: ++ /* LDW_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xb: ++ /* LDL_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp12, 0, 0); ++ break; ++ case 0xc: ++ /* LDD_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp12, 1, 0); ++ break; ++ case 0xd: ++ /* STW_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xe: ++ /* STL_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xf: ++ /* STD_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp12, 1, ++ 0); ++ break; ++ default: ++ goto do_invalid; ++ } ++ break; ++ case 0x9: ++ /* LDWE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldwe, ra, rb, disp16, 0); ++ break; ++ case 0x0a: ++ /* LDSE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldse, ra, rb, disp16, 0); ++ break; ++ case 0x0b: ++ /* LDDE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldde, ra, rb, disp16, 0); ++ break; ++ case 0x0c: ++ /* VLDS */ ++ gen_load_mem_simd(ctx, &gen_qemu_vlds, ra, rb, disp16, 0); ++ break; ++ case 0x0d: ++ /* VLDD */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp16, 0); ++ break; ++ case 0x0e: ++ /* VSTS */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts, ra, rb, disp16, 0); ++ break; ++ case 0x0f: ++ /* VSTD */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp16, 0); ++ break; ++ case 0x10: ++ if (unlikely(rc == 31)) break; ++ if (fn11 == 0x70) { ++ /* FIMOVS */ ++ va = cpu_fr[ra]; ++ vc = load_gir(ctx, rc); ++ tmp32 = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp32, va); ++ tcg_gen_ext_i32_i64(vc, tmp32); ++ tcg_temp_free_i32(tmp32); ++ } else if (fn11 == 0x78) { ++ /* FIMOVD */ ++ va = cpu_fr[ra]; ++ vc = load_gir(ctx, rc); ++ tcg_gen_mov_i64(vc, va); ++ } else { ++ va = load_gir(ctx, ra); ++ vb = load_gir(ctx, rb); ++ vc = load_gir(ctx, rc); ++ cal_with_iregs_2(ctx, vc, va, vb, disp13, fn11); ++ } ++ break; ++ case 0x11: ++ if (unlikely(rc == 31)) break; ++ va = load_gir(ctx, ra); ++ vb = load_gir(ctx, rb); ++ vc = load_gir(ctx, rc); ++ vd = load_gir(ctx, rd); ++ cal_with_iregs_3(ctx, vc, va, vb, vd, fn3); ++ break; ++ case 0x12: ++ if (unlikely(rc == 31)) break; ++ va = load_gir(ctx, ra); ++ vc = load_gir(ctx, rc); ++ cal_with_imm_2(ctx, vc, va, disp8, fn8); ++ break; ++ case 0x13: ++ if (rc == 31) /* Special deal */ ++ break; ++ va = load_gir(ctx, ra); ++ vc = load_gir(ctx, rc); ++ vd = load_gir(ctx, rd); ++ cal_with_imm_3(ctx, vc, va, disp8, vd, fn3); ++ break; ++ case 0x14: ++ case 0x15: ++ case 0x16: ++ case 0x17: ++ /* VLOGZZ */ ++ tcg_gen_vlogzz_i64(ctx, opc, ra, rb, rd, rc, fn6); ++ break; ++ case 0x18: ++ if (unlikely(rc == 31)) break; ++ cal_with_fregs_2(ctx, rc, ra, rb, fn8); ++ break; ++ case 0x19: ++ if (unlikely(rc == 31)) break; ++ cal_with_fregs_4(ctx, rc, ra, rb, rd, fn6); ++ break; ++ case 0x1A: ++ /* SIMD */ ++ if (unlikely(rc == 31)) break; ++ switch (fn8) { ++ case 0x00: ++ /* VADDW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], 0xffffffffUL); ++ tcg_gen_add_i64(tmp64, va, vb); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], ++ 0xffffffff00000000UL); ++ tcg_gen_add_i64(vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x20: ++ /* VADDW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_addi_i64(tmp64, va, disp8); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_addi_i64(vc, va, ((uint64_t)disp8 << 32)); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x01: ++ /* VSUBW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], 0xffffffffUL); ++ tcg_gen_sub_i64(tmp64, va, vb); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], ++ 0xffffffff00000000UL); ++ tcg_gen_sub_i64(vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x21: ++ /* VSUBW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_subi_i64(tmp64, va, disp8); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_subi_i64(vc, va, ((uint64_t)disp8 << 32)); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x02: ++ /* VCMPGEW */ ++ tmp64 = tcg_const_i64(0); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32s_i64(vb, cpu_fr[rb + i]); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_shri_i64(vb, cpu_fr[rb + i], 32); ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_ext32s_i64(vb, vb); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x22: ++ /* VCMPGEW */ ++ tmp64 = tcg_const_i64(0); ++ va = tcg_temp_new(); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x03: ++ /* VCMPEQW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_EQ, ra, rb, rc); ++ break; ++ case 0x23: ++ /* VCMPEQW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_EQ, ra, disp8, rc); ++ break; ++ case 0x04: ++ /* VCMPLEW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LE, ra, rb, rc); ++ break; ++ case 0x24: ++ /* VCMPLEW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LE, ra, disp8, rc); ++ break; ++ case 0x05: ++ /* VCMPLTW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LT, ra, rb, rc); ++ break; ++ case 0x25: ++ /* VCMPLTW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LT, ra, disp8, rc); ++ break; ++ case 0x06: ++ /* VCMPULEW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LEU, ra, rb, rc); ++ break; ++ case 0x26: ++ /* VCMPULEW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LEU, ra, disp8, rc); ++ break; ++ case 0x07: ++ /* VCMPULTW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LTU, ra, rb, rc); ++ break; ++ case 0x27: ++ /* VCMPULTW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LTU, ra, disp8, rc); ++ break; ++ case 0x08: ++ /* VSLLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_shl_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_ext32u_i64(tmp64, vc); ++ ++ tcg_gen_andi_i64(vc, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_shl_i64(vc, vc, shift); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x28: ++ /* VSLLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_shl_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_ext32u_i64(tmp64, vc); ++ ++ tcg_gen_andi_i64(vc, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_shl_i64(vc, vc, shift); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x09: ++ /* VSRLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_ext32u_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_shr_i64(tmp64, vc, shift); ++ ++ tcg_gen_shr_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x29: ++ /* VSRLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_ext32u_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_shr_i64(tmp64, vc, shift); ++ ++ tcg_gen_shr_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0A: ++ /* VSRAW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_ext32s_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_sar_i64(tmp64, vc, shift); ++ ++ tcg_gen_sar_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x2A: ++ /* VSRAWI */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_ext32s_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_sar_i64(tmp64, vc, shift); ++ ++ tcg_gen_sar_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0B: ++ /* VROLW */ ++ tmpa = tcg_temp_new_i32(); ++ tmpb = tcg_temp_new_i32(); ++ tmpc = tcg_temp_new_i32(); ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_extrl_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_extrl_i64_i32(tmpb, shift); ++ ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(tmp64, tmpc); ++ ++ tcg_gen_extrh_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(vc, tmpc); ++ tcg_gen_shli_i64(vc, vc, 32); ++ ++ tcg_gen_or_i64(cpu_fr[rc + i], vc, tmp64); ++ } ++ tcg_temp_free_i32(tmpa); ++ tcg_temp_free_i32(tmpb); ++ tcg_temp_free_i32(tmpc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x2B: ++ /* VROLW */ ++ tmpa = tcg_temp_new_i32(); ++ tmpb = tcg_temp_new_i32(); ++ tmpc = tcg_temp_new_i32(); ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_extrl_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_extrl_i64_i32(tmpb, shift); ++ ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(tmp64, tmpc); ++ ++ tcg_gen_extrh_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(vc, tmpc); ++ tcg_gen_shli_i64(vc, vc, 32); ++ ++ tcg_gen_or_i64(cpu_fr[rc + i], vc, tmp64); ++ } ++ tcg_temp_free_i32(tmpa); ++ tcg_temp_free_i32(tmpb); ++ tcg_temp_free_i32(tmpc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0C: ++ /* SLLOW */ ++ tcg_gen_sllow_i64(ra, rc, rb); ++ break; ++ case 0x2C: ++ /* SLLOW */ ++ tcg_gen_sllowi_i64(ra, rc, disp8); ++ break; ++ case 0x0D: ++ /* SRLOW */ ++ tcg_gen_srlow_i64(ra, rc, rb); ++ break; ++ case 0x2D: ++ /* SRLOW */ ++ tcg_gen_srlowi_i64(ra, rc, disp8); ++ break; ++ case 0x0E: ++ /* VADDL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_add_i64(cpu_fr[rc + i], cpu_fr[ra + i], ++ cpu_fr[rb + i]); ++ } ++ break; ++ case 0x2E: ++ /* VADDL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_addi_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8); ++ } ++ break; ++ case 0x0F: ++ /* VSUBL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_sub_i64(cpu_fr[rc + i], cpu_fr[ra + i], ++ cpu_fr[rb + i]); ++ } ++ break; ++ case 0x2F: ++ /* VSUBL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_subi_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8); ++ } ++ break; ++ case 0x18: ++ /* CTPOPOW */ ++ tmp64 = tcg_const_i64(0); ++ tmp64_0 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ctpop_i64(tmp64_0, cpu_fr[ra + i]); ++ tcg_gen_add_i64(tmp64, tmp64, tmp64_0); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x19: ++ /* CTLZOW */ ++ va = tcg_const_i64(ra); ++ gen_helper_ctlzow(cpu_fr[rc], cpu_env, va); ++ tcg_temp_free(va); ++ break; ++ case 0x40: ++ /* VUCADDW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddw(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x60: ++ /* VUCADDW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddwi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x41: ++ /* VUCSUBW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubw(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x61: ++ /* VUCSUBW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubwi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x42: ++ /* VUCADDH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddh(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x62: ++ /* VUCADDH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddhi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x43: ++ /* VUCSUBH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubh(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x63: ++ /* VUCSUBH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubhi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x44: ++ /* VUCADDB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddb(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x64: ++ /* VUCADDB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddbi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x45: ++ /* VUCSUBB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubb(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x65: ++ /* VUCSUBB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubbi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x80: ++ /* VADDS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fadds(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x81: ++ /* VADDD */ ++ for (i = 0; i < 128; i += 32) ++ gen_faddd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x82: ++ /* VSUBS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fsubs(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x83: ++ /* VSUBD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fsubd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x84: ++ /* VMULS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fmuls(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x85: ++ /* VMULD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fmuld(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x86: ++ /* VDIVS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fdivs(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x87: ++ /* VDIVD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fdivd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x88: ++ /* VSQRTS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fsqrts(cpu_fr[rc + i], cpu_env, ++ cpu_fr[rb + i]); ++ break; ++ case 0x89: ++ /* VSQRTD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fsqrt(cpu_fr[rc + i], cpu_env, ++ cpu_fr[rb + i]); ++ break; ++ case 0x8C: ++ /* VFCMPEQ */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmpeq(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8D: ++ /* VFCMPLE */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmple(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8E: ++ /* VFCMPLT */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmplt(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8F: ++ /* VFCMPUN */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmpun(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x90: ++ /* VCPYS */ ++ tcg_gen_vcpys_i64(ra, rb, rc); ++ break; ++ case 0x91: ++ /* VCPYSE */ ++ tcg_gen_vcpyse_i64(ra, rb, rc); ++ break; ++ case 0x92: ++ /* VCPYSN */ ++ tcg_gen_vcpysn_i64(ra, rb, rc); ++ break; ++ case 0x93: ++ /* VSUMS */ ++ gen_fadds(ctx, ra, ra + 32, rc); ++ gen_fadds(ctx, rc, ra + 64, rc); ++ gen_fadds(ctx, rc, ra + 96, rc); ++ break; ++ case 0x94: ++ /* VSUMD */ ++ gen_faddd(ctx, ra, ra + 32, rc); ++ gen_faddd(ctx, rc, ra + 64, rc); ++ gen_faddd(ctx, rc, ra + 96, rc); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn8); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x1B: ++ /* SIMD */ ++ if (unlikely(rc == 31)) break; ++ switch (fn6) { ++ case 0x00: ++ /* VMAS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmas(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x01: ++ /* VMAD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmad(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x02: ++ /* VMSS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmss(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x03: ++ /* VMSD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmsd(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x04: ++ /* VNMAS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmas(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x05: ++ /* VNMAD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmad(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x06: ++ /* VNMSS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmss(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x07: ++ /* VNMSD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmsd(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x10: ++ /* VFSELEQ */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ for (i = 0; i < 128; i += 32) { ++ gen_helper_fcmpeq(tmp64, cpu_env, cpu_fr[ra + i], ++ tmp64_0); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x12: ++ /* VFSELLT */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ tmp64_1 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(tmp64, cpu_fr[ra + i], ++ 0x7fffffffffffffffUL); ++ tcg_gen_setcond_i64(TCG_COND_NE, tmp64, tmp64, ++ tmp64_0); ++ tcg_gen_shri_i64(tmp64_1, cpu_fr[ra +i], 63); ++ tcg_gen_and_i64(tmp64, tmp64_1, tmp64); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64_1); ++ break; ++ case 0x13: ++ /* VFSELLE */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ tmp64_1 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(tmp64, cpu_fr[ra + i], ++ 0x7fffffffffffffffUL); ++ tcg_gen_setcond_i64(TCG_COND_EQ, tmp64, tmp64, ++ tmp64_0); ++ tcg_gen_shri_i64(tmp64_1, cpu_fr[ra + i], 63); ++ tcg_gen_or_i64(tmp64, tmp64_1, tmp64); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64_1); ++ break; ++ case 0x18: ++ /* VSELEQW */ ++ gen_qemu_vselxxw(TCG_COND_EQ, ra, rb, rd, rc, 0); ++ break; ++ case 0x38: ++ /* VSELEQW */ ++ gen_qemu_vselxxwi(TCG_COND_EQ, ra, rb, disp5, rc, 0); ++ break; ++ case 0x19: ++ /* VSELLBCW */ ++ gen_qemu_vselxxw(TCG_COND_EQ, ra, rb, rd, rc, 1); ++ break; ++ case 0x39: ++ /* VSELLBCW */ ++ gen_qemu_vselxxwi(TCG_COND_EQ, ra, rb, disp5, rc, 1); ++ break; ++ case 0x1A: ++ /* VSELLTW */ ++ gen_qemu_vselxxw(TCG_COND_LT, ra, rb, rd, rc, 0); ++ break; ++ case 0x3A: ++ /* VSELLTW */ ++ gen_qemu_vselxxwi(TCG_COND_LT, ra, rb, disp5, rc, 0); ++ break; ++ case 0x1B: ++ /* VSELLEW */ ++ gen_qemu_vselxxw(TCG_COND_LE, ra, rb, rd, rc, 0); ++ break; ++ case 0x3B: ++ /* VSELLEW */ ++ gen_qemu_vselxxwi(TCG_COND_LE, ra, rb, disp5, rc, 0); ++ break; ++ case 0x20: ++ /* VINSW */ ++ if (disp5 > 7) break; ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp32, cpu_fr[ra]); ++ tcg_gen_extu_i32_i64(tmp64, tmp32); ++ tcg_gen_shli_i64(tmp64, tmp64, (disp5 % 2) * 32); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[rb + i]); ++ } ++ if (disp5 % 2) { ++ tcg_gen_andi_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], ++ 0xffffffffUL); ++ } else { ++ tcg_gen_andi_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], ++ 0xffffffff00000000UL); ++ } ++ tcg_gen_or_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], tmp64); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x21: ++ /* VINSF */ ++ if (disp5 > 3) break; ++ tmp64 = tcg_temp_new(); ++ tcg_gen_mov_i64(tmp64, cpu_fr[ra]); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[rb + i]); ++ } ++ tcg_gen_mov_i64(cpu_fr[rc + disp5 * 32], tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x22: ++ /* VEXTW */ ++ if (disp5 > 7) break; ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + (disp5 / 2) * 32], ++ (disp5 % 2) * 32); ++ tcg_gen_extrl_i64_i32(tmp32, tmp64); ++ gen_helper_memory_to_s(tmp64, tmp32); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x23: ++ /* VEXTF */ ++ if (disp5 > 3) break; ++ tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra + disp5 * 32]); ++ break; ++ case 0x24: ++ /* VCPYW */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_temp_new(); ++ /* FIXME: for debug ++ tcg_gen_movi_i64(tmp64, ra); ++ gen_helper_v_print(cpu_env, tmp64); ++ */ ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 29); ++ tcg_gen_andi_i64(tmp64_0, tmp64, 0x3fffffffUL); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 62); ++ tcg_gen_shli_i64(tmp64, tmp64, 30); ++ tcg_gen_or_i64(tmp64_0, tmp64, tmp64_0); ++ tcg_gen_mov_i64(tmp64, tmp64_0); ++ tcg_gen_shli_i64(tmp64, tmp64, 32); ++ tcg_gen_or_i64(tmp64_0, tmp64_0, tmp64); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64_0); ++ tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); ++ tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); ++ tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); ++ /* FIXME: for debug ++ tcg_gen_movi_i64(tmp64, rb); ++ gen_helper_v_print(cpu_env, tmp64); ++ tcg_gen_movi_i64(tmp64, rc); ++ gen_helper_v_print(cpu_env, tmp64); ++ */ ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x25: ++ /* VCPYF */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[ra]); ++ } ++ break; ++ case 0x26: ++ /* VCONW */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x7ul); ++ gen_helper_vconw(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x27: ++ /* VSHFW */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ vd = tcg_const_i64(rc); ++ gen_helper_vshfw(cpu_env, tmp64, vd, cpu_fr[rd]); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x28: ++ /* VCONS */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); ++ gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x29: ++ /* FIXME: VCOND maybe it's wrong in the instruction book ++ * that there are no temp. */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 3); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); ++ gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn6); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x1C: ++ switch (fn4) { ++ case 0x0: ++ /* VLDW_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x1: ++ /* VSTW_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x2: ++ /* VLDS_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vlds, ra, rb, disp12, ++ ~0xfUL); ++ break; ++ case 0x3: ++ /* VSTS_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts, ra, rb, disp12, ++ ~0xfUL); ++ break; ++ case 0x4: ++ /* VLDD_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x5: ++ /* VSTD_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x8: ++ /* VSTW_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstw_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0x9: ++ /* VSTW_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstw_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xa: ++ /* VSTS_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0xb: ++ /* VSTS_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xc: ++ /* VSTD_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0xd: ++ /* VSTD_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xe: ++ /* VLDD_NC */ ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, 0); ++ break; ++ case 0xf: ++ /* VSTD_NC */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, 0); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn4); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x20: ++ /* LDBU */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0); ++ break; ++ case 0x21: ++ /* LDHU */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0); ++ break; ++ case 0x22: ++ /* LDW */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0); ++ break; ++ case 0x23: ++ /* LDL */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0); ++ break; ++ case 0x24: ++ /* LDL_U */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1); ++ break; ++ case 0x25: ++ /* PRI_LD */ ++#ifndef CONFIG_USER_ONLY ++ if ((insn >> 12) & 1) { ++ gen_load_mem(ctx, &gen_qemu_pri_ldl, ra, rb, disp12, 0, 1); ++ } else { ++ gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, 1); ++ } ++#endif ++ break; ++ case 0x26: ++ /* FLDS */ ++ gen_load_mem(ctx, &gen_qemu_flds, ra, rb, disp16, 1, 0); ++ break; ++ case 0x27: ++ /* FLDD */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0); ++ break; ++ case 0x28: ++ /* STB */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0); ++ break; ++ case 0x29: ++ /* STH */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2a: ++ /* STW */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2b: ++ /* STL */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2c: ++ /* STL_U */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1); ++ break; ++ case 0x2d: ++ /* PRI_ST */ ++#ifndef CONFIG_USER_ONLY ++ if ((insn >> 12) & 1) { ++ gen_store_mem(ctx, &gen_qemu_pri_stl, ra, rb, disp12, 0, 1); ++ } else { ++ gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, 1); ++ } ++#endif ++ break; ++ case 0x2e: ++ /* FSTS */ ++ gen_store_mem(ctx, &gen_qemu_fsts, ra, rb, disp16, 1, 0); ++ break; ++ case 0x2f: ++ /* FSTD */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0); ++ break; ++ case 0x30: ++ /* BEQ */ ++ ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x31: ++ /* BNE */ ++ ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x32: ++ /* BLT */ ++ ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x33: ++ /* BLE */ ++ ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x34: ++ /* BGT */ ++ ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x35: ++ /* BGE */ ++ ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x36: ++ /* BLBC */ ++ ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1); ++ break; ++ case 0x37: ++ /* BLBS */ ++ ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1); ++ break; ++ case 0x38: ++ /* FBEQ */ ++ ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21); ++ break; ++ case 0x39: ++ /* FBNE */ ++ ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21); ++ break; ++ case 0x3a: ++ /* FBLT */ ++ ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21); ++ break; ++ case 0x3b: ++ /* FBLE */ ++ ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21); ++ break; ++ case 0x3c: ++ /* FBGT */ ++ ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21); ++ break; ++ case 0x3d: ++ /* FBGE */ ++ ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21); ++ break; ++ case 0x3f: ++ /* LDIH */ ++ disp16 = ((uint32_t)disp16) << 16; ++ if (ra == 31) break; ++ va = load_gir(ctx, ra); ++ if (rb == 31) { ++ tcg_gen_movi_i64(va, disp16); ++ } else { ++ tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); ++ } ++ break; ++ case 0x3e: ++ /* LDI */ ++ if (ra == 31) break; ++ va = load_gir(ctx, ra); ++ if (rb == 31) { ++ tcg_gen_movi_i64(va, disp16); ++ } else { ++ tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); ++ } ++ break; ++ do_invalid: ++ default: ++ printf("ILLEGAL BELOW OPC[%x] insn[%08x]\n", opc, insn); ++ ret = gen_invalid(ctx); ++ } ++ return ret; ++} ++static void sw64_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ CPUSW64State* env = cpu->env_ptr; /*init by instance_initfn*/ ++ ++ ctx->tbflags = ctx->base.tb->flags; ++ ctx->mem_idx = cpu_mmu_index(env, false); ++#ifdef CONFIG_USER_ONLY ++ ctx->ir = cpu_std_ir; ++#else ++ ctx->ir = (ctx->tbflags & ENV_FLAG_HM_MODE ? cpu_hm_ir : cpu_std_ir); ++#endif ++ ctx->zero = NULL; ++} ++ ++static void sw64_tr_tb_start(DisasContextBase *db, CPUState *cpu) ++{ ++} ++ ++static void sw64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ tcg_gen_insn_start(dcbase->pc_next); ++} ++ ++static void sw64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ CPUSW64State *env = cpu->env_ptr; ++ uint32_t insn; ++ ++ insn = cpu_ldl_code(env, ctx->base.pc_next & (~3UL)); ++ ctx->env = env; ++ ctx->base.pc_next += 4; ++ ctx->base.is_jmp = ctx->translate_one(dcbase, insn, cpu); ++ ++ free_context_temps(ctx); ++ translator_loop_temp_check(&ctx->base); ++} ++ ++/* FIXME:Linhainan */ ++static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ ++ switch (ctx->base.is_jmp) { ++ case DISAS_NORETURN: ++ break; ++ case DISAS_TOO_MANY: ++ if (use_goto_tb(ctx, ctx->base.pc_next)) { ++ tcg_gen_goto_tb(0); ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ tcg_gen_exit_tb(ctx->base.tb, 0); ++ } ++ /* FALLTHRU */ ++ case DISAS_PC_STALE: ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ /* FALLTHRU */ ++ case DISAS_PC_UPDATED: ++ if (!use_exit_tb(ctx)) { ++ tcg_gen_lookup_and_goto_ptr(); ++ break; ++ } ++ /* FALLTHRU */ ++ case DISAS_PC_UPDATED_NOCHAIN: ++ if (ctx->base.singlestep_enabled) { ++ /* FIXME: for gdb*/ ++ cpu_loop_exit(cpu); ++ } else { ++ tcg_gen_exit_tb(NULL, 0); ++ } ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void sw64_tr_disas_log(const DisasContextBase* dcbase, CPUState* cpu) { ++ SW64CPU* sc = SW64_CPU(cpu); ++ qemu_log("IN(%d): %s\n", sc->cid, ++ lookup_symbol(dcbase->pc_first)); ++ log_target_disas(cpu, dcbase->pc_first & (~0x3UL), dcbase->tb->size); ++} ++ ++static void init_transops(CPUState *cpu, DisasContext *dc) ++{ ++ dc->translate_one = translate_one; ++} ++ ++void restore_state_to_opc(CPUSW64State* env, TranslationBlock* tb, ++ target_ulong* data) { ++ env->pc = data[0]; ++} ++ ++static const TranslatorOps sw64_trans_ops = { ++ .init_disas_context = sw64_tr_init_disas_context, ++ .tb_start = sw64_tr_tb_start, ++ .insn_start = sw64_tr_insn_start, ++ .translate_insn = sw64_tr_translate_insn, ++ .tb_stop = sw64_tr_tb_stop, ++ .disas_log = sw64_tr_disas_log, ++}; ++ ++void gen_intermediate_code(CPUState* cpu, TranslationBlock* tb, int max_insns) ++{ ++ DisasContext dc; ++ init_transops(cpu, &dc); ++ translator_loop(&sw64_trans_ops, &dc.base, cpu, tb, max_insns); ++} +diff --git a/target/sw64/translate.h b/target/sw64/translate.h +new file mode 100644 +index 0000000000..e93df0815e +--- /dev/null ++++ b/target/sw64/translate.h +@@ -0,0 +1,60 @@ ++#ifndef SW64_TRANSLATE_H ++#define SW64_TRANSLATE_H ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "sysemu/cpus.h" ++#include "disas/disas.h" ++#include "qemu/host-utils.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "tcg/tcg-op.h" ++#include "exec/helper-proto.h" ++#include "exec/helper-gen.h" ++#include "trace-tcg.h" ++#include "exec/translator.h" ++#include "exec/log.h" ++ ++#define DISAS_PC_UPDATED_NOCHAIN DISAS_TARGET_0 ++#define DISAS_PC_UPDATED DISAS_TARGET_1 ++#define DISAS_PC_STALE DISAS_TARGET_2 ++#define DISAS_PC_UPDATED_T DISAS_TOO_MANY ++ ++typedef struct DisasContext DisasContext; ++struct DisasContext { ++ DisasContextBase base; ++ ++ uint32_t tbflags; ++ ++ /* The set of registers active in the current context. */ ++ TCGv *ir; ++ ++ /* Accel: Temporaries for $31 and $f31 as source and destination. */ ++ TCGv zero; ++ int mem_idx; ++ CPUSW64State *env; ++ DisasJumpType (*translate_one)(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++}; ++ ++extern TCGv cpu_pc; ++extern TCGv cpu_std_ir[31]; ++extern TCGv cpu_fr[128]; ++extern TCGv cpu_lock_addr; ++extern TCGv cpu_lock_flag; ++extern TCGv cpu_lock_success; ++#ifdef SW64_FIXLOCK ++extern TCGv cpu_lock_value; ++#endif ++#ifndef CONFIG_USER_ONLY ++extern TCGv cpu_hm_ir[31]; ++#endif ++ ++DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++DisasJumpType th1_translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++bool use_exit_tb(DisasContext *ctx); ++bool use_goto_tb(DisasContext *ctx, uint64_t dest); ++void insn_profile(DisasContext *ctx, uint32_t insn); ++extern void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src); ++#endif +diff --git a/tcg/sw64/tcg-target-con-set.h b/tcg/sw64/tcg-target-con-set.h +new file mode 100755 +index 0000000000..71fdfdcbef +--- /dev/null ++++ b/tcg/sw64/tcg-target-con-set.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Define SW_64 target-specific constraint sets. ++ * Copyright (c) 2021 Linaro ++ */ ++ ++/* ++ * C_On_Im(...) defines a constraint set with outputs and inputs. ++ * Each operand should be a sequence of constraint letters as defined by ++ * tcg-target-con-str.h; the constraint combination is inclusive or. ++ */ ++C_O0_I1(r) ++C_O0_I2(lZ, l) ++C_O0_I2(r, rA) ++C_O0_I2(rZ, r) ++C_O0_I2(w, r) ++C_O1_I1(r, l) ++C_O1_I1(r, r) ++C_O1_I1(w, r) ++C_O1_I1(w, w) ++C_O1_I1(w, wr) ++C_O1_I2(r, 0, rZ) ++C_O1_I2(r, r, r) ++C_O1_I2(r, r, rA) ++C_O1_I2(r, r, rAL) ++C_O1_I2(r, r, ri) ++C_O1_I2(r, r, rL) ++C_O1_I2(r, rZ, rZ) ++C_O1_I2(w, 0, w) ++C_O1_I2(w, w, w) ++C_O1_I2(w, w, wN) ++C_O1_I2(w, w, wO) ++C_O1_I2(w, w, wZ) ++C_O1_I3(w, w, w, w) ++C_O1_I4(r, r, rA, rZ, rZ) ++C_O2_I4(r, r, rZ, rZ, rA, rMZ) ++C_O1_I4(r, r, rU, rZ, rZ) ++C_O0_I2(r, rU) ++C_O1_I2(r, r, rU) +diff --git a/tcg/sw64/tcg-target-con-str.h b/tcg/sw64/tcg-target-con-str.h +new file mode 100755 +index 0000000000..47edb3837b +--- /dev/null ++++ b/tcg/sw64/tcg-target-con-str.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Define sw_64 target-specific operand constraints. ++ * Copyright (c) 2021 Linaro ++ */ ++ ++/* ++ * Define constraint letters for register sets: ++ * REGS(letter, register_mask) ++ */ ++REGS('r', ALL_GENERAL_REGS) ++REGS('l', ALL_QLDST_REGS) ++REGS('w', ALL_VECTOR_REGS) ++ ++/* ++ * Define constraint letters for constants: ++ * CONST(letter, TCG_CT_CONST_* bit set) ++ */ ++ ++CONST('Z', TCG_CT_CONST_ZERO) ++CONST('A', TCG_CT_CONST_LONG) ++CONST('M', TCG_CT_CONST_MONE) ++CONST('O', TCG_CT_CONST_ORRI) ++CONST('W', TCG_CT_CONST_WORD) ++CONST('L', TCG_CT_CONST_LONG) ++CONST('U', TCG_CT_CONST_U8) ++CONST('S', TCG_CT_CONST_S8) ++ +diff --git a/tcg/sw64/tcg-target.c.inc b/tcg/sw64/tcg-target.c.inc +new file mode 100755 +index 0000000000..982f159e23 +--- /dev/null ++++ b/tcg/sw64/tcg-target.c.inc +@@ -0,0 +1,2109 @@ ++/* ++ * Initial TCG Implementation for sw_64 ++ * ++ */ ++ ++#include "../tcg-pool.c.inc" ++#include "qemu/bitops.h" ++ ++/* We're going to re-use TCGType in setting of the SF bit, which controls ++ the size of the operation performed. If we know the values match, it ++ makes things much cleaner. */ ++QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1); ++static const tcg_insn_unit *tb_ret_addr; ++ ++#ifdef CONFIG_DEBUG_TCG ++static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ++ "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", ++ "X8", "X9", "X10", "X11", "X12", "X13", "X14", "fp", ++ "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", ++ "X24", "X25", "X26", "X27", "X28", "X29", "Xsp", "X31", ++ ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", ++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", ++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", ++}; ++#endif /* CONFIG_DEBUG_TCG */ ++ ++static const int tcg_target_reg_alloc_order[] = { ++ /* TCG_REG_X9 qemu saved for AREG0*/ ++ TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, ++ ++ TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, ++ TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, ++ ++ TCG_REG_X22, TCG_REG_X23, TCG_REG_X24, /*TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, */ ++ ++ /* TCG_REG_SP=TCG_REG_X15 saved for system*/ ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, TCG_REG_X28, /* TCG_REG_X29, TCG_REG_X30, TCG_REG_X31 */ ++ ++ /* TCG_REG_TMP=TCG_REG_X27 reserved as temporary register */ ++ /* TCG_REG_TMP2=TCG_REG_X25 reserved as temporary register */ ++ /* TCG_REG_RA=TCG_REG_X26 reserved as temporary */ ++ /* TCG_REG_GP=TCG_REG_X29 gp saved for system*/ ++ /* TCG_REG_SP=TCG_REG_X30 sp saved for system*/ ++ /* TCG_REG_ZERO=TCG_REG_X31 zero saved for system*/ ++ ++ TCG_REG_F2, TCG_REG_F3, TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, TCG_REG_F8, TCG_REG_F9, /* f2-f9 saved registers */ ++ /* TCG_VEC_TMP=TCG_REG_F10, TCG_VEC_TMP2=TCG_REG_F11, are saved as temporary */ ++ TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, /* f10-f15 temporary registers */ ++ ++ TCG_REG_F22, TCG_REG_F23, TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, /* f22-f30 temporary registers */ ++ /* TCG_REG_F31, zero saved for system */ ++ ++ TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, TCG_REG_F20, TCG_REG_F21, /* input args */ ++ ++ TCG_REG_F0, TCG_REG_F1, /*output args */ ++}; ++ ++static const int tcg_target_call_iarg_regs[6] = { ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, ++}; ++static const int tcg_target_call_oarg_regs[1] = { ++ TCG_REG_X0, ++}; ++ ++#define TCG_REG_TMP TCG_REG_X27 ++#define TCG_REG_TMP2 TCG_REG_X25 ++#define TCG_FLOAT_TMP TCG_REG_F10 ++#define TCG_FLOAT_TMP2 TCG_REG_F11 ++ ++#define ALL_GENERAL_REGS 0xffffffffu ++#define ALL_QLDST_REGS ALL_GENERAL_REGS ++#define PUSH_SIZE ((15-9+1+1) * 8) ++#define FRAME_SIZE \ ++ ((PUSH_SIZE \ ++ + TCG_STATIC_CALL_ARGS_SIZE \ ++ + CPU_TEMP_BUF_NLONGS * sizeof(long) \ ++ + TCG_TARGET_STACK_ALIGN - 1) \ ++ & ~(TCG_TARGET_STACK_ALIGN - 1)) ++ ++/* We encode the format of the insn into the beginning of the name, so that ++ we can have the preprocessor help "typecheck" the insn vs the output ++ function. We don't have nice names for the formats, so we use the section ++ number of the architecture reference manual in which the instruction ++ group is described. */ ++#define OPC_OP(x) ((x & 0x3f) << 26) ++#define OPC_FUNC(x) ((x & 0xff) << 5) ++#define OPC_FUNC_COMPLEX(x) ((x & 0xff) << 10) ++typedef enum { ++ OPC_NOP =0X43ff075f, ++ OPC_SYS_CALL =OPC_OP(0x00), ++ OPC_CALL =OPC_OP(0x01), ++ OPC_RET =OPC_OP(0x02), ++ OPC_JMP =OPC_OP(0x03), ++ OPC_BR =OPC_OP(0x04), ++ OPC_BSR =OPC_OP(0x05), ++ OPC_PRI_RET =OPC_OP(0x07), ++ OPC_LDWE =OPC_OP(0x09), ++ OPC_LDSE =OPC_OP(0x0A), ++ OPC_LDDE =OPC_OP(0x0B), ++ OPC_VLDS =OPC_OP(0x0C), ++ OPC_VLDD =OPC_OP(0x0D), ++ OPC_VSTS =OPC_OP(0x0E), ++ OPC_VSTD =OPC_OP(0x0F), ++ ++ OPC_LDBU =OPC_OP(0x20), ++ OPC_LDHU =OPC_OP(0x21), ++ OPC_LDW =OPC_OP(0x22), ++ OPC_LDL =OPC_OP(0x23), ++ OPC_LDL_U =OPC_OP(0x24), ++ OPC_FLDS =OPC_OP(0X26), ++ OPC_PRI_LD =OPC_OP(0x25), ++ OPC_FLDD =OPC_OP(0X27), ++ OPC_STB =OPC_OP(0X28), ++ OPC_STH =OPC_OP(0x29), ++ OPC_STW =OPC_OP(0x2a), ++ OPC_STL =OPC_OP(0x2B), ++ OPC_STL_U =OPC_OP(0x2C), ++ OPC_PRI_ST =OPC_OP(0x2D), ++ OPC_FSTS =OPC_OP(0x2E), ++ OPC_FSTD =OPC_OP(0x2F), ++ ++ OPC_BEQ =OPC_OP(0x30), ++ OPC_BNE =OPC_OP(0x31), ++ OPC_BLT =OPC_OP(0x32), ++ OPC_BLE =OPC_OP(0x33), ++ OPC_BGT =OPC_OP(0x34), ++ OPC_BGE =OPC_OP(0x35), ++ OPC_BLBC =OPC_OP(0x36), ++ OPC_BLBS =OPC_OP(0x37), ++ ++ OPC_FBEQ =OPC_OP(0x38), ++ OPC_FBNE =OPC_OP(0x39), ++ OPC_FBLT =OPC_OP(0x3A), ++ OPC_FBLE =OPC_OP(0x3B), ++ OPC_FBGT =OPC_OP(0x3C), ++ OPC_FBGE =OPC_OP(0x3D), ++ OPC_LDI =OPC_OP(0x3E), ++ OPC_LDIH =OPC_OP(0x3F), ++ ++ OPC_ADDW =(OPC_OP(0x10) | OPC_FUNC(0x0)), ++ OPC_ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x0)), ++ OPC_SUBW =(OPC_OP(0x10) | OPC_FUNC(0x1)), ++ OPC_SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x1)), ++ OPC_S4ADDW =(OPC_OP(0x10) | OPC_FUNC(0x02)), ++ OPC_S4ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x02)), ++ OPC_S4SUBW =(OPC_OP(0x10) | OPC_FUNC(0x03)), ++ OPC_S4SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x03)), ++ ++ OPC_S8ADDW =(OPC_OP(0x10) | OPC_FUNC(0x04)), ++ OPC_S8ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x04)), ++ OPC_S8SUBW =(OPC_OP(0x10) | OPC_FUNC(0x05)), ++ OPC_S8SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x05)), ++ ++ OPC_ADDL =(OPC_OP(0x10) | OPC_FUNC(0x8)), ++ OPC_ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0x8)), ++ OPC_SUBL =(OPC_OP(0x10) | OPC_FUNC(0x9)), ++ OPC_SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0x9)), ++ ++ OPC_S4ADDL =(OPC_OP(0x10) | OPC_FUNC(0xA)), ++ OPC_S4ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xA)), ++ OPC_S4SUBL =(OPC_OP(0x10) | OPC_FUNC(0xB)), ++ OPC_S4SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xB)), ++ ++ OPC_S8ADDL =(OPC_OP(0x10) | OPC_FUNC(0xC)), ++ OPC_S8ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xC)), ++ OPC_S8SUBL =(OPC_OP(0x10) | OPC_FUNC(0xD)), ++ OPC_S8SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xD)), ++ ++ OPC_MULW =(OPC_OP(0x10) | OPC_FUNC(0x10)), ++ OPC_MULW_I =(OPC_OP(0x12) | OPC_FUNC(0x10)), ++ OPC_MULL =(OPC_OP(0x10) | OPC_FUNC(0x18)), ++ OPC_MULL_I =(OPC_OP(0x12) | OPC_FUNC(0x18)), ++ ++ OPC_UMULH =(OPC_OP(0x10) | OPC_FUNC(0x19)), ++ OPC_UMULH_I =(OPC_OP(0x12) | OPC_FUNC(0x19)), ++ ++ OPC_CTPOP =(OPC_OP(0x10) | OPC_FUNC(0x58)), ++ OPC_CTLZ =(OPC_OP(0x10) | OPC_FUNC(0x59)), ++ OPC_CTTZ =(OPC_OP(0x10) | OPC_FUNC(0x5A)), ++ ++ OPC_ZAP =(OPC_OP(0x10) | OPC_FUNC(0x68)), ++ OPC_ZAP_I =(OPC_OP(0x12) | OPC_FUNC(0x68)), ++ OPC_ZAPNOT =(OPC_OP(0x10) | OPC_FUNC(0x69)), ++ OPC_ZAPNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x69)), ++ ++ OPC_SEXTB =(OPC_OP(0x10) | OPC_FUNC(0x6A)), ++ OPC_SEXTB_I =(OPC_OP(0x12) | OPC_FUNC(0x6A)), ++ OPC_SEXTH =(OPC_OP(0x10) | OPC_FUNC(0x6B)), ++ OPC_SEXTH_I =(OPC_OP(0x12) | OPC_FUNC(0x6B)), ++ ++ OPC_CMPEQ =(OPC_OP(0x10) | OPC_FUNC(0x28)), ++ OPC_CMPEQ_I =(OPC_OP(0x12) | OPC_FUNC(0x28)), ++ ++ OPC_CMPLT =(OPC_OP(0x10) | OPC_FUNC(0x29)), ++ OPC_CMPLT_I =(OPC_OP(0x12) | OPC_FUNC(0x29)), ++ OPC_CMPLE =(OPC_OP(0x10) | OPC_FUNC(0x2A)), ++ OPC_CMPLE_I =(OPC_OP(0x12) | OPC_FUNC(0x2A)), ++ ++ OPC_CMPULT =(OPC_OP(0x10) | OPC_FUNC(0x2B)), ++ OPC_CMPULT_I =(OPC_OP(0x12) | OPC_FUNC(0x2B)), ++ OPC_CMPULE =(OPC_OP(0x10) | OPC_FUNC(0x2C)), ++ OPC_CMPULE_I =(OPC_OP(0x12) | OPC_FUNC(0x2C)), ++ ++ OPC_AND =(OPC_OP(0x10) | OPC_FUNC(0x38)), ++ OPC_BIC =(OPC_OP(0x10) | OPC_FUNC(0x39)), ++ OPC_BIS =(OPC_OP(0x10) | OPC_FUNC(0x3A)), ++ OPC_ORNOT =(OPC_OP(0x10) | OPC_FUNC(0x3B)), ++ OPC_XOR =(OPC_OP(0x10) | OPC_FUNC(0x3C)), ++ OPC_EQV =(OPC_OP(0x10) | OPC_FUNC(0x3D)), ++ ++ OPC_AND_I =(OPC_OP(0x12) | OPC_FUNC(0x38)), ++ OPC_BIC_I =(OPC_OP(0x12) | OPC_FUNC(0x39)), ++ OPC_BIS_I =(OPC_OP(0x12) | OPC_FUNC(0x3A)), ++ OPC_ORNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x3B)), ++ OPC_XOR_I =(OPC_OP(0x12) | OPC_FUNC(0x3C)), ++ OPC_EQV_I =(OPC_OP(0x12) | OPC_FUNC(0x3D)), ++ ++ OPC_SLL =(OPC_OP(0x10) | OPC_FUNC(0x48)), ++ OPC_SRL =(OPC_OP(0x10) | OPC_FUNC(0x49)), ++ OPC_SRA =(OPC_OP(0x10) | OPC_FUNC(0x4A)), ++ OPC_SLL_I =(OPC_OP(0x12) | OPC_FUNC(0x48)), ++ OPC_SRL_I =(OPC_OP(0x12) | OPC_FUNC(0x49)), ++ OPC_SRA_I =(OPC_OP(0x12) | OPC_FUNC(0x4A)), ++ ++ OPC_SELEQ =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x00)), ++ OPC_SELGE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x01)), ++ OPC_SELGT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x02)), ++ OPC_SELLE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x03)), ++ OPC_SELLT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x04)), ++ OPC_SELNE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x05)), ++ OPC_SELLBC =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x06)), ++ OPC_SELLBS =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x07)), ++ OPC_SELEQ_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x00)), ++ OPC_SELGE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x01)), ++ OPC_SELGT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x02)), ++ OPC_SELLE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x03)), ++ OPC_SELLT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x04)), ++ OPC_SELNE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x05)), ++ OPC_SELLBC_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x06)), ++ OPC_SELLBS_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x07)), ++ ++ OPC_INS0B =(OPC_OP(0x10) | OPC_FUNC(0x40)), ++ OPC_INS1B =(OPC_OP(0x10) | OPC_FUNC(0x41)), ++ OPC_INS2B =(OPC_OP(0x10) | OPC_FUNC(0x42)), ++ OPC_INS3B =(OPC_OP(0x10) | OPC_FUNC(0x43)), ++ OPC_INS4B =(OPC_OP(0x10) | OPC_FUNC(0x44)), ++ OPC_INS5B =(OPC_OP(0x10) | OPC_FUNC(0x45)), ++ OPC_INS6B =(OPC_OP(0x10) | OPC_FUNC(0x46)), ++ OPC_INS7B =(OPC_OP(0x10) | OPC_FUNC(0x47)), ++ OPC_INS0B_I =(OPC_OP(0x12) | OPC_FUNC(0x40)), ++ OPC_INS1B_I =(OPC_OP(0x12) | OPC_FUNC(0x41)), ++ OPC_INS2B_I =(OPC_OP(0x12) | OPC_FUNC(0x42)), ++ OPC_INS3B_I =(OPC_OP(0x12) | OPC_FUNC(0x43)), ++ OPC_INS4B_I =(OPC_OP(0x12) | OPC_FUNC(0x44)), ++ OPC_INS5B_I =(OPC_OP(0x12) | OPC_FUNC(0x45)), ++ OPC_INS6B_I =(OPC_OP(0x12) | OPC_FUNC(0x46)), ++ OPC_INS7B_I =(OPC_OP(0x12) | OPC_FUNC(0x47)), ++ ++ OPC_EXT0B =(OPC_OP(0x10) | OPC_FUNC(0x50)), ++ OPC_EXT1B =(OPC_OP(0x10) | OPC_FUNC(0x51)), ++ OPC_EXT2B =(OPC_OP(0x10) | OPC_FUNC(0x52)), ++ OPC_EXT3B =(OPC_OP(0x10) | OPC_FUNC(0x53)), ++ OPC_EXT4B =(OPC_OP(0x10) | OPC_FUNC(0x54)), ++ OPC_EXT5B =(OPC_OP(0x10) | OPC_FUNC(0x55)), ++ OPC_EXT6B =(OPC_OP(0x10) | OPC_FUNC(0x56)), ++ OPC_EXT7B =(OPC_OP(0x10) | OPC_FUNC(0x57)), ++ OPC_EXT0B_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), ++ OPC_EXT1B_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), ++ OPC_EXT2B_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), ++ OPC_EXT3B_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), ++ OPC_EXT4B_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), ++ OPC_EXT5B_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), ++ OPC_EXT6B_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), ++ OPC_EXT7B_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), ++ ++ OPC_MASK0B =(OPC_OP(0x10) | OPC_FUNC(0x60)), ++ OPC_MASK1B =(OPC_OP(0x10) | OPC_FUNC(0x61)), ++ OPC_MASK2B =(OPC_OP(0x10) | OPC_FUNC(0x62)), ++ OPC_MASK3B =(OPC_OP(0x10) | OPC_FUNC(0x63)), ++ OPC_MASK4B =(OPC_OP(0x10) | OPC_FUNC(0x64)), ++ OPC_MASK5B =(OPC_OP(0x10) | OPC_FUNC(0x65)), ++ OPC_MASK6B =(OPC_OP(0x10) | OPC_FUNC(0x66)), ++ OPC_MASK7B =(OPC_OP(0x10) | OPC_FUNC(0x67)), ++ OPC_MASK0B_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), ++ OPC_MASK1B_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), ++ OPC_MASK2B_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), ++ OPC_MASK3B_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), ++ OPC_MASK4B_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), ++ OPC_MASK5B_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), ++ OPC_MASK6B_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), ++ OPC_MASK7B_I =(OPC_OP(0x12) | OPC_FUNC(0x67)), ++ ++ OPC_CNPGEB =(OPC_OP(0x10) | OPC_FUNC(0x6C)), ++ OPC_CNPGEB_I =(OPC_OP(0x12) | OPC_FUNC(0x6C)), ++ ++ OPC_MEMB =(OPC_OP(0x06) | OPC_FUNC(0x0)), ++ OPC_RTC =(OPC_OP(0x06) | OPC_FUNC(0x20)), ++ ++ /*float insn*/ ++ OPC_RFPCR = (OPC_OP(0x18) | OPC_FUNC(0x50)), ++ OPC_WFPCR = (OPC_OP(0x18) | OPC_FUNC(0x51)), ++ OPC_SETFPEC0 = (OPC_OP(0x18) | OPC_FUNC(0x54)), ++ OPC_SETFPEC1 = (OPC_OP(0x18) | OPC_FUNC(0x55)), ++ OPC_SETFPEC2 = (OPC_OP(0x18) | OPC_FUNC(0x56)), ++ OPC_SETFPEC3 = (OPC_OP(0x18) | OPC_FUNC(0x57)), ++ ++ ++ OPC_IFMOVS = (OPC_OP(0x18) | OPC_FUNC(0x40)), ++ OPC_IFMOVD = (OPC_OP(0x18) | OPC_FUNC(0x41)), ++ OPC_FIMOVS = (OPC_OP(0x10) | OPC_FUNC(0x70)), ++ OPC_FIMOVD = (OPC_OP(0x10) | OPC_FUNC(0x78)), ++ ++ /*translate S--D*/ ++ /*translate S/D--Long*/ ++ OPC_FCVTSD = (OPC_OP(0x18) | OPC_FUNC(0x20)), ++ OPC_FCVTDS = (OPC_OP(0x18) | OPC_FUNC(0x21)), ++ OPC_FCVTDL_G = (OPC_OP(0x18) | OPC_FUNC(0x22)), ++ OPC_FCVTDL_P = (OPC_OP(0x18) | OPC_FUNC(0x23)), ++ OPC_FCVTDL_Z = (OPC_OP(0x18) | OPC_FUNC(0x24)), ++ OPC_FCVTDL_N = (OPC_OP(0x18) | OPC_FUNC(0x25)), ++ OPC_FCVTDL = (OPC_OP(0x18) | OPC_FUNC(0x27)), ++ OPC_FCVTLS = (OPC_OP(0x18) | OPC_FUNC(0x2D)), ++ OPC_FCVTLD = (OPC_OP(0x18) | OPC_FUNC(0x2F)), ++ ++ ++ OPC_FADDS = (OPC_OP(0x18) | OPC_FUNC(0x00)), ++ OPC_FADDD = (OPC_OP(0x18) | OPC_FUNC(0x01)), ++ OPC_FSUBS = (OPC_OP(0x18) | OPC_FUNC(0x02)), ++ OPC_FSUBD = (OPC_OP(0x18) | OPC_FUNC(0x03)), ++ OPC_FMULS = (OPC_OP(0x18) | OPC_FUNC(0x04)), ++ OPC_FMULD = (OPC_OP(0x18) | OPC_FUNC(0x05)), ++ OPC_FDIVS = (OPC_OP(0x18) | OPC_FUNC(0x06)), ++ OPC_FDIVD = (OPC_OP(0x18) | OPC_FUNC(0x07)), ++ OPC_FSQRTS = (OPC_OP(0x18) | OPC_FUNC(0x08)), ++ OPC_FSQRTD = (OPC_OP(0x18) | OPC_FUNC(0x09)), ++}SW_64Insn; ++ ++static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64); ++static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16); ++static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm); ++static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64); ++static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64); ++static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64); ++static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64); ++static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm); ++static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,TCGReg a1,TCGReg a2, bool const_b, TCGReg v1, TCGReg v2); ++static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target); ++static inline uint32_t tcg_in32(TCGContext *s); ++static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn); ++static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign); ++static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b); ++static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t aimm); ++static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m); ++static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); ++static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); ++static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); ++static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); ++static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, TCGReg rn, TCGArg b, bool const_b); ++static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn); ++static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi); ++static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext); ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg arg1, TCGReg arg2); ++static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); ++static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); ++static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm); ++ ++#define tcg_out_insn_jump tcg_out_insn_ldst ++#define tcg_out_insn_bitReg tcg_out_insn_simpleReg ++ ++static void tcg_target_init(TCGContext *s) ++{ ++ tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull; ++ tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull; ++ tcg_target_call_clobber_regs = -1ull; ++ ++ //sw_64 callee saved x9-x15 ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X9); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X10); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X11); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X12); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X13); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X14); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X15); ++ ++ //sw_64 callee saved f2~f9 ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F2); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F3); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F4); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F5); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F6); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F7); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F8); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F9); ++ ++ s->reserved_regs = 0; ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); //TCG_REG_X27 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); //TCG_REG_X25 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); //TCG_REG_X26 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); /*sw_64 platform register */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); /*sw_64 platform register */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); /*sw_64 platform register */ ++} ++ ++ ++#ifndef CONFIG_SOFTMMU ++ #define USE_GUEST_BASE guest_base != 0 ++ #define TCG_REG_GUEST_BASE TCG_REG_X14 ++#endif ++ ++ ++#define zeroExt 0 ++#define sigExt 1 ++ ++ ++static void tcg_target_qemu_prologue(TCGContext *s) ++{ ++ TCGReg r; ++ int ofs; ++ ++ /* allocate space for all saved registers */ ++ /* subl $sp,PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); ++ ++ /* Push (FP, LR) */ ++ /* stl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* stl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_RA, TCG_REG_SP, 8); ++ ++ ++ /* Set up frame pointer for canonical unwinding. */ ++ /* TCG_REG_FP=TCG_REG_SP */ ++ tcg_out_movr(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP); ++ ++ /* Store callee-preserved regs x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1){ ++ ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_STL, r, TCG_REG_SP, ofs); ++ } ++ ++ /* Make stack space for TCG locals. */ ++ /* subl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ ++ /* Inform TCG about how to find TCG locals with register, offset, size. */ ++ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, ++ CPU_TEMP_BUF_NLONGS * sizeof(long)); ++ ++#if !defined(CONFIG_SOFTMMU) ++ if (USE_GUEST_BASE) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); ++ } ++#endif ++ ++ /* TCG_AREG0=tcg_target_call_iarg_regs[0], on sw, we mov $16 to $9 */ ++ tcg_out_mov(s, TCG_TYPE_I64, TCG_AREG0, tcg_target_call_iarg_regs[0]); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); ++ ++ /* ++ * Return path for goto_ptr. Set return value to 0, a-la exit_tb, ++ * and fall through to the rest of the epilogue. ++ */ ++ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, 0); ++ ++ /* TB epilogue */ ++ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); ++ ++ /* Remove TCG locals stack space. */ ++ /* addl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ ++ /* Restore registers x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1) { ++ int ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_LDL, r, TCG_REG_SP, ofs); ++ } ++ ++ ++ /* Pop (FP, LR) */ ++ /* ldl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* ldl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_RA, TCG_REG_SP, 8); ++ ++ /* restore SP to previous frame. */ ++ /* addl $sp,PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); ++ ++ tcg_out_insn_jump(s, OPC_RET, TCG_REG_ZERO, TCG_REG_RA, 0); ++} ++ ++static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) ++{ ++ if (ret == arg) { ++ return true; ++ } ++ switch (type) { ++ case TCG_TYPE_I32: ++ case TCG_TYPE_I64: ++ if (ret < 32 && arg < 32) { ++ tcg_out_movr(s, type, ret, arg); ++ break; ++ } else if (ret < 32) { ++ break; ++ } else if (arg < 32) { ++ break; ++ } ++ /* FALLTHRU */ ++ default: ++ g_assert_not_reached(); ++ } ++ return true; ++} ++ ++ ++static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) ++{ ++ switch (op) { ++ case INDEX_op_goto_ptr: ++ return C_O0_I1(r); ++ ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld8u_i64: ++ case INDEX_op_ld8s_i64: ++ case INDEX_op_ld16u_i64: ++ case INDEX_op_ld16s_i64: ++ case INDEX_op_ld32u_i64: ++ case INDEX_op_ld32s_i64: ++ case INDEX_op_ld_i64: ++ case INDEX_op_neg_i32: ++ case INDEX_op_neg_i64: ++ case INDEX_op_not_i32: ++ case INDEX_op_not_i64: ++ case INDEX_op_bswap16_i32: ++ case INDEX_op_bswap32_i32: ++ case INDEX_op_bswap16_i64: ++ case INDEX_op_bswap32_i64: ++ case INDEX_op_bswap64_i64: ++ case INDEX_op_ext8s_i32: ++ case INDEX_op_ext16s_i32: ++ case INDEX_op_ext8u_i32: ++ case INDEX_op_ext16u_i32: ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext32s_i64: ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext32u_i64: ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_extract_i32: ++ case INDEX_op_extract_i64: ++ case INDEX_op_sextract_i32: ++ case INDEX_op_sextract_i64: ++ return C_O1_I1(r, r); ++ ++ case INDEX_op_st8_i32: ++ case INDEX_op_st16_i32: ++ case INDEX_op_st_i32: ++ case INDEX_op_st8_i64: ++ case INDEX_op_st16_i64: ++ case INDEX_op_st32_i64: ++ case INDEX_op_st_i64: ++ return C_O0_I2(rZ, r); ++ ++ case INDEX_op_add_i32: ++ case INDEX_op_add_i64: ++ case INDEX_op_sub_i32: ++ case INDEX_op_sub_i64: ++ return C_O1_I2(r, r, rU);//rA ++ ++ case INDEX_op_setcond_i32: ++ case INDEX_op_setcond_i64: ++ return C_O1_I2(r, r, rU);//compare,rA ++ ++ case INDEX_op_mul_i32: ++ case INDEX_op_mul_i64: ++ case INDEX_op_div_i32: ++ case INDEX_op_div_i64: ++ case INDEX_op_divu_i32: ++ case INDEX_op_divu_i64: ++ case INDEX_op_rem_i32: ++ case INDEX_op_rem_i64: ++ case INDEX_op_remu_i32: ++ case INDEX_op_remu_i64: ++ case INDEX_op_muluh_i64: ++ case INDEX_op_mulsh_i64: ++ return C_O1_I2(r, r, r); ++ ++ case INDEX_op_and_i32: ++ case INDEX_op_and_i64: ++ case INDEX_op_or_i32: ++ case INDEX_op_or_i64: ++ case INDEX_op_xor_i32: ++ case INDEX_op_xor_i64: ++ case INDEX_op_andc_i32: ++ case INDEX_op_andc_i64: ++ case INDEX_op_orc_i32: ++ case INDEX_op_orc_i64: ++ case INDEX_op_eqv_i32: ++ case INDEX_op_eqv_i64: ++ return C_O1_I2(r, r, rU);//rL ++ ++ case INDEX_op_shl_i32: ++ case INDEX_op_shr_i32: ++ case INDEX_op_sar_i32: ++ case INDEX_op_rotl_i32: ++ case INDEX_op_rotr_i32: ++ case INDEX_op_shl_i64: ++ case INDEX_op_shr_i64: ++ case INDEX_op_sar_i64: ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotr_i64: ++ return C_O1_I2(r, r, ri); ++ ++ case INDEX_op_clz_i32: ++ case INDEX_op_clz_i64: ++ return C_O1_I2(r, r, r); //rAL ++ ++ case INDEX_op_ctz_i32: ++ case INDEX_op_ctz_i64: ++ return C_O1_I2(r, r, r);//rAL ++ ++ case INDEX_op_brcond_i32: ++ case INDEX_op_brcond_i64: ++ return C_O0_I2(r, rU);//rA ++ ++ case INDEX_op_movcond_i32: ++ case INDEX_op_movcond_i64: ++ return C_O1_I4(r, r, rU, rZ, rZ);//rA->rU ++ ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ return C_O1_I1(r, l); ++ ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ return C_O0_I2(lZ, l); ++ ++ case INDEX_op_deposit_i32: ++ case INDEX_op_deposit_i64: ++ return C_O1_I2(r, 0, rZ); ++ ++ case INDEX_op_extract2_i32: ++ case INDEX_op_extract2_i64: ++ return C_O1_I2(r, rZ, rZ); ++ ++ case INDEX_op_add2_i32: ++ case INDEX_op_add2_i64: ++ case INDEX_op_sub2_i32: ++ case INDEX_op_sub2_i64: ++ return C_O2_I4(r, r, rZ, rZ, rA, rMZ); ++ ++ case INDEX_op_add_vec: ++ case INDEX_op_sub_vec: ++ case INDEX_op_mul_vec: ++ case INDEX_op_xor_vec: ++ case INDEX_op_ssadd_vec: ++ case INDEX_op_sssub_vec: ++ case INDEX_op_usadd_vec: ++ case INDEX_op_ussub_vec: ++ case INDEX_op_smax_vec: ++ case INDEX_op_smin_vec: ++ case INDEX_op_umax_vec: ++ case INDEX_op_umin_vec: ++ case INDEX_op_shlv_vec: ++ case INDEX_op_shrv_vec: ++ case INDEX_op_sarv_vec: ++ return C_O1_I2(w, w, w); ++ case INDEX_op_not_vec: ++ case INDEX_op_neg_vec: ++ case INDEX_op_abs_vec: ++ case INDEX_op_shli_vec: ++ case INDEX_op_shri_vec: ++ case INDEX_op_sari_vec: ++ return C_O1_I1(w, w); ++ case INDEX_op_ld_vec: ++ case INDEX_op_dupm_vec: ++ return C_O1_I1(w, r); ++ case INDEX_op_st_vec: ++ return C_O0_I2(w, r); ++ case INDEX_op_dup_vec: ++ return C_O1_I1(w, wr); ++ case INDEX_op_or_vec: ++ case INDEX_op_andc_vec: ++ return C_O1_I2(w, w, wO); ++ case INDEX_op_and_vec: ++ case INDEX_op_orc_vec: ++ return C_O1_I2(w, w, wN); ++ case INDEX_op_cmp_vec: ++ return C_O1_I2(w, w, wZ); ++ case INDEX_op_bitsel_vec: ++ return C_O1_I3(w, w, w, w); ++ ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++ ++static void tcg_out_nop_fill(tcg_insn_unit *p, int count) ++{ ++ int i; ++ for (i = 0; i < count; ++i) { ++ p[i] = OPC_NOP; ++ } ++} ++ ++/* SW instruction format of syscall ++ * insn = opcode[31,26]:Function[25,0], ++ */ ++ ++/* SW instruction format of br(alias jump) ++ * insn = opcode[31,26]:Rd[25,21]:disp[20,0], ++ */ ++static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64) ++{ ++ tcg_debug_assert(imm64 <= 0xfffff && imm64 >= -0x100000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (imm64 & 0x1fffff)); ++} ++ ++ ++/* SW instruction format of (load and store) ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16]:disp[15,0] ++ */ ++static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16) ++{ ++ tcg_debug_assert(imm16 <= 0x7fff && imm16 >= -0x8000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (rn & 0x1f) << 16 | (imm16 & 0xffff)); ++} ++ ++ ++/* SW instruction format of simple operator for Register ++ * insn = opcode[31,26]:rn(ra)[25,21]:rn(rb)[20,16]:Zeors[15,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (rn & 0x1f) << 21 | (rm & 0x1f) << 16 | (rd & 0x1f)); ++} ++ ++/* SW instruction format of simple operator for imm ++ * insn = opcode[31,26]:rn(ra)[25,21]:disp[20,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64) ++{ ++ if(imm64 <= 0x7f && imm64 >= -0x80) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ } ++} ++ ++ ++static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64) ++{ ++ tcg_debug_assert(imm64 <= 0x7f && imm64 >= -0x80); ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ ++} ++ ++static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ tcg_debug_assert(imm64 <= 255); ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++} ++/* sw bit operation: and bis etc */ ++static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ if (imm64 <= 255) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_bitReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ } ++} ++ ++/* SW instruction format of complex operator ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16],function[15,10]:rm[9,5]:rx[4,0] ++ */ ++static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (cond & 0x1f) << 21 | (rn & 0x1f) << 16 | (rm & 0x1f) << 5 | (rd & 0x1f)); ++} ++ ++static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target) ++{ ++ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); ++ ptrdiff_t offset = target - (src_rx + 1) ; ++ ++ if (offset == sextract64(offset, 0, 21)) { ++ /* read instruction, mask away previous PC_REL21 parameter contents, ++ set the proper offset, then write back the instruction. */ ++ *src_rw = deposit32(*src_rw, 0, 21, offset); ++ return true; ++ } ++ return false; ++} ++ ++/* sw*/ ++static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) ++{ ++ tcg_debug_assert(addend == 0); ++ switch (type) { ++ case R_SW_64_BRADDR: ++ return reloc_pc21(code_ptr, (const tcg_insn_unit *)value); ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static inline uint32_t tcg_in32(TCGContext *s) ++{ ++ uint32_t v = *(uint32_t *)s->code_ptr; ++ return v; ++} ++ ++/*SW Register to register move using ADDL*/ ++static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) ++{ ++ tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); ++ if (ext == TCG_TYPE_I32){ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++} ++ ++/*sw ++ *put imm into rd ++ */ ++static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) ++{ ++ long l0, l1, l2=0, l3=0, extra=0; ++ tcg_target_long val = orig; ++ TCGReg rs = TCG_REG_ZERO; ++ ++ if (type == TCG_TYPE_I32) ++ val = (int32_t)val; ++ ++ l0 = (int16_t)val; ++ val = (val - l0) >> 16; ++ l1 = (int16_t)val; ++ ++ if (orig >> 31 == -1 || orig >> 31 == 0) { ++ if (l1 < 0 && orig >= 0) { ++ extra = 0x4000; ++ l1 = (int16_t)(val - 0x4000); ++ } ++ } else { ++ val = (val - l1) >> 16; ++ l2 = (int16_t)val; ++ val = (val - l2) >> 16; ++ l3 = (int16_t)val; ++ ++ if (l3) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l3); ++ rs = rd; ++ } ++ if (l2) { ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l2); ++ rs = rd; ++ } ++ if (l3 || l2) ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, rd, rd, 32); ++ } ++ ++ if (l1) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l1); ++ rs = rd; ++ } ++ ++ if (extra) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, extra); ++ rs = rd; ++ } ++ ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l0); ++} ++ ++ ++/*sw ++* memory <=> Reg in (B H W L) bytes ++*/ ++static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign) ++{ ++ int16_t lo = offset; ++ if (offset != lo) { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset - lo); ++ if (rn != TCG_REG_ZERO) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, TCG_REG_TMP, rn); ++ } ++ tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP, lo); ++ } ++ else { ++ tcg_out_insn_ldst(s, insn, rd, rn, lo); ++ } ++ ++ switch (insn) { ++ case OPC_LDBU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld8s_i32/64,set rd[63,8]=1 ++ break; ++ case OPC_LDHU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld16s_i32/64,set rd[63,16]=1 ++ break; ++ case OPC_LDW: ++ if (!sign) ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); //for micro-op:INDEX_op_ld32u_i32/64,set rd[63,32]=0 ++ break; ++ default: ++ break; ++ } ++} ++ ++/* TCG_REG_TMP stores result_of_condition_compare */ ++static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b) ++{ ++ if (const_b) { ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ break; ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simple(s, OPC_CMPEQ_I, OPC_CMPEQ, ret, a, b); ++ break; ++ case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simple(s, OPC_CMPLT_I, OPC_CMPLT, ret, a, b); ++ break; ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simple(s, OPC_CMPLE_I, OPC_CMPLE, ret, a, b); ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simple(s, OPC_CMPULT_I, OPC_CMPULT, ret, a, b); ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simple(s, OPC_CMPULE_I, OPC_CMPULE, ret, a, b); ++ break; ++ }//cond ++ }//if (const_b) ++ else { ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ break; ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simpleReg(s, OPC_CMPEQ, ret, a, b); ++ break; ++ case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simpleReg(s, OPC_CMPLT, ret, a, b); ++ break; ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simpleReg(s, OPC_CMPLE, ret, a, b); ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULT, ret, a, b); ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULE, ret, a, b); ++ break; ++ }//cond ++ }//else ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ case TCG_COND_EQ: ++ case TCG_COND_LT: ++ case TCG_COND_LE: ++ case TCG_COND_LTU: ++ case TCG_COND_LEU: ++ break; ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_bitImm(s, OPC_XOR_I, ret, ret, 0x1); ++ break; ++ } ++} ++ ++/* sw ++ * step1 tcg_out_cmp() ,"eq" and "ne" in the same case with the same insn; ++ * store compare result by TCG_REG_TMP, for step2; ++ * step2: jump address with compare result. in last "switch" section, we diff qe/ne by different case with different insn. ++ */ ++static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond cond, TCGArg a, TCGArg b, bool b_const, TCGLabel *l) ++{ ++ intptr_t offset; ++ bool need_cmp; ++ ++ if (b_const && b == 0 && (cond == TCG_COND_EQ || cond == TCG_COND_NE)) { ++ need_cmp = false; ++ } else { ++ need_cmp = true; ++ tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a, b, b_const); ++ } ++ ++ if (!l->has_value) { ++ tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); ++ offset=0; //offset = tcg_in32(s) >> 5; br $31, 0, do not jump here! ++ } else { ++ offset = tcg_pcrel_diff(s, l->u.value_ptr) ; ++ offset = offset >> 2; ++ tcg_debug_assert(offset == sextract64(offset, 0, 21)); ++ } ++ ++ if (need_cmp) { ++ tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, offset); //a cond b,jmp ++ } else if (cond == TCG_COND_EQ) { ++ tcg_out_insn_br(s, OPC_BEQ, a, offset); ++ } else { ++ tcg_out_insn_br(s, OPC_BNE, a, offset); ++ } ++} ++ ++/*sw ++ * contact with "tcg-target-con-str.h" ++ */ ++#define TCG_CT_CONST_ZERO 0x100 ++#define TCG_CT_CONST_LONG 0x200 ++#define TCG_CT_CONST_MONE 0x400 ++#define TCG_CT_CONST_ORRI 0x800 ++#define TCG_CT_CONST_WORD 0X1000 ++#define TCG_CT_CONST_U8 0x2000 ++#define TCG_CT_CONST_S8 0X4000 ++ ++#define ALL_GENERAL_REGS 0xffffffffu ++#define ALL_VECTOR_REGS 0xffffffff00000000ull ++ ++ ++#ifdef CONFIG_SOFTMMU ++/*sw #define ALL_QLDST_REGS */ ++#else ++ #define ALL_QLDST_REGS ALL_GENERAL_REGS ++#endif ++ ++/* sw test if a constant matches the constraint */ ++static bool tcg_target_const_match(int64_t val, TCGType type, int ct) ++{ ++ if (ct & TCG_CT_CONST) { ++ return 1; ++ } ++ if (type == TCG_TYPE_I32) { ++ val = (int32_t)val; ++ } ++ if ((ct & TCG_CT_CONST_U8) && 0 <= val && val <= 255) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_LONG)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_MONE)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ORRI)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_WORD)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { ++ return 1; ++ } ++ return 0; ++} ++ ++static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++{ ++ switch (type) { ++ case TCG_TYPE_I32: ++ tcg_out_ldst(s, OPC_LDW, rd, rn, ofs, sigExt); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tcg_out_st(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++{ ++ switch (type) { ++ case TCG_TYPE_I32: ++ tcg_out_insn_ldst(s, OPC_STW, rd, rn, ofs); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_insn_ldst(s, OPC_STL, rd, rn, ofs); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, intptr_t ofs) ++{ ++ if (type <= TCG_TYPE_I64 && val == 0) { ++ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); ++ return true; ++ } ++ return false; ++} ++ ++static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t imm64) ++{ ++ if (imm64 >= 0) { ++ if(0 <=imm64 && imm64 <= 255) { ++ /* we use tcg_out_insn_bitImm because imm64 is between 0~255 */ ++ tcg_out_insn_bitImm(s, OPC_ADDL_I, rd, rn, imm64); ++ }//aimm>0 && aimm == sextract64(aim, 0, 8) ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); ++ }//aimm>0 && aimm != sextract64(aim, 0, 8) ++ } else { ++ if(0 < -imm64 && -imm64 <= 255) { ++ /* we use tcg_out_insn_bitImm because -imm64 is between 0~255 */ ++ tcg_out_insn_bitImm(s, OPC_SUBL_I, rd, rn, -imm64); ++ }//aimm<0 && aimm == sextract64(aim, 0, 8) ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); ++ }//aimm<0 && aimm != sextract64(aim, 0, 8) ++ } ++} ++ ++static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ tcg_debug_assert(offset == sextract64(offset, 0, 21)); ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); ++} ++ ++static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ if (0 <= offset && offset <= 0x1fffff) { ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ } ++} ++ ++ ++/*sw ++* call subroutine ++*/ ++static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ if (offset == sextract64(offset, 0, 21)) { ++ tcg_out_insn_br(s, OPC_BSR, TCG_REG_RA, offset); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); ++ tcg_out_insn_jump(s, OPC_CALL, TCG_REG_RA, TCG_REG_TMP, 0); ++ } ++} ++ ++void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) ++{ ++ tcg_debug_assert(0); ++ //sw not support ++} ++ ++static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) ++{ ++ if (!l->has_value) { ++ tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, 0); ++ } else { ++ tcg_out_goto(s, l->u.value_ptr); ++ } ++} ++ ++/* sw ++ * resut: rd=rn(64,64-m]:rm(64-m,0] ++ * 1: rn(m,0]--->TCG_REG_TMP(64,64-m] ++ * 2: rm(64,64-m]--->rm(64-m,0] ++ * 3: rd=TCG_REG_TMP(64,64-m]:rm(64-m,0] ++ */ ++static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw ++ * loop right shift ++ */ ++static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw loop right shift ++ */ ++static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ int bits = ext ? 64 : 32; ++ //get TCG_REG_TMP=64-[rm] ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn right part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw ++ * loop left shift ++ */ ++static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); //get rn right part to left ++} ++ ++ ++/* sw loop left shift ++ */ ++static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ int bits = ext ? 64 : 32; ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); //rm = 64-rm ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); //get rn right part to left ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++ ++ ++static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) ++{ ++ /* 99% of the time, we can signal the use of extension registers ++ by looking to see if the opcode handles 64-bit data. */ ++ TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0; ++ /* Hoist the loads of the most common arguments. */ ++ TCGArg a0 = args[0]; ++ TCGArg a1 = args[1]; ++ TCGArg a2 = args[2]; ++ int c2 = const_args[2]; ++ ++ /* Some operands are defined with "rZ" constraint, a register or ++ the zero register. These need not actually test args[I] == 0. */ ++ #define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) ++ ++ switch (opc) { ++ case INDEX_op_exit_tb: ++ /* Reuse the zeroing that exists for goto_ptr. */ ++ if (a0 == 0) { ++ tcg_out_goto_long(s, tcg_code_gen_epilogue); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); ++ tcg_out_goto_long(s, tb_ret_addr); ++ } ++ break; ++ ++ case INDEX_op_goto_tb: ++ if (s->tb_jmp_insn_offset != NULL) { ++ /* TCG_TARGET_HAS_direct_jump */ ++ tcg_debug_assert(0); ++ /* not support here */ ++ } else { ++ /* !TCG_TARGET_HAS_direct_jump */ ++ tcg_debug_assert(s->tb_jmp_target_addr != NULL); ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); ++ } ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ set_jmp_reset_offset(s, a0); ++ break; ++ ++ case INDEX_op_goto_ptr: ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, 0); ++ break; ++ ++ case INDEX_op_br: ++ tcg_out_goto_label(s, arg_label(a0)); ++ break; ++ ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8u_i64: ++ tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld8s_i64: ++ tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16u_i64: ++ tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld16s_i64: ++ tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld_i32: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld32u_i64: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld32s_i64: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld_i64: ++ tcg_out_ldst(s, OPC_LDL, a0, a1, a2, 1); ++ break; ++ case INDEX_op_st8_i32: ++ case INDEX_op_st8_i64: ++ tcg_out_ldst(s, OPC_STB, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st16_i32: ++ case INDEX_op_st16_i64: ++ tcg_out_ldst(s, OPC_STH, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st_i32: ++ case INDEX_op_st32_i64: ++ tcg_out_ldst(s, OPC_STW, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st_i64: ++ tcg_out_ldst(s, OPC_STL, a0, a1, a2, 0); ++ break; ++ ++ case INDEX_op_add_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_add_i64: ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sub_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, -a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_sub_i64: ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, -a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_neg_i64: ++ case INDEX_op_neg_i32: ++ tcg_out_insn_bitReg(s, OPC_SUBL, a0, TCG_REG_ZERO, a1); ++ break; ++ ++ case INDEX_op_and_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_and_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_andc_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_andc_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_or_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_or_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_orc_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_orc_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_xor_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_xor_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_eqv_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_eqv_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_not_i64: ++ case INDEX_op_not_i32: ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); ++ break; ++ ++ case INDEX_op_mul_i64: ++ case INDEX_op_mul_i32: ++ tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); ++ break; ++ ++ case INDEX_op_div_i64: /* a0=a1/a2 singed divide*/ ++ case INDEX_op_div_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_divu_i64: /* a0=a1/a2 unsigned divide */ ++ case INDEX_op_divu_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_rem_i64: /* if a1=17,a2=4, 17/4=4...1, a0=1 */ ++ case INDEX_op_rem_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_remu_i64: ++ case INDEX_op_remu_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_shl_i64: ++ case INDEX_op_shl_i32: /* sw logical left*/ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_shr_i64: ++ case INDEX_op_shr_i32: /* sw logical right */ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SRL_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sar_i64: ++ case INDEX_op_sar_i32: /* sw arithmetic right*/ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SRA_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRA, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_rotr_i64: ++ case INDEX_op_rotr_i32: /* loop shift */ ++ if (c2) {/* loop right shift a2*/ ++ tcg_out_rotr_Imm(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_rotr_Reg(s, ext, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotl_i32: /* loop shift */ ++ if (c2) {/* loop left shift a2*/ ++ tcg_out_rotl_Imm(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_rotl_Reg(s, ext, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_clz_i64: /* counting leading zero numbers */ ++ case INDEX_op_clz_i32: ++ tcg_out_cltz(s, OPC_CTLZ, ext, a0, a1, a2, c2); ++ break; ++ case INDEX_op_ctz_i64: /* counting tailing zero numbers */ ++ case INDEX_op_ctz_i32: ++ tcg_out_cltz(s, OPC_CTTZ, ext, a0, a1, a2, c2); ++ break; ++ ++ case INDEX_op_brcond_i32: ++ a1 = (int32_t)a1; ++ tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); ++ break; ++ ++ case INDEX_op_brcond_i64: ++ tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); ++ break; ++ ++ case INDEX_op_setcond_i32: ++ a2 = (int32_t)a2; ++ tcg_out_setcond(s, args[3], a0, a1, a2); ++ break; ++ ++ case INDEX_op_setcond_i64: ++ tcg_out_setcond(s, args[3], a0, a1, a2); ++ break; ++ ++ case INDEX_op_movcond_i32: ++ a2 = (int32_t)a2; ++ tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ break; ++ ++ /* FALLTHRU */ ++ case INDEX_op_movcond_i64: ++ tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ break; ++ ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ tcg_out_qemu_ld(s, a0, a1, a2, ext); ++ break; ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ tcg_out_qemu_st(s, REG0(0), a1, a2); ++ break; ++ ++ case INDEX_op_bswap64_i64: /* 0x123456789abcdef--->0xefcdab8967452301 */ ++ tcg_debug_assert(0); ++ tcg_out_bswap64(s, a0, a1); ++ break; ++ case INDEX_op_bswap32_i64: /* 0x123456789abcdef--->0x67452301efcdab89 */ ++ tcg_debug_assert(0); ++ tcg_out_bswap32u(s, a0, a1); ++ break; ++ case INDEX_op_bswap32_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_bswap16_i64: /* 0x123456789abcdef--->0x23016745ab89efcd */ ++ case INDEX_op_bswap16_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext8s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext16s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_ext32s_i64: ++ tcg_out_insn_simpleReg(s, OPC_ADDW, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext8u_i32: ++ tcg_out_insn_simpleImm(s, OPC_EXT0B_I, a0, a1, 0x0); ++ break; ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext16u_i32: ++ tcg_out_insn_simpleImm(s, OPC_EXT1B_I, a0, a1, 0x0); ++ break; ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_ext32u_i64: ++ tcg_out_movr(s, TCG_TYPE_I32, a0, a1); ++ break; ++ ++ case INDEX_op_deposit_i64: ++ case INDEX_op_deposit_i32: ++ tcg_out_dep(s, a0, a2, args[3], args[4]); ++ break; ++ ++ case INDEX_op_extract_i64: ++ case INDEX_op_extract_i32: ++ tcg_out_extract(s, a0, a1, a2, args[3]); ++ break; ++ ++ case INDEX_op_sextract_i64: ++ case INDEX_op_sextract_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_extract2_i64: ++ case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_add2_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_add2_i64: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_sub2_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_sub2_i64: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_muluh_i64: ++ tcg_out_insn_simpleReg(s, OPC_UMULH, a0, a1, a2); ++ break; ++ case INDEX_op_mulsh_i64: /* sw not support */ ++ tcg_out_mulsh64(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_mb: ++ break; ++ ++ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ ++ case INDEX_op_mov_i64: ++ case INDEX_op_call: /* Always emitted via tcg_out_call. */ ++ default: ++ g_assert_not_reached(); ++ } ++ ++#undef REG0 ++} ++ ++ ++ ++/*sw ++* counting heading/tailing zero numbers ++*/ ++static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, ++ TCGReg rn, TCGArg b, bool const_b) ++{ ++ /* cond1. b is a const, and b=64 or b=32 */ ++ if (const_b && b == (ext ? 64 : 32)) { ++ /* count rn zero numbers, and writes to rd */ ++ tcg_out_insn_simpleReg(s, opc_clz, rd, TCG_REG_ZERO, rn); ++ }else { ++ /* TCG_REG_TMP= counting rn heading/tailing zero numbers */ ++ tcg_out_insn_simpleReg(s, opc_clz, TCG_REG_TMP, TCG_REG_ZERO, rn); ++ ++ if (const_b) { ++ if (b == -1) { ++ /* cond2. b is const and b=-1 */ ++ /* if rn != 0 , rd= counting rn heading/tailing zero numbers, else rd = 0xffffffffffffffff*/ ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } ++ else if (b == 0) { ++ /* cond3. b is const and b=0 */ ++ /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else rd = TCG_REG_ZERO */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_ZERO); ++ } else { ++ /* cond4. b is const */ ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, b); ++ /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else mov b to rd */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } ++ } ++ else { ++ /* if b is register */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, b); ++ } ++ } ++} ++ ++/*sw ++ * unsigned 16bit, ab->ba ++ */ ++static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP1 = rd; ++ /*t1=00b0*/ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); ++ /*t1=(0000)000a*/ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP0, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP0, TCG_TMP0, 0x1); ++ /*t1=ooba*/ ++ tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP0); ++} ++ ++/*sw ++ * signed 16bit, ab->ssba ++ */ ++static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = rn; ++ /*t1=(ssss)ssb0*/ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x2); ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, TCG_TMP1, TCG_REG_ZERO, TCG_TMP1); ++ /*t2=(0000)000a*/ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP2, 0x1); ++ /*t2=(ssss)ssba*/ ++ tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP2); ++} ++ ++ ++/*sw ++ * signed 32bit, abcd -> ssdcba ++ */ ++static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ /*swap32 -- 32-bit swap. a0 = abcd.*/ ++ ++ /* t3 = (ssss)d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x0f); ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, TCG_TMP1, TCG_REG_ZERO, TCG_TMP0); ++ tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x0f); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++ /* t1 = 000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x1); ++ ++ /* t2 = 00c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ ++ /* t3 = (ssss)d00a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++ /* t1 = 0abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); ++ ++ /* t2 = 0c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); ++ /* t1 = 00b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = (ssss)dc0a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = (ssss)dcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++} ++ ++/*sw ++ * unsigned 32bit, abcd->dcba ++ */ ++static void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ ++ /*bswap32u -- unsigned 32-bit swap. a0 = ....abcd.*/ ++ /* t1 = (0000)000d */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP1, TCG_TMP0, 0xff); ++ /* t3 = 000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP3, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x1); ++ /* t1 = (0000)d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); ++ /* t2 = 00c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ /* t3 = d00a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 0abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); ++ /* t2 = 0c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); ++ /* t1 = 00b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = dc0a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = dcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++} ++ ++ ++ ++/*sw ++ * swap 64bit, abcdefgh->hgfedcba ++ */ ++static void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ ++ /* bswap64 -- 64-bit swap. a0 = abcdefgh*/ ++ ++ /* t3 = h0000000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 56); ++ /* t1 = 0000000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 56); ++ /* t2 = 000000g0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ /* t3 = h000000a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 00000abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 40); ++ /* t2 = 0g000000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); ++ /* t1 = 000000b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = hg00000a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t2 = 0000abcd */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 32); ++ /* t3 = hg0000ba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 000000c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP2, 0x2); ++ /* t2 = 0000000d */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP2, 0xff); ++ /* t1 = 00000c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 8); ++ /* t2 = 0000d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 24); ++ /* t3 = hg000cba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 00abcdef */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 16); ++ /* t3 = hg00dcba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t2 = 0000000f */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP1, 0xff); ++ /* t1 = 000000e0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t2 = 00f00000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); ++ /* t1 = 000e0000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); ++ /* t3 = hgf0dcba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = hgfedcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++} ++ ++static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext) ++{ ++#ifndef CONFIG_SOFTMMU ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TCG_TYPE_I64; ++ ++ if (USE_GUEST_BASE) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); ++ tcg_out_qemu_ld_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); ++ } else { ++ tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ } ++#endif /* CONFIG_SOFTMMU */ ++ ++} ++ ++static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, ++ MemOpIdx oi) ++{ ++#ifndef CONFIG_SOFTMMU ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TCG_TYPE_I64; ++ ++ if (USE_GUEST_BASE) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); ++ tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); ++ } else { ++ tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ } ++#endif /* CONFIG_SOFTMMU */ ++} ++ ++ ++/*sw ++ * if cond is successful, ret=1, otherwise ret = 0 ++ */ ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGReg arg1, TCGReg arg2) ++{ ++ switch(cond) { ++ case TCG_COND_EQ: ++ case TCG_COND_LT: ++ case TCG_COND_LE: ++ case TCG_COND_LTU: ++ case TCG_COND_LEU: ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_cond_cmp(s, cond, ret, arg1, arg2, 0); ++ break; ++ default: ++ tcg_abort(); ++ break; ++ } ++} ++/*sw ++ * cond(a1,a2), yes:v1->ret, no:v2->ret ++ */ ++static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGReg a1, TCGReg a2, bool const_b, TCGReg v1, TCGReg v2) ++{ ++ tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a1, a2, const_b); ++ tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); ++} ++ ++ ++ ++/*sw ++ * extract rn[lsb, lsb+len-1] -> rd[0, len-1] ++ */ ++static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) ++{ ++ //get 000..111..0000 ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ /* get rn[lsb, lsb+len-1]-->rd[lsb, lsb+len-1] */ ++ tcg_out_insn_bitReg(s, OPC_AND, rd, rn, TCG_REG_TMP); ++ ++ /* rd[lsb, lsb+len-1] --> rd[0, len-1] */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, rd, rd, lsb); ++} ++ ++ ++/*sw ++ * depos: rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] ++ * len = msb -lsb + 1 ++ */ ++static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) ++{ ++ ++ //get 000..111..0000 ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ ++ /* TCG_REG_TMP2 = rn[msb,lsb] */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, TCG_REG_TMP2, 64-len-lsb); ++ ++ /* clear rd[msb,lsb] */ ++ tcg_out_insn_bitReg(s, OPC_BIC, rd, rd, TCG_REG_TMP); ++ /* rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] */ ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, rd, TCG_REG_TMP2); ++} ++ ++/*sw ++ * get val_s64(rn) * val_s64(rm) -> res_128 ++ * res[127:64] -> rd ++ * warn:maybe rd=rn or rm ++ */ ++static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out_insn_simpleReg(s, OPC_UMULH, TCG_REG_TMP, rn, rm); ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rm); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP2); ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rn); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++typedef struct { ++ DebugFrameHeader h; ++ uint8_t fde_def_cfa[4]; ++ uint8_t fde_reg_ofs[8 * 2]; ++} DebugFrame; ++ ++#define ELF_HOST_MACHINE EM_SW_64 ++/* GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, ++ which is good because they're really quite complicated for SW_64. */ ++ ++static const DebugFrame debug_frame = { ++ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ ++ .h.cie.id = -1, ++ .h.cie.version = 1, ++ .h.cie.code_align = 1, ++ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ ++ .h.cie.return_column = TCG_REG_RA, ++ ++ /* Total FDE size does not include the "len" member. */ ++ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), ++ ++ .fde_def_cfa = { ++ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ ++ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ ++ (FRAME_SIZE >> 7) ++ }, ++ .fde_reg_ofs = { ++ 0x80 + 14, 1, /* DW_CFA_offset, */ ++ 0x80 + 13, 2, /* DW_CFA_offset, */ ++ 0x80 + 12, 3, /* DW_CFA_offset, */ ++ 0x80 + 11, 4, /* DW_CFA_offset, */ ++ 0x80 + 10, 5, /* DW_CFA_offset, */ ++ 0x80 + 9, 6, /* DW_CFA_offset, */ ++ 0x80 + 26, 7, /* DW_CFA_offset, ra, -24 */ ++ 0x80 + 15, 8, /* DW_CFA_offset, fp, -8 */ ++ } ++}; ++ ++void tcg_register_jit(const void *buf, size_t buf_size) ++{ ++ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); ++} +diff --git a/tcg/sw64/tcg-target.h b/tcg/sw64/tcg-target.h +new file mode 100755 +index 0000000000..3093e4fece +--- /dev/null ++++ b/tcg/sw64/tcg-target.h +@@ -0,0 +1,123 @@ ++/* ++ * Initial TCG Implementation for sw_64 ++ * ++ */ ++ ++#ifndef SW_64_TCG_TARGET_H ++#define SW_64_TCG_TARGET_H ++ ++#define TCG_TARGET_INSN_UNIT_SIZE 4 ++ ++typedef enum { ++ TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, ++ TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, ++ TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, ++ TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15, ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, ++ TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, ++ TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, ++ TCG_REG_X28, TCG_REG_X29, TCG_REG_X30, TCG_REG_X31, ++ ++ TCG_REG_F0=32, TCG_REG_F1, TCG_REG_F2, TCG_REG_F3, ++ TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, ++ TCG_REG_F8, TCG_REG_F9, TCG_REG_F10, TCG_REG_F11, ++ TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, ++ TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, ++ TCG_REG_F20, TCG_REG_F21, TCG_REG_F22, TCG_REG_F23, ++ TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, ++ TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, TCG_REG_F31, ++ ++ /* Aliases. */ ++ TCG_REG_FP = TCG_REG_X15, ++ TCG_REG_RA = TCG_REG_X26, ++ TCG_REG_GP = TCG_REG_X29, ++ TCG_REG_SP = TCG_REG_X30, ++ TCG_REG_ZERO = TCG_REG_X31, ++ TCG_AREG0 = TCG_REG_X9, ++} TCGReg; ++ ++#define TCG_TARGET_NB_REGS 64 ++#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) ++ ++/* used for function call generation */ ++#define TCG_REG_CALL_STACK TCG_REG_SP ++#define TCG_TARGET_STACK_ALIGN 16 ++#define TCG_TARGET_CALL_ALIGN_ARGS 1 /*luo*/ ++#define TCG_TARGET_CALL_STACK_OFFSET 0 /*luo*/ ++#define TCG_TARGET_HAS_neg_i64 1 ++#define TCG_TARGET_HAS_direct_jump 0 ++#define TCG_TARGET_HAS_goto_ptr 1 ++#define TCG_TARGET_HAS_qemu_st8_i32 0 ++#define TCG_TARGET_HAS_not_i32 1 ++#define TCG_TARGET_HAS_neg_i32 1 ++#define TCG_TARGET_HAS_div_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 1 ++#define TCG_TARGET_HAS_rem_i32 0 ++#define TCG_TARGET_HAS_rot_i32 1 ++#define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_extract_i32 1 ++#define TCG_TARGET_HAS_sextract_i32 0 ++#define TCG_TARGET_HAS_extract2_i32 0 ++#define TCG_TARGET_HAS_add2_i32 0 ++#define TCG_TARGET_HAS_sub2_i32 0 ++#define TCG_TARGET_HAS_sub2_i32 0 ++#define TCG_TARGET_HAS_mulu2_i32 0 ++#define TCG_TARGET_HAS_muluh_i32 0 ++#define TCG_TARGET_HAS_muls2_i32 0 ++#define TCG_TARGET_HAS_not_i32 1 ++#define TCG_TARGET_HAS_mulsh_i32 0 ++#define TCG_TARGET_HAS_ext8s_i32 0 ++#define TCG_TARGET_HAS_ext16s_i32 0 ++#define TCG_TARGET_HAS_ext8u_i32 1 ++#define TCG_TARGET_HAS_ext16u_i32 1 ++#define TCG_TARGET_HAS_bswap16_i32 0 ++#define TCG_TARGET_HAS_bswap32_i32 0 ++#define TCG_TARGET_HAS_andc_i32 0 ++#define TCG_TARGET_HAS_eqv_i32 0 ++#define TCG_TARGET_HAS_nand_i32 0 ++#define TCG_TARGET_HAS_nor_i32 0 ++#define TCG_TARGET_HAS_clz_i32 0 ++#define TCG_TARGET_HAS_ctz_i32 0 ++#define TCG_TARGET_HAS_orc_i32 0 ++#define TCG_TARGET_HAS_ctpop_i32 0 ++#define TCG_TARGET_HAS_movcond_i64 1 ++#define TCG_TARGET_HAS_div_i64 1 ++#define TCG_TARGET_HAS_rem_i64 0 ++#define TCG_TARGET_HAS_div2_i64 0 ++#define TCG_TARGET_HAS_rot_i64 1 ++#define TCG_TARGET_HAS_deposit_i64 1 ++#define TCG_TARGET_HAS_extract_i64 1 ++#define TCG_TARGET_HAS_sextract_i64 0 ++#define TCG_TARGET_HAS_extract2_i64 0 ++#define TCG_TARGET_HAS_extrl_i64_i32 0 ++#define TCG_TARGET_HAS_extrh_i64_i32 0 ++#define TCG_TARGET_HAS_ext8s_i64 0 ++#define TCG_TARGET_HAS_ext16s_i64 0 ++#define TCG_TARGET_HAS_ext32s_i64 1 ++#define TCG_TARGET_HAS_ext8u_i64 1 ++#define TCG_TARGET_HAS_ext16u_i64 1 ++#define TCG_TARGET_HAS_ext32u_i64 1 ++#define TCG_TARGET_HAS_bswap16_i64 0 ++#define TCG_TARGET_HAS_bswap32_i64 0 ++#define TCG_TARGET_HAS_bswap64_i64 0 ++#define TCG_TARGET_HAS_not_i64 1 ++#define TCG_TARGET_HAS_andc_i64 0 ++#define TCG_TARGET_HAS_orc_i64 1 ++#define TCG_TARGET_HAS_eqv_i64 0 ++#define TCG_TARGET_HAS_nand_i64 0 ++#define TCG_TARGET_HAS_nor_i64 0 ++#define TCG_TARGET_HAS_clz_i64 1 ++#define TCG_TARGET_HAS_ctz_i64 1 ++#define TCG_TARGET_HAS_ctpop_i64 0 ++#define TCG_TARGET_HAS_add2_i64 0 ++#define TCG_TARGET_HAS_sub2_i64 0 ++#define TCG_TARGET_HAS_mulu2_i64 0 ++#define TCG_TARGET_HAS_muls2_i64 0 ++#define TCG_TARGET_HAS_muluh_i64 1 ++#define TCG_TARGET_HAS_mulsh_i64 1 ++#define TCG_TARGET_DEFAULT_MO (0) ++#define TCG_TARGET_HAS_MEMORY_BSWAP 0 ++/* optional instructions */ ++void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); ++#define TCG_TARGET_NEED_POOL_LABELS ++#endif /* SW_64_TCG_TARGET_H */ +diff --git a/tcg/sw64/tcg-target.opc.h b/tcg/sw64/tcg-target.opc.h +new file mode 100755 +index 0000000000..bce30accd9 +--- /dev/null ++++ b/tcg/sw64/tcg-target.opc.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2019 Linaro ++ * ++ * 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 for details. ++ * ++ * Target-specific opcodes for host vector expansion. These will be ++ * emitted by tcg_expand_vec_op. For those familiar with GCC internals, ++ * consider these to be UNSPEC with names. ++ */ ++ ++DEF(aa64_sshl_vec, 1, 2, 0, IMPLVEC) ++DEF(aa64_sli_vec, 1, 2, 1, IMPLVEC) +-- +2.27.0 + diff --git a/sw_64-Added-sw64-architecture-related-updates.patch b/sw_64-Added-sw64-architecture-related-updates.patch new file mode 100644 index 0000000000000000000000000000000000000000..dd2500908b9f79f15d8826a011992ca7d3e53a6a --- /dev/null +++ b/sw_64-Added-sw64-architecture-related-updates.patch @@ -0,0 +1,6108 @@ +From 91b0065ca578a6e494b39736f746fcddddfc2978 Mon Sep 17 00:00:00 2001 +From: Lu Feifei +Date: Wed, 26 Jul 2023 14:19:42 +0800 +Subject: [PATCH] sw_64: Added sw64 architecture related updates + +Signed-off-by: Lu Feifei +--- + configs/targets/sw64-linux-user.mak | 5 + + configs/targets/sw64-softmmu.mak | 1 + + disas/sw64.c | 41 +- + gdb-xml/sw64-core.xml | 43 + + hw/rtc/sun4v-rtc.c | 11 - + hw/sw64/Kconfig | 5 +- + hw/sw64/core3.c | 25 +- + hw/sw64/core3_board.c | 73 +- + hw/sw64/sw64_iommu.c | 11 +- + linux-headers/asm-sw64/kvm.h | 14 + + linux-user/elfload.c | 16 + + linux-user/host/sw64/host-signal.h | 46 + + linux-user/host/sw64/hostdep.h | 14 + + linux-user/sw64/cpu_loop.c | 5 +- + linux-user/sw64/meson.build | 5 + + linux-user/sw64/signal.c | 33 +- + linux-user/sw64/syscall.tbl | 488 +++++ + linux-user/sw64/syscallhdr.sh | 32 + + linux-user/sw64/target_cpu.h | 15 +- + linux-user/sw64/target_errno_defs.h | 204 ++ + linux-user/sw64/target_signal.h | 2 + + linux-user/sw64/target_syscall.h | 12 +- + linux-user/sw64/termbits.h | 1 + + linux-user/syscall_defs.h | 46 +- + pc-bios/core3-hmcode | Bin 225904 -> 227168 bytes + pc-bios/core3-reset | Bin 5032 -> 229200 bytes + pc-bios/uefi-bios-sw | Bin 3145728 -> 3145728 bytes + target/sw64/Makefile.objs | 1 + + target/sw64/cpu-param.h | 8 +- + target/sw64/cpu.c | 163 +- + target/sw64/cpu.h | 17 +- + target/sw64/gdbstub.c | 56 + + target/sw64/helper.c | 142 +- + target/sw64/kvm.c | 146 +- + target/sw64/kvm_sw64.h | 9 + + target/sw64/machine.c | 2 +- + target/sw64/meson.build | 1 + + target/sw64/translate.c | 2 +- + tcg/sw64/tcg-target.c.inc | 2839 +++++++++++++++------------ + tcg/sw64/tcg-target.h | 3 + + 40 files changed, 3043 insertions(+), 1494 deletions(-) + create mode 100644 configs/targets/sw64-linux-user.mak + create mode 100644 gdb-xml/sw64-core.xml + create mode 100644 linux-user/host/sw64/host-signal.h + create mode 100755 linux-user/host/sw64/hostdep.h + create mode 100644 linux-user/sw64/meson.build + create mode 100644 linux-user/sw64/syscall.tbl + create mode 100644 linux-user/sw64/syscallhdr.sh + create mode 100644 linux-user/sw64/target_errno_defs.h + mode change 100755 => 100644 pc-bios/core3-hmcode + create mode 100644 target/sw64/gdbstub.c + +diff --git a/configs/targets/sw64-linux-user.mak b/configs/targets/sw64-linux-user.mak +new file mode 100644 +index 0000000000..ae00665692 +--- /dev/null ++++ b/configs/targets/sw64-linux-user.mak +@@ -0,0 +1,5 @@ ++TARGET_ARCH=sw64 ++TARGET_SYSTBL_ABI=common ++TARGET_SYSTBL=syscall.tbl ++TARGET_ALIGNED_ONLY=y ++TARGET_XML_FILES= gdb-xml/sw64-core.xml +diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak +index 37cc2e05a6..9cf002df8c 100644 +--- a/configs/targets/sw64-softmmu.mak ++++ b/configs/targets/sw64-softmmu.mak +@@ -6,3 +6,4 @@ TARGET_ARCH=sw64 + TARGET_BASE_ARCH=sw64 + TARGET_ABI_DIR=sw64 + TARGET_SUPPORTS_MTTCG=y ++TARGET_XML_FILES= gdb-xml/sw64-core.xml +diff --git a/disas/sw64.c b/disas/sw64.c +index c5bd578e07..16504c673a 100755 +--- a/disas/sw64.c ++++ b/disas/sw64.c +@@ -62,7 +62,7 @@ extern const unsigned sw_64_num_opcodes; + #define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ + #define SW_LITOP(i) (((i) >> 26) & 0x3D) + +-#define SW_OPCODE_NOHM (~(SW_OPCODE_BASE|SW_OPCODE_CORE3)) ++#define SW_OPCODE_NOHMCODE (~(SW_OPCODE_BASE|SW_OPCODE_CORE3)) + + /* A macro to extract the major opcode from an instruction. */ + #define SW_OP(i) (((i) >> 26) & 0x3F) +@@ -328,18 +328,6 @@ static int extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) + return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); + } + +-static unsigned insert_bdisp26(unsigned insn, int value, const char **errmsg) +-{ +- if (errmsg != (const char **)NULL && (value & 3)) +- *errmsg = "branch operand unaligned"; +- return insn | ((value / 4) & 0x3FFFFFF); +-} +- +-static int extract_bdisp26(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +-{ +- return 4 * (((insn & 0x3FFFFFF) ^ 0x2000000) - 0x2000000); +-} +- + /* The hint field of a JMP/JSR insn. */ + /* sw use 16 bits hint disp. */ + static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) +@@ -480,13 +468,9 @@ const struct sw_64_operand sw_64_operands[] = { + { 16, 0, -HWINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, + + /* The 13-bit branch hint for the core3 hw_jmp/jsr (pal1e) insn. */ +-#define HWJMPHINT (HWINDEX + 1) +- { 8, 0, -HWJMPHINT, +- SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, +- insert_sw4hwjhint, extract_sw4hwjhint }, + + /* for the third operand of ternary operands integer insn. */ +-#define R3 (HWJMPHINT + 1) ++#define R3 (HWINDEX + 1) + { 5, 5, 0, SW_OPERAND_IR, 0, 0 }, + /* The plain fp register fields */ + #define F3 (R3 + 1) +@@ -494,19 +478,10 @@ const struct sw_64_operand sw_64_operands[] = { + /* sw simd settle instruction lit */ + #define FMALIT (F3 + 1) + { 5, 5, -FMALIT, SW_OPERAND_UNSIGNED, 0, 0 }, //V1.1 +-#define LMDISP (FMALIT + 1) +- { 15, 0, -LMDISP, SW_OPERAND_UNSIGNED, 0, 0 }, +-#define RPIINDEX (LMDISP + 1) ++#define RPIINDEX (FMALIT + 1) + { 8, 0, -RPIINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, + #define ATMDISP (RPIINDEX + 1) + { 12, 0, -ATMDISP, SW_OPERAND_SIGNED, 0, 0 }, +-#define DISP13 (ATMDISP + 1) +- { 13, 13, -DISP13, SW_OPERAND_SIGNED, 0, 0}, +-#define BDISP26 (DISP13 + 1) +- { 26, 0, 222, +- SW_OPERAND_RELATIVE, insert_bdisp26, extract_bdisp26 }, +-#define DPFTH (BDISP26 + 1) +- { 5, 21, -DPFTH, SW_OPERAND_UNSIGNED, 0, 0} + }; + + const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_operands); +@@ -578,7 +553,7 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera + #define PRIRET_MASK (OP_MASK | 0x100000) + #define PRIRET(oo,h) PRIRET_(oo,h), PRIRET_MASK + +-/* sw rpi_rcsr,rpi_wcsr. */ ++/* sw pri_rcsr,pri_wcsr. */ + #define CSR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 8)) + #define CSR_MASK (OP_MASK | 0xFF00) + #define CSR(oo,ff) CSR_(oo,ff), CSR_MASK +@@ -610,8 +585,6 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera + #define ARG_FMEM { FA, MDISP, PRB } + #define ARG_OPR { RA, RB, DRC1 } + +-#define ARG_OPRCAS { RA, RB, RC } +- + #define ARG_OPRL { RA, LIT, DRC1 } + #define ARG_OPRZ1 { ZA, RB, DRC1 } + #define ARG_OPRLZ1 { ZA, LIT, RC } +@@ -625,9 +598,6 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera + #define ARG_FMAL { FA,FB,FMALIT, DFC1 } + #define ARG_ATMEM { RA, ATMDISP, PRB } + #define ARG_VUAMEM { FA, ATMDISP, PRB } +-#define ARG_OPRLZ3 { RA, LIT, ZC } +- +-#define ARG_DISP13 {DISP13, RC} + + /* The opcode table. + +@@ -662,6 +632,7 @@ const struct sw_64_opcode sw_64_opcodes[] = { + { "jmp", MEM(0x03), BASE, { RA, CPRB, JMPHINT } }, + { "br", BRA(0x04), BASE, { ZA, BDISP } }, + { "br", BRA(0x04), BASE, ARG_BRA }, ++ { "bsr", BRA(0x05), BASE, { ZA, BDISP } }, + { "bsr", BRA(0x05), BASE, ARG_BRA }, + { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, + { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, +@@ -1110,7 +1081,7 @@ int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) + regnames = vms_regnames; + else + regnames = osf_regnames; +- isa_mask = SW_OPCODE_NOHM; ++ isa_mask = SW_OPCODE_NOHMCODE; + switch (info->mach) { + case bfd_mach_sw_64_core3: + isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE3; +diff --git a/gdb-xml/sw64-core.xml b/gdb-xml/sw64-core.xml +new file mode 100644 +index 0000000000..24527c175b +--- /dev/null ++++ b/gdb-xml/sw64-core.xml +@@ -0,0 +1,43 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c +index 58a0cff483..e037acd1b5 100644 +--- a/hw/rtc/sun4v-rtc.c ++++ b/hw/rtc/sun4v-rtc.c +@@ -32,17 +32,10 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr, + unsigned size) + { + uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; +-#if defined(__sw_64__) +- if (addr & 4ULL) { +- /* accessing the high 32 bits */ +- val >>= 32; +- } +-#else + if (!(addr & 4ULL)) { + /* accessing the high 32 bits */ + val >>= 32; + } +-#endif + trace_sun4v_rtc_read(addr, val); + return val; + } +@@ -56,11 +49,7 @@ static void sun4v_rtc_write(void *opaque, hwaddr addr, + static const MemoryRegionOps sun4v_rtc_ops = { + .read = sun4v_rtc_read, + .write = sun4v_rtc_write, +-#if defined(__sw_64__) +- .endianness = DEVICE_LITTLE_ENDIAN, +-#else + .endianness = DEVICE_NATIVE_ENDIAN, +-#endif + }; + + void sun4v_rtc_init(hwaddr addr) +diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig +index 2bf19e8234..0dc49576a5 100644 +--- a/hw/sw64/Kconfig ++++ b/hw/sw64/Kconfig +@@ -7,5 +7,8 @@ config CORE3 + select SUN4V_RTC + select VIRTIO_MMIO + select SERIAL +- select IDE_CMD646 + select VIRTIO_VGA ++ select IDE_CMD646 ++ select ISA_BUS ++ select PCKBD ++ select MSI_NONBROKEN +diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c +index dbe4ed6fa1..eceeb3bec3 100644 +--- a/hw/sw64/core3.c ++++ b/hw/sw64/core3.c +@@ -25,6 +25,10 @@ + #include "core.h" + #include "hw/boards.h" + #include "sysemu/numa.h" ++#include "qemu/uuid.h" ++#include "qemu/bswap.h" ++ ++#define VMUUID 0xFF40 + + static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) + { +@@ -69,6 +73,7 @@ static const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms) + ms->possible_cpus->cpus[i].vcpus_count = 1; + ms->possible_cpus->cpus[i].arch_id = i; + ms->possible_cpus->cpus[i].props.has_thread_id = true; ++ ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = i; + } + +@@ -96,6 +101,7 @@ static void core3_init(MachineState *machine) + uint64_t kernel_entry, kernel_low, kernel_high; + BOOT_PARAMS *core3_boot_params = g_new0(BOOT_PARAMS, 1); + uint64_t param_offset; ++ QemuUUID uuid_out_put; + + memset(cpus, 0, sizeof(cpus)); + +@@ -112,6 +118,9 @@ static void core3_init(MachineState *machine) + + rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); + ++ uuid_out_put = qemu_uuid; ++ uuid_out_put = qemu_uuid_bswap(uuid_out_put); ++ pstrcpy_targphys("vm-uuid", VMUUID, 0x12, (char *)&(uuid_out_put)); + param_offset = 0x90B000UL; + core3_boot_params->cmdline = param_offset | 0xfff0000000000000UL; + rom_add_blob_fixed("core3_boot_params", (core3_boot_params), 0x48, 0x90A100); +@@ -137,13 +146,24 @@ static void core3_init(MachineState *machine) + + /* Start all cpus at the hmcode RESET entry point. */ + for (i = 0; i < machine->smp.cpus; ++i) { +- cpus[i]->env.pc = hmcode_entry; ++ if (kvm_enabled()) ++ cpus[i]->env.pc = init_pc; ++ else ++ cpus[i]->env.pc = hmcode_entry; + cpus[i]->env.hm_entry = hmcode_entry; + } + + if (!kernel_filename) { + uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "uefi-bios-sw"); +- load_image_targphys(uefi_filename, 0x2f00000UL, -1); ++ if (uefi_filename == NULL) { ++ error_report("no virtual bios provided"); ++ exit(1); ++ } ++ size = load_image_targphys(uefi_filename, 0x2f00000UL, -1); ++ if (size < 0) { ++ error_report("could not load virtual bios: '%s'", uefi_filename); ++ exit(1); ++ } + g_free(uefi_filename); + } else { + /* Load a kernel. */ +@@ -170,6 +190,7 @@ static void core3_machine_init(MachineClass *mc) + mc->init = core3_init; + mc->block_default_type = IF_IDE; + mc->max_cpus = MAX_CPUS_CORE3; ++ mc->pci_allow_0_address = true; + mc->is_default = 0; + mc->reset = board_reset; + mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; +diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c +index 7853e01edb..7f623cf773 100644 +--- a/hw/sw64/core3_board.c ++++ b/hw/sw64/core3_board.c +@@ -16,17 +16,27 @@ + #include "hw/ide/ahci.h" + #include "sysemu/numa.h" + #include "sysemu/kvm.h" +-#include "hw/rtc/sun4v-rtc.h" ++#include "sysemu/cpus.h" + #include "hw/pci/msi.h" + #include "hw/sw64/sw64_iommu.h" ++#include "hw/loader.h" ++#include "hw/nvram/fw_cfg.h" + + #define TYPE_SWBOARD_PCI_HOST_BRIDGE "core_board-pcihost" + #define SWBOARD_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) + ++#define CORE3_MAX_CPUS_MASK 0x3ff ++#define CORE3_CORES_SHIFT 10 ++#define CORE3_CORES_MASK 0x3ff ++#define CORE3_THREADS_SHIFT 20 ++#define CORE3_THREADS_MASK 0xfff ++ + #define MAX_IDE_BUS 2 + #define SW_PIN_TO_IRQ 16 + ++#define SW_FW_CFG_P_BASE (0x804920000000ULL) ++ + typedef struct SWBoard { + SW64CPU *cpu[MAX_CPUS_CORE3]; + } SWBoard; +@@ -43,6 +53,16 @@ typedef struct TimerState { + int order; + } TimerState; + ++static void sw_create_fw_cfg(hwaddr addr) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ uint16_t smp_cpus = ms->smp.cpus; ++ FWCfgState *fw_cfg; ++ fw_cfg = fw_cfg_init_mem_wide(addr + 8, addr, 8, addr + 16, &address_space_memory); ++ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, smp_cpus); ++ rom_set_fw(fw_cfg); ++} ++ + #ifndef CONFIG_KVM + static void swboard_alarm_timer(void *opaque) + { +@@ -65,10 +85,13 @@ static PCIINTxRoute sw_route_intx_pin_to_irq(void *opaque, int pin) + + static uint64_t convert_bit(int n) + { +- uint64_t ret = (1UL << n) - 1; ++ uint64_t ret; + + if (n == 64) + ret = 0xffffffffffffffffUL; ++ else ++ ret = (1UL << n) - 1; ++ + return ret; + } + +@@ -76,6 +99,9 @@ static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) + { + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; ++ unsigned int smp_threads = ms->smp.threads; ++ unsigned int smp_cores = ms->smp.cores; ++ unsigned int max_cpus = ms->smp.max_cpus; + uint64_t ret = 0; + switch (addr) { + case 0x0000: +@@ -86,6 +112,12 @@ static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) + ret |= (1UL << i); + } + break; ++ case 0x0080: ++ /* SMP_INFO */ ++ ret = (smp_threads & CORE3_THREADS_MASK) << CORE3_THREADS_SHIFT; ++ ret += (smp_cores & CORE3_CORES_MASK) << CORE3_CORES_SHIFT; ++ ret += max_cpus & CORE3_MAX_CPUS_MASK; ++ break; + /*IO_START*/ + case 0x1300: + ret = 0x1; +@@ -186,7 +218,7 @@ static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + val &= 0x1f; + cpu = bs->sboard.cpu[val]; + cpu->env.csr[II_REQ] = 0x100000; +- cpu_interrupt(CPU(cpu),CPU_INTERRUPT_IIMAIL); ++ cpu_interrupt(CPU(cpu),CPU_INTERRUPT_II0); + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); +@@ -254,6 +286,33 @@ static const MemoryRegionOps msi_ops = { + }, + }; + ++static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; ++ return val; ++} ++ ++static void rtc_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++} ++ ++static const MemoryRegionOps rtc_ops = { ++ .read = rtc_read, ++ .write = rtc_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ + static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) + { + return 1; +@@ -392,7 +451,7 @@ void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) + MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); + MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); + MemoryRegion *io_ep = g_new(MemoryRegion, 1); +- ++ MemoryRegion *io_rtc = g_new(MemoryRegion, 1); + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + +@@ -452,6 +511,10 @@ void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) + "pci0-ep-conf-io", 4 * GB); + memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, + conf_piu0); ++ memory_region_init_io(io_rtc, OBJECT(bs), &rtc_ops, b, ++ "sw64-rtc", 0x08ULL); ++ memory_region_add_subregion(get_system_memory(), 0x804910000000ULL, ++ io_rtc); + #ifdef SW64_VT_IOMMU + sw64_vt_iommu_init(b); + #endif +@@ -476,7 +539,7 @@ void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) + DEVICE_LITTLE_ENDIAN); + } + pci_create_simple(phb->bus, -1, "nec-usb-xhci"); +- sun4v_rtc_init(0x804910000000ULL); ++ sw_create_fw_cfg(SW_FW_CFG_P_BASE); + } + + static const TypeInfo swboard_pcihost_info = { +diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c +index 8ded65f213..1ede2a2ce4 100644 +--- a/hw/sw64/sw64_iommu.c ++++ b/hw/sw64/sw64_iommu.c +@@ -124,7 +124,7 @@ static int get_pte(dma_addr_t baseaddr, uint64_t *pte) + + /* TODO: guarantee 64-bit single-copy atomicity */ + ret = dma_memory_read(&address_space_memory, baseaddr, +- (uint8_t *)pte, sizeof(*pte)); ++ (uint8_t *)pte, sizeof(*pte), MEMTXATTRS_UNSPECIFIED); + + if (ret != MEMTX_OK) + return -EINVAL; +@@ -195,15 +195,18 @@ static void swvt_ptiotlb_inv_all(SW64IOMMUState *s) + g_hash_table_remove_all(s->ptiotlb); + } + +-static void swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, +- hwaddr addr, IOMMUTLBEntry *entry) ++static IOMMUTLBEntry *swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, ++ hwaddr addr) + { + SW64PTIOTLBKey ptkey; ++ IOMMUTLBEntry *entry = NULL; + + ptkey.source_id = source_id; + ptkey.iova = addr; + + entry = g_hash_table_lookup(s->ptiotlb, &ptkey); ++ ++ return entry; + } + + static IOMMUTLBEntry sw64_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, +@@ -230,7 +233,7 @@ static IOMMUTLBEntry sw64_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, + + aligned_addr = addr & IOMMU_PAGE_MASK_8K; + +- swvt_lookup_ptiotlb(s, aligned_addr, source_id, cached_entry); ++ cached_entry = swvt_lookup_ptiotlb(s, source_id, aligned_addr); + + if (cached_entry) + goto out; +diff --git a/linux-headers/asm-sw64/kvm.h b/linux-headers/asm-sw64/kvm.h +index b0ce2ca346..5de7014b52 100644 +--- a/linux-headers/asm-sw64/kvm.h ++++ b/linux-headers/asm-sw64/kvm.h +@@ -2,6 +2,9 @@ + #define __LINUX_KVM_SW64_H + + #include ++ ++#define __KVM_HAVE_GUEST_DEBUG ++ + /* + * for KVM_GET_REGS and KVM_SET_REGS + */ +@@ -88,6 +91,16 @@ struct vcpucb { + unsigned long exit_reason; + unsigned long ipaddr; + unsigned long vcpu_irq_vector; ++ unsigned long pri_base; ++ unsigned long stack_pc_dfault; ++ unsigned long guest_p20; ++ unsigned long guest_dfault_double; ++ unsigned long guest_irqs_pending; ++ unsigned long guest_hm_r30; ++ unsigned long migration_mark; ++ unsigned long guest_longtime; ++ unsigned long guest_longtime_offset; ++ unsigned long reserved[3]; + }; + + /* +@@ -100,6 +113,7 @@ struct kvm_fpu { + * KVM SW_64 specific structures and definitions + */ + struct kvm_debug_exit_arch { ++ unsigned long epc; + }; + + /* for KVM_SET_GUEST_DEBUG */ +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 2625af99dd..e274c0bd33 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -1549,6 +1549,22 @@ static inline void init_thread(struct target_pt_regs *regs, + + #endif /* TARGET_HPPA */ + ++#ifdef TARGET_SW64 ++ ++#define ELF_CLASS ELFCLASS64 ++#define ELF_ARCH EM_SW64 ++ ++#define ELF_START_MMAP (0x30000000000ULL) ++ ++static inline void init_thread(struct target_pt_regs *regs, ++ struct image_info *infop) ++{ ++ regs->pc = infop->entry; ++ regs->usp = infop->start_stack; ++} ++ ++#endif /* TARGET_SW64 */ ++ + #ifdef TARGET_XTENSA + + #define ELF_START_MMAP 0x20000000 +diff --git a/linux-user/host/sw64/host-signal.h b/linux-user/host/sw64/host-signal.h +new file mode 100644 +index 0000000000..11d6e97605 +--- /dev/null ++++ b/linux-user/host/sw64/host-signal.h +@@ -0,0 +1,46 @@ ++/* ++ * host-signal.h: signal info dependent on the host architecture ++ * ++ * Copyright (c) 2023 wxiat ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW64_HOST_SIGNAL_H ++#define SW64_HOST_SIGNAL_H ++ ++static inline uintptr_t host_signal_pc(ucontext_t *uc) ++{ ++ return uc->uc_mcontext.sc_pc; ++} ++ ++static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc) ++{ ++ uc->uc_mcontext.sc_pc = pc; ++} ++ ++static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc) ++{ ++ uint32_t *pc = (uint32_t *)host_signal_pc(uc); ++ uint32_t insn = *pc; ++ ++ /* XXX: need kernel patch to get write flag faster */ ++ switch (insn >> 26) { ++ case 0x0d: /* stw */ ++ case 0x0e: /* stb */ ++ case 0x0f: /* stq_u */ ++ case 0x24: /* stf */ ++ case 0x25: /* stg */ ++ case 0x26: /* sts */ ++ case 0x27: /* stt */ ++ case 0x2c: /* stl */ ++ case 0x2d: /* stq */ ++ case 0x2e: /* stl_c */ ++ case 0x2f: /* stq_c */ ++ return true; ++ } ++ return false; ++} ++ ++#endif +diff --git a/linux-user/host/sw64/hostdep.h b/linux-user/host/sw64/hostdep.h +new file mode 100755 +index 0000000000..b30ac70100 +--- /dev/null ++++ b/linux-user/host/sw64/hostdep.h +@@ -0,0 +1,14 @@ ++/* ++ * hostdep.h : things which are dependent on the host architecture ++ * ++ * * Written by Wang Yuanheng ++ * ++ * Copyright (C) 2023 wxiat ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW_64_HOSTDEP_H ++#define SW_64_HOSTDEP_H ++#endif +diff --git a/linux-user/sw64/cpu_loop.c b/linux-user/sw64/cpu_loop.c +index 3f2fde0fba..389b753401 100644 +--- a/linux-user/sw64/cpu_loop.c ++++ b/linux-user/sw64/cpu_loop.c +@@ -18,8 +18,11 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu-common.h" + #include "qemu.h" ++#include "user-internals.h" + #include "cpu_loop-common.h" ++#include "signal-common.h" + + void cpu_loop(CPUSW64State *env) + { +@@ -89,7 +92,7 @@ void cpu_loop(CPUSW64State *env) + } + process_pending_signals (env); + +- /* Most of the traps imply a transition through HMcode, which ++ /* Most of the traps imply a transition through hmcode, which + implies an REI instruction has been executed. Which means + that RX and LOCK_ADDR should be cleared. But there are a + few exceptions for traps internal to QEMU. */ +diff --git a/linux-user/sw64/meson.build b/linux-user/sw64/meson.build +new file mode 100644 +index 0000000000..eda0056782 +--- /dev/null ++++ b/linux-user/sw64/meson.build +@@ -0,0 +1,5 @@ ++syscall_nr_generators += { ++ 'sw64': generator(sh, ++ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ], ++ output: '@BASENAME@_nr.h') ++} +diff --git a/linux-user/sw64/signal.c b/linux-user/sw64/signal.c +index 5822e808d3..572e192a95 100644 +--- a/linux-user/sw64/signal.c ++++ b/linux-user/sw64/signal.c +@@ -18,6 +18,7 @@ + */ + #include "qemu/osdep.h" + #include "qemu.h" ++#include "user-internals.h" + #include "signal-common.h" + #include "linux-user/trace.h" + +@@ -138,8 +139,8 @@ void setup_frame(int sig, struct target_sigaction *ka, + + setup_sigcontext(&frame->sc, env, frame_addr, set); + +- if (ka->sa_restorer) { +- r26 = ka->sa_restorer; ++ if (ka->ka_restorer) { ++ r26 = ka->ka_restorer; + } else { + __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, +@@ -192,8 +193,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, + __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); + } + +- if (ka->sa_restorer) { +- r26 = ka->sa_restorer; ++ if (ka->ka_restorer) { ++ r26 = ka->ka_restorer; + } else { + __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, +@@ -256,11 +257,7 @@ long do_rt_sigreturn(CPUSW64State *env) + set_sigmask(&set); + + restore_sigcontext(env, &frame->uc.tuc_mcontext); +- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, +- uc.tuc_stack), +- 0, env->ir[IDX_SP]) == -EFAULT) { +- goto badframe; +- } ++ target_restore_altstack(&frame->uc.tuc_stack, env); + + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; +@@ -271,3 +268,21 @@ badframe: + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; + } ++ ++void setup_sigtramp(abi_ulong sigtramp_page) ++{ ++ uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0); ++ assert(tramp != NULL); ++ ++ default_sigreturn = sigtramp_page; ++ __put_user(INSN_MOV_R30_R16, &tramp[0]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]); ++ __put_user(INSN_CALLSYS, &tramp[2]); ++ ++ default_rt_sigreturn = sigtramp_page + 3 * 4; ++ __put_user(INSN_MOV_R30_R16, &tramp[3]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]); ++ __put_user(INSN_CALLSYS, &tramp[5]); ++ ++ unlock_user(tramp, sigtramp_page, 6 * 4); ++} +diff --git a/linux-user/sw64/syscall.tbl b/linux-user/sw64/syscall.tbl +new file mode 100644 +index 0000000000..d007c7bb07 +--- /dev/null ++++ b/linux-user/sw64/syscall.tbl +@@ -0,0 +1,488 @@ ++# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++# ++# system call numbers and entry vectors for sw64 ++# ++# The format is: ++# ++# ++# The is always "common" for this file ++# ++0 common osf_syscall sw64_syscall_zero ++1 common exit sys_exit ++2 common fork sw64_fork ++3 common read sys_read ++4 common write sys_write ++5 common osf_old_open sys_ni_syscall ++6 common close sys_close ++7 common osf_wait4 sys_osf_wait4 ++8 common osf_old_creat sys_ni_syscall ++9 common link sys_link ++10 common unlink sys_unlink ++11 common osf_execve sys_ni_syscall ++12 common chdir sys_chdir ++13 common fchdir sys_fchdir ++14 common mknod sys_mknod ++15 common chmod sys_chmod ++16 common chown sys_chown ++17 common brk sys_osf_brk ++18 common osf_getfsstat sys_ni_syscall ++19 common lseek sys_lseek ++20 common getxpid sys_getxpid ++21 common osf_mount sys_osf_mount ++22 common umount2 sys_umount ++23 common setuid sys_setuid ++24 common getxuid sys_getxuid ++25 common exec_with_loader sys_ni_syscall ++26 common ptrace sys_ptrace ++27 common osf_nrecvmsg sys_ni_syscall ++28 common osf_nsendmsg sys_ni_syscall ++29 common osf_nrecvfrom sys_ni_syscall ++30 common osf_naccept sys_ni_syscall ++31 common osf_ngetpeername sys_ni_syscall ++32 common osf_ngetsockname sys_ni_syscall ++33 common access sys_access ++34 common osf_chflags sys_ni_syscall ++35 common osf_fchflags sys_ni_syscall ++36 common sync sys_sync ++37 common kill sys_kill ++38 common osf_old_stat sys_ni_syscall ++39 common setpgid sys_setpgid ++40 common osf_old_lstat sys_ni_syscall ++41 common dup sys_dup ++42 common pipe sys_sw64_pipe ++43 common osf_set_program_attributes sys_osf_set_program_attributes ++44 common osf_profil sys_ni_syscall ++45 common open sys_open ++46 common osf_old_sigaction sys_ni_syscall ++47 common getxgid sys_getxgid ++48 common osf_sigprocmask sys_osf_sigprocmask ++49 common osf_getlogin sys_ni_syscall ++50 common osf_setlogin sys_ni_syscall ++51 common acct sys_acct ++52 common sigpending sys_sigpending ++54 common ioctl sys_ioctl ++55 common osf_reboot sys_ni_syscall ++56 common osf_revoke sys_ni_syscall ++57 common symlink sys_symlink ++58 common readlink sys_readlink ++59 common execve sys_execve ++60 common umask sys_umask ++61 common chroot sys_chroot ++62 common osf_old_fstat sys_ni_syscall ++63 common getpgrp sys_getpgrp ++64 common getpagesize sys_getpagesize ++65 common osf_mremap sys_ni_syscall ++66 common vfork sw64_vfork ++67 common stat sys_newstat ++68 common lstat sys_newlstat ++69 common osf_sbrk sys_ni_syscall ++70 common osf_sstk sys_ni_syscall ++71 common mmap sys_osf_mmap ++72 common osf_old_vadvise sys_ni_syscall ++73 common munmap sys_munmap ++74 common mprotect sys_mprotect ++75 common madvise sys_madvise ++76 common vhangup sys_vhangup ++77 common osf_kmodcall sys_ni_syscall ++78 common osf_mincore sys_ni_syscall ++79 common getgroups sys_getgroups ++80 common setgroups sys_setgroups ++81 common osf_old_getpgrp sys_ni_syscall ++82 common setpgrp sys_setpgid ++83 common osf_setitimer compat_sys_setitimer ++84 common osf_old_wait sys_ni_syscall ++85 common osf_table sys_ni_syscall ++86 common osf_getitimer compat_sys_getitimer ++87 common gethostname sys_gethostname ++88 common sethostname sys_sethostname ++89 common getdtablesize sys_getdtablesize ++90 common dup2 sys_dup2 ++91 common fstat sys_newfstat ++92 common fcntl sys_fcntl ++93 common osf_select sys_osf_select ++94 common poll sys_poll ++95 common fsync sys_fsync ++96 common setpriority sys_setpriority ++97 common socket sys_socket ++98 common connect sys_connect ++99 common accept sys_accept ++100 common getpriority sys_osf_getpriority ++101 common send sys_send ++102 common recv sys_recv ++103 common sigreturn sys_sigreturn ++104 common bind sys_bind ++105 common setsockopt sys_setsockopt ++106 common listen sys_listen ++107 common osf_plock sys_ni_syscall ++108 common osf_old_sigvec sys_ni_syscall ++109 common osf_old_sigblock sys_ni_syscall ++110 common osf_old_sigsetmask sys_ni_syscall ++111 common sigsuspend sys_sigsuspend ++112 common osf_sigstack sys_osf_sigstack ++113 common recvmsg sys_recvmsg ++114 common sendmsg sys_sendmsg ++115 common osf_old_vtrace sys_ni_syscall ++116 common osf_gettimeofday sys_osf_gettimeofday ++117 common osf_getrusage sys_osf_getrusage ++118 common getsockopt sys_getsockopt ++120 common readv sys_osf_readv ++121 common writev sys_osf_writev ++122 common osf_settimeofday sys_osf_settimeofday ++123 common fchown sys_fchown ++124 common fchmod sys_fchmod ++125 common recvfrom sys_recvfrom ++126 common setreuid sys_setreuid ++127 common setregid sys_setregid ++128 common rename sys_rename ++129 common truncate sys_truncate ++130 common ftruncate sys_ftruncate ++131 common flock sys_flock ++132 common setgid sys_setgid ++133 common sendto sys_sendto ++134 common shutdown sys_shutdown ++135 common socketpair sys_socketpair ++136 common mkdir sys_mkdir ++137 common rmdir sys_rmdir ++138 common osf_utimes sys_osf_utimes ++139 common osf_old_sigreturn sys_ni_syscall ++140 common osf_adjtime sys_ni_syscall ++141 common getpeername sys_getpeername ++142 common osf_gethostid sys_ni_syscall ++143 common osf_sethostid sys_ni_syscall ++144 common getrlimit sys_getrlimit ++145 common setrlimit sys_setrlimit ++146 common osf_old_killpg sys_ni_syscall ++147 common setsid sys_setsid ++148 common quotactl sys_quotactl ++149 common osf_oldquota sys_ni_syscall ++150 common getsockname sys_getsockname ++153 common osf_pid_block sys_ni_syscall ++154 common osf_pid_unblock sys_ni_syscall ++156 common sigaction sys_osf_sigaction ++157 common osf_sigwaitprim sys_ni_syscall ++158 common osf_nfssvc sys_ni_syscall ++159 common osf_getdirentries sys_osf_getdirentries ++160 common osf_statfs sys_osf_statfs ++161 common osf_fstatfs sys_osf_fstatfs ++163 common osf_asynch_daemon sys_ni_syscall ++164 common osf_getfh sys_ni_syscall ++165 common osf_getdomainname sys_osf_getdomainname ++166 common setdomainname sys_setdomainname ++169 common osf_exportfs sys_ni_syscall ++181 common osf_alt_plock sys_ni_syscall ++184 common osf_getmnt sys_ni_syscall ++187 common osf_alt_sigpending sys_ni_syscall ++188 common osf_alt_setsid sys_ni_syscall ++199 common osf_swapon sys_swapon ++200 common msgctl sys_old_msgctl ++201 common msgget sys_msgget ++202 common msgrcv sys_msgrcv ++203 common msgsnd sys_msgsnd ++204 common semctl sys_old_semctl ++205 common semget sys_semget ++206 common semop sys_semop ++207 common osf_utsname sys_osf_utsname ++208 common lchown sys_lchown ++209 common shmat sys_shmat ++210 common shmctl sys_old_shmctl ++211 common shmdt sys_shmdt ++212 common shmget sys_shmget ++213 common osf_mvalid sys_ni_syscall ++214 common osf_getaddressconf sys_ni_syscall ++215 common osf_msleep sys_ni_syscall ++216 common osf_mwakeup sys_ni_syscall ++217 common msync sys_msync ++218 common osf_signal sys_ni_syscall ++219 common osf_utc_gettime sys_ni_syscall ++220 common osf_utc_adjtime sys_ni_syscall ++222 common osf_security sys_ni_syscall ++223 common osf_kloadcall sys_ni_syscall ++224 common osf_stat sys_osf_stat ++225 common osf_lstat sys_osf_lstat ++226 common osf_fstat sys_osf_fstat ++227 common osf_statfs64 sys_osf_statfs64 ++228 common osf_fstatfs64 sys_osf_fstatfs64 ++233 common getpgid sys_getpgid ++234 common getsid sys_getsid ++235 common sigaltstack sys_sigaltstack ++236 common osf_waitid sys_ni_syscall ++237 common osf_priocntlset sys_ni_syscall ++238 common osf_sigsendset sys_ni_syscall ++239 common osf_set_speculative sys_ni_syscall ++240 common osf_msfs_syscall sys_ni_syscall ++241 common osf_sysinfo sys_osf_sysinfo ++242 common osf_uadmin sys_ni_syscall ++243 common osf_fuser sys_ni_syscall ++244 common osf_proplist_syscall sys_osf_proplist_syscall ++245 common osf_ntp_adjtime sys_ni_syscall ++246 common osf_ntp_gettime sys_ni_syscall ++247 common osf_pathconf sys_ni_syscall ++248 common osf_fpathconf sys_ni_syscall ++250 common osf_uswitch sys_ni_syscall ++251 common osf_usleep_thread sys_osf_usleep_thread ++252 common osf_audcntl sys_ni_syscall ++253 common osf_audgen sys_ni_syscall ++254 common sysfs sys_sysfs ++255 common osf_subsys_info sys_ni_syscall ++256 common osf_getsysinfo sys_osf_getsysinfo ++257 common osf_setsysinfo sys_osf_setsysinfo ++258 common osf_afs_syscall sys_ni_syscall ++259 common osf_swapctl sys_ni_syscall ++260 common osf_memcntl sys_ni_syscall ++261 common osf_fdatasync sys_ni_syscall ++300 common bdflush sys_bdflush ++301 common sethae sys_sethae ++302 common mount sys_mount ++303 common old_adjtimex sys_old_adjtimex ++304 common swapoff sys_swapoff ++305 common getdents sys_getdents ++306 common create_module sys_ni_syscall ++307 common init_module sys_init_module ++308 common delete_module sys_delete_module ++309 common get_kernel_syms sys_ni_syscall ++310 common syslog sys_syslog ++311 common reboot sys_reboot ++312 common clone sw64_clone ++313 common uselib sys_uselib ++314 common mlock sys_mlock ++315 common munlock sys_munlock ++316 common mlockall sys_mlockall ++317 common munlockall sys_munlockall ++318 common sysinfo sys_sysinfo ++319 common _sysctl sys_ni_syscall ++# 320 was sys_idle ++321 common oldumount sys_oldumount ++322 common swapon sys_swapon ++323 common times sys_times ++324 common personality sys_personality ++325 common setfsuid sys_setfsuid ++326 common setfsgid sys_setfsgid ++327 common ustat sys_ustat ++328 common statfs sys_statfs ++329 common fstatfs sys_fstatfs ++330 common sched_setparam sys_sched_setparam ++331 common sched_getparam sys_sched_getparam ++332 common sched_setscheduler sys_sched_setscheduler ++333 common sched_getscheduler sys_sched_getscheduler ++334 common sched_yield sys_sched_yield ++335 common sched_get_priority_max sys_sched_get_priority_max ++336 common sched_get_priority_min sys_sched_get_priority_min ++337 common sched_rr_get_interval sys_sched_rr_get_interval ++338 common afs_syscall sys_ni_syscall ++339 common uname sys_newuname ++340 common nanosleep sys_nanosleep ++341 common mremap sys_mremap ++342 common nfsservctl sys_ni_syscall ++343 common setresuid sys_setresuid ++344 common getresuid sys_getresuid ++345 common pciconfig_read sys_pciconfig_read ++346 common pciconfig_write sys_pciconfig_write ++347 common query_module sys_ni_syscall ++348 common prctl sys_prctl ++349 common pread64 sys_pread64 ++350 common pwrite64 sys_pwrite64 ++351 common rt_sigreturn sys_rt_sigreturn ++352 common rt_sigaction sys_rt_sigaction ++353 common rt_sigprocmask sys_rt_sigprocmask ++354 common rt_sigpending sys_rt_sigpending ++355 common rt_sigtimedwait sys_rt_sigtimedwait ++356 common rt_sigqueueinfo sys_rt_sigqueueinfo ++357 common rt_sigsuspend sys_rt_sigsuspend ++358 common select sys_select ++359 common gettimeofday sys_gettimeofday ++360 common settimeofday sys_settimeofday ++361 common getitimer sys_getitimer ++362 common setitimer sys_setitimer ++363 common utimes sys_utimes ++364 common getrusage sys_getrusage ++365 common wait4 sys_wait4 ++366 common adjtimex sys_adjtimex ++367 common getcwd sys_getcwd ++368 common capget sys_capget ++369 common capset sys_capset ++370 common sendfile sys_sendfile64 ++371 common setresgid sys_setresgid ++372 common getresgid sys_getresgid ++373 common dipc sys_ni_syscall ++374 common pivot_root sys_pivot_root ++375 common mincore sys_mincore ++376 common pciconfig_iobase sys_pciconfig_iobase ++377 common getdents64 sys_getdents64 ++378 common gettid sys_gettid ++379 common readahead sys_readahead ++# 380 is unused ++381 common tkill sys_tkill ++382 common setxattr sys_setxattr ++383 common lsetxattr sys_lsetxattr ++384 common fsetxattr sys_fsetxattr ++385 common getxattr sys_getxattr ++386 common lgetxattr sys_lgetxattr ++387 common fgetxattr sys_fgetxattr ++388 common listxattr sys_listxattr ++389 common llistxattr sys_llistxattr ++390 common flistxattr sys_flistxattr ++391 common removexattr sys_removexattr ++392 common lremovexattr sys_lremovexattr ++393 common fremovexattr sys_fremovexattr ++394 common futex sys_futex ++395 common sched_setaffinity sys_sched_setaffinity ++396 common sched_getaffinity sys_sched_getaffinity ++397 common tuxcall sys_ni_syscall ++398 common io_setup sys_io_setup ++399 common io_destroy sys_io_destroy ++400 common io_getevents sys_io_getevents ++401 common io_submit sys_io_submit ++402 common io_cancel sys_io_cancel ++405 common exit_group sys_exit_group ++406 common lookup_dcookie sys_lookup_dcookie ++407 common epoll_create sys_epoll_create ++408 common epoll_ctl sys_epoll_ctl ++409 common epoll_wait sys_epoll_wait ++410 common remap_file_pages sys_remap_file_pages ++411 common set_tid_address sys_set_tid_address ++412 common restart_syscall sys_restart_syscall ++413 common fadvise64 sys_fadvise64 ++414 common timer_create sys_timer_create ++415 common timer_settime sys_timer_settime ++416 common timer_gettime sys_timer_gettime ++417 common timer_getoverrun sys_timer_getoverrun ++418 common timer_delete sys_timer_delete ++419 common clock_settime sys_clock_settime ++420 common clock_gettime sys_clock_gettime ++421 common clock_getres sys_clock_getres ++422 common clock_nanosleep sys_clock_nanosleep ++423 common semtimedop sys_semtimedop ++424 common tgkill sys_tgkill ++425 common stat64 sys_stat64 ++426 common lstat64 sys_lstat64 ++427 common fstat64 sys_fstat64 ++428 common vserver sys_ni_syscall ++429 common mbind sys_ni_syscall ++430 common get_mempolicy sys_ni_syscall ++431 common set_mempolicy sys_ni_syscall ++432 common mq_open sys_mq_open ++433 common mq_unlink sys_mq_unlink ++434 common mq_timedsend sys_mq_timedsend ++435 common mq_timedreceive sys_mq_timedreceive ++436 common mq_notify sys_mq_notify ++437 common mq_getsetattr sys_mq_getsetattr ++438 common waitid sys_waitid ++439 common add_key sys_add_key ++440 common request_key sys_request_key ++441 common keyctl sys_keyctl ++442 common ioprio_set sys_ioprio_set ++443 common ioprio_get sys_ioprio_get ++444 common inotify_init sys_inotify_init ++445 common inotify_add_watch sys_inotify_add_watch ++446 common inotify_rm_watch sys_inotify_rm_watch ++447 common fdatasync sys_fdatasync ++448 common kexec_load sys_kexec_load ++449 common migrate_pages sys_migrate_pages ++450 common openat sys_openat ++451 common mkdirat sys_mkdirat ++452 common mknodat sys_mknodat ++453 common fchownat sys_fchownat ++454 common futimesat sys_futimesat ++455 common fstatat64 sys_fstatat64 ++456 common unlinkat sys_unlinkat ++457 common renameat sys_renameat ++458 common linkat sys_linkat ++459 common symlinkat sys_symlinkat ++460 common readlinkat sys_readlinkat ++461 common fchmodat sys_fchmodat ++462 common faccessat sys_faccessat ++463 common pselect6 sys_pselect6 ++464 common ppoll sys_ppoll ++465 common unshare sys_unshare ++466 common set_robust_list sys_set_robust_list ++467 common get_robust_list sys_get_robust_list ++468 common splice sys_splice ++469 common sync_file_range sys_sync_file_range ++470 common tee sys_tee ++471 common vmsplice sys_vmsplice ++472 common move_pages sys_move_pages ++473 common getcpu sys_getcpu ++474 common epoll_pwait sys_epoll_pwait ++475 common utimensat sys_utimensat ++476 common signalfd sys_signalfd ++477 common timerfd sys_ni_syscall ++478 common eventfd sys_eventfd ++479 common recvmmsg sys_recvmmsg ++480 common fallocate sys_fallocate ++481 common timerfd_create sys_timerfd_create ++482 common timerfd_settime sys_timerfd_settime ++483 common timerfd_gettime sys_timerfd_gettime ++484 common signalfd4 sys_signalfd4 ++485 common eventfd2 sys_eventfd2 ++486 common epoll_create1 sys_epoll_create1 ++487 common dup3 sys_dup3 ++488 common pipe2 sys_pipe2 ++489 common inotify_init1 sys_inotify_init1 ++490 common preadv sys_preadv ++491 common pwritev sys_pwritev ++492 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo ++493 common perf_event_open sys_perf_event_open ++494 common fanotify_init sys_fanotify_init ++495 common fanotify_mark sys_fanotify_mark ++496 common prlimit64 sys_prlimit64 ++497 common name_to_handle_at sys_name_to_handle_at ++498 common open_by_handle_at sys_open_by_handle_at ++499 common clock_adjtime sys_clock_adjtime ++500 common syncfs sys_syncfs ++501 common setns sys_setns ++502 common accept4 sys_accept4 ++503 common sendmmsg sys_sendmmsg ++504 common process_vm_readv sys_process_vm_readv ++505 common process_vm_writev sys_process_vm_writev ++506 common kcmp sys_kcmp ++507 common finit_module sys_finit_module ++508 common sched_setattr sys_sched_setattr ++509 common sched_getattr sys_sched_getattr ++510 common renameat2 sys_renameat2 ++511 common getrandom sys_getrandom ++512 common memfd_create sys_memfd_create ++513 common execveat sys_execveat ++514 common seccomp sys_seccomp ++515 common bpf sys_bpf ++516 common userfaultfd sys_userfaultfd ++517 common membarrier sys_membarrier ++518 common mlock2 sys_mlock2 ++519 common copy_file_range sys_copy_file_range ++520 common preadv2 sys_preadv2 ++521 common pwritev2 sys_pwritev2 ++522 common statx sys_statx ++523 common io_pgetevents sys_io_pgetevents ++524 common pkey_mprotect sys_pkey_mprotect ++525 common pkey_alloc sys_pkey_alloc ++526 common pkey_free sys_pkey_free ++527 common rseq sys_rseq ++528 common statfs64 sys_statfs64 ++529 common fstatfs64 sys_fstatfs64 ++530 common getegid sys_getegid ++531 common geteuid sys_geteuid ++532 common getppid sys_getppid ++# all other architectures have common numbers for new syscall, sw64 ++# is the exception. ++534 common pidfd_send_signal sys_pidfd_send_signal ++535 common io_uring_setup sys_io_uring_setup ++536 common io_uring_enter sys_io_uring_enter ++537 common io_uring_register sys_io_uring_register ++538 common open_tree sys_open_tree ++539 common move_mount sys_move_mount ++540 common fsopen sys_fsopen ++541 common fsconfig sys_fsconfig ++542 common fsmount sys_fsmount ++543 common fspick sys_fspick ++544 common pidfd_open sys_pidfd_open ++# 545 reserved for clone3 ++546 common close_range sys_close_range ++547 common openat2 sys_openat2 ++548 common pidfd_getfd sys_pidfd_getfd ++549 common faccessat2 sys_faccessat2 ++550 common process_madvise sys_process_madvise ++551 common epoll_pwait2 sys_epoll_pwait2 ++552 common mount_setattr sys_mount_setattr ++# 553 reserved for quotactl_path ++554 common landlock_create_ruleset sys_landlock_create_ruleset ++555 common landlock_add_rule sys_landlock_add_rule ++556 common landlock_restrict_self sys_landlock_restrict_self +diff --git a/linux-user/sw64/syscallhdr.sh b/linux-user/sw64/syscallhdr.sh +new file mode 100644 +index 0000000000..46c166d8ae +--- /dev/null ++++ b/linux-user/sw64/syscallhdr.sh +@@ -0,0 +1,32 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++ ++in="$1" ++out="$2" ++my_abis=`echo "($3)" | tr ',' '|'` ++prefix="$4" ++offset="$5" ++ ++fileguard=LINUX_USER_SW64_`basename "$out" | sed \ ++ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ ++ -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` ++grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( ++ printf "#ifndef %s\n" "${fileguard}" ++ printf "#define %s\n" "${fileguard}" ++ printf "\n" ++ ++ nxt=0 ++ while read nr abi name entry ; do ++ if [ -z "$offset" ]; then ++ printf "#define TARGET_NR_%s%s\t%s\n" \ ++ "${prefix}" "${name}" "${nr}" ++ else ++ printf "#define TARGET_NR_%s%s\t(%s + %s)\n" \ ++ "${prefix}" "${name}" "${offset}" "${nr}" ++ fi ++ nxt=$((nr+1)) ++ done ++ ++ printf "\n" ++ printf "#endif /* %s */" "${fileguard}" ++) > "$out" +diff --git a/linux-user/sw64/target_cpu.h b/linux-user/sw64/target_cpu.h +index 1b87c8ba6d..63afa699c3 100644 +--- a/linux-user/sw64/target_cpu.h ++++ b/linux-user/sw64/target_cpu.h +@@ -17,13 +17,26 @@ + #ifndef SW64_TARGET_CPU_H + #define SW64_TARGET_CPU_H + +-static inline void cpu_clone_regs(CPUSW64State *env, target_ulong newsp) ++static inline void cpu_clone_regs_child(CPUSW64State *env, target_ulong newsp, unsigned flags) + { + if (newsp) { + env->ir[IDX_SP] = newsp; + } + env->ir[IDX_V0] = 0; + env->ir[IDX_A3] = 0; ++ env->ir[IDX_A4] = 1; /* OSF/1 secondary return: child */ ++} ++ ++static inline void cpu_clone_regs_parent(CPUSW64State *env, unsigned flags) ++{ ++ /* ++ * OSF/1 secondary return: parent ++ * Note that the kernel does not do this if SETTLS, because the ++ * settls argument register is still live after copy_thread. ++ */ ++ if (!(flags & CLONE_SETTLS)) { ++ env->ir[IDX_A4] = 0; ++ } + } + + static inline void cpu_set_tls(CPUSW64State *env, target_ulong newtls) +diff --git a/linux-user/sw64/target_errno_defs.h b/linux-user/sw64/target_errno_defs.h +new file mode 100644 +index 0000000000..fd637f5bc9 +--- /dev/null ++++ b/linux-user/sw64/target_errno_defs.h +@@ -0,0 +1,204 @@ ++#ifndef sw64_TARGET_ERRNO_DEFS_H ++#define sw64_TARGET_ERRNO_DEFS_H ++ ++#include "../generic/target_errno_defs.h" ++ ++/* ++ * Generic target errno overridden with definitions taken ++ * from asm-sw64/errno.h ++ */ ++#undef TARGET_EWOULDBLOCK ++#define TARGET_EWOULDBLOCK TARGET_EAGAIN ++#undef TARGET_EDEADLK ++#define TARGET_EDEADLK 11 ++#undef TARGET_EAGAIN ++#define TARGET_EAGAIN 35 ++#undef TARGET_EINPROGRESS ++#define TARGET_EINPROGRESS 36 ++#undef TARGET_EALREADY ++#define TARGET_EALREADY 37 ++#undef TARGET_ENOTSOCK ++#define TARGET_ENOTSOCK 38 ++#undef TARGET_EDESTADDRREQ ++#define TARGET_EDESTADDRREQ 39 ++#undef TARGET_EMSGSIZE ++#define TARGET_EMSGSIZE 40 ++#undef TARGET_EPROTOTYPE ++#define TARGET_EPROTOTYPE 41 ++#undef TARGET_ENOPROTOOPT ++#define TARGET_ENOPROTOOPT 42 ++#undef TARGET_EPROTONOSUPPORT ++#define TARGET_EPROTONOSUPPORT 43 ++#undef TARGET_ESOCKTNOSUPPORT ++#define TARGET_ESOCKTNOSUPPORT 44 ++#undef TARGET_EOPNOTSUPP ++#define TARGET_EOPNOTSUPP 45 ++#undef TARGET_EPFNOSUPPORT ++#define TARGET_EPFNOSUPPORT 46 ++#undef TARGET_EAFNOSUPPORT ++#define TARGET_EAFNOSUPPORT 47 ++#undef TARGET_EADDRINUSE ++#define TARGET_EADDRINUSE 48 ++#undef TARGET_EADDRNOTAVAIL ++#define TARGET_EADDRNOTAVAIL 49 ++#undef TARGET_ENETDOWN ++#define TARGET_ENETDOWN 50 ++#undef TARGET_ENETUNREACH ++#define TARGET_ENETUNREACH 51 ++#undef TARGET_ENETRESET ++#define TARGET_ENETRESET 52 ++#undef TARGET_ECONNABORTED ++#define TARGET_ECONNABORTED 53 ++#undef TARGET_ECONNRESET ++#define TARGET_ECONNRESET 54 ++#undef TARGET_ENOBUFS ++#define TARGET_ENOBUFS 55 ++#undef TARGET_EISCONN ++#define TARGET_EISCONN 56 ++#undef TARGET_ENOTCONN ++#define TARGET_ENOTCONN 57 ++#undef TARGET_ESHUTDOWN ++#define TARGET_ESHUTDOWN 58 ++#undef TARGET_ETOOMANYREFS ++#define TARGET_ETOOMANYREFS 59 ++#undef TARGET_ETIMEDOUT ++#define TARGET_ETIMEDOUT 60 ++#undef TARGET_ECONNREFUSED ++#define TARGET_ECONNREFUSED 61 ++#undef TARGET_ELOOP ++#define TARGET_ELOOP 62 ++#undef TARGET_ENAMETOOLONG ++#define TARGET_ENAMETOOLONG 63 ++#undef TARGET_EHOSTDOWN ++#define TARGET_EHOSTDOWN 64 ++#undef TARGET_EHOSTUNREACH ++#define TARGET_EHOSTUNREACH 65 ++#undef TARGET_ENOTEMPTY ++#define TARGET_ENOTEMPTY 66 ++/* Unused 67 */ ++#undef TARGET_EUSERS ++#define TARGET_EUSERS 68 ++#undef TARGET_EDQUOT ++#define TARGET_EDQUOT 69 ++#undef TARGET_ESTALE ++#define TARGET_ESTALE 70 ++#undef TARGET_EREMOTE ++#define TARGET_EREMOTE 71 ++/* Unused 72-76 */ ++#undef TARGET_ENOLCK ++#define TARGET_ENOLCK 77 ++#undef TARGET_ENOSYS ++#define TARGET_ENOSYS 78 ++/* Unused 79 */ ++#undef TARGET_ENOMSG ++#define TARGET_ENOMSG 80 ++#undef TARGET_EIDRM ++#define TARGET_EIDRM 81 ++#undef TARGET_ENOSR ++#define TARGET_ENOSR 82 ++#undef TARGET_ETIME ++#define TARGET_ETIME 83 ++#undef TARGET_EBADMSG ++#define TARGET_EBADMSG 84 ++#undef TARGET_EPROTO ++#define TARGET_EPROTO 85 ++#undef TARGET_ENODATA ++#define TARGET_ENODATA 86 ++#undef TARGET_ENOSTR ++#define TARGET_ENOSTR 87 ++#undef TARGET_ECHRNG ++#define TARGET_ECHRNG 88 ++#undef TARGET_EL2NSYNC ++#define TARGET_EL2NSYNC 89 ++#undef TARGET_EL3HLT ++#define TARGET_EL3HLT 90 ++#undef TARGET_EL3RST ++#define TARGET_EL3RST 91 ++#undef TARGET_ENOPKG ++#define TARGET_ENOPKG 92 ++#undef TARGET_ELNRNG ++#define TARGET_ELNRNG 93 ++#undef TARGET_EUNATCH ++#define TARGET_EUNATCH 94 ++#undef TARGET_ENOCSI ++#define TARGET_ENOCSI 95 ++#undef TARGET_EL2HLT ++#define TARGET_EL2HLT 96 ++#undef TARGET_EBADE ++#define TARGET_EBADE 97 ++#undef TARGET_EBADR ++#define TARGET_EBADR 98 ++#undef TARGET_EXFULL ++#define TARGET_EXFULL 99 ++#undef TARGET_ENOANO ++#define TARGET_ENOANO 100 ++#undef TARGET_EBADRQC ++#define TARGET_EBADRQC 101 ++#undef TARGET_EBADSLT ++#define TARGET_EBADSLT 102 ++/* Unused 103 */ ++#undef TARGET_EBFONT ++#define TARGET_EBFONT 104 ++#undef TARGET_ENONET ++#define TARGET_ENONET 105 ++#undef TARGET_ENOLINK ++#define TARGET_ENOLINK 106 ++#undef TARGET_EADV ++#define TARGET_EADV 107 ++#undef TARGET_ESRMNT ++#define TARGET_ESRMNT 108 ++#undef TARGET_ECOMM ++#define TARGET_ECOMM 109 ++#undef TARGET_EMULTIHOP ++#define TARGET_EMULTIHOP 110 ++#undef TARGET_EDOTDOT ++#define TARGET_EDOTDOT 111 ++#undef TARGET_EOVERFLOW ++#define TARGET_EOVERFLOW 112 ++#undef TARGET_ENOTUNIQ ++#define TARGET_ENOTUNIQ 113 ++#undef TARGET_EBADFD ++#define TARGET_EBADFD 114 ++#undef TARGET_EREMCHG ++#define TARGET_EREMCHG 115 ++#undef TARGET_EILSEQ ++#define TARGET_EILSEQ 116 ++/* Same as default 117-121 */ ++#undef TARGET_ELIBACC ++#define TARGET_ELIBACC 122 ++#undef TARGET_ELIBBAD ++#define TARGET_ELIBBAD 123 ++#undef TARGET_ELIBSCN ++#define TARGET_ELIBSCN 124 ++#undef TARGET_ELIBMAX ++#define TARGET_ELIBMAX 125 ++#undef TARGET_ELIBEXEC ++#define TARGET_ELIBEXEC 126 ++#undef TARGET_ERESTART ++#define TARGET_ERESTART 127 ++#undef TARGET_ESTRPIPE ++#define TARGET_ESTRPIPE 128 ++#undef TARGET_ENOMEDIUM ++#define TARGET_ENOMEDIUM 129 ++#undef TARGET_EMEDIUMTYPE ++#define TARGET_EMEDIUMTYPE 130 ++#undef TARGET_ECANCELED ++#define TARGET_ECANCELED 131 ++#undef TARGET_ENOKEY ++#define TARGET_ENOKEY 132 ++#undef TARGET_EKEYEXPIRED ++#define TARGET_EKEYEXPIRED 133 ++#undef TARGET_EKEYREVOKED ++#define TARGET_EKEYREVOKED 134 ++#undef TARGET_EKEYREJECTED ++#define TARGET_EKEYREJECTED 135 ++#undef TARGET_EOWNERDEAD ++#define TARGET_EOWNERDEAD 136 ++#undef TARGET_ENOTRECOVERABLE ++#define TARGET_ENOTRECOVERABLE 137 ++#undef TARGET_ERFKILL ++#define TARGET_ERFKILL 138 ++#undef TARGET_EHWPOISON ++#define TARGET_EHWPOISON 139 ++ ++#endif +diff --git a/linux-user/sw64/target_signal.h b/linux-user/sw64/target_signal.h +index 6393a7542f..8cc1693b05 100644 +--- a/linux-user/sw64/target_signal.h ++++ b/linux-user/sw64/target_signal.h +@@ -95,4 +95,6 @@ typedef struct target_sigaltstack { + #define TARGET_GEN_SUBRNG7 -25 + + #define TARGET_ARCH_HAS_SETUP_FRAME ++#define TARGET_ARCH_HAS_KA_RESTORER ++#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 + #endif /* SW64_TARGET_SIGNAL_H */ +diff --git a/linux-user/sw64/target_syscall.h b/linux-user/sw64/target_syscall.h +index c901ae95d8..418905110c 100644 +--- a/linux-user/sw64/target_syscall.h ++++ b/linux-user/sw64/target_syscall.h +@@ -23,22 +23,26 @@ struct target_pt_regs { + abi_ulong r27; + abi_ulong r28; + abi_ulong hae; +-/* JRP - These are the values provided to a0-a2 by HMcode */ ++/* JRP - These are the values provided to a0-a2 by hmcode */ + abi_ulong trap_a0; + abi_ulong trap_a1; + abi_ulong trap_a2; +-/* These are saved by HMcode: */ ++/* These are saved by hmcode: */ + abi_ulong ps; + abi_ulong pc; + abi_ulong gp; + abi_ulong r16; + abi_ulong r17; + abi_ulong r18; ++/* Those is needed by qemu to temporary store the user stack pointer */ ++ abi_ulong usp; ++ abi_ulong unique; + }; + +-#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +-#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + ++#define TARGET_MCL_CURRENT 0x2000 ++#define TARGET_MCL_FUTURE 0x4000 ++#define TARGET_MCL_ONFAULT 0x8000 + + #define UNAME_MACHINE "sw64" + #define UNAME_MINIMUM_RELEASE "2.6.32" +diff --git a/linux-user/sw64/termbits.h b/linux-user/sw64/termbits.h +index 37dd77120c..5c40efcb20 100644 +--- a/linux-user/sw64/termbits.h ++++ b/linux-user/sw64/termbits.h +@@ -156,6 +156,7 @@ struct target_termios { + #define TARGET_FLUSHO 0x00800000 + #define TARGET_PENDIN 0x20000000 + #define TARGET_IEXTEN 0x00000400 ++#define TARGET_EXTPROC 0x10000000 + + #define TARGET_FIOCLEX TARGET_IO('f', 1) + #define TARGET_FIONCLEX TARGET_IO('f', 2) +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index 04ca5fe7a0..a04f399278 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -85,7 +85,7 @@ + + #elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ + defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \ +- defined(TARGET_MIPS) ++ defined(TARGET_MIPS) || defined(TARGET_SW64) + + #define TARGET_IOC_SIZEBITS 13 + #define TARGET_IOC_DIRBITS 3 +@@ -2270,6 +2270,50 @@ struct target_stat { + int __unused[2]; + }; + ++#elif defined(TARGET_SW64) ++ ++struct target_stat { ++ unsigned int st_dev; ++ unsigned int st_ino; ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ unsigned int st_uid; ++ unsigned int st_gid; ++ unsigned int st_rdev; ++ abi_long st_size; ++ abi_ulong target_st_atime; ++ abi_ulong target_st_mtime; ++ abi_ulong target_st_ctime; ++ unsigned int st_blksize; ++ unsigned int st_blocks; ++ unsigned int st_flags; ++ unsigned int st_gen; ++}; ++ ++#define TARGET_HAS_STRUCT_STAT64 ++struct target_stat64 { ++ abi_ulong st_dev; ++ abi_ulong st_ino; ++ abi_ulong st_rdev; ++ abi_long st_size; ++ abi_ulong st_blocks; ++ ++ unsigned int st_mode; ++ unsigned int st_uid; ++ unsigned int st_gid; ++ unsigned int st_blksize; ++ unsigned int st_nlink; ++ unsigned int __pad0; ++ ++ abi_ulong target_st_atime; ++ abi_ulong target_st_atime_nsec; ++ abi_ulong target_st_mtime; ++ abi_ulong target_st_mtime_nsec; ++ abi_ulong target_st_ctime; ++ abi_ulong target_st_ctime_nsec; ++ abi_long __unused[3]; ++}; ++ + #else + #error unsupported CPU + #endif +diff --git a/target/sw64/Makefile.objs b/target/sw64/Makefile.objs +index 1e549d141c..c702eaa26d 100644 +--- a/target/sw64/Makefile.objs ++++ b/target/sw64/Makefile.objs +@@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o + obj-y += cpu.o translate.o profile.o helper.o + obj-y += int_helper.o float_helper.o simd_helper.o helper.o exception.o + obj-$(CONFIG_KVM) += kvm.o ++obj-y += gdbstub.o +diff --git a/target/sw64/cpu-param.h b/target/sw64/cpu-param.h +index 978a3cd572..464cfb3dc1 100644 +--- a/target/sw64/cpu-param.h ++++ b/target/sw64/cpu-param.h +@@ -7,18 +7,12 @@ + #ifndef SW64_CPU_PARAM_H + #define SW64_CPU_PARAM_H 1 + +-#define TARGET_LONG_BITS 64 /* if use th-1 ,TARGET_PAGE_BITS is 12 */ ++#define TARGET_LONG_BITS 64 + #define TARGET_PAGE_BITS 13 + +-#ifdef CONFIG_USER_ONLY + #define TARGET_VIRT_ADDR_SPACE_BITS 64 +-#else + #define TARGET_PHYS_ADDR_SPACE_BITS 48 +-#define TARGET_VIRT_ADDR_SPACE_BITS 64 +-#endif + +-#ifndef CONFIG_USER_ONLY + #define NB_MMU_MODES 4 +-#endif + + #endif +diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c +index 89c21850e1..8987361346 100644 +--- a/target/sw64/cpu.c ++++ b/target/sw64/cpu.c +@@ -26,7 +26,6 @@ + #include "sysemu/reset.h" + #include "hw/qdev-properties.h" + +- + static void sw64_cpu_set_pc(CPUState *cs, vaddr value) + { + SW64CPU *cpu = SW64_CPU(cs); +@@ -36,7 +35,6 @@ static void sw64_cpu_set_pc(CPUState *cs, vaddr value) + + static void sw64_cpu_dump_state(CPUState *cs, FILE *f, int flags) + { +-#ifndef CONFIG_KVM + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + int i; +@@ -91,7 +89,6 @@ static void sw64_cpu_dump_state(CPUState *cs, FILE *f, int flags) + qemu_fprintf(f, "\n"); + } + qemu_fprintf(f, "\n"); +-#endif + } + + #ifndef CONFIG_USER_ONLY +@@ -137,7 +134,6 @@ static void core3_init(Object *obj) + CPUSW64State *env = cs->env_ptr; + #ifdef CONFIG_USER_ONLY + env->fpcr = 0x680e800000000000; +- parallel_cpus = true; + #endif + set_feature(env, SW64_FEATURE_CORE3); + } +@@ -168,7 +164,7 @@ bool sw64_cpu_has_work(CPUState *cs) + * wake up by hard interrupt, timer, ii, mail or mchk. + */ + return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER | +- CPU_INTERRUPT_IIMAIL | CPU_INTERRUPT_MCHK); ++ CPU_INTERRUPT_II0| CPU_INTERRUPT_MCHK); + } + + static void sw64_cpu_initfn(Object *obj) +@@ -204,136 +200,6 @@ static void sw64_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr + } + #endif + +-#define a0(func) (((func & 0xFF) >> 6) & 0x1) +-#define a1(func) ((((func & 0xFF) >> 6) & 0x2) >> 1) +- +-#define t(func) ((a0(func) ^ a1(func)) & 0x1) +-#define b0(func) (t(func) | a0(func)) +-#define b1(func) ((~t(func) & 1) | a1(func)) +- +-#define START_SYS_CALL_ADDR(func) \ +- (b1(func) << 14) | (b0(func) << 13) | ((func & 0x3F) << 7) +- +-static void sw64_cpu_do_interrupt(CPUState *cs) +-{ +- int i = cs->exception_index; +- +- cs->exception_index = -1; +-#if !defined(CONFIG_USER_ONLY) +- SW64CPU *cpu = SW64_CPU(cs); +- CPUSW64State *env = &cpu->env; +- switch (i) { +- case EXCP_OPCDEC: +- cpu_abort(cs, "ILLEGAL INSN"); +- break; +- case EXCP_CALL_SYS: +- i = START_SYS_CALL_ADDR(env->error_code); +- if (i <= 0x3F) { +- i += 0x4000; +- } else if (i >= 0x40 && i <= 0x7F) { +- i += 0x2000; +- } else if (i >= 0x80 && i <= 0x8F) { +- i += 0x6000; +- } +- break; +- case EXCP_ARITH: +- env->error_code = -1; +- env->csr[EXC_PC] = env->pc - 4; +- env->csr[EXC_SUM] = 1; +- i = 0xB80; +- break; +- case EXCP_UNALIGN: +- i = 0xB00; +- env->csr[EXC_PC] = env->pc - 4; +- break; +- case EXCP_CLK_INTERRUPT: +- case EXCP_DEV_INTERRUPT: +- i = 0xE80; +- break; +- case EXCP_MMFAULT: +- i = 0x980; +- env->csr[EXC_PC] = env->pc; +- break; +- case EXCP_IIMAIL: +- env->csr[EXC_PC] = env->pc; +- i = 0xE00; +- break; +- default: +- break; +- } +- env->pc = env->hm_entry + i; +- env->flags = ENV_FLAG_HM_MODE; +-#else +- switch (i) { +- case EXCP_OPCDEC: +- cpu_abort(cs, "ILLEGAL INSN"); +- break; +- case EXCP_CALL_SYS: +- default: +- break; +- } +-#endif +-} +- +-#ifndef CONFIG_USER_ONLY +-static bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +-{ +- SW64CPU *cpu = SW64_CPU(cs); +- CPUSW64State *env = &cpu->env; +- int idx = -1; +- /* We never take interrupts while in Hardmode. */ +- if (env->flags & ENV_FLAG_HM_MODE) +- return false; +- +- if (interrupt_request & CPU_INTERRUPT_IIMAIL) { +- idx = EXCP_IIMAIL; +- env->csr[INT_STAT] |= 1UL << 6; +- if ((env->csr[IER] & env->csr[INT_STAT]) == 0) +- return false; +- cs->interrupt_request &= ~CPU_INTERRUPT_IIMAIL; +- goto done; +- } +- +- if (interrupt_request & CPU_INTERRUPT_TIMER) { +- idx = EXCP_CLK_INTERRUPT; +- env->csr[INT_STAT] |= 1UL << 4; +- if ((env->csr[IER] & env->csr[INT_STAT]) == 0) +- return false; +- cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; +- goto done; +- } +- +- if (interrupt_request & CPU_INTERRUPT_HARD) { +- idx = EXCP_DEV_INTERRUPT; +- env->csr[INT_STAT] |= 1UL << 12; +- if ((env->csr[IER] & env->csr[INT_STAT]) == 0) +- return false; +- cs->interrupt_request &= ~CPU_INTERRUPT_HARD; +- goto done; +- } +- +- if (interrupt_request & CPU_INTERRUPT_PCIE) { +- idx = EXCP_DEV_INTERRUPT; +- env->csr[INT_STAT] |= 1UL << 1; +- env->csr[INT_PCI_INT] = 0x10; +- if ((env->csr[IER] & env->csr[INT_STAT]) == 0) +- return false; +- cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; +- goto done; +- } +- +-done: +- if (idx >= 0) { +- cs->exception_index = idx; +- env->error_code = 0; +- env->csr[EXC_PC] = env->pc; +- sw64_cpu_do_interrupt(cs); +- return true; +- } +- return false; +-} +-#endif +- + static void sw64_cpu_reset(DeviceState *dev) + { + CPUState *s = CPU(dev); +@@ -370,17 +236,15 @@ static const struct SysemuCPUOps sw64_sysemu_ops = { + #include "hw/core/tcg-cpu-ops.h" + + static const struct TCGCPUOps sw64_tcg_ops = { +-#ifdef CONFIG_TCG + .initialize = sw64_translate_init, +- .tlb_fill = sw64_cpu_tlb_fill, +-#endif /* CONFIG_TCG */ + +-#if !defined(CONFIG_USER_ONLY) ++#ifndef CONFIG_USER_ONLY ++ .tlb_fill = sw64_cpu_tlb_fill, + .do_unaligned_access = sw64_cpu_do_unaligned_access, + .cpu_exec_interrupt = sw64_cpu_exec_interrupt, + .do_transaction_failed = sw64_cpu_do_transaction_failed, +-#endif /* !CONFIG_USER_ONLY */ + .do_interrupt = sw64_cpu_do_interrupt, ++#endif /* !CONFIG_USER_ONLY */ + }; + + static void sw64_cpu_class_init(ObjectClass *oc, void *data) +@@ -389,21 +253,26 @@ static void sw64_cpu_class_init(ObjectClass *oc, void *data) + CPUClass *cc = CPU_CLASS(oc); + SW64CPUClass *scc = SW64_CPU_CLASS(oc); + +- device_class_set_parent_realize(dc, sw64_cpu_realizefn, +- &scc->parent_realize); +- device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); +- device_class_set_props(dc, sw64_cpu_properties); ++ device_class_set_parent_realize(dc, sw64_cpu_realizefn, &scc->parent_realize); ++ device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); ++ device_class_set_props(dc, sw64_cpu_properties); + + cc->class_by_name = sw64_cpu_class_by_name; ++#ifndef CONFIG_USER_ONLY + dc->vmsd = &vmstate_sw64_cpu; ++ cc->sysemu_ops = &sw64_sysemu_ops; ++#endif + cc->has_work = sw64_cpu_has_work; + cc->set_pc = sw64_cpu_set_pc; + cc->disas_set_info = sw64_cpu_disas_set_info; + cc->dump_state = sw64_cpu_dump_state; ++ ++ cc->gdb_read_register = sw64_cpu_gdb_read_register; ++ cc->gdb_write_register = sw64_cpu_gdb_write_register; ++ cc->gdb_num_core_regs = 67; ++ cc->gdb_core_xml_file = "sw64-core.xml"; ++ + cc->tcg_ops = &sw64_tcg_ops; +-#ifndef CONFIG_USER_ONLY +- cc->sysemu_ops = &sw64_sysemu_ops; +-#endif + } + + static const SW64CPUInfo sw64_cpus[] = +diff --git a/target/sw64/cpu.h b/target/sw64/cpu.h +index 5a490e2b4a..4e14891e84 100644 +--- a/target/sw64/cpu.h ++++ b/target/sw64/cpu.h +@@ -60,6 +60,8 @@ + + #define MCU_CLOCK 25000000 + ++#define init_pc 0xffffffff80011100 ++ + typedef struct CPUSW64State CPUSW64State; + typedef CPUSW64State CPUArchState; + typedef SW64CPU ArchCPU; +@@ -136,7 +138,7 @@ struct SW64CPU { + CPUSW64State env; + + uint64_t k_regs[158]; +- uint64_t k_vcb[36]; ++ uint64_t k_vcb[48]; + QEMUTimer *alarm_timer; + target_ulong irq; + uint32_t cid; +@@ -227,6 +229,8 @@ static inline SW64CPU *sw64_env_get_cpu(CPUSW64State *env) + #define SW64_CPU_TYPE_SUFFIX "-" TYPE_SW64_CPU + #define SW64_CPU_TYPE_NAME(name) (name SW64_CPU_TYPE_SUFFIX) + int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); ++int sw64_cpu_gdb_read_register(CPUState *cs, uint8_t *buf, int reg); ++int sw64_cpu_gdb_write_register(CPUState *cs, uint8_t *buf, int reg); + bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); +@@ -236,6 +240,10 @@ void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val); + uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr); + void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val); + uint64_t cpu_sw64_load_fpcr(CPUSW64State *env); ++#ifndef CONFIG_USER_ONLY ++void sw64_cpu_do_interrupt(CPUState *cs); ++bool sw64_cpu_exec_interrupt(CPUState *cpu, int int_req); ++#endif + void cpu_sw64_store_fpcr(CPUSW64State *env, uint64_t val); + void sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, +@@ -245,7 +253,7 @@ extern struct VMStateDescription vmstate_sw64_cpu; + + /* SW64-specific interrupt pending bits */ + #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 +-#define CPU_INTERRUPT_IIMAIL CPU_INTERRUPT_TGT_EXT_1 ++#define CPU_INTERRUPT_II0 CPU_INTERRUPT_TGT_EXT_1 + #define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 + #define CPU_INTERRUPT_PCIE CPU_INTERRUPT_TGT_EXT_3 + #define CPU_INTERRUPT_WAKEUP CPU_INTERRUPT_TGT_EXT_3 +@@ -281,11 +289,14 @@ enum { + SWCSR(PTBR, 0x8), + SWCSR(PRI_BASE, 0x10), + SWCSR(TIMER_CTL, 0x2a), ++ SWCSR(TIMER_TH, 0x2b), + SWCSR(INT_STAT, 0x30), + SWCSR(INT_CLR, 0x31), + SWCSR(IER, 0x32), + SWCSR(INT_PCI_INT, 0x33), + SWCSR(DVA, 0x4e), ++ SWCSR(SOFT_CID, 0xc9), ++ SWCSR(SHTCLOCK, 0xca), + }; + + #include "exec/cpu-all.h" +@@ -302,7 +313,7 @@ void sw64_translate_init(void); + enum { + EXCP_NONE, + EXCP_HALT, +- EXCP_IIMAIL, ++ EXCP_II0, + EXCP_OPCDEC, + EXCP_CALL_SYS, + EXCP_ARITH, +diff --git a/target/sw64/gdbstub.c b/target/sw64/gdbstub.c +new file mode 100644 +index 0000000000..da4d39d215 +--- /dev/null ++++ b/target/sw64/gdbstub.c +@@ -0,0 +1,56 @@ ++/* ++ * SW64 gdb server stub ++ * ++ * Copyright (c) 2023 Lu Feifei ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "cpu.h" ++#include "exec/gdbstub.h" ++ ++int sw64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ ++ if (n < 31) { ++ return gdb_get_regl(mem_buf, env->ir[n]); ++ } else if (n == 31) { ++ return gdb_get_regl(mem_buf, 0); ++ } else if (n == 64) { ++ return gdb_get_regl(mem_buf, env->pc); ++ } ++ return 0; ++} ++ ++int sw64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ ++ if (n < 31) { ++ env->ir[n] = ldtul_p(mem_buf); ++ return sizeof(target_ulong); ++ } else if (n == 31) { ++ /* discard writes to r31 */ ++ return sizeof(target_ulong); ++ } else if (n == 64) { ++ env->pc = ldtul_p(mem_buf); ++ return sizeof(target_ulong); ++ } ++ ++ return 0; ++} +diff --git a/target/sw64/helper.c b/target/sw64/helper.c +index 0cc0af7087..e317c08f0a 100644 +--- a/target/sw64/helper.c ++++ b/target/sw64/helper.c +@@ -23,18 +23,7 @@ + #include "hw/core/cpu.h" + #include "exec/memattrs.h" + +-#if defined(CONFIG_USER_ONLY) +-bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, +- MMUAccessType access_type, int mmu_idx, +- bool probe, uintptr_t retaddr) +-{ +- SW64CPU *cpu = SW64_CPU(cs); +- +- cs->exception_index = EXCP_MMFAULT; +- cpu->env.trap_arg0 = address; +- cpu_loop_exit_restore(cs, retaddr); +-} +-#else ++#ifndef CONFIG_USER_ONLY + static target_ulong ldq_phys_clear(CPUState *cs, target_ulong phys) + { + return ldq_phys(cs->as, phys & ~(3UL)); +@@ -49,7 +38,7 @@ static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, + int prot = 0; + int ret = MM_K_ACV; + target_ulong L1pte, L2pte, L3pte, L4pte; +- target_ulong pt, index, pte_pfn_s; ++ target_ulong pt = 0, index = 0, pte_pfn_s = 0; + + if (((addr >> 28) & 0xffffffff8) == 0xffffffff8) { + phys = (~(0xffffffff80000000)) & addr; +@@ -217,6 +206,124 @@ do_pgmiss: + done: + return (fail >= 0 ? -1 : phys); + } ++ ++#define a0(func) (((func & 0xFF) >> 6) & 0x1) ++#define a1(func) ((((func & 0xFF) >> 6) & 0x2) >> 1) ++ ++#define t(func) ((a0(func) ^ a1(func)) & 0x1) ++#define b0(func) (t(func) | a0(func)) ++#define b1(func) ((~t(func) & 1) | a1(func)) ++ ++#define START_SYS_CALL_ADDR(func) \ ++ (b1(func) << 14) | (b0(func) << 13) | ((func & 0x3F) << 7) ++ ++void sw64_cpu_do_interrupt(CPUState *cs) ++{ ++ int i = cs->exception_index; ++ ++ cs->exception_index = -1; ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ switch (i) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL INSN"); ++ break; ++ case EXCP_CALL_SYS: ++ i = START_SYS_CALL_ADDR(env->error_code); ++ if (i <= 0x3F) { ++ i += 0x4000; ++ } else if (i >= 0x40 && i <= 0x7F) { ++ i += 0x2000; ++ } else if (i >= 0x80 && i <= 0x8F) { ++ i += 0x6000; ++ } ++ break; ++ case EXCP_ARITH: ++ env->error_code = -1; ++ env->csr[EXC_PC] = env->pc - 4; ++ env->csr[EXC_SUM] = 1; ++ i = 0xB80; ++ break; ++ case EXCP_UNALIGN: ++ i = 0xB00; ++ env->csr[EXC_PC] = env->pc - 4; ++ break; ++ case EXCP_CLK_INTERRUPT: ++ case EXCP_DEV_INTERRUPT: ++ i = 0xE80; ++ break; ++ case EXCP_MMFAULT: ++ i = 0x980; ++ env->csr[EXC_PC] = env->pc; ++ break; ++ case EXCP_II0: ++ env->csr[EXC_PC] = env->pc; ++ i = 0xE00; ++ break; ++ default: ++ break; ++ } ++ env->pc = env->hm_entry + i; ++ env->flags = ENV_FLAG_HM_MODE; ++} ++ ++bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ int idx = -1; ++ /* We never take interrupts while in PALmode. */ ++ if (env->flags & ENV_FLAG_HM_MODE) ++ return false; ++ ++ if (interrupt_request & CPU_INTERRUPT_II0) { ++ idx = EXCP_II0; ++ env->csr[INT_STAT] |= 1UL << 6; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_II0; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_TIMER) { ++ idx = EXCP_CLK_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 4; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_HARD) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 12; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_HARD; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_PCIE) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 1; ++ env->csr[INT_PCI_INT] = 0x10; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; ++ goto done; ++ } ++ ++done: ++ if (idx >= 0) { ++ cs->exception_index = idx; ++ env->error_code = 0; ++ env->csr[EXC_PC] = env->pc; ++ sw64_cpu_do_interrupt(cs); ++ return true; ++ } ++ ++ return false; ++} + #endif + + static void update_fpcr_status_mask(CPUSW64State* env) { +@@ -286,7 +393,9 @@ void cpu_sw64_store_fpcr(CPUSW64State* env, uint64_t val) { + uint64_t helper_read_csr(CPUSW64State *env, uint64_t index) + { + if (index == PRI_BASE) +- return 0x10000; ++ env->csr[index] = 0x10000; ++ if (index == SHTCLOCK) ++ env->csr[index] = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 40; + return env->csr[index]; + } + +@@ -311,9 +420,12 @@ void helper_write_csr(CPUSW64State *env, uint64_t index, uint64_t va) + (index == ITB_IS) || (index == PTBR)) { + tlb_flush(cs); + } +- if (index == INT_CLR || index == INT_PCI_INT) { ++ if (index == INT_CLR) { + env->csr[INT_STAT] &= ~va; + } ++ if ((index == TIMER_CTL) && (va == 1)) { ++ timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[TIMER_TH]); ++ } + + if (index == TIMER_CTL && env->csr[index] == 1) { + timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1000000000 / 250); +diff --git a/target/sw64/kvm.c b/target/sw64/kvm.c +index fc134c83fb..c38db7cabe 100644 +--- a/target/sw64/kvm.c ++++ b/target/sw64/kvm.c +@@ -25,7 +25,6 @@ + #include "hw/boards.h" + #include "qemu/log.h" + +-#define init_pc 0xffffffff80011000 + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; +@@ -71,6 +70,7 @@ void kvm_sw64_reset_vcpu(SW64CPU *cpu) + CPUState *cs = CPU(cpu); + struct kvm_regs *regs; + int ret; ++ struct vcpucb *vcb; + + regs = (struct kvm_regs *)cpu->k_regs; + regs->pc = init_pc; +@@ -82,6 +82,9 @@ void kvm_sw64_reset_vcpu(SW64CPU *cpu) + abort(); + } + ++ vcb = (struct vcpucb *)cpu->k_vcb; ++ vcb->vcpu_irq_disabled = 1; ++ + ret = kvm_vcpu_ioctl(cs, KVM_SW64_VCPU_INIT, NULL); + + if (ret < 0) { +@@ -113,12 +116,38 @@ int kvm_arch_destroy_vcpu(CPUState *cs) + + int kvm_arch_get_registers(CPUState *cs) + { +- int ret; ++ int ret, i; + SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &cpu->k_regs); + if (ret < 0) + return ret; +- return kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < 16; i++) ++ env->ir[i] = cpu->k_regs[i]; ++ ++ env->ir[16] = cpu->k_regs[155]; ++ env->ir[17] = cpu->k_regs[156]; ++ env->ir[18] = cpu->k_regs[157]; ++ ++ for (i = 19; i < 29; i++) ++ env->ir[i] = cpu->k_regs[i-3]; ++ ++ env->ir[29] = cpu->k_regs[154]; ++ ++ if (cpu->k_regs[152] >> 3) ++ env->ir[30] = cpu->k_vcb[3]; /* usp */ ++ else ++ env->ir[30] = cpu->k_vcb[2]; /* ksp */ ++ ++ env->pc = cpu->k_regs[153]; ++ ++ return 0; + } + + int kvm_arch_put_registers(CPUState *cs, int level) +@@ -126,15 +155,88 @@ int kvm_arch_put_registers(CPUState *cs, int level) + int ret; + SW64CPU *cpu = SW64_CPU(cs); + struct vcpucb *vcb; ++ ++ if (level == KVM_PUT_RUNTIME_STATE) { ++ int i; ++ CPUSW64State *env = &cpu->env; ++ ++ for (i = 0; i < 16; i++) ++ cpu->k_regs[i] = env->ir[i]; ++ ++ for (i = 19; i < 29; i++) ++ cpu->k_regs[i-3] = env->ir[i]; ++ ++ cpu->k_regs[155] = env->ir[16]; ++ cpu->k_regs[156] = env->ir[17]; ++ cpu->k_regs[157] = env->ir[18]; ++ ++ cpu->k_regs[154] = env->ir[29]; ++ ++ if (cpu->k_regs[152] >> 3) ++ cpu->k_vcb[3] = env->ir[30]; /* usp */ ++ else ++ cpu->k_vcb[2] = env->ir[30]; /* ksp */ ++ ++ cpu->k_regs[153] = env->pc; ++ } ++ + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &cpu->k_regs); + if (ret < 0) + return ret; + vcb = (struct vcpucb *)cpu->k_vcb; + vcb->whami = kvm_arch_vcpu_id(cs); + fprintf(stderr,"vcpu %ld init.\n", vcb->whami); ++ ++ if (level == KVM_PUT_RESET_STATE) ++ vcb->pcbb = 0; ++ + return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); + } + ++static const uint32_t brk_insn = 0x00000080; ++ ++int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ static uint32_t brk; ++ ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || ++ brk != brk_insn || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int kvm_arch_insert_hw_breakpoint(target_ulong addr, ++ target_ulong len, int type) ++{ ++ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); ++ return -EINVAL; ++} ++ ++int kvm_arch_remove_hw_breakpoint(target_ulong addr, ++ target_ulong len, int type) ++{ ++ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); ++ return -EINVAL; ++} ++ ++void kvm_arch_remove_all_hw_breakpoints(void) ++{ ++ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); ++} ++ + int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, + int vector, PCIDevice *dev) + { +@@ -156,10 +258,42 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) + return MEMTXATTRS_UNSPECIFIED; + } + ++bool kvm_sw64_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ ++ /* Ensure PC is synchronised */ ++ kvm_cpu_synchronize_state(cs); ++ ++ if (cs->singlestep_enabled) { ++ return true; ++ } else if (kvm_find_sw_breakpoint(cs, debug_exit->epc)) { ++ return true; ++ } else { ++ error_report("%s: unhandled debug exit (%"PRIx64", %"PRIx64")", ++ __func__, env->pc, debug_exit->epc); ++ } ++ ++ return false; ++} + + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + { +- return -1; ++ int ret = 0; ++ ++ switch (run->exit_reason) { ++ case KVM_EXIT_DEBUG: ++ if (kvm_sw64_handle_debug(cs, &run->debug.arch)) { ++ ret = EXCP_DEBUG; ++ } /* otherwise return to guest */ ++ break; ++ default: ++ qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", ++ __func__, run->exit_reason); ++ break; ++ } ++ return ret; + } + + bool kvm_arch_stop_on_emulation_error(CPUState *cs) +@@ -213,3 +347,7 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; + } ++ ++void kvm_arch_accel_class_init(ObjectClass *oc) ++{ ++} +diff --git a/target/sw64/kvm_sw64.h b/target/sw64/kvm_sw64.h +index 5ebd4ec6fd..81dd760008 100644 +--- a/target/sw64/kvm_sw64.h ++++ b/target/sw64/kvm_sw64.h +@@ -44,4 +44,13 @@ typedef struct SW64HostCPUClass { + uint32_t target; + const char *dtb_compatible; + } SW64HostCPUClass; ++ ++/** ++ * kvm_sw64_handle_debug: ++ * @cs: CPUState ++ * @debug_exit: debug part of the KVM exit structure ++ * ++ * Returns: TRUE if the debug exception was handled. ++ */ ++bool kvm_sw64_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit); + #endif +diff --git a/target/sw64/machine.c b/target/sw64/machine.c +index df18d3faba..93b1968ad8 100644 +--- a/target/sw64/machine.c ++++ b/target/sw64/machine.c +@@ -11,7 +11,7 @@ VMStateDescription vmstate_sw64_cpu = { + .fields = (VMStateField[]) { + #ifdef CONFIG_KVM + VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 158), +- VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 36), ++ VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 48), + #endif + VMSTATE_END_OF_LIST() + } +diff --git a/target/sw64/meson.build b/target/sw64/meson.build +index ee49e45927..332f2c2ee6 100644 +--- a/target/sw64/meson.build ++++ b/target/sw64/meson.build +@@ -4,6 +4,7 @@ sw64_ss.add(files( + 'exception.c', + 'float_helper.c', + 'helper.c', ++ 'gdbstub.c', + 'int_helper.c', + 'profile.c', + 'simd_helper.c', +diff --git a/target/sw64/translate.c b/target/sw64/translate.c +index 37b7e89077..1e725b9294 100644 +--- a/target/sw64/translate.c ++++ b/target/sw64/translate.c +@@ -2298,7 +2298,7 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, + /* RCID */ + if (disp16 && unlikely(ra == 31)) break; + va = load_gir(ctx, ra); +- read_csr(0xc4, va); ++ read_csr(0xc9, va); + break; + case 0x0080: + /* HALT */ +diff --git a/tcg/sw64/tcg-target.c.inc b/tcg/sw64/tcg-target.c.inc +index 982f159e23..da938a7382 100755 +--- a/tcg/sw64/tcg-target.c.inc ++++ b/tcg/sw64/tcg-target.c.inc +@@ -10,7 +10,6 @@ + the size of the operation performed. If we know the values match, it + makes things much cleaner. */ + QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1); +-static const tcg_insn_unit *tb_ret_addr; + + #ifdef CONFIG_DEBUG_TCG + static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { +@@ -33,13 +32,14 @@ static const int tcg_target_reg_alloc_order[] = { + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, + TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, + +- TCG_REG_X22, TCG_REG_X23, TCG_REG_X24, /*TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, */ ++ TCG_REG_X22, TCG_REG_X23, /* TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, */ + + /* TCG_REG_SP=TCG_REG_X15 saved for system*/ + TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, TCG_REG_X28, /* TCG_REG_X29, TCG_REG_X30, TCG_REG_X31 */ + + /* TCG_REG_TMP=TCG_REG_X27 reserved as temporary register */ + /* TCG_REG_TMP2=TCG_REG_X25 reserved as temporary register */ ++ /* TCG_REG_TMP3=TCG_REG_X24 reserved as temporary register */ + /* TCG_REG_RA=TCG_REG_X26 reserved as temporary */ + /* TCG_REG_GP=TCG_REG_X29 gp saved for system*/ + /* TCG_REG_SP=TCG_REG_X30 sp saved for system*/ +@@ -66,27 +66,103 @@ static const int tcg_target_call_oarg_regs[1] = { + + #define TCG_REG_TMP TCG_REG_X27 + #define TCG_REG_TMP2 TCG_REG_X25 ++#define TCG_REG_TMP3 TCG_REG_X24 + #define TCG_FLOAT_TMP TCG_REG_F10 + #define TCG_FLOAT_TMP2 TCG_REG_F11 + ++#define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) ++#define tcg_out_insn_jump tcg_out_insn_ldst ++#define tcg_out_insn_bitReg tcg_out_insn_simpleReg ++#define zeroExt 0 ++#define sigExt 1 ++#define noPara 0//represent this parament of function isnot needed. ++ ++#ifndef CONFIG_SOFTMMU ++#define USE_GUEST_BASE (guest_base != 0 || TARGET_LONG_BITS == 32) ++#define TCG_REG_GUEST_BASE TCG_REG_X14 ++#endif ++ ++static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target) ++{ ++ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); ++ ptrdiff_t offset = target - src_rx -1; ++ ++ if (offset == sextract64(offset, 0, 21)) { ++ /* read instruction, mask away previous PC_REL21 parameter contents, ++ set the proper offset, then write back the instruction. */ ++ *src_rw = deposit32(*src_rw, 0, 21, offset); ++ return true; ++ } ++ return false; ++} ++ ++static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) ++{ ++ tcg_debug_assert(addend == 0); ++ switch (type) { ++ case R_SW_64_BRADDR: ++ value = value; ++ return reloc_pc21(code_ptr, (const tcg_insn_unit *)value); ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++/* ++* contact with "tcg-target-con-str.h" ++*/ ++#define TCG_CT_CONST_ZERO 0x100 ++#define TCG_CT_CONST_LONG 0x200 ++#define TCG_CT_CONST_MONE 0x400 ++#define TCG_CT_CONST_ORRI 0x800 ++#define TCG_CT_CONST_WORD 0X1000 ++#define TCG_CT_CONST_U8 0x2000 ++#define TCG_CT_CONST_S8 0X4000 ++ + #define ALL_GENERAL_REGS 0xffffffffu ++#define ALL_VECTOR_REGS 0xffffffff00000000ull ++ ++#ifdef CONFIG_SOFTMMU ++#define ALL_QLDST_REGS \ ++ (ALL_GENERAL_REGS & ~((1 << TCG_REG_X0) | (1 << TCG_REG_X1) | \ ++ (1 << TCG_REG_X2) | (1 << TCG_REG_X3))) ++#else + #define ALL_QLDST_REGS ALL_GENERAL_REGS +-#define PUSH_SIZE ((15-9+1+1) * 8) +-#define FRAME_SIZE \ +- ((PUSH_SIZE \ +- + TCG_STATIC_CALL_ARGS_SIZE \ +- + CPU_TEMP_BUF_NLONGS * sizeof(long) \ +- + TCG_TARGET_STACK_ALIGN - 1) \ +- & ~(TCG_TARGET_STACK_ALIGN - 1)) +- +-/* We encode the format of the insn into the beginning of the name, so that +- we can have the preprocessor help "typecheck" the insn vs the output +- function. We don't have nice names for the formats, so we use the section +- number of the architecture reference manual in which the instruction +- group is described. */ +-#define OPC_OP(x) ((x & 0x3f) << 26) +-#define OPC_FUNC(x) ((x & 0xff) << 5) +-#define OPC_FUNC_COMPLEX(x) ((x & 0xff) << 10) ++#endif ++ ++/* sw test if a constant matches the constraint */ ++static bool tcg_target_const_match(tcg_target_long val, TCGType type, int ct) ++{ ++ if (ct & TCG_CT_CONST) { ++ return 1; ++ } ++ if (type == TCG_TYPE_I32) { ++ val = (int32_t)val; ++ } ++ if ((ct & TCG_CT_CONST_U8) && 0 <= val && val <= 255) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_LONG)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_MONE)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ORRI)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_WORD)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { ++ return 1; ++ } ++ return 0; ++} ++ ++#define OPC_OP(x) (((x) & 0x3f) << 26) ++#define OPC_FUNC(x) (((x) & 0xff) << 5) ++#define OPC_FUNC_COMPLEX(x) (((x) & 0xff) << 10) + typedef enum { + OPC_NOP =0X43ff075f, + OPC_SYS_CALL =OPC_OP(0x00), +@@ -103,7 +179,7 @@ typedef enum { + OPC_VLDD =OPC_OP(0x0D), + OPC_VSTS =OPC_OP(0x0E), + OPC_VSTD =OPC_OP(0x0F), +- ++ + OPC_LDBU =OPC_OP(0x20), + OPC_LDHU =OPC_OP(0x21), + OPC_LDW =OPC_OP(0x22), +@@ -120,7 +196,7 @@ typedef enum { + OPC_PRI_ST =OPC_OP(0x2D), + OPC_FSTS =OPC_OP(0x2E), + OPC_FSTD =OPC_OP(0x2F), +- ++ + OPC_BEQ =OPC_OP(0x30), + OPC_BNE =OPC_OP(0x31), + OPC_BLT =OPC_OP(0x32), +@@ -129,7 +205,7 @@ typedef enum { + OPC_BGE =OPC_OP(0x35), + OPC_BLBC =OPC_OP(0x36), + OPC_BLBS =OPC_OP(0x37), +- ++ + OPC_FBEQ =OPC_OP(0x38), + OPC_FBNE =OPC_OP(0x39), + OPC_FBLT =OPC_OP(0x3A), +@@ -138,7 +214,7 @@ typedef enum { + OPC_FBGE =OPC_OP(0x3D), + OPC_LDI =OPC_OP(0x3E), + OPC_LDIH =OPC_OP(0x3F), +- ++ + OPC_ADDW =(OPC_OP(0x10) | OPC_FUNC(0x0)), + OPC_ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x0)), + OPC_SUBW =(OPC_OP(0x10) | OPC_FUNC(0x1)), +@@ -147,62 +223,62 @@ typedef enum { + OPC_S4ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x02)), + OPC_S4SUBW =(OPC_OP(0x10) | OPC_FUNC(0x03)), + OPC_S4SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x03)), +- ++ + OPC_S8ADDW =(OPC_OP(0x10) | OPC_FUNC(0x04)), + OPC_S8ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x04)), + OPC_S8SUBW =(OPC_OP(0x10) | OPC_FUNC(0x05)), + OPC_S8SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x05)), +- ++ + OPC_ADDL =(OPC_OP(0x10) | OPC_FUNC(0x8)), + OPC_ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0x8)), + OPC_SUBL =(OPC_OP(0x10) | OPC_FUNC(0x9)), + OPC_SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0x9)), +- ++ + OPC_S4ADDL =(OPC_OP(0x10) | OPC_FUNC(0xA)), + OPC_S4ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xA)), + OPC_S4SUBL =(OPC_OP(0x10) | OPC_FUNC(0xB)), + OPC_S4SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xB)), +- ++ + OPC_S8ADDL =(OPC_OP(0x10) | OPC_FUNC(0xC)), + OPC_S8ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xC)), + OPC_S8SUBL =(OPC_OP(0x10) | OPC_FUNC(0xD)), + OPC_S8SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xD)), +- ++ + OPC_MULW =(OPC_OP(0x10) | OPC_FUNC(0x10)), + OPC_MULW_I =(OPC_OP(0x12) | OPC_FUNC(0x10)), + OPC_MULL =(OPC_OP(0x10) | OPC_FUNC(0x18)), + OPC_MULL_I =(OPC_OP(0x12) | OPC_FUNC(0x18)), +- ++ + OPC_UMULH =(OPC_OP(0x10) | OPC_FUNC(0x19)), + OPC_UMULH_I =(OPC_OP(0x12) | OPC_FUNC(0x19)), +- ++ + OPC_CTPOP =(OPC_OP(0x10) | OPC_FUNC(0x58)), + OPC_CTLZ =(OPC_OP(0x10) | OPC_FUNC(0x59)), + OPC_CTTZ =(OPC_OP(0x10) | OPC_FUNC(0x5A)), +- ++ + OPC_ZAP =(OPC_OP(0x10) | OPC_FUNC(0x68)), + OPC_ZAP_I =(OPC_OP(0x12) | OPC_FUNC(0x68)), + OPC_ZAPNOT =(OPC_OP(0x10) | OPC_FUNC(0x69)), + OPC_ZAPNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x69)), +- ++ + OPC_SEXTB =(OPC_OP(0x10) | OPC_FUNC(0x6A)), + OPC_SEXTB_I =(OPC_OP(0x12) | OPC_FUNC(0x6A)), + OPC_SEXTH =(OPC_OP(0x10) | OPC_FUNC(0x6B)), + OPC_SEXTH_I =(OPC_OP(0x12) | OPC_FUNC(0x6B)), +- ++ + OPC_CMPEQ =(OPC_OP(0x10) | OPC_FUNC(0x28)), + OPC_CMPEQ_I =(OPC_OP(0x12) | OPC_FUNC(0x28)), +- ++ + OPC_CMPLT =(OPC_OP(0x10) | OPC_FUNC(0x29)), + OPC_CMPLT_I =(OPC_OP(0x12) | OPC_FUNC(0x29)), + OPC_CMPLE =(OPC_OP(0x10) | OPC_FUNC(0x2A)), + OPC_CMPLE_I =(OPC_OP(0x12) | OPC_FUNC(0x2A)), +- ++ + OPC_CMPULT =(OPC_OP(0x10) | OPC_FUNC(0x2B)), + OPC_CMPULT_I =(OPC_OP(0x12) | OPC_FUNC(0x2B)), + OPC_CMPULE =(OPC_OP(0x10) | OPC_FUNC(0x2C)), + OPC_CMPULE_I =(OPC_OP(0x12) | OPC_FUNC(0x2C)), +- ++ + OPC_AND =(OPC_OP(0x10) | OPC_FUNC(0x38)), + OPC_BIC =(OPC_OP(0x10) | OPC_FUNC(0x39)), + OPC_BIS =(OPC_OP(0x10) | OPC_FUNC(0x3A)), +@@ -216,14 +292,14 @@ typedef enum { + OPC_ORNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x3B)), + OPC_XOR_I =(OPC_OP(0x12) | OPC_FUNC(0x3C)), + OPC_EQV_I =(OPC_OP(0x12) | OPC_FUNC(0x3D)), +- ++ + OPC_SLL =(OPC_OP(0x10) | OPC_FUNC(0x48)), + OPC_SRL =(OPC_OP(0x10) | OPC_FUNC(0x49)), + OPC_SRA =(OPC_OP(0x10) | OPC_FUNC(0x4A)), + OPC_SLL_I =(OPC_OP(0x12) | OPC_FUNC(0x48)), + OPC_SRL_I =(OPC_OP(0x12) | OPC_FUNC(0x49)), + OPC_SRA_I =(OPC_OP(0x12) | OPC_FUNC(0x4A)), +- ++ + OPC_SELEQ =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x00)), + OPC_SELGE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x01)), + OPC_SELGT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x02)), +@@ -240,7 +316,7 @@ typedef enum { + OPC_SELNE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x05)), + OPC_SELLBC_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x06)), + OPC_SELLBS_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x07)), +- ++ + OPC_INS0B =(OPC_OP(0x10) | OPC_FUNC(0x40)), + OPC_INS1B =(OPC_OP(0x10) | OPC_FUNC(0x41)), + OPC_INS2B =(OPC_OP(0x10) | OPC_FUNC(0x42)), +@@ -258,39 +334,39 @@ typedef enum { + OPC_INS6B_I =(OPC_OP(0x12) | OPC_FUNC(0x46)), + OPC_INS7B_I =(OPC_OP(0x12) | OPC_FUNC(0x47)), + +- OPC_EXT0B =(OPC_OP(0x10) | OPC_FUNC(0x50)), +- OPC_EXT1B =(OPC_OP(0x10) | OPC_FUNC(0x51)), +- OPC_EXT2B =(OPC_OP(0x10) | OPC_FUNC(0x52)), +- OPC_EXT3B =(OPC_OP(0x10) | OPC_FUNC(0x53)), +- OPC_EXT4B =(OPC_OP(0x10) | OPC_FUNC(0x54)), +- OPC_EXT5B =(OPC_OP(0x10) | OPC_FUNC(0x55)), +- OPC_EXT6B =(OPC_OP(0x10) | OPC_FUNC(0x56)), +- OPC_EXT7B =(OPC_OP(0x10) | OPC_FUNC(0x57)), +- OPC_EXT0B_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), +- OPC_EXT1B_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), +- OPC_EXT2B_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), +- OPC_EXT3B_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), +- OPC_EXT4B_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), +- OPC_EXT5B_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), +- OPC_EXT6B_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), +- OPC_EXT7B_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), ++ OPC_EXTLB =(OPC_OP(0x10) | OPC_FUNC(0x50)), ++ OPC_EXTLH =(OPC_OP(0x10) | OPC_FUNC(0x51)), ++ OPC_EXTLW =(OPC_OP(0x10) | OPC_FUNC(0x52)), ++ OPC_EXTLL =(OPC_OP(0x10) | OPC_FUNC(0x53)), ++ OPC_EXTHB =(OPC_OP(0x10) | OPC_FUNC(0x54)), ++ OPC_EXTHH =(OPC_OP(0x10) | OPC_FUNC(0x55)), ++ OPC_EXTHW =(OPC_OP(0x10) | OPC_FUNC(0x56)), ++ OPC_EXTHL =(OPC_OP(0x10) | OPC_FUNC(0x57)), ++ OPC_EXTLB_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), ++ OPC_EXTLH_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), ++ OPC_EXTLW_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), ++ OPC_EXTLL_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), ++ OPC_EXTHB_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), ++ OPC_EXTHH_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), ++ OPC_EXTHW_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), ++ OPC_EXTHL_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), + +- OPC_MASK0B =(OPC_OP(0x10) | OPC_FUNC(0x60)), +- OPC_MASK1B =(OPC_OP(0x10) | OPC_FUNC(0x61)), +- OPC_MASK2B =(OPC_OP(0x10) | OPC_FUNC(0x62)), +- OPC_MASK3B =(OPC_OP(0x10) | OPC_FUNC(0x63)), +- OPC_MASK4B =(OPC_OP(0x10) | OPC_FUNC(0x64)), +- OPC_MASK5B =(OPC_OP(0x10) | OPC_FUNC(0x65)), +- OPC_MASK6B =(OPC_OP(0x10) | OPC_FUNC(0x66)), +- OPC_MASK7B =(OPC_OP(0x10) | OPC_FUNC(0x67)), +- OPC_MASK0B_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), +- OPC_MASK1B_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), +- OPC_MASK2B_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), +- OPC_MASK3B_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), +- OPC_MASK4B_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), +- OPC_MASK5B_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), +- OPC_MASK6B_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), +- OPC_MASK7B_I =(OPC_OP(0x12) | OPC_FUNC(0x67)), ++ OPC_MASKLB =(OPC_OP(0x10) | OPC_FUNC(0x60)), ++ OPC_MASKLH =(OPC_OP(0x10) | OPC_FUNC(0x61)), ++ OPC_MASKLW =(OPC_OP(0x10) | OPC_FUNC(0x62)), ++ OPC_MASKLL =(OPC_OP(0x10) | OPC_FUNC(0x63)), ++ OPC_MASKHB =(OPC_OP(0x10) | OPC_FUNC(0x64)), ++ OPC_MASKHH =(OPC_OP(0x10) | OPC_FUNC(0x65)), ++ OPC_MASKHW =(OPC_OP(0x10) | OPC_FUNC(0x66)), ++ OPC_MASKHL =(OPC_OP(0x10) | OPC_FUNC(0x67)), ++ OPC_MASKLB_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), ++ OPC_MASKLH_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), ++ OPC_MASKLW_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), ++ OPC_MASKLL_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), ++ OPC_MASKHB_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), ++ OPC_MASKHH_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), ++ OPC_MASKHW_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), ++ OPC_MASKHL_I =(OPC_OP(0x12) | OPC_FUNC(0x67)), + + OPC_CNPGEB =(OPC_OP(0x10) | OPC_FUNC(0x6C)), + OPC_CNPGEB_I =(OPC_OP(0x12) | OPC_FUNC(0x6C)), +@@ -337,168 +413,162 @@ typedef enum { + OPC_FSQRTD = (OPC_OP(0x18) | OPC_FUNC(0x09)), + }SW_64Insn; + +-static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64); +-static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16); +-static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm); +-static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64); +-static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64); +-static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64); +-static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64); +-static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm); +-static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,TCGReg a1,TCGReg a2, bool const_b, TCGReg v1, TCGReg v2); +-static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target); +-static inline uint32_t tcg_in32(TCGContext *s); +-static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn); +-static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign); +-static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b); +-static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t aimm); +-static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m); +-static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); +-static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); +-static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); +-static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); +-static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, TCGReg rn, TCGArg b, bool const_b); +-static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn); +-static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn); +-static inline void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn); +-static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn); +-static inline void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn); +-static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi); +-static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext); +-static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg arg1, TCGReg arg2); +-static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); +-static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); +-static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm); +- +-#define tcg_out_insn_jump tcg_out_insn_ldst +-#define tcg_out_insn_bitReg tcg_out_insn_simpleReg ++static inline uint32_t tcg_in32(TCGContext *s) ++{ ++ uint32_t v = *(uint32_t *)s->code_ptr; ++ return v; ++} + +-static void tcg_target_init(TCGContext *s) ++/* ++ * SW instruction format of br(alias jump) ++ * insn = opcode[31,26]:Rd[25,21]:disp[20,0], ++ */ ++static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64) + { +- tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu; +- tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu; +- tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull; +- tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull; +- tcg_target_call_clobber_regs = -1ull; +- +- //sw_64 callee saved x9-x15 +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X9); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X10); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X11); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X12); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X13); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X14); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X15); +- +- //sw_64 callee saved f2~f9 +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F2); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F3); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F4); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F5); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F6); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F7); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F8); +- tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F9); ++ tcg_debug_assert(imm64 <= 0xfffff && imm64 >= -0x100000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (imm64 & 0x1fffff)); ++} + +- s->reserved_regs = 0; +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); //TCG_REG_X27 +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); //TCG_REG_X25 +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); //TCG_REG_X26 +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); /*sw_64 platform register */ +- tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); /*sw_64 platform register */ +- tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); /*sw_64 platform register */ ++/* ++ * SW instruction format of (load and store) ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16]:disp[15,0] ++ */ ++static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16) ++{ ++ tcg_debug_assert(imm16 <= 0x7fff && imm16 >= -0x8000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (rn & 0x1f) << 16 | (imm16 & 0xffff)); + } + ++/* ++ * SW instruction format of simple operator for Register ++ * insn = opcode[31,26]:rn(ra)[25,21]:rn(rb)[20,16]:Zeors[15,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn,TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (rn & 0x1f) << 21 | (rm & 0x1f) << 16 | (rd & 0x1f)); ++} + +-#ifndef CONFIG_SOFTMMU +- #define USE_GUEST_BASE guest_base != 0 +- #define TCG_REG_GUEST_BASE TCG_REG_X14 +-#endif ++/* ++ * SW instruction format of simple operator for imm ++ * insn = opcode[31,26]:rn(ra)[25,21]:disp[20,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64) ++{ ++ if (imm64 <= 0x7f && imm64 >= -0x80) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP3, imm64); ++ tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP3); ++ } ++} + ++static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ tcg_debug_assert(imm64 <= 255); ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++} + +-#define zeroExt 0 +-#define sigExt 1 ++/* ++ * sw bit operation: and bis etc ++ */ ++static void tcg_out_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ if (imm64 <= 255) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_bitReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ } ++} + ++/* ++ * SW instruction format of complex operator ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16],function[15,10]:rm[9,5]:rx[4,0] ++ */ ++static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (cond & 0x1f) << 21 | (rn & 0x1f) << 16 | (rm & 0x1f) << 5 | (rd & 0x1f)); ++} + +-static void tcg_target_qemu_prologue(TCGContext *s) ++static void tcg_out_insn_complexImm(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, intptr_t imm8, TCGReg rm) + { +- TCGReg r; +- int ofs; +- +- /* allocate space for all saved registers */ +- /* subl $sp,PUSH_SIZE,$sp */ +- tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); +- +- /* Push (FP, LR) */ +- /* stl $fp,0($sp) */ +- tcg_out_insn_ldst(s, OPC_STL, TCG_REG_FP, TCG_REG_SP, 0); +- /* stl $26,8($sp) */ +- tcg_out_insn_ldst(s, OPC_STL, TCG_REG_RA, TCG_REG_SP, 8); ++ tcg_out32(s, insn | (cond & 0x1f) << 21 | (imm8 & 0xff) << 13 | (rm & 0x1f) << 5 | (rd & 0x1f)); ++} + ++static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) ++{ ++ if (ext == TCG_TYPE_I64) { ++ tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); ++ } ++} + +- /* Set up frame pointer for canonical unwinding. */ +- /* TCG_REG_FP=TCG_REG_SP */ +- tcg_out_movr(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP); ++static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) ++{ ++ tcg_target_long l0=0, l1=0, l2=0, l3=0, extra=0; ++ tcg_target_long val = orig; ++ TCGReg rs = TCG_REG_ZERO; + +- /* Store callee-preserved regs x9..x14. */ +- for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1){ +- ofs = (r - TCG_REG_X9 + 2) * 8; +- tcg_out_insn_ldst(s, OPC_STL, r, TCG_REG_SP, ofs); ++ if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { ++ val = (int32_t)val;//val64bit + } + +- /* Make stack space for TCG locals. */ +- /* subl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ +- tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ if (orig == (int16_t)orig) { ++ tcg_out_insn_ldst(s, OPC_LDI, rd, TCG_REG_ZERO, (int16_t)orig); ++ return; ++ } + +- /* Inform TCG about how to find TCG locals with register, offset, size. */ +- tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, +- CPU_TEMP_BUF_NLONGS * sizeof(long)); ++ if (orig == (uint8_t)orig) { ++ tcg_out_insn_simpleImm(s, OPC_BIS_I, rd, TCG_REG_ZERO, (uint8_t)orig); ++ return; ++ } + +-#if !defined(CONFIG_SOFTMMU) +- if (USE_GUEST_BASE) { +- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); ++ if (type == TCG_TYPE_I32) { ++ val = (int32_t)val; + } +-#endif +- +- /* TCG_AREG0=tcg_target_call_iarg_regs[0], on sw, we mov $16 to $9 */ +- tcg_out_mov(s, TCG_TYPE_I64, TCG_AREG0, tcg_target_call_iarg_regs[0]); +- tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); + +- /* +- * Return path for goto_ptr. Set return value to 0, a-la exit_tb, +- * and fall through to the rest of the epilogue. +- */ +- tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, 0); ++ l0 = (int16_t)val; ++ val = (val - l0) >> 16; ++ l1 = (int16_t)val; + +- /* TB epilogue */ +- tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); ++ if (orig >> 31 == -1 || orig >> 31 == 0) { ++ if (l1 < 0 && orig >= 0) { ++ extra = 0x4000; ++ l1 = (int16_t)(val - 0x4000); ++ } ++ } else { ++ val = (val - l1) >> 16; ++ l2 = (int16_t)val; ++ val = (val - l2) >> 16; ++ l3 = (int16_t)val; + +- /* Remove TCG locals stack space. */ +- /* addl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ +- tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ if (l3) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l3); ++ rs = rd; ++ } ++ if (l2) { ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l2); ++ rs = rd; ++ } ++ if (l3 || l2) ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, rd, rd, 32); ++ } + +- /* Restore registers x9..x14. */ +- for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1) { +- int ofs = (r - TCG_REG_X9 + 2) * 8; +- tcg_out_insn_ldst(s, OPC_LDL, r, TCG_REG_SP, ofs); ++ if (l1) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l1); ++ rs = rd; + } + +- +- /* Pop (FP, LR) */ +- /* ldl $fp,0($sp) */ +- tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_FP, TCG_REG_SP, 0); +- /* ldl $26,8($sp) */ +- tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_RA, TCG_REG_SP, 8); +- +- /* restore SP to previous frame. */ +- /* addl $sp,PUSH_SIZE,$sp */ +- tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); +- +- tcg_out_insn_jump(s, OPC_RET, TCG_REG_ZERO, TCG_REG_RA, 0); ++ if (extra) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, extra); ++ rs = rd; ++ } ++ ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l0); ++ if (type == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } + } + + static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) +@@ -513,614 +583,541 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) + tcg_out_movr(s, type, ret, arg); + break; + } else if (ret < 32) { ++ tcg_debug_assert(0); + break; + } else if (arg < 32) { ++ tcg_debug_assert(0); + break; + } + /* FALLTHRU */ ++ case TCG_TYPE_V64: ++ case TCG_TYPE_V128: ++ tcg_debug_assert(0); ++ break; + default: + g_assert_not_reached(); + } + return true; + } + ++static inline void tcg_out_sxt(TCGContext *s, TCGType ext, MemOp s_bits, ++ TCGReg rd, TCGReg rn) ++{ ++ /* ++ * Using ALIASes SXTB, SXTH, SXTW, of SBFM Xd, Xn, #0, #7|15|31 ++ * int bits = (8 << s_bits) - 1; ++ * tcg_out_sbfm(s, ext, rd, rn, 0, bits); ++ */ ++ switch (s_bits) { ++ case MO_8: ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rn); ++ break; ++ case MO_16: ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rn); ++ break; ++ case MO_32: ++ tcg_out_insn_simpleReg(s, OPC_ADDW, rd, rn, TCG_REG_ZERO); ++ break; ++ default: ++ tcg_debug_assert(0); ++ break; ++ } ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++} + +-static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) ++/* ++ * counting heading/tailing zero numbers ++ */ ++static void tcg_out_ctz64(TCGContext *s, SW_64Insn opc, TCGReg rd, TCGReg rn, TCGArg b, bool const_b) + { +- switch (op) { +- case INDEX_op_goto_ptr: +- return C_O0_I1(r); ++ if (const_b && b == 64) { ++ if (opc == OPC_CTLZ) { ++ tcg_out_insn_simpleReg(s, OPC_CTLZ, rd, TCG_REG_ZERO, rn); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_CTTZ, rd, TCG_REG_ZERO, rn); ++ } ++ } else { ++ if (opc == OPC_CTLZ) { ++ tcg_out_insn_simpleReg(s, OPC_CTLZ, TCG_REG_TMP2, TCG_REG_ZERO, rn); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_CTTZ, TCG_REG_TMP2, TCG_REG_ZERO, rn); ++ } ++ if (const_b) { ++ if (b == -1) { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, rd, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, rd); ++ } else if (b == 0) { ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, TCG_REG_ZERO); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, rd, b); ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, rd); ++ } ++ } else { ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, b); ++ } ++ } ++} + +- case INDEX_op_ld8u_i32: +- case INDEX_op_ld8s_i32: +- case INDEX_op_ld16u_i32: +- case INDEX_op_ld16s_i32: +- case INDEX_op_ld_i32: +- case INDEX_op_ld8u_i64: +- case INDEX_op_ld8s_i64: +- case INDEX_op_ld16u_i64: +- case INDEX_op_ld16s_i64: +- case INDEX_op_ld32u_i64: +- case INDEX_op_ld32s_i64: +- case INDEX_op_ld_i64: +- case INDEX_op_neg_i32: +- case INDEX_op_neg_i64: +- case INDEX_op_not_i32: +- case INDEX_op_not_i64: +- case INDEX_op_bswap16_i32: +- case INDEX_op_bswap32_i32: +- case INDEX_op_bswap16_i64: +- case INDEX_op_bswap32_i64: +- case INDEX_op_bswap64_i64: +- case INDEX_op_ext8s_i32: +- case INDEX_op_ext16s_i32: +- case INDEX_op_ext8u_i32: +- case INDEX_op_ext16u_i32: +- case INDEX_op_ext8s_i64: +- case INDEX_op_ext16s_i64: +- case INDEX_op_ext32s_i64: +- case INDEX_op_ext8u_i64: +- case INDEX_op_ext16u_i64: +- case INDEX_op_ext32u_i64: +- case INDEX_op_ext_i32_i64: +- case INDEX_op_extu_i32_i64: +- case INDEX_op_extract_i32: +- case INDEX_op_extract_i64: +- case INDEX_op_sextract_i32: +- case INDEX_op_sextract_i64: +- return C_O1_I1(r, r); ++/* ++ * counting heading/tailing zero numbers ++ */ ++static void tcg_out_ctz32(TCGContext *s, SW_64Insn opc, TCGReg rd, TCGReg rn, TCGArg b, bool const_b) ++{ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, rn, 0xf); + +- case INDEX_op_st8_i32: +- case INDEX_op_st16_i32: +- case INDEX_op_st_i32: +- case INDEX_op_st8_i64: +- case INDEX_op_st16_i64: +- case INDEX_op_st32_i64: +- case INDEX_op_st_i64: +- return C_O0_I2(rZ, r); ++ if (const_b && b == 32) { ++ if (opc == OPC_CTLZ) { ++ tcg_out_insn_simpleReg(s, OPC_CTLZ, rd, TCG_REG_ZERO, TCG_REG_TMP); ++ tcg_out_insn_simpleImm(s, OPC_SUBW_I, rd, rd, 32); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_CTTZ, rd, TCG_REG_ZERO, TCG_REG_TMP); ++ tcg_out_insn_complexImm(s, OPC_SELEQ_I, TCG_REG_TMP, rd, 32, rd); ++ } ++ } else { ++ if (opc == OPC_CTLZ) { ++ tcg_out_insn_simpleReg(s, OPC_CTLZ, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_TMP); ++ tcg_out_insn_simpleImm(s, OPC_SUBW_I, TCG_REG_TMP2, TCG_REG_TMP2, 32); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_CTTZ, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_TMP); ++ tcg_out_insn_complexImm(s, OPC_SELEQ_I, TCG_REG_TMP, TCG_REG_TMP2, 32, TCG_REG_TMP2); ++ } ++ if (const_b) { ++ if (b == -1) { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, rd, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, rd); ++ } else if (b == 0) { ++ tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, TCG_REG_ZERO); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I32, rd, b); ++ tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, rd); ++ } ++ } else { ++ tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, b); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++ } ++} + +- case INDEX_op_add_i32: +- case INDEX_op_add_i64: +- case INDEX_op_sub_i32: +- case INDEX_op_sub_i64: +- return C_O1_I2(r, r, rU);//rA ++/* ++ * memory protect for order of (ld and st) ++ */ ++static void tcg_out_mb(TCGContext *s) ++{ ++ tcg_out32(s, OPC_MEMB); ++} + +- case INDEX_op_setcond_i32: +- case INDEX_op_setcond_i64: +- return C_O1_I2(r, r, rU);//compare,rA ++static inline void tcg_out_bswap16(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) ++{ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 1); + +- case INDEX_op_mul_i32: +- case INDEX_op_mul_i64: +- case INDEX_op_div_i32: +- case INDEX_op_div_i64: +- case INDEX_op_divu_i32: +- case INDEX_op_divu_i64: +- case INDEX_op_rem_i32: +- case INDEX_op_rem_i64: +- case INDEX_op_remu_i32: +- case INDEX_op_remu_i64: +- case INDEX_op_muluh_i64: +- case INDEX_op_mulsh_i64: +- return C_O1_I2(r, r, r); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_and_i32: +- case INDEX_op_and_i64: +- case INDEX_op_or_i32: +- case INDEX_op_or_i64: +- case INDEX_op_xor_i32: +- case INDEX_op_xor_i64: +- case INDEX_op_andc_i32: +- case INDEX_op_andc_i64: +- case INDEX_op_orc_i32: +- case INDEX_op_orc_i64: +- case INDEX_op_eqv_i32: +- case INDEX_op_eqv_i64: +- return C_O1_I2(r, r, rU);//rL ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 3); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_shl_i32: +- case INDEX_op_shr_i32: +- case INDEX_op_sar_i32: +- case INDEX_op_rotl_i32: +- case INDEX_op_rotr_i32: +- case INDEX_op_shl_i64: +- case INDEX_op_shr_i64: +- case INDEX_op_sar_i64: +- case INDEX_op_rotl_i64: +- case INDEX_op_rotr_i64: +- return C_O1_I2(r, r, ri); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); + +- case INDEX_op_clz_i32: +- case INDEX_op_clz_i64: +- return C_O1_I2(r, r, r); //rAL ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_ctz_i32: +- case INDEX_op_ctz_i64: +- return C_O1_I2(r, r, r);//rAL ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_brcond_i32: +- case INDEX_op_brcond_i64: +- return C_O0_I2(r, rU);//rA ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_movcond_i32: +- case INDEX_op_movcond_i64: +- return C_O1_I4(r, r, rU, rZ, rZ);//rA->rU ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 7); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_qemu_ld_i32: +- case INDEX_op_qemu_ld_i64: +- return C_O1_I1(r, l); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); ++ } ++} + +- case INDEX_op_qemu_st_i32: +- case INDEX_op_qemu_st_i64: +- return C_O0_I2(lZ, l); ++static void tcg_out_bswap32(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) ++{ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 3); + +- case INDEX_op_deposit_i32: +- case INDEX_op_deposit_i64: +- return C_O1_I2(r, 0, rZ); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_extract2_i32: +- case INDEX_op_extract2_i64: +- return C_O1_I2(r, rZ, rZ); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 1); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- case INDEX_op_add2_i32: +- case INDEX_op_add2_i64: +- case INDEX_op_sub2_i32: +- case INDEX_op_sub2_i64: +- return C_O2_I4(r, r, rZ, rZ, rA, rMZ); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); + +- case INDEX_op_add_vec: +- case INDEX_op_sub_vec: +- case INDEX_op_mul_vec: +- case INDEX_op_xor_vec: +- case INDEX_op_ssadd_vec: +- case INDEX_op_sssub_vec: +- case INDEX_op_usadd_vec: +- case INDEX_op_ussub_vec: +- case INDEX_op_smax_vec: +- case INDEX_op_smin_vec: +- case INDEX_op_umax_vec: +- case INDEX_op_umin_vec: +- case INDEX_op_shlv_vec: +- case INDEX_op_shrv_vec: +- case INDEX_op_sarv_vec: +- return C_O1_I2(w, w, w); +- case INDEX_op_not_vec: +- case INDEX_op_neg_vec: +- case INDEX_op_abs_vec: +- case INDEX_op_shli_vec: +- case INDEX_op_shri_vec: +- case INDEX_op_sari_vec: +- return C_O1_I1(w, w); +- case INDEX_op_ld_vec: +- case INDEX_op_dupm_vec: +- return C_O1_I1(w, r); +- case INDEX_op_st_vec: +- return C_O0_I2(w, r); +- case INDEX_op_dup_vec: +- return C_O1_I1(w, wr); +- case INDEX_op_or_vec: +- case INDEX_op_andc_vec: +- return C_O1_I2(w, w, wO); +- case INDEX_op_and_vec: +- case INDEX_op_orc_vec: +- return C_O1_I2(w, w, wN); +- case INDEX_op_cmp_vec: +- return C_O1_I2(w, w, wZ); +- case INDEX_op_bitsel_vec: +- return C_O1_I3(w, w, w, w); ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +- default: +- g_assert_not_reached(); +- } +-} ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 7); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +-static void tcg_out_nop_fill(tcg_insn_unit *p, int count) +-{ +- int i; +- for (i = 0; i < count; ++i) { +- p[i] = OPC_NOP; ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); ++ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } + } + +-/* SW instruction format of syscall +- * insn = opcode[31,26]:Function[25,0], +- */ +- +-/* SW instruction format of br(alias jump) +- * insn = opcode[31,26]:Rd[25,21]:disp[20,0], +- */ +-static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64) ++static void tcg_out_bswap64(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) + { +- tcg_debug_assert(imm64 <= 0xfffff && imm64 >= -0x100000); +- tcg_out32(s, insn | (rd & 0x1f) << 21 | (imm64 & 0x1fffff)); +-} ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 7); + ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +-/* SW instruction format of (load and store) +- * insn = opcode[31,26]:rd[25,21]:rn[20,16]:disp[15,0] +- */ +-static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16) +-{ +- tcg_debug_assert(imm16 <= 0x7fff && imm16 >= -0x8000); +- tcg_out32(s, insn | (rd & 0x1f) << 21 | (rn & 0x1f) << 16 | (imm16 & 0xffff)); +-} ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + +-/* SW instruction format of simple operator for Register +- * insn = opcode[31,26]:rn(ra)[25,21]:rn(rb)[20,16]:Zeors[15,13]:function[12,5]:rd(rc)[4,0] +- */ +-static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm) +-{ +- tcg_out32(s, insn | (rn & 0x1f) << 21 | (rm & 0x1f) << 16 | (rd & 0x1f)); ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 3); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); ++ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); ++ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 1); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); ++ ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } + +-/* SW instruction format of simple operator for imm +- * insn = opcode[31,26]:rn(ra)[25,21]:disp[20,13]:function[12,5]:rd(rc)[4,0] +- */ +-static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64) ++static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) + { +- if(imm64 <= 0x7f && imm64 >= -0x80) { +- tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); +- } +- else { +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); +- tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP); +- } +-} ++ //get 000..111..0000 ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ /* get rn[lsb, lsb+len-1]-->rd[lsb, lsb+len-1] */ ++ tcg_out_insn_bitReg(s, OPC_AND, rd, rn, TCG_REG_TMP); + ++ /* rd[lsb, lsb+len-1] --> rd[0, len-1] */ ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, rd, rd, lsb); ++} + +-static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64) ++static void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, int lsb, int len) + { +- tcg_debug_assert(imm64 <= 0x7f && imm64 >= -0x80); +- tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ ++ /* TCG_REG_TMP2 = rn[msb,lsb] */ ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, TCG_REG_TMP2, 64-len-lsb); + ++ /* clear rd[msb,lsb] */ ++ tcg_out_insn_bitReg(s, OPC_BIC, rd, rd, TCG_REG_TMP); ++ /* rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] */ ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, rd, TCG_REG_TMP2); ++ ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } + } + +-static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64) ++static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) + { +- tcg_debug_assert(imm64 <= 255); +- tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ tcg_out_insn_simpleReg(s, OPC_UMULH, TCG_REG_TMP, rn, rm); ++ ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rm); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP2); ++ ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rn); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, TCG_REG_TMP, TCG_REG_TMP2); + } +-/* sw bit operation: and bis etc */ +-static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64) ++ ++static void tcg_out_sar(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGArg a2, bool c2) + { +- if (imm64 <= 255) { +- tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); +- } +- else { +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); +- tcg_out_insn_bitReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ unsigned int bits = ext ? 64 : 32; ++ unsigned int max = bits - 1; ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleReg(s, OPC_ADDW, TCG_REG_TMP, rn, TCG_REG_ZERO); ++ ++ if (c2) { ++ tcg_out_insn_simpleImm(s, OPC_SRA_I, rd, TCG_REG_TMP, a2 & max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRA, rd, TCG_REG_TMP, a2); ++ } ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } else { ++ if (c2) { ++ tcg_out_insn_simpleImm(s, OPC_SRA_I, rd, rn, a2 & max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRA, rd, rn, a2); ++ } + } + } + +-/* SW instruction format of complex operator +- * insn = opcode[31,26]:rd[25,21]:rn[20,16],function[15,10]:rm[9,5]:rx[4,0] ++/* ++ * memory <=> Reg in (B H W L) bytes + */ +-static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm) +-{ +- tcg_out32(s, insn | (cond & 0x1f) << 21 | (rn & 0x1f) << 16 | (rm & 0x1f) << 5 | (rd & 0x1f)); +-} +- +-static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target) ++static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign) + { +- const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); +- ptrdiff_t offset = target - (src_rx + 1) ; ++ if (offset != sextract64(offset, 0, 15)) { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, offset); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP2, TCG_REG_TMP2, rn); ++ tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP2, 0); ++ } else { ++ tcg_out_insn_ldst(s, insn, rd, rn, offset); ++ } + +- if (offset == sextract64(offset, 0, 21)) { +- /* read instruction, mask away previous PC_REL21 parameter contents, +- set the proper offset, then write back the instruction. */ +- *src_rw = deposit32(*src_rw, 0, 21, offset); +- return true; ++ switch (insn) { ++ case OPC_LDBU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd); ++ break; ++ case OPC_LDHU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd); ++ break; ++ case OPC_LDW: ++ if (!sign) ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ break; ++ default: ++ break; + } +- return false; + } + +-/* sw*/ +-static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) ++static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) + { +- tcg_debug_assert(addend == 0); + switch (type) { +- case R_SW_64_BRADDR: +- return reloc_pc21(code_ptr, (const tcg_insn_unit *)value); ++ case TCG_TYPE_I32: ++ tcg_out_ldst(s, OPC_LDW, rd, rn, ofs, zeroExt); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); ++ break; ++ case TCG_TYPE_V64: ++ case TCG_TYPE_V128: ++ tcg_debug_assert(0); ++ break; + default: + g_assert_not_reached(); + } + } + +-static inline uint32_t tcg_in32(TCGContext *s) ++static void tcg_out_st(TCGContext *s, TCGType type, TCGReg rd,TCGReg rn, intptr_t ofs) + { +- uint32_t v = *(uint32_t *)s->code_ptr; +- return v; +-} +- +-/*SW Register to register move using ADDL*/ +-static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +-{ +- tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); +- if (ext == TCG_TYPE_I32){ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ switch (type) { ++ case TCG_TYPE_I32: ++ tcg_out_ldst(s, OPC_STW, rd, rn, ofs, noPara); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_ldst(s, OPC_STL, rd, rn, ofs, noPara); ++ break; ++ case TCG_TYPE_V64: ++ case TCG_TYPE_V128: ++ tcg_debug_assert(0); ++ break; ++ default: ++ g_assert_not_reached(); + } + } + +-/*sw +- *put imm into rd +- */ +-static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) ++static void tcg_out_cond_cmp(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, TCGArg a, tcg_target_long b, bool const_b) + { +- long l0, l1, l2=0, l3=0, extra=0; +- tcg_target_long val = orig; +- TCGReg rs = TCG_REG_ZERO; +- +- if (type == TCG_TYPE_I32) +- val = (int32_t)val; +- +- l0 = (int16_t)val; +- val = (val - l0) >> 16; +- l1 = (int16_t)val; +- +- if (orig >> 31 == -1 || orig >> 31 == 0) { +- if (l1 < 0 && orig >= 0) { +- extra = 0x4000; +- l1 = (int16_t)(val - 0x4000); +- } +- } else { +- val = (val - l1) >> 16; +- l2 = (int16_t)val; +- val = (val - l2) >> 16; +- l3 = (int16_t)val; +- +- if (l3) { +- tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l3); +- rs = rd; +- } +- if (l2) { +- tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l2); +- rs = rd; +- } +- if (l3 || l2) +- tcg_out_insn_simpleImm(s, OPC_SLL_I, rd, rd, 32); +- } +- +- if (l1) { +- tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l1); +- rs = rd; ++ if (const_b && (b < 0 || b > 0xff)) { ++ tcg_out_movi(s, ext, TCG_REG_TMP2, b); ++ b = TCG_REG_TMP2; ++ const_b = 0; + } +- +- if (extra) { +- tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, extra); +- rs = rd; +- } +- +- tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l0); +-} + +- +-/*sw +-* memory <=> Reg in (B H W L) bytes +-*/ +-static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign) +-{ +- int16_t lo = offset; +- if (offset != lo) { +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset - lo); +- if (rn != TCG_REG_ZERO) { +- tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, TCG_REG_TMP, rn); ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleReg(s, OPC_ADDW, a, a, TCG_REG_ZERO); ++ if (!const_b) { ++ tcg_out_insn_simpleReg(s, OPC_ADDW, b, b, TCG_REG_ZERO); ++ } else { ++ b = (int32_t)b; + } +- tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP, lo); +- } +- else { +- tcg_out_insn_ldst(s, insn, rd, rn, lo); + } + +- switch (insn) { +- case OPC_LDBU: +- if (sign) +- tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld8s_i32/64,set rd[63,8]=1 +- break; +- case OPC_LDHU: +- if (sign) +- tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld16s_i32/64,set rd[63,16]=1 +- break; +- case OPC_LDW: +- if (!sign) +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); //for micro-op:INDEX_op_ld32u_i32/64,set rd[63,32]=0 +- break; +- default: +- break; +- } +-} +- +-/* TCG_REG_TMP stores result_of_condition_compare */ +-static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b) +-{ + if (const_b) { +- switch(cond) { +- case TCG_COND_ALWAYS: +- case TCG_COND_NEVER: +- break; +- case TCG_COND_EQ: +- case TCG_COND_NE: +- tcg_out_insn_simple(s, OPC_CMPEQ_I, OPC_CMPEQ, ret, a, b); +- break; +- case TCG_COND_LT: +- case TCG_COND_GE: +- tcg_out_insn_simple(s, OPC_CMPLT_I, OPC_CMPLT, ret, a, b); +- break; +- case TCG_COND_LE: +- case TCG_COND_GT: +- tcg_out_insn_simple(s, OPC_CMPLE_I, OPC_CMPLE, ret, a, b); +- break; +- case TCG_COND_LTU: +- case TCG_COND_GEU: +- tcg_out_insn_simple(s, OPC_CMPULT_I, OPC_CMPULT, ret, a, b); +- break; +- case TCG_COND_LEU: +- case TCG_COND_GTU: +- tcg_out_insn_simple(s, OPC_CMPULE_I, OPC_CMPULE, ret, a, b); +- break; +- }//cond +- }//if (const_b) +- else { +- switch(cond) { +- case TCG_COND_ALWAYS: +- case TCG_COND_NEVER: +- break; +- case TCG_COND_EQ: +- case TCG_COND_NE: +- tcg_out_insn_simpleReg(s, OPC_CMPEQ, ret, a, b); +- break; +- case TCG_COND_LT: +- case TCG_COND_GE: +- tcg_out_insn_simpleReg(s, OPC_CMPLT, ret, a, b); +- break; +- case TCG_COND_LE: +- case TCG_COND_GT: +- tcg_out_insn_simpleReg(s, OPC_CMPLE, ret, a, b); +- break; +- case TCG_COND_LTU: +- case TCG_COND_GEU: +- tcg_out_insn_simpleReg(s, OPC_CMPULT, ret, a, b); +- break; +- case TCG_COND_LEU: +- case TCG_COND_GTU: +- tcg_out_insn_simpleReg(s, OPC_CMPULE, ret, a, b); +- break; +- }//cond +- }//else +- switch(cond) { +- case TCG_COND_ALWAYS: +- case TCG_COND_NEVER: ++ switch (cond) { + case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simpleImm(s, OPC_CMPEQ_I, ret, a, b); ++ break; + case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simpleImm(s, OPC_CMPLT_I, ret, a, b); ++ break; + case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simpleImm(s, OPC_CMPLE_I, ret, a, b); ++ break; + case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simpleImm(s, OPC_CMPULT_I, ret, a, b); ++ break; + case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simpleImm(s, OPC_CMPULE_I, ret, a, b); + break; +- case TCG_COND_NE: +- case TCG_COND_GE: +- case TCG_COND_GT: +- case TCG_COND_GEU: +- case TCG_COND_GTU: +- tcg_out_insn_bitImm(s, OPC_XOR_I, ret, ret, 0x1); ++ default: ++ tcg_debug_assert(0); ++ break; ++ } ++ } else { ++ switch (cond) { ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simpleReg(s, OPC_CMPEQ, ret, a, b); + break; ++ case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simpleReg(s, OPC_CMPLT, ret, a, b); ++ break; ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simpleReg(s, OPC_CMPLE, ret, a, b); ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULT, ret, a, b); ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULE, ret, a, b); ++ break; ++ default: ++ tcg_debug_assert(0); ++ break; ++ } ++ } ++ ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a, a, 0xf); ++ if (!const_b) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, b, b, 0xf); ++ } ++ } ++ ++ switch (cond) { ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simpleImm(s, OPC_XOR_I, ret, ret, 0x1); ++ break; ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ tcg_debug_assert(0); ++ break; ++ default: ++ break; + } + } + +-/* sw ++/* + * step1 tcg_out_cmp() ,"eq" and "ne" in the same case with the same insn; + * store compare result by TCG_REG_TMP, for step2; + * step2: jump address with compare result. in last "switch" section, we diff qe/ne by different case with different insn. + */ +-static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond cond, TCGArg a, TCGArg b, bool b_const, TCGLabel *l) ++static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond cond, TCGArg a, tcg_target_long b, bool b_const, TCGLabel *l) + { + intptr_t offset; + bool need_cmp; + + if (b_const && b == 0 && (cond == TCG_COND_EQ || cond == TCG_COND_NE)) { + need_cmp = false; ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, a, 0xf); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP, a, TCG_REG_ZERO); ++ } + } else { + need_cmp = true; +- tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a, b, b_const); ++ tcg_out_cond_cmp(s, ext, cond, TCG_REG_TMP, a, b, b_const); + } + + if (!l->has_value) { + tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); +- offset=0; //offset = tcg_in32(s) >> 5; br $31, 0, do not jump here! ++ offset=0; //offset = tcg_in32(s) >> 5;//luo br $31, 0, do not jump here! + } else { +- offset = tcg_pcrel_diff(s, l->u.value_ptr) ; +- offset = offset >> 2; ++ offset = tcg_pcrel_diff(s, l->u.value_ptr); ++ offset = offset - 4; ++ offset = offset >> 2; + tcg_debug_assert(offset == sextract64(offset, 0, 21)); + } + + if (need_cmp) { +- tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, offset); //a cond b,jmp ++ tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, offset); + } else if (cond == TCG_COND_EQ) { +- tcg_out_insn_br(s, OPC_BEQ, a, offset); ++ tcg_out_insn_br(s, OPC_BEQ, TCG_REG_TMP, offset); + } else { +- tcg_out_insn_br(s, OPC_BNE, a, offset); +- } +-} +- +-/*sw +- * contact with "tcg-target-con-str.h" +- */ +-#define TCG_CT_CONST_ZERO 0x100 +-#define TCG_CT_CONST_LONG 0x200 +-#define TCG_CT_CONST_MONE 0x400 +-#define TCG_CT_CONST_ORRI 0x800 +-#define TCG_CT_CONST_WORD 0X1000 +-#define TCG_CT_CONST_U8 0x2000 +-#define TCG_CT_CONST_S8 0X4000 +- +-#define ALL_GENERAL_REGS 0xffffffffu +-#define ALL_VECTOR_REGS 0xffffffff00000000ull +- +- +-#ifdef CONFIG_SOFTMMU +-/*sw #define ALL_QLDST_REGS */ +-#else +- #define ALL_QLDST_REGS ALL_GENERAL_REGS +-#endif +- +-/* sw test if a constant matches the constraint */ +-static bool tcg_target_const_match(int64_t val, TCGType type, int ct) +-{ +- if (ct & TCG_CT_CONST) { +- return 1; +- } +- if (type == TCG_TYPE_I32) { +- val = (int32_t)val; +- } +- if ((ct & TCG_CT_CONST_U8) && 0 <= val && val <= 255) { +- return 1; +- } +- if ((ct & TCG_CT_CONST_LONG)) { +- return 1; +- } +- if ((ct & TCG_CT_CONST_MONE)) { +- return 1; +- } +- if ((ct & TCG_CT_CONST_ORRI)) { +- return 1; +- } +- if ((ct & TCG_CT_CONST_WORD)) { +- return 1; +- } +- if ((ct & TCG_CT_CONST_ZERO) && val == 0) { +- return 1; ++ tcg_out_insn_br(s, OPC_BNE, TCG_REG_TMP, offset); + } +- return 0; + } + +-static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++static void tcg_out_setcond(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, ++ TCGReg a, tcg_target_long b, bool const_b) + { +- switch (type) { +- case TCG_TYPE_I32: +- tcg_out_ldst(s, OPC_LDW, rd, rn, ofs, sigExt); +- break; +- case TCG_TYPE_I64: +- tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); ++ switch (cond) { ++ case TCG_COND_EQ: ++ case TCG_COND_LT: ++ case TCG_COND_LE: ++ case TCG_COND_LTU: ++ case TCG_COND_LEU: ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_cond_cmp(s, ext, cond, ret, a, b, const_b); + break; + default: +- g_assert_not_reached(); ++ tcg_abort(); ++ break; + } + } + +-static void tcg_out_st(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++static void tcg_out_movcond(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, ++ TCGReg a1, tcg_target_long a2, bool const_b, TCGReg v1, TCGReg v2) + { +- switch (type) { +- case TCG_TYPE_I32: +- tcg_out_insn_ldst(s, OPC_STW, rd, rn, ofs); +- break; +- case TCG_TYPE_I64: +- tcg_out_insn_ldst(s, OPC_STL, rd, rn, ofs); +- break; +- default: +- g_assert_not_reached(); +- } ++ tcg_out_cond_cmp(s, ext, cond, TCG_REG_TMP, a1, a2, const_b); ++ tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); + } + +-static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, intptr_t ofs) ++static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,TCGReg base, intptr_t ofs) + { + if (type <= TCG_TYPE_I64 && val == 0) { + tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); +@@ -1129,66 +1126,123 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg b + return false; + } + +-static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t imm64) ++static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd,TCGReg rn, int64_t imm64) + { +- if (imm64 >= 0) { +- if(0 <=imm64 && imm64 <= 255) { +- /* we use tcg_out_insn_bitImm because imm64 is between 0~255 */ +- tcg_out_insn_bitImm(s, OPC_ADDL_I, rd, rn, imm64); +- }//aimm>0 && aimm == sextract64(aim, 0, 8) +- else { +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); +- tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); +- }//aimm>0 && aimm != sextract64(aim, 0, 8) ++ if (ext == TCG_TYPE_I64) { ++ if (imm64 >= 0) { ++ if (0 <=imm64 && imm64 <= 255) { ++ /* we use tcg_out_insn_simpleImm because imm64 is between 0~255 */ ++ tcg_out_insn_simpleImm(s, OPC_ADDL_I, rd, rn, imm64); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); ++ } ++ } else { ++ if (0 < -imm64 && -imm64 <= 255) { ++ /* we use tcg_out_insn_simpleImm because -imm64 is between 0~255 */ ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, rd, rn, -imm64); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); ++ } ++ } + } else { +- if(0 < -imm64 && -imm64 <= 255) { +- /* we use tcg_out_insn_bitImm because -imm64 is between 0~255 */ +- tcg_out_insn_bitImm(s, OPC_SUBL_I, rd, rn, -imm64); +- }//aimm<0 && aimm == sextract64(aim, 0, 8) +- else { +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); +- tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); +- }//aimm<0 && aimm != sextract64(aim, 0, 8) ++ if (imm64 >= 0) { ++ if (0 <=imm64 && imm64 <= 255) { ++ /* we use tcg_out_insn_simpleImm because imm64 is between 0~255 */ ++ tcg_out_insn_simpleImm(s, OPC_ADDW_I, rd, rn, imm64); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, OPC_ADDW, rd, rn, TCG_REG_TMP); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++ } else { ++ if (0 < -imm64 && -imm64 <= 255) { ++ /* we use tcg_out_insn_simpleImm because -imm64 is between 0~255 */ ++ tcg_out_insn_simpleImm(s, OPC_SUBW_I, rd, rn, -imm64); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, -imm64); ++ tcg_out_insn_simpleReg(s, OPC_SUBW, rd, rn, TCG_REG_TMP); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++ } + } + } + + static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) + { +- ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ ptrdiff_t offset = (tcg_pcrel_diff(s, target) - 4) >> 2; + tcg_debug_assert(offset == sextract64(offset, 0, 21)); + tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); + } + + static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) + { +- ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; +- if (0 <= offset && offset <= 0x1fffff) { ++ ptrdiff_t offset = (tcg_pcrel_diff(s, target) - 4) >> 2; ++ if (offset == sextract64(offset, 0 ,21)) { + tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); +- tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, noPara); + } + } + +- +-/*sw +-* call subroutine +-*/ + static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) + { +- ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ ptrdiff_t offset = (tcg_pcrel_diff(s, target) - 4) >> 2; + if (offset == sextract64(offset, 0, 21)) { + tcg_out_insn_br(s, OPC_BSR, TCG_REG_RA, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); +- tcg_out_insn_jump(s, OPC_CALL, TCG_REG_RA, TCG_REG_TMP, 0); ++ tcg_out_insn_jump(s, OPC_CALL, TCG_REG_RA, TCG_REG_TMP, noPara); ++ } ++} ++ ++static void modify_direct_addr(uintptr_t addr, uintptr_t jmp_rw, uintptr_t jmp_rx) ++{ ++ tcg_target_long l0=0, l1=0; ++ tcg_target_long val = addr; ++ TCGReg rs = TCG_REG_ZERO; ++ TCGReg rd = TCG_REG_TMP; ++ tcg_insn_unit i_nop=0, i1=0, i2=0; ++ uint64_t pair = 0; ++ i_nop = OPC_NOP; ++ uintptr_t jmp = jmp_rw; ++ ++ l0 = (int16_t)val; ++ val = (val - l0) >> 16; ++ l1 = (int16_t)val; ++ if (l1) { ++ i1 = OPC_LDIH | (rd & 0x1f) << 21 | (rs & 0x1f) << 16 | (l1 & 0xffff); ++ } else { ++ i1 = i_nop; + } ++ i2 = OPC_LDI | (rd & 0x1f) << 21 | (rs & 0x1f) << 16 | (l0 & 0xffff); ++ pair = (uint64_t)i1 << 32 | i2; ++ qatomic_set((uint64_t *)jmp, pair); ++ flush_idcache_range(jmp_rx, jmp_rw, 8); + } + + void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) + { +- tcg_debug_assert(0); +- //sw not support ++ tcg_insn_unit i1, i2; ++ uint64_t pair; ++ ++ ptrdiff_t offset = addr - jmp_rx -4; ++ ++ if (offset == sextract64(offset, 0, 21)) { ++ i1 = OPC_BR | (TCG_REG_ZERO & 0x1f) << 21| ((offset >> 2) & 0x1fffff); ++ i2 = OPC_NOP; ++ pair = (uint64_t)i2 << 32 | i1; ++ qatomic_set((uint64_t *)jmp_rw, pair); ++ flush_idcache_range(jmp_rx, jmp_rw, 8); ++ } else if (offset == sextract64(offset, 0, 32)) { ++ modify_direct_addr(addr, jmp_rw, jmp_rx); ++ } else { ++ tcg_debug_assert("tb_target"); ++ } + } + + static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) +@@ -1201,8 +1255,8 @@ static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) + } + } + +-/* sw +- * resut: rd=rn(64,64-m]:rm(64-m,0] ++/* ++ * result: rd=rn(64,64-m]:rm(64-m,0] + * 1: rn(m,0]--->TCG_REG_TMP(64,64-m] + * 2: rm(64,64-m]--->rm(64-m,0] + * 3: rd=TCG_REG_TMP(64,64-m]:rm(64-m,0] +@@ -1211,84 +1265,442 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn + { + int bits = ext ? 64 : 32; + int max = bits - 1; +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + } + +-/* sw +- * loop right shift +- */ + static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) + { +- int bits = ext ? 64 : 32; +- int max = bits - 1; +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); +- tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ unsigned int bits = ext ? 64 : 32; ++ unsigned int max = bits - 1; ++ if (ext == TCG_TYPE_I64) { ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rd, bits - (m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rd, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } + } + +-/* sw loop right shift +- */ + static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) + { +- int bits = ext ? 64 : 32; +- //get TCG_REG_TMP=64-[rm] ++ unsigned int bits = ext ? 64 : 32; + tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); +- tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ tcg_out_insn_bitReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); + +- tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn right part to TCG_REG_TMP +- tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); //get rn left part to TCG_REG_TMP +- tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ if (ext == TCG_TYPE_I64) { ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rd, TCG_REG_TMP); ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rd, rm); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } + } + +-/* sw +- * loop left shift +- */ + static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) + { +- int bits = ext ? 64 : 32; +- int max = bits - 1; ++ unsigned int bits = ext ? 64 : 32; ++ unsigned int max = bits - 1; ++ ++ if (ext == TCG_TYPE_I64) { ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, rd, bits -(m & max)); ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rd, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++} ++ ++static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ unsigned int bits = ext ? 64 : 32; ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); ++ tcg_out_insn_bitReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ ++ if (ext == TCG_TYPE_I64) { ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rd, TCG_REG_TMP); ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rd, rm); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++} ++ ++#ifdef CONFIG_SOFTMMU ++#include "../tcg-ldst.c.inc" ++ ++static void * const qemu_ld_helpers[(MO_SIZE | MO_BSWAP) + 1] = { ++ [MO_UB] = helper_ret_ldub_mmu, ++ [MO_LEUW] = helper_le_lduw_mmu, ++ [MO_LEUL] = helper_le_ldul_mmu, ++ [MO_LEQ] = helper_le_ldq_mmu, ++ [MO_BEUW] = helper_be_lduw_mmu, ++ [MO_BEUL] = helper_be_ldul_mmu, ++ [MO_BEQ] = helper_be_ldq_mmu, ++}; ++ ++static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = { ++ [MO_UB] = helper_ret_stb_mmu, ++ [MO_LEUW] = helper_le_stw_mmu, ++ [MO_LEUL] = helper_le_stl_mmu, ++ [MO_LEQ] = helper_le_stq_mmu, ++ [MO_BEUW] = helper_be_stw_mmu, ++ [MO_BEUL] = helper_be_stl_mmu, ++ [MO_BEQ] = helper_be_stq_mmu, ++}; ++ ++static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target); ++ tcg_debug_assert(offset == sextract64(offset, 0, 21)); ++ tcg_out_insn_br(s, OPC_BR, rd, 0); ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, rd, rd, 4); ++ if (offset >= 0) { ++ tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, rd, rd, offset); ++ } else { ++ tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, rd, rd, -offset); ++ } ++} ++ ++static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) ++{ ++ MemOpIdx oi = lb->oi; ++ MemOp opc = get_memop(oi); ++ MemOp size = opc & MO_SIZE; ++ ++ if (!reloc_pc21(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { ++ return false; ++ } ++ ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X16, TCG_AREG0); ++ tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X17, lb->addrlo_reg); ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X18, oi); ++ tcg_out_adr(s, TCG_REG_X19, lb->raddr); ++ tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); ++ if (opc & MO_SIGN) { ++ tcg_out_sxt(s, lb->type, size, lb->datalo_reg, TCG_REG_X0); ++ } else { ++ tcg_out_mov(s, size == MO_64, lb->datalo_reg, TCG_REG_X0); ++ } ++ ++ tcg_out_goto(s, lb->raddr); ++ return true; ++} ++ ++static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) ++{ ++ MemOpIdx oi = lb->oi; ++ MemOp opc = get_memop(oi); ++ MemOp size = opc & MO_SIZE; ++ ++ if (!reloc_pc21(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { ++ return false; ++ } ++ ++ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X16, TCG_AREG0); ++ tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X17, lb->addrlo_reg); ++ tcg_out_mov(s, size == MO_64, TCG_REG_X18, lb->datalo_reg); ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X19, oi); ++ tcg_out_adr(s, TCG_REG_X20, lb->raddr); ++ tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); ++ tcg_out_goto(s, lb->raddr); ++ return true; ++} + +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); //get rn left part to TCG_REG_TMP +- tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); //get rn right part to left ++static void add_qemu_ldst_label(TCGContext *s, bool is_ld, MemOpIdx oi, ++ TCGType ext, TCGReg data_reg, TCGReg addr_reg, ++ tcg_insn_unit *raddr, tcg_insn_unit *label_ptr) ++{ ++ TCGLabelQemuLdst *label = new_ldst_label(s); ++ ++ label->is_ld = is_ld; ++ label->oi = oi; ++ label->type = ext; ++ label->datalo_reg = data_reg; ++ label->addrlo_reg = addr_reg; ++ label->raddr = tcg_splitwx_to_rx(raddr); ++ label->label_ptr[0] = label_ptr; + } + ++/* We expect to use a 7-bit scaled negative offset from ENV. */ ++QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0); ++QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -512); ++ ++/* These offsets are built into the LDP below. */ ++QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); ++QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); + +-/* sw loop left shift ++/* ++ * Load and compare a TLB entry, emitting the conditional jump to the ++ * slow path for the failure case, which will be patched later when finalizing ++ * the slow path. Generated code returns the host addend in X1, ++ * clobbers X0,X2,X3,TMP. + */ +-static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, ++ tcg_insn_unit **label_ptr, int mem_index, ++ bool is_read) ++{ ++ unsigned a_bits = get_alignment_bits(opc); ++ unsigned s_bits = opc & MO_SIZE; ++ unsigned a_mask = (1u << a_bits) - 1; ++ unsigned s_mask = (1u << s_bits) - 1; ++ TCGReg x3; ++ TCGType mask_type; ++ uint64_t compare_mask; ++ ++ mask_type = (TARGET_PAGE_BITS + CPU_TLB_DYN_MAX_BITS > 32 ++ ? TCG_TYPE_I64 : TCG_TYPE_I32); ++ ++ /* Load env_tlb(env)->f[mmu_idx].{mask,table} into {x0,x1}. */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_X0, TCG_AREG0, TLB_MASK_TABLE_OFS(mem_index)); ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_X1, TCG_AREG0, TLB_MASK_TABLE_OFS(mem_index)+8); ++ ++ /* Extract the TLB index from the address into X0. */ ++ if (mask_type == TCG_TYPE_I64) { ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ++ tcg_out_insn_bitReg(s, OPC_AND, TCG_REG_X0, TCG_REG_X0, TCG_REG_TMP); ++ } else { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, addr_reg, 0xf); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ++ tcg_out_insn_bitReg(s, OPC_AND, TCG_REG_X0, TCG_REG_X0, TCG_REG_TMP); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X0, TCG_REG_X0, 0xf); ++ } ++ /* Add the tlb_table pointer, creating the CPUTLBEntry address into X1. */ ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_X1, TCG_REG_X1, TCG_REG_X0); ++ ++ /* Load the tlb comparator into X0, and the fast path addend into X1. */ ++ tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_X0, TCG_REG_X1, is_read ++ ? offsetof(CPUTLBEntry, addr_read) ++ : offsetof(CPUTLBEntry, addr_write)); ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_X1, TCG_REG_X1, ++ offsetof(CPUTLBEntry, addend)); ++ ++ /* For aligned accesses, we check the first byte and include the alignment ++ bits within the address. For unaligned access, we check that we don't ++ cross pages using the address of the last byte of the access. */ ++ if (a_bits >= s_bits) { ++ x3 = addr_reg; ++ } else { ++ if (s_mask >= a_mask) { ++ tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_X3, addr_reg, s_mask - a_mask); ++ } else { ++ tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_X3, addr_reg, a_mask - s_mask); ++ } ++ ++ if (TARGET_LONG_BITS != 64) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X3, TCG_REG_X3, 0xf); ++ } ++ x3 = TCG_REG_X3; ++ } ++ compare_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; ++ ++ /* Store the page mask part of the address into X3. */ ++ tcg_out_bit(s, OPC_AND_I, OPC_AND, TCG_REG_X3, x3, compare_mask); ++ if (TARGET_LONG_BITS != 64) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X3, TCG_REG_X3, 0xf); ++ } ++ ++ /* Perform the address comparison. */ ++ tcg_out_cond_cmp(s, TARGET_LONG_BITS == 64, TCG_COND_NE, TCG_REG_TMP, TCG_REG_X0, TCG_REG_X3, 0); ++ ++ /* If not equal, we jump to the slow path. */ ++ *label_ptr = s->code_ptr; ++ tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, 0); ++} ++ ++#endif /* CONFIG_SOFTMMU */ ++ ++static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext, ++ TCGReg data_r, TCGReg addr_r, ++ TCGType otype, TCGReg off_r) ++{ ++ if (otype == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, off_r, 0xf); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, TCG_REG_TMP); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, off_r); ++ } ++ ++ const MemOp bswap = memop & MO_BSWAP; ++ ++ switch (memop & MO_SSIZE) { ++ case MO_UB: ++ tcg_out_ldst(s, OPC_LDBU, data_r, TCG_REG_TMP, 0, zeroExt); ++ break; ++ case MO_SB: ++ tcg_out_ldst(s, OPC_LDBU, data_r, TCG_REG_TMP, 0, sigExt); ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, data_r, data_r, 0xf); ++ } ++ break; ++ case MO_UW: ++ tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, zeroExt); ++ if (bswap) { ++ tcg_out_bswap16(s, ext, data_r, data_r); ++ } ++ break; ++ case MO_SW: ++ if (bswap) { ++ tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, zeroExt); ++ tcg_out_bswap16(s, ext, data_r, data_r); ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, data_r, TCG_REG_ZERO, data_r); ++ } else { ++ tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, sigExt); ++ } ++ ++ if (ext == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, data_r, data_r, 0xf); ++ } ++ break; ++ case MO_UL: ++ tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, zeroExt); ++ if (bswap) { ++ tcg_out_bswap32(s, ext, data_r, data_r); ++ } ++ break; ++ case MO_SL: ++ if (bswap) { ++ tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, zeroExt); ++ tcg_out_bswap32(s, ext, data_r, data_r); ++ tcg_out_insn_simpleReg(s, OPC_ADDW, data_r, data_r, TCG_REG_ZERO); ++ } else { ++ tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, sigExt); ++ } ++ break; ++ case MO_Q: ++ tcg_out_ldst(s, OPC_LDL, data_r, TCG_REG_TMP, 0, zeroExt); ++ if (bswap) { ++ tcg_out_bswap64(s, ext, data_r, data_r); ++ } ++ break; ++ default: ++ tcg_abort(); ++ } ++} ++ ++static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext) ++{ ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64: TCG_TYPE_I32; ++#ifdef CONFIG_SOFTMMU ++ unsigned mem_index = get_mmuidx(oi); ++ tcg_insn_unit *label_ptr; ++ ++ tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 1); ++ tcg_out_qemu_ld_direct(s, memop, ext, data_reg, ++ TCG_REG_X1, otype, addr_reg); ++ add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg, ++ s->code_ptr, label_ptr); ++#else /* !CONFIG_SOFTMMU */ ++ if (USE_GUEST_BASE) { ++ tcg_out_qemu_ld_direct(s, memop, ext, data_reg, TCG_REG_GUEST_BASE, otype, addr_reg); ++ } else { ++ tcg_out_qemu_ld_direct(s, memop, ext, data_reg, addr_reg, TCG_TYPE_I64, TCG_REG_ZERO); ++ } ++#endif /* CONFIG_SOFTMMU */ ++} ++ ++static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop, ++ TCGReg data_r, TCGReg addr_r, ++ TCGType otype, TCGReg off_r) + { +- int bits = ext ? 64 : 32; +- tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); //rm = 64-rm +- tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ if (otype == TCG_TYPE_I32) { ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, off_r, 0xf); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, TCG_REG_TMP); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, off_r); ++ } ++ ++ const MemOp bswap = memop & MO_BSWAP; + +- tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn left part to TCG_REG_TMP +- tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); //get rn right part to left +- tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ switch (memop & MO_SIZE) { ++ case MO_8: ++ tcg_out_ldst(s, OPC_STB, data_r, TCG_REG_TMP, 0, 0); ++ break; ++ case MO_16: ++ if (bswap && data_r != TCG_REG_ZERO) { ++ tcg_out_bswap16(s, TCG_TYPE_I32, TCG_REG_TMP3, data_r); ++ data_r = TCG_REG_TMP3; ++ } ++ tcg_out_ldst(s, OPC_STH, data_r, TCG_REG_TMP, 0, 0); ++ break; ++ case MO_32: ++ if (bswap && data_r != TCG_REG_ZERO) { ++ tcg_out_bswap32(s, TCG_TYPE_I32, TCG_REG_TMP3, data_r); ++ data_r = TCG_REG_TMP3; ++ } ++ tcg_out_ldst(s, OPC_STW, data_r, TCG_REG_TMP, 0, 0); ++ break; ++ case MO_64: ++ if (bswap && data_r != TCG_REG_ZERO) { ++ tcg_out_bswap64(s, TCG_TYPE_I64, TCG_REG_TMP3, data_r); ++ data_r = TCG_REG_TMP3; ++ } ++ tcg_out_ldst(s, OPC_STL, data_r, TCG_REG_TMP, 0, 0); ++ break; ++ default: ++ tcg_abort(); ++ } + } + ++static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, ++ MemOpIdx oi) ++{ ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64: TCG_TYPE_I32; ++#ifdef CONFIG_SOFTMMU ++ unsigned mem_index = get_mmuidx(oi); ++ tcg_insn_unit *label_ptr; ++ ++ tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 0); ++ tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_X1, otype, addr_reg); ++ add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64, data_reg, addr_reg, s->code_ptr, label_ptr); ++#else /* !CONFIG_SOFTMMU */ ++ if (USE_GUEST_BASE) { ++ tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, addr_reg); ++ } else { ++ tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, TCG_REG_ZERO); ++ } ++#endif /* CONFIG_SOFTMMU */ ++} + ++static const tcg_insn_unit *tb_ret_addr; + +-static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) ++static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], ++ const int const_args[TCG_MAX_OP_ARGS]) + { + /* 99% of the time, we can signal the use of extension registers +- by looking to see if the opcode handles 64-bit data. */ ++ * by looking to see if the opcode handles 64-bit data. */ + TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0; +- /* Hoist the loads of the most common arguments. */ ++ /* Hoist the loads of the most common arguments. */ + TCGArg a0 = args[0]; + TCGArg a1 = args[1]; + TCGArg a2 = args[2]; + int c2 = const_args[2]; + + /* Some operands are defined with "rZ" constraint, a register or +- the zero register. These need not actually test args[I] == 0. */ +- #define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) ++ * the zero register. These need not actually test args[I] == 0. */ + + switch (opc) { + case INDEX_op_exit_tb: +- /* Reuse the zeroing that exists for goto_ptr. */ ++ /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_goto_long(s, tcg_code_gen_epilogue); + } else { +@@ -1296,34 +1708,39 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + tcg_out_goto_long(s, tb_ret_addr); + } + break; +- + case INDEX_op_goto_tb: + if (s->tb_jmp_insn_offset != NULL) { + /* TCG_TARGET_HAS_direct_jump */ +- tcg_debug_assert(0); +- /* not support here */ ++ /* Ensure that ADRP+ADD are 8-byte aligned so that an atomic ++ write can be used to patch the target address. */ ++ if ((uintptr_t)s->code_ptr & 7) { ++ tcg_out32(s, OPC_NOP); ++ } ++ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); ++ tcg_out32(s, OPC_NOP); ++ tcg_out32(s, OPC_NOP); + } else { + /* !TCG_TARGET_HAS_direct_jump */ + tcg_debug_assert(s->tb_jmp_target_addr != NULL); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); + } +- tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, noPara); + set_jmp_reset_offset(s, a0); + break; +- + case INDEX_op_goto_ptr: +- tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, 0); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, noPara); + break; +- + case INDEX_op_br: + tcg_out_goto_label(s, arg_label(a0)); + break; +- + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 0); + break; + case INDEX_op_ld8s_i32: ++ tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; + case INDEX_op_ld8s_i64: + tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); + break; +@@ -1332,11 +1749,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 0); + break; + case INDEX_op_ld16s_i32: ++ tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; + case INDEX_op_ld16s_i64: + tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); + break; + case INDEX_op_ld_i32: +- tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 0); + break; + case INDEX_op_ld32u_i64: + tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 0); +@@ -1349,26 +1769,26 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + break; + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: +- tcg_out_ldst(s, OPC_STB, a0, a1, a2, 0); ++ tcg_out_ldst(s, OPC_STB, REG0(0), a1, a2, 0); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: +- tcg_out_ldst(s, OPC_STH, a0, a1, a2, 0); ++ tcg_out_ldst(s, OPC_STH, REG0(0), a1, a2, 0); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: +- tcg_out_ldst(s, OPC_STW, a0, a1, a2, 0); ++ tcg_out_ldst(s, OPC_STW, REG0(0), a1, a2, 0); + break; + case INDEX_op_st_i64: +- tcg_out_ldst(s, OPC_STL, a0, a1, a2, 0); ++ tcg_out_ldst(s, OPC_STL, REG0(0), a1, a2, 0); + break; +- + case INDEX_op_add_i32: + a2 = (int32_t)a2; + if (c2) { + tcg_out_addsubi(s, ext, a0, a1, a2); + } else { +- tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); ++ tcg_out_insn_simpleReg(s, OPC_ADDW, a0, a1, a2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } + break; + case INDEX_op_add_i64: +@@ -1378,13 +1798,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); + } + break; +- + case INDEX_op_sub_i32: + a2 = (int32_t)a2; + if (c2) { + tcg_out_addsubi(s, ext, a0, a1, -a2); + } else { +- tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); ++ tcg_out_insn_simpleReg(s, OPC_SUBW, a0, a1, a2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } + break; + case INDEX_op_sub_i64: +@@ -1394,230 +1814,207 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); + } + break; +- +- case INDEX_op_neg_i64: + case INDEX_op_neg_i32: ++ tcg_out_insn_bitReg(s, OPC_SUBW, a0, TCG_REG_ZERO, a1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; ++ case INDEX_op_neg_i64: + tcg_out_insn_bitReg(s, OPC_SUBL, a0, TCG_REG_ZERO, a1); + break; +- + case INDEX_op_and_i32: +- a2 = (int32_t)a2; + if (c2) { +- tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ a2 = (int32_t)a2; ++ tcg_out_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); + } ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_and_i64: + if (c2) { +- tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ tcg_out_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); + } + break; + case INDEX_op_andc_i32: +- a2 = (int32_t)a2; +- tcg_debug_assert(0); +- if (c2) { +- tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); +- } else { +- tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); +- } +- break; + case INDEX_op_andc_i64: + tcg_debug_assert(0); +- if (c2) { +- tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); +- } else { +- tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); +- } + break; +- + case INDEX_op_or_i32: +- a2 = (int32_t)a2; + if (c2) { +- tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ a2 = (int32_t)a2; ++ tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); + } ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_or_i64: + if (c2) { +- tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); + } + break; +- + case INDEX_op_orc_i32: +- a2 = (int32_t)a2; +- tcg_debug_assert(0); + if (c2) { +- tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ a2 = (int32_t)a2; ++ tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); + } ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_orc_i64: +- tcg_debug_assert(0); + if (c2) { +- tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); + } + break; +- + case INDEX_op_xor_i32: +- a2 = (int32_t)a2; + if (c2) { +- tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ a2 = (int32_t)a2; ++ tcg_out_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); + } ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_xor_i64: + if (c2) { +- tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ tcg_out_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); + } + break; +- + case INDEX_op_eqv_i32: +- a2 = (int32_t)a2; +- tcg_debug_assert(0); +- if (c2) { +- tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); +- } else { +- tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); +- } +- break; +- + case INDEX_op_eqv_i64: + tcg_debug_assert(0); +- if (c2) { +- tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); +- } else { +- tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); +- } + break; +- +- case INDEX_op_not_i64: + case INDEX_op_not_i32: + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; ++ case INDEX_op_not_i64: ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); + break; +- +- case INDEX_op_mul_i64: + case INDEX_op_mul_i32: +- tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); ++ tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; ++ case INDEX_op_mul_i64: ++ tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); + break; +- +- case INDEX_op_div_i64: /* a0=a1/a2 singed divide*/ + case INDEX_op_div_i32: ++ case INDEX_op_div_i64: + tcg_debug_assert(0); + break; +- case INDEX_op_divu_i64: /* a0=a1/a2 unsigned divide */ + case INDEX_op_divu_i32: ++ case INDEX_op_divu_i64: + tcg_debug_assert(0); + break; +- +- case INDEX_op_rem_i64: /* if a1=17,a2=4, 17/4=4...1, a0=1 */ + case INDEX_op_rem_i32: ++ case INDEX_op_rem_i64: + tcg_debug_assert(0); + break; +- case INDEX_op_remu_i64: + case INDEX_op_remu_i32: ++ case INDEX_op_remu_i64: + tcg_debug_assert(0); + break; +- +- case INDEX_op_shl_i64: + case INDEX_op_shl_i32: /* sw logical left*/ + if (c2) { +- int bits = ext ? 64 : 32; +- int max = bits - 1; +- tcg_out_insn_bitImm(s, OPC_SLL_I, a0, a1, a2&max); ++ unsigned int bits = ext ? 64 : 32; ++ unsigned int max = bits - 1; ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, a0, a1, a2&max); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ } ++ break; ++ case INDEX_op_shl_i64: ++ if (c2) { ++ unsigned int bits = ext ? 64 : 32; ++ unsigned int max = bits - 1; ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); + } + break; +- +- case INDEX_op_shr_i64: + case INDEX_op_shr_i32: /* sw logical right */ ++ a2 = (int32_t)a2; + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; +- tcg_out_insn_bitImm(s, OPC_SRL_I, a0, a1, a2&max); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); + } + break; +- +- case INDEX_op_sar_i64: +- case INDEX_op_sar_i32: /* sw arithmetic right*/ ++ case INDEX_op_shr_i64: + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; +- tcg_out_insn_bitImm(s, OPC_SRA_I, a0, a1, a2&max); ++ tcg_out_insn_simpleImm(s, OPC_SRL_I, a0, a1, a2&max); + } else { +- tcg_out_insn_bitReg(s, OPC_SRA, a0, a1, a2); ++ tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); + } + break; +- +- case INDEX_op_rotr_i64: ++ case INDEX_op_sar_i32: ++ a2 = (int32_t)a2; ++ tcg_out_sar(s, ext, a0, a1, a2, c2); ++ break; ++ case INDEX_op_sar_i64: /* sw arithmetic right*/ ++ tcg_out_sar(s, ext, a0, a1, a2, c2); ++ break; + case INDEX_op_rotr_i32: /* loop shift */ ++ case INDEX_op_rotr_i64: + if (c2) {/* loop right shift a2*/ + tcg_out_rotr_Imm(s, ext, a0, a1, a2); + } else { + tcg_out_rotr_Reg(s, ext, a0, a1, a2); + } + break; +- +- case INDEX_op_rotl_i64: + case INDEX_op_rotl_i32: /* loop shift */ ++ case INDEX_op_rotl_i64: /* sw */ + if (c2) {/* loop left shift a2*/ + tcg_out_rotl_Imm(s, ext, a0, a1, a2); + } else { + tcg_out_rotl_Reg(s, ext, a0, a1, a2); + } + break; +- +- case INDEX_op_clz_i64: /* counting leading zero numbers */ + case INDEX_op_clz_i32: +- tcg_out_cltz(s, OPC_CTLZ, ext, a0, a1, a2, c2); ++ tcg_out_ctz32(s, OPC_CTLZ, a0, a1, a2, c2); ++ break; ++ case INDEX_op_clz_i64: /* counting leading zero numbers */ ++ tcg_out_ctz64(s, OPC_CTLZ, a0, a1, a2, c2); + break; +- case INDEX_op_ctz_i64: /* counting tailing zero numbers */ + case INDEX_op_ctz_i32: +- tcg_out_cltz(s, OPC_CTTZ, ext, a0, a1, a2, c2); ++ tcg_out_ctz32(s, OPC_CTTZ, a0, a1, a2, c2); + break; +- +- case INDEX_op_brcond_i32: +- a1 = (int32_t)a1; +- tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); ++ case INDEX_op_ctz_i64: /* counting tailing zero numbers */ ++ tcg_out_ctz64(s, OPC_CTTZ, a0, a1, a2, c2); + break; +- ++ case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: + tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); + break; +- + case INDEX_op_setcond_i32: + a2 = (int32_t)a2; +- tcg_out_setcond(s, args[3], a0, a1, a2); ++ tcg_out_setcond(s, ext, args[3], a0, a1, a2, c2); + break; +- + case INDEX_op_setcond_i64: +- tcg_out_setcond(s, args[3], a0, a1, a2); ++ tcg_out_setcond(s, ext, args[3], a0, a1, a2, c2); + break; +- + case INDEX_op_movcond_i32: + a2 = (int32_t)a2; +- tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ tcg_out_movcond(s, ext, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); + break; +- +- /* FALLTHRU */ + case INDEX_op_movcond_i64: +- tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ tcg_out_movcond(s, ext, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); + break; +- + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld_i64: + tcg_out_qemu_ld(s, a0, a1, a2, ext); +@@ -1626,443 +2023,399 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_O + case INDEX_op_qemu_st_i64: + tcg_out_qemu_st(s, REG0(0), a1, a2); + break; +- +- case INDEX_op_bswap64_i64: /* 0x123456789abcdef--->0xefcdab8967452301 */ +- tcg_debug_assert(0); +- tcg_out_bswap64(s, a0, a1); +- break; +- case INDEX_op_bswap32_i64: /* 0x123456789abcdef--->0x67452301efcdab89 */ +- tcg_debug_assert(0); +- tcg_out_bswap32u(s, a0, a1); ++ case INDEX_op_bswap64_i64: ++ tcg_out_bswap64(s, ext, a0, a1); + break; + case INDEX_op_bswap32_i32: +- tcg_debug_assert(0); ++ case INDEX_op_bswap32_i64: ++ tcg_out_bswap32(s, ext, a0, a1); + break; +- case INDEX_op_bswap16_i64: /* 0x123456789abcdef--->0x23016745ab89efcd */ + case INDEX_op_bswap16_i32: +- tcg_debug_assert(0); ++ case INDEX_op_bswap16_i64: ++ tcg_out_bswap16(s, ext, a0, a1); + break; +- +- case INDEX_op_ext8s_i64: + case INDEX_op_ext8s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; ++ case INDEX_op_ext8s_i64: + tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); + break; +- case INDEX_op_ext16s_i64: + case INDEX_op_ext16s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); ++ break; ++ case INDEX_op_ext16s_i64: + tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_ext_i32_i64: + case INDEX_op_ext32s_i64: + tcg_out_insn_simpleReg(s, OPC_ADDW, a0, TCG_REG_ZERO, a1); + break; +- case INDEX_op_ext8u_i64: + case INDEX_op_ext8u_i32: +- tcg_out_insn_simpleImm(s, OPC_EXT0B_I, a0, a1, 0x0); ++ case INDEX_op_ext8u_i64: ++ tcg_out_insn_simpleImm(s, OPC_EXTLB_I, a0, a1, 0x0); + break; +- case INDEX_op_ext16u_i64: + case INDEX_op_ext16u_i32: +- tcg_out_insn_simpleImm(s, OPC_EXT1B_I, a0, a1, 0x0); ++ case INDEX_op_ext16u_i64: ++ tcg_out_insn_simpleImm(s, OPC_EXTLH_I, a0, a1, 0x0); + break; + case INDEX_op_extu_i32_i64: + case INDEX_op_ext32u_i64: +- tcg_out_movr(s, TCG_TYPE_I32, a0, a1); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a1, 0xf); + break; +- +- case INDEX_op_deposit_i64: + case INDEX_op_deposit_i32: +- tcg_out_dep(s, a0, a2, args[3], args[4]); ++ case INDEX_op_deposit_i64: ++ tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]); + break; +- +- case INDEX_op_extract_i64: + case INDEX_op_extract_i32: ++ case INDEX_op_extract_i64: + tcg_out_extract(s, a0, a1, a2, args[3]); + break; +- +- case INDEX_op_sextract_i64: + case INDEX_op_sextract_i32: ++ case INDEX_op_sextract_i64: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ ++ case INDEX_op_extract2_i64: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_add2_i32: ++ case INDEX_op_add2_i64: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_sub2_i32: ++ case INDEX_op_sub2_i64: + tcg_debug_assert(0); + break; ++ case INDEX_op_muluh_i64: ++ tcg_out_insn_simpleReg(s, OPC_UMULH, a0, a1, a2); ++ break; ++ case INDEX_op_mulsh_i64: ++ tcg_out_mulsh64(s, a0, a1, a2); ++ break; ++ case INDEX_op_mb: ++ tcg_out_mb(s); ++ break; ++ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ ++ break; ++ case INDEX_op_mov_i64: ++ break; ++ case INDEX_op_call: /* Always emitted via tcg_out_call. */ ++ default: ++ g_assert_not_reached(); ++ } ++#undef REG0 ++} + ++static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) ++{ ++ switch (op) { ++ case INDEX_op_goto_ptr: ++ return C_O0_I1(r); ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld8u_i64: ++ case INDEX_op_ld8s_i64: ++ case INDEX_op_ld16u_i64: ++ case INDEX_op_ld16s_i64: ++ case INDEX_op_ld32u_i64: ++ case INDEX_op_ld32s_i64: ++ case INDEX_op_ld_i64: ++ case INDEX_op_neg_i32: ++ case INDEX_op_neg_i64: ++ case INDEX_op_not_i32: ++ case INDEX_op_not_i64: ++ case INDEX_op_bswap16_i32: ++ case INDEX_op_bswap32_i32: ++ case INDEX_op_bswap16_i64: ++ case INDEX_op_bswap32_i64: ++ case INDEX_op_bswap64_i64: ++ case INDEX_op_ext8s_i32: ++ case INDEX_op_ext16s_i32: ++ case INDEX_op_ext8u_i32: ++ case INDEX_op_ext16u_i32: ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext32s_i64: ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext32u_i64: ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_extract_i32: ++ case INDEX_op_extract_i64: ++ case INDEX_op_sextract_i32: ++ case INDEX_op_sextract_i64: ++ return C_O1_I1(r, r); ++ case INDEX_op_st8_i32: ++ case INDEX_op_st16_i32: ++ case INDEX_op_st_i32: ++ case INDEX_op_st8_i64: ++ case INDEX_op_st16_i64: ++ case INDEX_op_st32_i64: ++ case INDEX_op_st_i64: ++ return C_O0_I2(rZ, r); ++ case INDEX_op_add_i32: ++ case INDEX_op_add_i64: ++ case INDEX_op_sub_i32: ++ case INDEX_op_sub_i64: ++ return C_O1_I2(r, r, rU); ++ case INDEX_op_setcond_i32: ++ case INDEX_op_setcond_i64: ++ return C_O1_I2(r, r, rU); ++ case INDEX_op_mul_i32: ++ case INDEX_op_mul_i64: ++ case INDEX_op_div_i32: ++ case INDEX_op_div_i64: ++ case INDEX_op_divu_i32: ++ case INDEX_op_divu_i64: ++ case INDEX_op_rem_i32: ++ case INDEX_op_rem_i64: ++ case INDEX_op_remu_i32: ++ case INDEX_op_remu_i64: ++ case INDEX_op_muluh_i64: ++ case INDEX_op_mulsh_i64: ++ return C_O1_I2(r, r, r); ++ case INDEX_op_and_i32: ++ case INDEX_op_and_i64: ++ case INDEX_op_or_i32: ++ case INDEX_op_or_i64: ++ case INDEX_op_xor_i32: ++ case INDEX_op_xor_i64: ++ case INDEX_op_andc_i32: ++ case INDEX_op_andc_i64: ++ case INDEX_op_orc_i32: ++ case INDEX_op_orc_i64: ++ case INDEX_op_eqv_i32: ++ case INDEX_op_eqv_i64: ++ return C_O1_I2(r, r, rU); ++ case INDEX_op_shl_i32: ++ case INDEX_op_shr_i32: ++ case INDEX_op_sar_i32: ++ case INDEX_op_rotl_i32: ++ case INDEX_op_rotr_i32: ++ case INDEX_op_shl_i64: ++ case INDEX_op_shr_i64: ++ case INDEX_op_sar_i64: ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotr_i64: ++ return C_O1_I2(r, r, ri); ++ case INDEX_op_clz_i32: ++ case INDEX_op_clz_i64: ++ return C_O1_I2(r, r, r); ++ case INDEX_op_ctz_i32: ++ case INDEX_op_ctz_i64: ++ return C_O1_I2(r, r, r); ++ case INDEX_op_brcond_i32: ++ case INDEX_op_brcond_i64: ++ return C_O0_I2(r, rU); ++ case INDEX_op_movcond_i32: ++ case INDEX_op_movcond_i64: ++ return C_O1_I4(r, r, rU, rZ, rZ); ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ return C_O1_I1(r, l); ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ return C_O0_I2(lZ, l); ++ case INDEX_op_deposit_i32: ++ case INDEX_op_deposit_i64: ++ return C_O1_I2(r, 0, rZ); ++ case INDEX_op_extract2_i32: + case INDEX_op_extract2_i64: +- case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ +- tcg_debug_assert(0); +- break; +- ++ return C_O1_I2(r, rZ, rZ); + case INDEX_op_add2_i32: +- tcg_debug_assert(0); +- break; + case INDEX_op_add2_i64: +- tcg_debug_assert(0); +- break; + case INDEX_op_sub2_i32: +- tcg_debug_assert(0); +- break; + case INDEX_op_sub2_i64: +- tcg_debug_assert(0); +- break; +- +- case INDEX_op_muluh_i64: +- tcg_out_insn_simpleReg(s, OPC_UMULH, a0, a1, a2); +- break; +- case INDEX_op_mulsh_i64: /* sw not support */ +- tcg_out_mulsh64(s, a0, a1, a2); +- break; +- +- case INDEX_op_mb: +- break; +- +- case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ +- case INDEX_op_mov_i64: +- case INDEX_op_call: /* Always emitted via tcg_out_call. */ ++ return C_O2_I4(r, r, rZ, rZ, rA, rMZ); ++ case INDEX_op_add_vec: ++ case INDEX_op_sub_vec: ++ case INDEX_op_mul_vec: ++ case INDEX_op_xor_vec: ++ case INDEX_op_ssadd_vec: ++ case INDEX_op_sssub_vec: ++ case INDEX_op_usadd_vec: ++ case INDEX_op_ussub_vec: ++ case INDEX_op_smax_vec: ++ case INDEX_op_smin_vec: ++ case INDEX_op_umax_vec: ++ case INDEX_op_umin_vec: ++ case INDEX_op_shlv_vec: ++ case INDEX_op_shrv_vec: ++ case INDEX_op_sarv_vec: ++ return C_O1_I2(w, w, w); ++ case INDEX_op_not_vec: ++ case INDEX_op_neg_vec: ++ case INDEX_op_abs_vec: ++ case INDEX_op_shli_vec: ++ case INDEX_op_shri_vec: ++ case INDEX_op_sari_vec: ++ return C_O1_I1(w, w); ++ case INDEX_op_ld_vec: ++ case INDEX_op_dupm_vec: ++ return C_O1_I1(w, r); ++ case INDEX_op_st_vec: ++ return C_O0_I2(w, r); ++ case INDEX_op_dup_vec: ++ return C_O1_I1(w, wr); ++ case INDEX_op_or_vec: ++ case INDEX_op_andc_vec: ++ return C_O1_I2(w, w, wO); ++ case INDEX_op_and_vec: ++ case INDEX_op_orc_vec: ++ return C_O1_I2(w, w, wN); ++ case INDEX_op_cmp_vec: ++ return C_O1_I2(w, w, wZ); ++ case INDEX_op_bitsel_vec: ++ return C_O1_I3(w, w, w, w); + default: + g_assert_not_reached(); + } +- +-#undef REG0 + } + + +- +-/*sw +-* counting heading/tailing zero numbers +-*/ +-static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, +- TCGReg rn, TCGArg b, bool const_b) +-{ +- /* cond1. b is a const, and b=64 or b=32 */ +- if (const_b && b == (ext ? 64 : 32)) { +- /* count rn zero numbers, and writes to rd */ +- tcg_out_insn_simpleReg(s, opc_clz, rd, TCG_REG_ZERO, rn); +- }else { +- /* TCG_REG_TMP= counting rn heading/tailing zero numbers */ +- tcg_out_insn_simpleReg(s, opc_clz, TCG_REG_TMP, TCG_REG_ZERO, rn); +- +- if (const_b) { +- if (b == -1) { +- /* cond2. b is const and b=-1 */ +- /* if rn != 0 , rd= counting rn heading/tailing zero numbers, else rd = 0xffffffffffffffff*/ +- tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_ZERO); +- tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); +- } +- else if (b == 0) { +- /* cond3. b is const and b=0 */ +- /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else rd = TCG_REG_ZERO */ +- tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_ZERO); +- } else { +- /* cond4. b is const */ +- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, b); +- /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else mov b to rd */ +- tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); +- } +- } +- else { +- /* if b is register */ +- tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, b); +- } +- } +-} +- +-/*sw +- * unsigned 16bit, ab->ba +- */ +-static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn) ++static void tcg_target_init(TCGContext *s) + { +- TCGReg TCG_TMP0 = rn; +- TCGReg TCG_TMP1 = rd; +- /*t1=00b0*/ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); +- /*t1=(0000)000a*/ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP0, TCG_TMP0, 8); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP0, TCG_TMP0, 0x1); +- /*t1=ooba*/ +- tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP0); +-} ++ tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull; ++ tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull; ++ tcg_target_call_clobber_regs = -1ull; + +-/*sw +- * signed 16bit, ab->ssba +- */ +-static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn) +-{ +- TCGReg TCG_TMP0 = rn; +- TCGReg TCG_TMP1 = TCG_REG_TMP; +- TCGReg TCG_TMP2 = rn; +- /*t1=(ssss)ssb0*/ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); +- tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x2); +- tcg_out_insn_simpleReg(s, OPC_SEXTH, TCG_TMP1, TCG_REG_ZERO, TCG_TMP1); +- /*t2=(0000)000a*/ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 8); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP2, 0x1); +- /*t2=(ssss)ssba*/ +- tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP2); +-} ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X9); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X10); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X11); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X12); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X13); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X14); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X15); + ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F2); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F3); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F4); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F5); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F6); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F7); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F8); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F9); + +-/*sw +- * signed 32bit, abcd -> ssdcba +- */ +-static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn) +-{ +- TCGReg TCG_TMP0 = rn; +- TCGReg TCG_TMP3 = rd; +- TCGReg TCG_TMP1 = TCG_REG_TMP; +- TCGReg TCG_TMP2 = TCG_REG_TMP2; +- /*swap32 -- 32-bit swap. a0 = abcd.*/ +- +- /* t3 = (ssss)d000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 24); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x0f); +- tcg_out_insn_simpleReg(s, OPC_SEXTB, TCG_TMP1, TCG_REG_ZERO, TCG_TMP0); +- tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x0f); +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- +- /* t1 = 000a */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 24); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x1); +- +- /* t2 = 00c0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); +- +- /* t3 = (ssss)d00a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- +- /* t1 = 0abc */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); +- +- /* t2 = 0c00 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); +- /* t1 = 00b0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); +- /* t3 = (ssss)dc0a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); +- /* t3 = (ssss)dcba -- delay slot */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ s->reserved_regs = 0; ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP3); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); + } + +-/*sw +- * unsigned 32bit, abcd->dcba +- */ +-static void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn) +-{ +- TCGReg TCG_TMP0 = rn; +- TCGReg TCG_TMP3 = rd; +- TCGReg TCG_TMP1 = TCG_REG_TMP; +- TCGReg TCG_TMP2 = TCG_REG_TMP2; +- +- /*bswap32u -- unsigned 32-bit swap. a0 = ....abcd.*/ +- /* t1 = (0000)000d */ +- tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP1, TCG_TMP0, 0xff); +- /* t3 = 000a */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP3, TCG_TMP0, 24); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x1); +- /* t1 = (0000)d000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); +- /* t2 = 00c0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); +- /* t3 = d00a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- /* t1 = 0abc */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); +- /* t2 = 0c00 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); +- /* t1 = 00b0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); +- /* t3 = dc0a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); +- /* t3 = dcba -- delay slot */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +-} ++ ++#define PUSH_SIZE ((15-9+1+1) * 8) ++#define FRAME_SIZE \ ++ ((PUSH_SIZE \ ++ + TCG_STATIC_CALL_ARGS_SIZE \ ++ + CPU_TEMP_BUF_NLONGS * sizeof(long) \ ++ + TCG_TARGET_STACK_ALIGN - 1) \ ++ & ~(TCG_TARGET_STACK_ALIGN - 1)) + + ++/* We're expecting a 2 byte uleb128 encoded value. */ ++QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); + +-/*sw +- * swap 64bit, abcdefgh->hgfedcba +- */ +-static void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn) ++/* We're expecting to use a single ADDI insn. */ ++QEMU_BUILD_BUG_ON(FRAME_SIZE - PUSH_SIZE > 0xfff); ++ ++static void tcg_target_qemu_prologue(TCGContext *s) + { ++ TCGReg r; ++ int ofs; + +- TCGReg TCG_TMP0 = rn; +- TCGReg TCG_TMP3 = rd; +- TCGReg TCG_TMP1 = TCG_REG_TMP; +- TCGReg TCG_TMP2 = TCG_REG_TMP2; +- +- /* bswap64 -- 64-bit swap. a0 = abcdefgh*/ +- +- /* t3 = h0000000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 56); +- /* t1 = 0000000a */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 56); +- /* t2 = 000000g0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); +- /* t3 = h000000a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- /* t1 = 00000abc */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 40); +- /* t2 = 0g000000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); +- /* t1 = 000000b0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); +- /* t3 = hg00000a */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); +- /* t2 = 0000abcd */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 32); +- /* t3 = hg0000ba */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- /* t1 = 000000c0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP2, 0x2); +- /* t2 = 0000000d */ +- tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP2, 0xff); +- /* t1 = 00000c00 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 8); +- /* t2 = 0000d000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 24); +- /* t3 = hg000cba */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +- /* t1 = 00abcdef */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 16); +- /* t3 = hg00dcba */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); +- /* t2 = 0000000f */ +- tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP1, 0xff); +- /* t1 = 000000e0 */ +- tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); +- /* t2 = 00f00000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); +- /* t1 = 000e0000 */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); +- /* t3 = hgf0dcba */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); +- /* t3 = hgfedcba -- delay slot */ +- tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* allocate space for all saved registers */ ++ /* subl $sp,PUSH_SIZE,$sp */ ++ tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); + +-} ++ /* Push (FP, LR) */ ++ /* stl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* stl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_RA, TCG_REG_SP, 8); + +-static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext) +-{ +-#ifndef CONFIG_SOFTMMU +- MemOp memop = get_memop(oi); +- const TCGType otype = TCG_TYPE_I64; + +- if (USE_GUEST_BASE) { +- tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); +- tcg_out_qemu_ld_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); +- } else { +- tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ /* Set up frame pointer for canonical unwinding. */ ++ /* TCG_REG_FP=TCG_REG_SP */ ++ tcg_out_movr(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP); ++ ++ /* Store callee-preserved regs x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1){ ++ ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_STL, r, TCG_REG_SP, ofs); + } +-#endif /* CONFIG_SOFTMMU */ + +-} ++ /* Make stack space for TCG locals. */ ++ /* subl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); + +-static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, +- MemOpIdx oi) +-{ +-#ifndef CONFIG_SOFTMMU +- MemOp memop = get_memop(oi); +- const TCGType otype = TCG_TYPE_I64; ++ /* Inform TCG about how to find TCG locals with register, offset, size. */ ++ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, ++ CPU_TEMP_BUF_NLONGS * sizeof(long)); + ++#ifndef CONFIG_SOFTMMU + if (USE_GUEST_BASE) { +- tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); +- tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); +- } else { +- tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); + } +-#endif /* CONFIG_SOFTMMU */ +-} +- +- +-/*sw +- * if cond is successful, ret=1, otherwise ret = 0 +- */ +-static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, +- TCGReg arg1, TCGReg arg2) +-{ +- switch(cond) { +- case TCG_COND_EQ: +- case TCG_COND_LT: +- case TCG_COND_LE: +- case TCG_COND_LTU: +- case TCG_COND_LEU: +- case TCG_COND_NE: +- case TCG_COND_GE: +- case TCG_COND_GT: +- case TCG_COND_GEU: +- case TCG_COND_GTU: +- tcg_out_cond_cmp(s, cond, ret, arg1, arg2, 0); +- break; +- default: +- tcg_abort(); +- break; +- } +-} +-/*sw +- * cond(a1,a2), yes:v1->ret, no:v2->ret +- */ +-static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, +- TCGReg a1, TCGReg a2, bool const_b, TCGReg v1, TCGReg v2) +-{ +- tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a1, a2, const_b); +- tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); +-} +- +- ++#endif + +-/*sw +- * extract rn[lsb, lsb+len-1] -> rd[0, len-1] +- */ +-static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) +-{ +- //get 000..111..0000 +- tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); +- /* get rn[lsb, lsb+len-1]-->rd[lsb, lsb+len-1] */ +- tcg_out_insn_bitReg(s, OPC_AND, rd, rn, TCG_REG_TMP); ++ /* TCG_AREG0=tcg_target_call_iarg_regs[0], on sw, we mov $16 to $9 */ ++ tcg_out_mov(s, TCG_TYPE_I64, TCG_AREG0, tcg_target_call_iarg_regs[0]); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], noPara); + +- /* rd[lsb, lsb+len-1] --> rd[0, len-1] */ +- tcg_out_insn_bitImm(s, OPC_SRL_I, rd, rd, lsb); +-} ++ /* ++ * Return path for goto_ptr. Set return value to 0, a-la exit_tb, ++ * and fall through to the rest of the epilogue. ++ */ ++ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, 0); + ++ /* TB epilogue */ ++ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); + +-/*sw +- * depos: rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] +- * len = msb -lsb + 1 +- */ +-static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) +-{ ++ /* Remove TCG locals stack space. */ ++ /* addl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); + +- //get 000..111..0000 +- tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ /* Restore registers x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1) { ++ int ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_LDL, r, TCG_REG_SP, ofs); ++ } + +- /* TCG_REG_TMP2 = rn[msb,lsb] */ +- tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, TCG_REG_TMP2, 64-len-lsb); ++ /* Pop (FP, LR) */ ++ /* ldl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* ldl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_RA, TCG_REG_SP, 8); + +- /* clear rd[msb,lsb] */ +- tcg_out_insn_bitReg(s, OPC_BIC, rd, rd, TCG_REG_TMP); +- /* rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] */ +- tcg_out_insn_bitReg(s, OPC_BIS, rd, rd, TCG_REG_TMP2); ++ /* restore SP to previous frame. */ ++ /* addl $sp,PUSH_SIZE,$sp */ ++ tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); ++ ++ tcg_out_insn_jump(s, OPC_RET, TCG_REG_ZERO, TCG_REG_RA, noPara); + } + +-/*sw +- * get val_s64(rn) * val_s64(rm) -> res_128 +- * res[127:64] -> rd +- * warn:maybe rd=rn or rm +- */ +-static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) ++static void tcg_out_nop_fill(tcg_insn_unit *p, int count) + { +- tcg_out_insn_simpleReg(s, OPC_UMULH, TCG_REG_TMP, rn, rm); +- +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, 63); +- tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rm); +- tcg_out_insn_simpleReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP2); +- +- tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, 63); +- tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rn); +- tcg_out_insn_simpleReg(s, OPC_SUBL, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ int i; ++ for (i = 0; i < count; ++i) { ++ p[i] = OPC_NOP; ++ } + } + + typedef struct { +@@ -2071,9 +2424,11 @@ typedef struct { + uint8_t fde_reg_ofs[8 * 2]; + } DebugFrame; + ++/* ++ * GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, ++ * which is good because they're really quite complicated for SW64. ++ */ + #define ELF_HOST_MACHINE EM_SW_64 +-/* GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, +- which is good because they're really quite complicated for SW_64. */ + + static const DebugFrame debug_frame = { + .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ +diff --git a/tcg/sw64/tcg-target.h b/tcg/sw64/tcg-target.h +index 3093e4fece..91681a0c75 100755 +--- a/tcg/sw64/tcg-target.h ++++ b/tcg/sw64/tcg-target.h +@@ -119,5 +119,8 @@ typedef enum { + #define TCG_TARGET_HAS_MEMORY_BSWAP 0 + /* optional instructions */ + void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); ++#ifdef CONFIG_SOFTMMU ++#define TCG_TARGET_NEED_LDST_LABELS ++#endif + #define TCG_TARGET_NEED_POOL_LABELS + #endif /* SW_64_TCG_TARGET_H */ +-- +2.41.0.windows.1 + diff --git a/tap-return-err-when-tap-TUNGETIFF-fail.patch b/tap-return-err-when-tap-TUNGETIFF-fail.patch new file mode 100644 index 0000000000000000000000000000000000000000..f74fa19abc42f16414dad411c06590d66c612922 --- /dev/null +++ b/tap-return-err-when-tap-TUNGETIFF-fail.patch @@ -0,0 +1,30 @@ +From 48a38f409a25f26605d65346c8ed9403c4b36c80 Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 10:28:59 +0800 +Subject: [PATCH] tap: return err when tap TUNGETIFF fail + +When hotplug ovs kernel netcard, even tap TUNGETIFF failed, +the hotplug would go on and would lead to qemu assert. +The failure should lead to the free_fail. + +Signed-off-by: miaoyubo +Signed-off-by: Yan Wang +--- + net/tap.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/tap.c b/net/tap.c +index f716be3e3f..c5cbeaa7a2 100644 +--- a/net/tap.c ++++ b/net/tap.c +@@ -900,6 +900,7 @@ int net_init_tap(const Netdev *netdev, const char *name, + if (i == 0) { + vnet_hdr = tap_probe_vnet_hdr(fd, errp); + if (vnet_hdr < 0) { ++ ret = -1; + goto free_fail; + } + } else if (vnet_hdr != tap_probe_vnet_hdr(fd, NULL)) { +-- +2.27.0 + diff --git a/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch b/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch index 4047145033d7010acfb3cfb002feb920fb303f0d..3bb8d6a46f4c0d762f2590250931e6347629c30a 100644 --- a/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch +++ b/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch @@ -1,7 +1,7 @@ -From 274d25bdb2df13a26ad6d2a8a06fcc281a22f642 Mon Sep 17 00:00:00 2001 +From e6dd7faeea77206d7e6589cbb54ad43926457052 Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:58 +0800 -Subject: [PATCH 7/9] target/arm: Add CPU features to query-cpu-model-expansion +Subject: [PATCH] target/arm: Add CPU features to query-cpu-model-expansion Add CPU features to the result of query-cpu-model-expansion so that other applications (such as libvirt) can know the supported CPU @@ -9,6 +9,7 @@ features. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu.c | 27 +++++++++++++++++++++++++++ target/arm/cpu.h | 2 ++ @@ -16,7 +17,7 @@ Signed-off-by: Peng Liang 3 files changed, 31 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index db46afba..dcf9f49e 100644 +index 3024f4a3f5..2d6a26336f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -25,6 +25,8 @@ @@ -26,9 +27,9 @@ index db46afba..dcf9f49e 100644 +#include "qapi/qmp/qdict.h" +#include "qom/qom-qobject.h" #include "cpu.h" - #include "internals.h" - #include "exec/exec-all.h" -@@ -1403,6 +1405,31 @@ static const CPUFeatureDep feature_dependencies[] = { + #ifdef CONFIG_TCG + #include "hw/core/tcg-cpu-ops.h" +@@ -1580,6 +1582,31 @@ static const CPUFeatureDep feature_dependencies[] = { }, }; @@ -46,7 +47,7 @@ index db46afba..dcf9f49e 100644 + } + + name = cpu_features[i].name; -+ prop = object_property_find(obj, name, NULL); ++ prop = object_property_find(obj, name); + if (prop) { + QObject *value; + @@ -61,10 +62,10 @@ index db46afba..dcf9f49e 100644 void *opaque, Error **errp) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 7bb481fb..068c3fa2 100644 +index 3dda33f347..947897d5ac 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h -@@ -3692,4 +3692,6 @@ static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) +@@ -4398,4 +4398,6 @@ static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id) #define cpu_isar_feature(name, cpu) \ ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); }) @@ -72,10 +73,10 @@ index 7bb481fb..068c3fa2 100644 + #endif diff --git a/target/arm/monitor.c b/target/arm/monitor.c -index e2b1d117..7c2ff3c0 100644 +index 80c64fa355..4c6f1181d9 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c -@@ -219,6 +219,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +@@ -217,6 +217,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, } } @@ -85,5 +86,5 @@ index e2b1d117..7c2ff3c0 100644 qobject_unref(qdict_out); } else { -- -2.25.1 +2.27.0 diff --git a/target-arm-Add-ID_AA64MMFR2_EL1.patch b/target-arm-Add-ID_AA64MMFR2_EL1.patch deleted file mode 100644 index eee33ae241bde2333d5308c7ca39297782598ccc..0000000000000000000000000000000000000000 --- a/target-arm-Add-ID_AA64MMFR2_EL1.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 3451fb922aa7b0fe532e508ca13d4ab4b3ec75bf Mon Sep 17 00:00:00 2001 -From: Richard Henderson -Date: Sat, 8 Feb 2020 12:58:13 +0000 -Subject: [PATCH 02/13] target/arm: Add ID_AA64MMFR2_EL1 - -Add definitions for all of the fields, up to ARMv8.5. -Convert the existing RESERVED register to a full register. -Query KVM for the value of the register for the host. - -Reviewed-by: Peter Maydell -Signed-off-by: Richard Henderson -Message-id: 20200208125816.14954-18-richard.henderson@linaro.org -Signed-off-by: Peter Maydell ---- - target/arm/cpu.h | 17 +++++++++++++++++ - target/arm/helper.c | 4 ++-- - target/arm/kvm64.c | 2 ++ - 3 files changed, 21 insertions(+), 2 deletions(-) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index fe310828..3e65bc50 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -866,6 +866,7 @@ struct ARMCPU { - uint64_t id_aa64pfr1; - uint64_t id_aa64mmfr0; - uint64_t id_aa64mmfr1; -+ uint64_t id_aa64mmfr2; - } isar; - uint32_t midr; - uint32_t revidr; -@@ -1762,6 +1763,22 @@ FIELD(ID_AA64MMFR1, PAN, 20, 4) - FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) - FIELD(ID_AA64MMFR1, XNX, 28, 4) - -+FIELD(ID_AA64MMFR2, CNP, 0, 4) -+FIELD(ID_AA64MMFR2, UAO, 4, 4) -+FIELD(ID_AA64MMFR2, LSM, 8, 4) -+FIELD(ID_AA64MMFR2, IESB, 12, 4) -+FIELD(ID_AA64MMFR2, VARANGE, 16, 4) -+FIELD(ID_AA64MMFR2, CCIDX, 20, 4) -+FIELD(ID_AA64MMFR2, NV, 24, 4) -+FIELD(ID_AA64MMFR2, ST, 28, 4) -+FIELD(ID_AA64MMFR2, AT, 32, 4) -+FIELD(ID_AA64MMFR2, IDS, 36, 4) -+FIELD(ID_AA64MMFR2, FWB, 40, 4) -+FIELD(ID_AA64MMFR2, TTL, 48, 4) -+FIELD(ID_AA64MMFR2, BBM, 52, 4) -+FIELD(ID_AA64MMFR2, EVT, 56, 4) -+FIELD(ID_AA64MMFR2, E0PD, 60, 4) -+ - FIELD(ID_DFR0, COPDBG, 0, 4) - FIELD(ID_DFR0, COPSDBG, 4, 4) - FIELD(ID_DFR0, MMAPDBG, 8, 4) -diff --git a/target/arm/helper.c b/target/arm/helper.c -index b74c23a9..c50b1ba1 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -6182,10 +6182,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, - .access = PL1_R, .type = ARM_CP_CONST, - .resetvalue = cpu->isar.id_aa64mmfr1 }, -- { .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, -+ { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = 0 }, -+ .resetvalue = cpu->isar.id_aa64mmfr2 }, - { .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, - .access = PL1_R, .type = ARM_CP_CONST, -diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index 4f0bf000..b794108a 100644 ---- a/target/arm/kvm64.c -+++ b/target/arm/kvm64.c -@@ -541,6 +541,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - ARM64_SYS_REG(3, 0, 0, 7, 0)); - err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, - ARM64_SYS_REG(3, 0, 0, 7, 1)); -+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, -+ ARM64_SYS_REG(3, 0, 0, 7, 2)); - - /* - * Note that if AArch32 support is not present in the host, --- -2.25.1 - diff --git a/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch b/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch deleted file mode 100644 index 7516ed8108de271970e600dbd03c964611b3b0ba..0000000000000000000000000000000000000000 --- a/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch +++ /dev/null @@ -1,166 +0,0 @@ -From 515975da851ca9567053bcf0487fde4447dfdc4f Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:04 +0000 -Subject: [PATCH 06/13] target/arm: Add _aa64_ and _any_ versions of pmu_8_1 - isar checks -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add the 64-bit version of the "is this a v8.1 PMUv3?" -ID register check function, and the _any_ version that -checks for either AArch32 or AArch64 support. We'll use -this in a later commit. - -We don't (yet) do any isar_feature checks on ID_AA64DFR1_EL1, -but we move id_aa64dfr1 into the ARMISARegisters struct with -id_aa64dfr0, for consistency. - -Reviewed-by: Richard Henderson -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Peter Maydell -Message-id: 20200214175116.9164-10-peter.maydell@linaro.org ---- - target/arm/cpu.c | 3 ++- - target/arm/cpu.h | 15 +++++++++++++-- - target/arm/cpu64.c | 8 ++++---- - target/arm/helper.c | 12 +++++++----- - 4 files changed, 26 insertions(+), 12 deletions(-) - -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 7e9b85a2..bb2edf4e 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -1522,7 +1522,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - cpu); - #endif - } else { -- cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); -+ cpu->isar.id_aa64dfr0 = -+ FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); - cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); - cpu->pmceid0 = 0; - cpu->pmceid1 = 0; -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 2d8d27e8..230130be 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -868,6 +868,8 @@ struct ARMCPU { - uint64_t id_aa64mmfr0; - uint64_t id_aa64mmfr1; - uint64_t id_aa64mmfr2; -+ uint64_t id_aa64dfr0; -+ uint64_t id_aa64dfr1; - } isar; - uint32_t midr; - uint32_t revidr; -@@ -884,8 +886,6 @@ struct ARMCPU { - uint32_t id_mmfr2; - uint32_t id_mmfr3; - uint32_t id_mmfr4; -- uint64_t id_aa64dfr0; -- uint64_t id_aa64dfr1; - uint64_t id_aa64afr0; - uint64_t id_aa64afr1; - uint32_t dbgdidr; -@@ -3657,6 +3657,17 @@ static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) - return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; - } - -+static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) -+{ -+ return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && -+ FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; -+} -+ -+static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) -+{ -+ return isar_feature_aa64_pmu_8_1(id) || isar_feature_aa32_pmu_8_1(id); -+} -+ - /* - * Forward to the above feature tests given an ARMCPU pointer. - */ -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index afdabbeb..aa96548f 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -137,7 +137,7 @@ static void aarch64_a57_initfn(Object *obj) - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_isar6 = 0; - cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->id_aa64dfr0 = 0x10305106; -+ cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; - cpu->dbgdidr = 0x3516d000; -@@ -191,7 +191,7 @@ static void aarch64_a53_initfn(Object *obj) - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_isar6 = 0; - cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->id_aa64dfr0 = 0x10305106; -+ cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ - cpu->dbgdidr = 0x3516d000; -@@ -244,7 +244,7 @@ static void aarch64_a72_initfn(Object *obj) - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->id_aa64dfr0 = 0x10305106; -+ cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; - cpu->dbgdidr = 0x3516d000; -@@ -276,7 +276,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) - cpu->midr = 0x480fd010; - cpu->ctr = 0x84448004; - cpu->isar.id_aa64pfr0 = 0x11001111; -- cpu->id_aa64dfr0 = 0x110305408; -+ cpu->isar.id_aa64dfr0 = 0x110305408; - cpu->isar.id_aa64isar0 = 0x10211120; - cpu->isar.id_aa64mmfr0 = 0x101125; - } -diff --git a/target/arm/helper.c b/target/arm/helper.c -index 3f06ca19..a71f4ef6 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -23,6 +23,7 @@ - #include "hw/semihosting/semihost.h" - #include "sysemu/cpus.h" - #include "sysemu/kvm.h" -+#include "sysemu/tcg.h" - #include "qemu/range.h" - #include "qapi/qapi-commands-machine-target.h" - #include "qapi/error.h" -@@ -5611,9 +5612,10 @@ static void define_debug_regs(ARMCPU *cpu) - * check that if they both exist then they agree. - */ - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); -- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); -- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) == ctx_cmps); -+ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); -+ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); -+ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) -+ == ctx_cmps); - } - - define_one_arm_cp_reg(cpu, &dbgdidr); -@@ -6112,11 +6114,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_aa64dfr0 }, -+ .resetvalue = cpu->isar.id_aa64dfr0 }, - { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_aa64dfr1 }, -+ .resetvalue = cpu->isar.id_aa64dfr1 }, - { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, - .access = PL1_R, .type = ARM_CP_CONST, --- -2.25.1 - diff --git a/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch b/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch deleted file mode 100644 index 66e4ec4ad078aacdd4e7cb9a76244e1460487551..0000000000000000000000000000000000000000 --- a/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 4001f3040937094660eab44dbb49b86817317ea9 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:01 +0000 -Subject: [PATCH 03/13] target/arm: Add and use FIELD definitions for - ID_AA64DFR0_EL1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add FIELD() definitions for the ID_AA64DFR0_EL1 and use them -where we currently have hard-coded bit values. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Richard Henderson -Signed-off-by: Peter Maydell -Message-id: 20200214175116.9164-7-peter.maydell@linaro.org ---- - target/arm/cpu.c | 2 +- - target/arm/cpu.h | 10 ++++++++++ - target/arm/helper.c | 6 +++--- - 3 files changed, 14 insertions(+), 4 deletions(-) - -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 811e5c63..dbd05e01 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -1522,7 +1522,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - cpu); - #endif - } else { -- cpu->id_aa64dfr0 &= ~0xf00; -+ cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); - cpu->id_dfr0 &= ~(0xf << 24); - cpu->pmceid0 = 0; - cpu->pmceid1 = 0; -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 3e65bc50..91cc02b4 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -1779,6 +1779,16 @@ FIELD(ID_AA64MMFR2, BBM, 52, 4) - FIELD(ID_AA64MMFR2, EVT, 56, 4) - FIELD(ID_AA64MMFR2, E0PD, 60, 4) - -+FIELD(ID_AA64DFR0, DEBUGVER, 0, 4) -+FIELD(ID_AA64DFR0, TRACEVER, 4, 4) -+FIELD(ID_AA64DFR0, PMUVER, 8, 4) -+FIELD(ID_AA64DFR0, BRPS, 12, 4) -+FIELD(ID_AA64DFR0, WRPS, 20, 4) -+FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) -+FIELD(ID_AA64DFR0, PMSVER, 32, 4) -+FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) -+FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) -+ - FIELD(ID_DFR0, COPDBG, 0, 4) - FIELD(ID_DFR0, COPSDBG, 4, 4) - FIELD(ID_DFR0, MMAPDBG, 8, 4) -diff --git a/target/arm/helper.c b/target/arm/helper.c -index c50b1ba1..419be640 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -5611,9 +5611,9 @@ static void define_debug_regs(ARMCPU *cpu) - * check that if they both exist then they agree. - */ - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -- assert(extract32(cpu->id_aa64dfr0, 12, 4) == brps); -- assert(extract32(cpu->id_aa64dfr0, 20, 4) == wrps); -- assert(extract32(cpu->id_aa64dfr0, 28, 4) == ctx_cmps); -+ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); -+ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); -+ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) == ctx_cmps); - } - - define_one_arm_cp_reg(cpu, &dbgdidr); --- -2.25.1 - diff --git a/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch b/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch deleted file mode 100644 index d6e29be12e1bbf6ef55d43bf35960e2168fc51e8..0000000000000000000000000000000000000000 --- a/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 6f18e959eabf9c752659eb3851f193bf343346c5 Mon Sep 17 00:00:00 2001 -From: Richard Henderson -Date: Sat, 8 Feb 2020 12:57:59 +0000 -Subject: [PATCH 01/13] target/arm: Add isar_feature tests for PAN + ATS1E1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Include definitions for all of the bits in ID_MMFR3. -We already have a definition for ID_AA64MMFR1.PAN. - -Reviewed-by: Alex Bennée -Reviewed-by: Peter Maydell -Signed-off-by: Richard Henderson -Message-id: 20200208125816.14954-4-richard.henderson@linaro.org -Signed-off-by: Peter Maydell ---- - target/arm/cpu.h | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 86eb79cd..fe310828 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -1680,6 +1680,15 @@ FIELD(ID_ISAR6, FHM, 8, 4) - FIELD(ID_ISAR6, SB, 12, 4) - FIELD(ID_ISAR6, SPECRES, 16, 4) - -+FIELD(ID_MMFR3, CMAINTVA, 0, 4) -+FIELD(ID_MMFR3, CMAINTSW, 4, 4) -+FIELD(ID_MMFR3, BPMAINT, 8, 4) -+FIELD(ID_MMFR3, MAINTBCST, 12, 4) -+FIELD(ID_MMFR3, PAN, 16, 4) -+FIELD(ID_MMFR3, COHWALK, 20, 4) -+FIELD(ID_MMFR3, CMEMSZ, 24, 4) -+FIELD(ID_MMFR3, SUPERSEC, 28, 4) -+ - FIELD(ID_MMFR4, SPECSEI, 0, 4) - FIELD(ID_MMFR4, AC2, 4, 4) - FIELD(ID_MMFR4, XNX, 8, 4) -@@ -3445,6 +3454,16 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) - return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4; - } - -+static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) -+{ -+ return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) != 0; -+} -+ -+static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) -+{ -+ return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; -+} -+ - /* - * 64-bit feature tests via id registers. - */ -@@ -3589,6 +3608,16 @@ static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) - return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; - } - -+static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) -+{ -+ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; -+} -+ -+static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) -+{ -+ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; -+} -+ - static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) - { - return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; --- -2.25.1 - diff --git a/target-arm-Add-missing-FEAT_TLBIOS-instructions.patch b/target-arm-Add-missing-FEAT_TLBIOS-instructions.patch new file mode 100644 index 0000000000000000000000000000000000000000..44483e199daf5ed6f16ba1d77e8ce72aa86ec3af --- /dev/null +++ b/target-arm-Add-missing-FEAT_TLBIOS-instructions.patch @@ -0,0 +1,90 @@ +From 1ac38ad4f16bf8fe4cabf1e41036f36ad08cf14f Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 15:07:57 +0000 +Subject: [PATCH 14/29] target/arm: Add missing FEAT_TLBIOS instructions + +mainline inclusion +commit b7469ef92a8034b32031ba22b84fb14046f9770e +category: bugfix + +------------------------------------------------------------ + +Some of the instructions added by the FEAT_TLBIOS extension were forgotten +when the extension was originally added to QEMU. + +Fixes: 7113d618505b ("target/arm: Add support for FEAT_TLBIOS") +Signed-off-by: Idan Horowitz +Reviewed-by: Richard Henderson +Message-id: 20211231103928.1455657-1-idan.horowitz@gmail.com +Signed-off-by: Peter Maydell + +Signed-off-by: tangbinzy +--- + target/arm/helper.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 80737a8d7b..1854c65863 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -6998,18 +6998,42 @@ static const ARMCPRegInfo tlbios_reginfo[] = { + .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0, + .access = PL1_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_vmalle1is_write }, ++ { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1, ++ .access = PL1_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae1is_write }, + { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2, + .access = PL1_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_vmalle1is_write }, ++ { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3, ++ .access = PL1_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae1is_write }, ++ { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5, ++ .access = PL1_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae1is_write }, ++ { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7, ++ .access = PL1_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae1is_write }, + { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_alle2is_write }, ++ { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1, ++ .access = PL2_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae2is_write }, + { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_alle1is_write }, ++ { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5, ++ .access = PL2_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae2is_write }, + { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6, + .access = PL2_W, .type = ARM_CP_NO_RAW, +@@ -7030,6 +7054,14 @@ static const ARMCPRegInfo tlbios_reginfo[] = { + .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 0, + .access = PL3_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_alle3is_write }, ++ { .name = "TLBI_VAE3OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 1, ++ .access = PL3_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae3is_write }, ++ { .name = "TLBI_VALE3OS", .state = ARM_CP_STATE_AA64, ++ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5, ++ .access = PL3_W, .type = ARM_CP_NO_RAW, ++ .writefn = tlbi_aa64_vae3is_write }, + REGINFO_SENTINEL + }; + +-- +2.27.0 + diff --git a/target-arm-Add-more-CPU-features.patch b/target-arm-Add-more-CPU-features.patch index a22e5177300d305df8c0430ee21e29c587bd5399..4b8c01d5038e29505e5b4d19d4467e5054de792a 100644 --- a/target-arm-Add-more-CPU-features.patch +++ b/target-arm-Add-more-CPU-features.patch @@ -1,21 +1,22 @@ -From 3eee1e4ff1ca342e760f759c727abc41780d0afa Mon Sep 17 00:00:00 2001 +From 85d5b46d8225c5875b8b3ff68967d46bcde9a549 Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Tue, 11 Aug 2020 10:28:10 +0800 -Subject: [PATCH 9/9] target/arm: Add more CPU features +Subject: [PATCH] target/arm: Add more CPU features Add i8mm, bf16, and dgh CPU features for AArch64. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index dcf9f49e..7ae2d3da 100644 +index 2d6a26336f..1c1647a0a8 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1132,6 +1132,9 @@ static struct CPUFeatureInfo cpu_features[] = { +@@ -1309,6 +1309,9 @@ static struct CPUFeatureInfo cpu_features[] = { FIELD_INFO("fhm", ID_ISAR6, FHM, false, 1, 0, true), FIELD_INFO("sb", ID_ISAR6, SB, false, 1, 0, true), FIELD_INFO("specres", ID_ISAR6, SPECRES, false, 1, 0, true), @@ -26,5 +27,5 @@ index dcf9f49e..7ae2d3da 100644 FIELD_INFO("cmaintva", ID_MMFR3, CMAINTVA, false, 1, 0, true), FIELD_INFO("cmaintsw", ID_MMFR3, CMAINTSW, false, 1, 0, true), -- -2.25.1 +2.27.0 diff --git a/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch b/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch deleted file mode 100644 index 49c7dc63022ec1196b8c225b1c5291fbbe10e1ad..0000000000000000000000000000000000000000 --- a/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 427975fbc87c3d999ee4d13b65a95ba496c148d6 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Fri, 29 May 2020 11:02:44 +0800 -Subject: [PATCH] target/arm: Add the kvm_adjvtime vcpu property for Cortex-A72 - -Add the kvm_adjvtime vcpu property for ARM Cortex-A72 cpu model, -so that virtual time adjust will be enabled for it. - -Signed-off-by: Ying Fang - -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index b30ca7c9..15f4ee92 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -257,6 +257,9 @@ static void aarch64_a72_initfn(Object *obj) - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); -+ if(kvm_enabled()) { -+ kvm_arm_add_vcpu_properties(obj); -+ } - } - - static void aarch64_kunpeng_920_initfn(Object *obj) --- -2.23.0 - diff --git a/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch b/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch index 81ad2961b00130a741079e0f38c56b7dffdcf803..84645718d5fb1bcc3179bdf28f61d9d954d2dc9e 100644 --- a/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch +++ b/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch @@ -1,7 +1,7 @@ -From 79a60f0eeb56faf5d162ca566d1cd9988c3e4d60 Mon Sep 17 00:00:00 2001 +From 0272c52e36ab95389e665ca19b129178b0b46eac Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:40 +0800 -Subject: [PATCH 4/9] target/arm: Allow ID registers to synchronize to KVM +Subject: [PATCH] target/arm: Allow ID registers to synchronize to KVM There are 2 steps to synchronize the values of system registers from CPU state to KVM: @@ -26,6 +26,7 @@ KVM. If the write is successful, then write to (index,value) list. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/helper.c | 31 ++++++++++++++++++++----------- target/arm/kvm.c | 38 ++++++++++++++++++++++++++++++++++++++ @@ -33,18 +34,18 @@ Signed-off-by: Peng Liang 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c -index 459af431..97b6b861 100644 +index b8ea1dc1f6..79f77705c3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c -@@ -32,6 +32,7 @@ - #include "arm_ldst.h" +@@ -35,6 +35,7 @@ #include "exec/cpu_ldst.h" + #include "semihosting/common-semi.h" #endif +#include "kvm_arm.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ - -@@ -267,30 +268,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) + #define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */ +@@ -149,30 +150,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) ok = false; continue; } @@ -95,10 +96,10 @@ index 459af431..97b6b861 100644 cpu->cpreg_values[i] = newval; } diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index 4f131f68..229b17ce 100644 +index bbf1ce7ba3..59d556724f 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c -@@ -457,6 +457,44 @@ out: +@@ -514,6 +514,44 @@ out: return ret; } @@ -144,10 +145,10 @@ index 4f131f68..229b17ce 100644 { CPUState *cs = CPU(cpu); diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 0de5f83e..9b7104d6 100644 +index b7f78b5215..f8e0e64363 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h -@@ -400,4 +400,7 @@ static inline const char *its_class_name(void) +@@ -528,4 +528,7 @@ static inline const char *its_class_name(void) } } @@ -156,5 +157,5 @@ index 0de5f83e..9b7104d6 100644 + #endif -- -2.25.1 +2.27.0 diff --git a/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch b/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch deleted file mode 100644 index ca4b796b58600aa35771d26a247690dfca413cc9..0000000000000000000000000000000000000000 --- a/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch +++ /dev/null @@ -1,41 +0,0 @@ -From cdc6896659b85f7ed8f7552850312e55170de0c5 Mon Sep 17 00:00:00 2001 -From: Christophe Lyon -Date: Fri, 25 Oct 2019 11:57:11 +0200 -Subject: [PATCH] target/arm: Allow reading flags from FPSCR for M-profile - -rt==15 is a special case when reading the flags: it means the -destination is APSR. This patch avoids rejecting -vmrs apsr_nzcv, fpscr -as illegal instruction. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Christophe Lyon -Message-id: 20191025095711.10853-1-christophe.lyon@linaro.org -[PMM: updated the comment] -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -(cherry picked from commit 2529ab43b8a05534494704e803e0332d111d8b91) -Signed-off-by: Michael Roth ---- - target/arm/translate-vfp.inc.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c -index ef45cecbea..75406fd9db 100644 ---- a/target/arm/translate-vfp.inc.c -+++ b/target/arm/translate-vfp.inc.c -@@ -704,9 +704,10 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) - if (arm_dc_feature(s, ARM_FEATURE_M)) { - /* - * The only M-profile VFP vmrs/vmsr sysreg is FPSCR. -- * Writes to R15 are UNPREDICTABLE; we choose to undef. -+ * Accesses to R15 are UNPREDICTABLE; we choose to undef. -+ * (FPSCR -> r15 is a special case which writes to the PSR flags.) - */ -- if (a->rt == 15 || a->reg != ARM_VFP_FPSCR) { -+ if (a->rt == 15 && (!a->l || a->reg != ARM_VFP_FPSCR)) { - return false; - } - } --- -2.23.0 diff --git a/target-arm-Copy-the-entire-vector-in-DO_ZIP.patch b/target-arm-Copy-the-entire-vector-in-DO_ZIP.patch new file mode 100644 index 0000000000000000000000000000000000000000..328c224b6a2bb5f6c59b5a5db50126332d041083 --- /dev/null +++ b/target-arm-Copy-the-entire-vector-in-DO_ZIP.patch @@ -0,0 +1,35 @@ +From 5386c69970911a73c705068b72048437b1c27df0 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Tue, 22 Nov 2022 17:52:53 +0800 +Subject: [PATCH 04/29] target/arm: Copy the entire vector in DO_ZIP + +With odd_ofs set, we weren't copying enough data. +Fixes: 09eb6d7025d1 ("target/arm: Move sve zip high_ofs into simd_data") + +Reported-by: Idan Horowitz +Signed-off-by: Richard Henderson +Signed-off-by: jianchunfu +--- + target/arm/sve_helper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c +index 07be55b7e1..03d58cabc8 100644 +--- a/target/arm/sve_helper.c ++++ b/target/arm/sve_helper.c +@@ -3387,10 +3387,10 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ + /* We produce output faster than we consume input. \ + Therefore we must be mindful of possible overlap. */ \ + if (unlikely((vn - vd) < (uintptr_t)oprsz)) { \ +- vn = memcpy(&tmp_n, vn, oprsz_2); \ ++ vn = memcpy(&tmp_n, vn, oprsz); \ + } \ + if (unlikely((vm - vd) < (uintptr_t)oprsz)) { \ +- vm = memcpy(&tmp_m, vm, oprsz_2); \ ++ vm = memcpy(&tmp_m, vm, oprsz); \ + } \ + for (i = 0; i < oprsz_2; i += sizeof(TYPE)) { \ + *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + H(i)); \ +-- +2.27.0 + diff --git a/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch b/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch deleted file mode 100644 index bfcce54936d4cb8c8ca1de997a6d0d469dab3bc1..0000000000000000000000000000000000000000 --- a/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 2eded1a4deeb5dd8d28414e54948bcf773f6b540 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:03 +0000 -Subject: [PATCH 05/13] target/arm: Define an aa32_pmu_8_1 isar feature test - function - -Instead of open-coding a check on the ID_DFR0 PerfMon ID register -field, create a standardly-named isar_feature for "does AArch32 have -a v8.1 PMUv3" and use it. - -This entails moving the id_dfr0 field into the ARMISARegisters struct. - -Reviewed-by: Richard Henderson -Signed-off-by: Peter Maydell -Message-id: 20200214175116.9164-9-peter.maydell@linaro.org ---- - hw/intc/armv7m_nvic.c | 2 +- - target/arm/cpu.c | 26 +++++++++++++------------- - target/arm/cpu.h | 9 ++++++++- - target/arm/cpu64.c | 6 +++--- - target/arm/helper.c | 5 ++--- - 5 files changed, 27 insertions(+), 21 deletions(-) - -diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c -index 9f8f0d3f..0741db7b 100644 ---- a/hw/intc/armv7m_nvic.c -+++ b/hw/intc/armv7m_nvic.c -@@ -1223,7 +1223,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) - case 0xd44: /* PFR1. */ - return cpu->id_pfr1; - case 0xd48: /* DFR0. */ -- return cpu->id_dfr0; -+ return cpu->isar.id_dfr0; - case 0xd4c: /* AFR0. */ - return cpu->id_afr0; - case 0xd50: /* MMFR0. */ -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 6ad211b1..7e9b85a2 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -1523,7 +1523,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - #endif - } else { - cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); -- cpu->id_dfr0 = FIELD_DP32(cpu->id_dfr0, ID_DFR0, PERFMON, 0); -+ cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); - cpu->pmceid0 = 0; - cpu->pmceid1 = 0; - } -@@ -1761,7 +1761,7 @@ static void arm1136_r2_initfn(Object *obj) - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->id_dfr0 = 0x2; -+ cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; - cpu->id_mmfr0 = 0x01130003; - cpu->id_mmfr1 = 0x10030302; -@@ -1793,7 +1793,7 @@ static void arm1136_initfn(Object *obj) - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->id_dfr0 = 0x2; -+ cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; - cpu->id_mmfr0 = 0x01130003; - cpu->id_mmfr1 = 0x10030302; -@@ -1826,7 +1826,7 @@ static void arm1176_initfn(Object *obj) - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x11; -- cpu->id_dfr0 = 0x33; -+ cpu->isar.id_dfr0 = 0x33; - cpu->id_afr0 = 0; - cpu->id_mmfr0 = 0x01130003; - cpu->id_mmfr1 = 0x10030302; -@@ -1856,7 +1856,7 @@ static void arm11mpcore_initfn(Object *obj) - cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->id_dfr0 = 0; -+ cpu->isar.id_dfr0 = 0; - cpu->id_afr0 = 0x2; - cpu->id_mmfr0 = 0x01100103; - cpu->id_mmfr1 = 0x10020302; -@@ -1888,7 +1888,7 @@ static void cortex_m3_initfn(Object *obj) - cpu->pmsav7_dregion = 8; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; -- cpu->id_dfr0 = 0x00100000; -+ cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x00000030; - cpu->id_mmfr1 = 0x00000000; -@@ -1919,7 +1919,7 @@ static void cortex_m4_initfn(Object *obj) - cpu->isar.mvfr2 = 0x00000000; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; -- cpu->id_dfr0 = 0x00100000; -+ cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x00000030; - cpu->id_mmfr1 = 0x00000000; -@@ -1952,7 +1952,7 @@ static void cortex_m33_initfn(Object *obj) - cpu->isar.mvfr2 = 0x00000040; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000210; -- cpu->id_dfr0 = 0x00200000; -+ cpu->isar.id_dfr0 = 0x00200000; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x00101F40; - cpu->id_mmfr1 = 0x00000000; -@@ -2003,7 +2003,7 @@ static void cortex_r5_initfn(Object *obj) - cpu->midr = 0x411fc153; /* r1p3 */ - cpu->id_pfr0 = 0x0131; - cpu->id_pfr1 = 0x001; -- cpu->id_dfr0 = 0x010400; -+ cpu->isar.id_dfr0 = 0x010400; - cpu->id_afr0 = 0x0; - cpu->id_mmfr0 = 0x0210030; - cpu->id_mmfr1 = 0x00000000; -@@ -2058,7 +2058,7 @@ static void cortex_a8_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x1031; - cpu->id_pfr1 = 0x11; -- cpu->id_dfr0 = 0x400; -+ cpu->isar.id_dfr0 = 0x400; - cpu->id_afr0 = 0; - cpu->id_mmfr0 = 0x31100003; - cpu->id_mmfr1 = 0x20000000; -@@ -2131,7 +2131,7 @@ static void cortex_a9_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x1031; - cpu->id_pfr1 = 0x11; -- cpu->id_dfr0 = 0x000; -+ cpu->isar.id_dfr0 = 0x000; - cpu->id_afr0 = 0; - cpu->id_mmfr0 = 0x00100103; - cpu->id_mmfr1 = 0x20000000; -@@ -2196,7 +2196,7 @@ static void cortex_a7_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x00001131; - cpu->id_pfr1 = 0x00011011; -- cpu->id_dfr0 = 0x02010555; -+ cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x10101105; - cpu->id_mmfr1 = 0x40000000; -@@ -2242,7 +2242,7 @@ static void cortex_a15_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x00001131; - cpu->id_pfr1 = 0x00011011; -- cpu->id_dfr0 = 0x02010555; -+ cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x10201105; - cpu->id_mmfr1 = 0x20000000; -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 91cc02b4..2d8d27e8 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -860,6 +860,7 @@ struct ARMCPU { - uint32_t mvfr0; - uint32_t mvfr1; - uint32_t mvfr2; -+ uint32_t id_dfr0; - uint64_t id_aa64isar0; - uint64_t id_aa64isar1; - uint64_t id_aa64pfr0; -@@ -875,7 +876,6 @@ struct ARMCPU { - uint32_t reset_sctlr; - uint32_t id_pfr0; - uint32_t id_pfr1; -- uint32_t id_dfr0; - uint64_t pmceid0; - uint64_t pmceid1; - uint32_t id_afr0; -@@ -3491,6 +3491,13 @@ static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) - return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; - } - -+static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) -+{ -+ /* 0xf means "non-standard IMPDEF PMU" */ -+ return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && -+ FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; -+} -+ - /* - * 64-bit feature tests via id registers. - */ -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 15f4ee92..afdabbeb 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -123,7 +123,7 @@ static void aarch64_a57_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->id_dfr0 = 0x03010066; -+ cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x10101105; - cpu->id_mmfr1 = 0x40000000; -@@ -177,7 +177,7 @@ static void aarch64_a53_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->id_dfr0 = 0x03010066; -+ cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x10101105; - cpu->id_mmfr1 = 0x40000000; -@@ -231,7 +231,7 @@ static void aarch64_a72_initfn(Object *obj) - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->id_dfr0 = 0x03010066; -+ cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->id_mmfr0 = 0x10201105; - cpu->id_mmfr1 = 0x40000000; -diff --git a/target/arm/helper.c b/target/arm/helper.c -index 419be640..3f06ca19 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -5907,7 +5907,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_dfr0 }, -+ .resetvalue = cpu->isar.id_dfr0 }, - { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, - .access = PL1_R, .type = ARM_CP_CONST, -@@ -6050,8 +6050,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - } else { - define_arm_cp_regs(cpu, not_v7_cp_reginfo); - } -- if (FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) >= 4 && -- FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) != 0xf) { -+ if (cpu_isar_feature(aa32_pmu_8_1, cpu)) { - ARMCPRegInfo v81_pmu_regs[] = { - { .name = "PMCEID2", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4, --- -2.25.1 - diff --git a/target-arm-Don-t-abort-on-M-profile-exception-return.patch b/target-arm-Don-t-abort-on-M-profile-exception-return.patch deleted file mode 100644 index b6796e25b8b04c76a117ad129cb807a0da93da45..0000000000000000000000000000000000000000 --- a/target-arm-Don-t-abort-on-M-profile-exception-return.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 9027d3fba605d8f6093342ebe4a1da450d374630 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Thu, 22 Aug 2019 14:15:34 +0100 -Subject: [PATCH] target/arm: Don't abort on M-profile exception return in - linux-user mode - -An attempt to do an exception-return (branch to one of the magic -addresses) in linux-user mode for M-profile should behave like -a normal branch, because linux-user mode is always going to be -in 'handler' mode. This used to work, but we broke it when we added -support for the M-profile security extension in commit d02a8698d7ae2bfed. - -In that commit we allowed even handler-mode calls to magic return -values to be checked for and dealt with by causing an -EXCP_EXCEPTION_EXIT exception to be taken, because this is -needed for the FNC_RETURN return-from-non-secure-function-call -handling. For system mode we added a check in do_v7m_exception_exit() -to make any spurious calls from Handler mode behave correctly, but -forgot that linux-user mode would also be affected. - -How an attempted return-from-non-secure-function-call in linux-user -mode should be handled is not clear -- on real hardware it would -result in return to secure code (not to the Linux kernel) which -could then handle the error in any way it chose. For QEMU we take -the simple approach of treating this erroneous return the same way -it would be handled on a CPU without the security extensions -- -treat it as a normal branch. - -The upshot of all this is that for linux-user mode we should never -do any of the bx_excret magic, so the code change is simple. - -This ought to be a weird corner case that only affects broken guest -code (because Linux user processes should never be attempting to do -exception returns or NS function returns), except that the code that -assigns addresses in RAM for the process and stack in our linux-user -code does not attempt to avoid this magic address range, so -legitimate code attempting to return to a trampoline routine on the -stack can fall into this case. This change fixes those programs, -but we should also look at restricting the range of memory we -use for M-profile linux-user guests to the area that would be -real RAM in hardware. - -Cc: qemu-stable@nongnu.org -Reported-by: Christophe Lyon -Reviewed-by: Richard Henderson -Signed-off-by: Peter Maydell -Message-id: 20190822131534.16602-1-peter.maydell@linaro.org -Fixes: https://bugs.launchpad.net/qemu/+bug/1840922 -Signed-off-by: Peter Maydell -(cherry picked from commit 5e5584c89f36b302c666bc6db535fd3f7ff35ad2) -Signed-off-by: Michael Roth ---- - target/arm/translate.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/target/arm/translate.c b/target/arm/translate.c -index 7853462b21..24cb4ba075 100644 ---- a/target/arm/translate.c -+++ b/target/arm/translate.c -@@ -952,10 +952,27 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var) - store_cpu_field(var, thumb); - } - --/* Set PC and Thumb state from var. var is marked as dead. -+/* -+ * Set PC and Thumb state from var. var is marked as dead. - * For M-profile CPUs, include logic to detect exception-return - * branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC, - * and BX reg, and no others, and happens only for code in Handler mode. -+ * The Security Extension also requires us to check for the FNC_RETURN -+ * which signals a function return from non-secure state; this can happen -+ * in both Handler and Thread mode. -+ * To avoid having to do multiple comparisons in inline generated code, -+ * we make the check we do here loose, so it will match for EXC_RETURN -+ * in Thread mode. For system emulation do_v7m_exception_exit() checks -+ * for these spurious cases and returns without doing anything (giving -+ * the same behaviour as for a branch to a non-magic address). -+ * -+ * In linux-user mode it is unclear what the right behaviour for an -+ * attempted FNC_RETURN should be, because in real hardware this will go -+ * directly to Secure code (ie not the Linux kernel) which will then treat -+ * the error in any way it chooses. For QEMU we opt to make the FNC_RETURN -+ * attempt behave the way it would on a CPU without the security extension, -+ * which is to say "like a normal branch". That means we can simply treat -+ * all branches as normal with no magic address behaviour. - */ - static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) - { -@@ -963,10 +980,12 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) - * s->base.is_jmp that we need to do the rest of the work later. - */ - gen_bx(s, var); -+#ifndef CONFIG_USER_ONLY - if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) || - (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) { - s->base.is_jmp = DISAS_BX_EXCRET; - } -+#endif - } - - static inline void gen_bx_excret_final_code(DisasContext *s) --- -2.23.0 diff --git a/target-arm-Don-t-set-syndrome-ISS-for-loads-and-stor.patch b/target-arm-Don-t-set-syndrome-ISS-for-loads-and-stor.patch new file mode 100644 index 0000000000000000000000000000000000000000..4fe6a0cd77d1839db5c46f6b149bc4b996cc8672 --- /dev/null +++ b/target-arm-Don-t-set-syndrome-ISS-for-loads-and-stor.patch @@ -0,0 +1,51 @@ +From dd5bf5817259ea414f40b25f4aef3864eddb9706 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 27 Nov 2023 03:24:57 +0000 +Subject: [PATCH] target/arm: Don't set syndrome ISS for loads and stores with + writeback mainline inclusion commit 53ae2fdef1f5661cbaa2ea571c517f98e6041cb8 + category: bugfix + +--------------------------------------------------------------- + +The architecture requires that for faults on loads and stores which +do writeback, the syndrome information does not have the ISS +instruction syndrome information (i.e. ISV is 0). We got this wrong +for the load and store instructions covered by disas_ldst_reg_imm9(). +Calculate iss_valid correctly so that if the insn is a writeback one +it is false. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1057 +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20220715123323.1550983-1-peter.maydell@linaro.org + +Signed-off-by: tangbinzy +--- + target/arm/translate-a64.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c +index cec672f229..549a671bea 100644 +--- a/target/arm/translate-a64.c ++++ b/target/arm/translate-a64.c +@@ -3039,7 +3039,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, + bool is_store = false; + bool is_extended = false; + bool is_unpriv = (idx == 2); +- bool iss_valid = !is_vector; ++ bool iss_valid; + bool post_index; + bool writeback; + int memidx; +@@ -3092,6 +3092,8 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, + g_assert_not_reached(); + } + ++ iss_valid = !is_vector && !writeback; ++ + if (rn == 31) { + gen_check_sp_alignment(s); + } +-- +2.27.0 + diff --git a/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch b/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch deleted file mode 100644 index d6e82fae2dc02954d37eb723f930bccd28b70618..0000000000000000000000000000000000000000 --- a/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 69eedbfc873ded9bf35439b813e9f6a7431dc727 Mon Sep 17 00:00:00 2001 -From: Richard Henderson -Date: Sat, 8 Feb 2020 12:58:12 +0000 -Subject: [PATCH 09/13] target/arm: Enable ARMv8.2-ATS1E1 in -cpu max - -This includes enablement of ARMv8.1-PAN. - -Reviewed-by: Peter Maydell -Signed-off-by: Richard Henderson -Message-id: 20200208125816.14954-17-richard.henderson@linaro.org -Signed-off-by: Peter Maydell ---- - target/arm/cpu.c | 4 ++++ - target/arm/cpu64.c | 5 +++++ - 2 files changed, 9 insertions(+) - -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index a23c71db..119bd275 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -2484,6 +2484,10 @@ static void arm_max_initfn(Object *obj) - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - -+ t = cpu->id_mmfr3; -+ t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ -+ cpu->id_mmfr3 = t; -+ - t = cpu->id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - cpu->id_mmfr4 = t; -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 7ad8b5e2..a0d07fd7 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -362,6 +362,7 @@ static void aarch64_max_initfn(Object *obj) - t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); -+ t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ - cpu->isar.id_aa64mmfr1 = t; - - /* Replicate the same data to the 32-bit id registers. */ -@@ -382,6 +383,10 @@ static void aarch64_max_initfn(Object *obj) - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - cpu->isar.id_isar6 = u; - -+ u = cpu->id_mmfr3; -+ u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ -+ cpu->id_mmfr3 = u; -+ - /* - * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, - * so do not set MVFR1.FPHP. Strictly speaking this is not legal, --- -2.25.1 - diff --git a/target-arm-Fix-PAuth-sbox-functions.patch b/target-arm-Fix-PAuth-sbox-functions.patch deleted file mode 100644 index ac8d05065f766eb8ca90cd00de6a60350c2306c3..0000000000000000000000000000000000000000 --- a/target-arm-Fix-PAuth-sbox-functions.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a7149fc18020c3d432c31838069dcfcb745299bf Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Sat, 20 Jun 2020 12:01:30 +0800 -Subject: [PATCH] target/arm: Fix PAuth sbox functions - -In the PAC computation, sbox was applied over wrong bits. -As this is a 4-bit sbox, bit index should be incremented by 4 instead of 16. - -Test vector from QARMA paper (https://eprint.iacr.org/2016/444.pdf) was -used to verify one computation of the pauth_computepac() function which -uses sbox2. - -Launchpad: https://bugs.launchpad.net/bugs/1859713 -Reviewed-by: Richard Henderson -Signed-off-by: Vincent DEHORS -Signed-off-by: Adrien GRASSEIN -Message-id: 20200116230809.19078-2-richard.henderson@linaro.org -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -Signed-off-by: zhanghailiang ---- - target/arm/pauth_helper.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c -index d3194f20..0a5f41e1 100644 ---- a/target/arm/pauth_helper.c -+++ b/target/arm/pauth_helper.c -@@ -89,7 +89,7 @@ static uint64_t pac_sub(uint64_t i) - uint64_t o = 0; - int b; - -- for (b = 0; b < 64; b += 16) { -+ for (b = 0; b < 64; b += 4) { - o |= (uint64_t)sub[(i >> b) & 0xf] << b; - } - return o; -@@ -104,7 +104,7 @@ static uint64_t pac_inv_sub(uint64_t i) - uint64_t o = 0; - int b; - -- for (b = 0; b < 64; b += 16) { -+ for (b = 0; b < 64; b += 4) { - o |= (uint64_t)inv_sub[(i >> b) & 0xf] << b; - } - return o; --- -2.23.0 - diff --git a/target-arm-Fix-some-compile-errors.patch b/target-arm-Fix-some-compile-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a0e1e9dda1b6552e33a9a5b93806e3c1d0d9305 --- /dev/null +++ b/target-arm-Fix-some-compile-errors.patch @@ -0,0 +1,89 @@ +From 6a5a391c9c6f6c0cd105ce3495acc10868bad884 Mon Sep 17 00:00:00 2001 +From: Dongxu Sun +Date: Tue, 15 Feb 2022 14:40:48 +0800 +Subject: [PATCH] target/arm: Fix some compile errors + +fix compile errors like: + "implicit declaration of function 'kvm_arm_cpu_feature_supported'"; + "undefined reference to 'kvm_arm_get_one_reg'" + "undefined reference to 'kvm_arm_set_one_reg'" + "'kvmval' may be used uninitialized" + "'oldval' may be used uninitialized" + +Signed-off-by: Dongxu Sun +--- + target/arm/helper.c | 4 ++-- + target/arm/kvm_arm.h | 23 ++++++++++++++++++++--- + 2 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 1dd5d64d96..80737a8d7b 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -168,8 +168,8 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) + if (kvm_sync) { + if (is_id_reg(ri)) { + /* Only sync if we can sync to KVM successfully. */ +- uint64_t oldval; +- uint64_t kvmval; ++ uint64_t oldval = 0; ++ uint64_t kvmval = 0; + + if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { + continue; +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 82145607ec..8b644b3924 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -377,6 +377,9 @@ void kvm_arm_pvtime_init(CPUState *cs, uint64_t ipa); + + int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); + ++int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *target); ++int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *source); ++ + #else + + /* +@@ -403,6 +406,11 @@ static inline bool kvm_arm_steal_time_supported(void) + return false; + } + ++static inline bool kvm_arm_cpu_feature_supported(void) ++{ ++ return false; ++} ++ + /* + * These functions should never actually be called without KVM support. + */ +@@ -451,6 +459,18 @@ static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) + g_assert_not_reached(); + } + ++static inline int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, ++ uint64_t *target) ++{ ++ g_assert_not_reached(); ++} ++ ++static inline int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, ++ uint64_t *source) ++{ ++ g_assert_not_reached(); ++} ++ + #endif + + static inline const char *gic_class_name(void) +@@ -535,7 +555,4 @@ static inline const char *its_class_name(void) + } + } + +-int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *target); +-int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *source); +- + #endif +-- +2.27.0 + diff --git a/target-arm-Fix-write-redundant-values-to-kvm.patch b/target-arm-Fix-write-redundant-values-to-kvm.patch index e165d04bafdd3fa3ceca0a1c0af68dfc0bb95df4..db03f8b6710f725610022f78d7b5c33a27ff3acc 100644 --- a/target-arm-Fix-write-redundant-values-to-kvm.patch +++ b/target-arm-Fix-write-redundant-values-to-kvm.patch @@ -1,4 +1,4 @@ -From 479c384f2944f52f9199bffa191b587a3f02663c Mon Sep 17 00:00:00 2001 +From 9680adfba5ca871f69a6fbd15b92571fc2a52d78 Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Wed, 9 Dec 2020 19:35:08 +0800 Subject: [PATCH] target/arm: Fix write redundant values to kvm @@ -10,15 +10,16 @@ for other registers. (cherry-picked from a0d7a9de807639fcfcbe1fe037cb8772d459a9cf) Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/helper.c | 73 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c -index b262f5d6c5..bddd355fa0 100644 +index 4c7b4cadfa..1dd5d64d96 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c -@@ -252,6 +252,16 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) +@@ -134,6 +134,16 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) return true; } @@ -35,7 +36,7 @@ index b262f5d6c5..bddd355fa0 100644 bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) { /* Write the coprocessor state from cpu->env to the (index,value) list. */ -@@ -268,38 +278,53 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) +@@ -150,38 +160,53 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) ok = false; continue; } diff --git a/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch b/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch deleted file mode 100644 index a46232f8ba04e1e2a956d8493dc1515fcf1f272a..0000000000000000000000000000000000000000 --- a/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 38fb634853ac6547326d9f88b9a068d9fc6b4ad4 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Tue, 27 Aug 2019 13:19:31 +0100 -Subject: [PATCH] target/arm: Free TCG temps in trans_VMOV_64_sp() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The function neon_store_reg32() doesn't free the TCG temp that it -is passed, so the caller must do that. We got this right in most -places but forgot to free the TCG temps in trans_VMOV_64_sp(). - -Cc: qemu-stable@nongnu.org -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 20190827121931.26836-1-peter.maydell@linaro.org -(cherry picked from commit 342d27581bd3ecdb995e4fc55fcd383cf3242888) -Signed-off-by: Michael Roth ---- - target/arm/translate-vfp.inc.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c -index 092eb5ec53..ef45cecbea 100644 ---- a/target/arm/translate-vfp.inc.c -+++ b/target/arm/translate-vfp.inc.c -@@ -881,8 +881,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a) - /* gpreg to fpreg */ - tmp = load_reg(s, a->rt); - neon_store_reg32(tmp, a->vm); -+ tcg_temp_free_i32(tmp); - tmp = load_reg(s, a->rt2); - neon_store_reg32(tmp, a->vm + 1); -+ tcg_temp_free_i32(tmp); - } - - return true; --- -2.23.0 diff --git a/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch b/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch deleted file mode 100644 index e7f2833ee889363902a3e063bffbbff4b4e2c6af..0000000000000000000000000000000000000000 --- a/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch +++ /dev/null @@ -1,158 +0,0 @@ -From df641941e6fd7fef78e5c77c9a809a7a8e148589 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:06 +0000 -Subject: [PATCH 08/13] target/arm: Move DBGDIDR into ARMISARegisters - -We're going to want to read the DBGDIDR register from KVM in -a subsequent commit, which means it needs to be in the -ARMISARegisters sub-struct. Move it. - -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Message-id: 20200214175116.9164-12-peter.maydell@linaro.org ---- - target/arm/cpu.c | 8 ++++---- - target/arm/cpu.h | 2 +- - target/arm/cpu64.c | 6 +++--- - target/arm/helper.c | 2 +- - target/arm/internals.h | 6 +++--- - 5 files changed, 12 insertions(+), 12 deletions(-) - -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index bb2edf4e..a23c71db 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -2070,7 +2070,7 @@ static void cortex_a8_initfn(Object *obj) - cpu->isar.id_isar2 = 0x21232031; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x00111142; -- cpu->dbgdidr = 0x15141000; -+ cpu->isar.dbgdidr = 0x15141000; - cpu->clidr = (1 << 27) | (2 << 24) | 3; - cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ -@@ -2143,7 +2143,7 @@ static void cortex_a9_initfn(Object *obj) - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x00111142; -- cpu->dbgdidr = 0x35141000; -+ cpu->isar.dbgdidr = 0x35141000; - cpu->clidr = (1 << 27) | (1 << 24) | 3; - cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ -@@ -2211,7 +2211,7 @@ static void cortex_a7_initfn(Object *obj) - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x10011142; -- cpu->dbgdidr = 0x3515f005; -+ cpu->isar.dbgdidr = 0x3515f005; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ -@@ -2254,7 +2254,7 @@ static void cortex_a15_initfn(Object *obj) - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x10011142; -- cpu->dbgdidr = 0x3515f021; -+ cpu->isar.dbgdidr = 0x3515f021; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 4b1ae32b..3040aa40 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -861,6 +861,7 @@ struct ARMCPU { - uint32_t mvfr1; - uint32_t mvfr2; - uint32_t id_dfr0; -+ uint32_t dbgdidr; - uint64_t id_aa64isar0; - uint64_t id_aa64isar1; - uint64_t id_aa64pfr0; -@@ -888,7 +889,6 @@ struct ARMCPU { - uint32_t id_mmfr4; - uint64_t id_aa64afr0; - uint64_t id_aa64afr1; -- uint32_t dbgdidr; - uint32_t clidr; - uint64_t mp_affinity; /* MP ID without feature bits */ - /* The elements of this array are the CCSIDR values for each cache, -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index aa96548f..7ad8b5e2 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -140,7 +140,7 @@ static void aarch64_a57_initfn(Object *obj) - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; -- cpu->dbgdidr = 0x3516d000; -+ cpu->isar.dbgdidr = 0x3516d000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ -@@ -194,7 +194,7 @@ static void aarch64_a53_initfn(Object *obj) - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ -- cpu->dbgdidr = 0x3516d000; -+ cpu->isar.dbgdidr = 0x3516d000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ -@@ -247,7 +247,7 @@ static void aarch64_a72_initfn(Object *obj) - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; -- cpu->dbgdidr = 0x3516d000; -+ cpu->isar.dbgdidr = 0x3516d000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ -diff --git a/target/arm/helper.c b/target/arm/helper.c -index c1ff4b6b..60ff7c0f 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -5597,7 +5597,7 @@ static void define_debug_regs(ARMCPU *cpu) - ARMCPRegInfo dbgdidr = { - .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL0_R, .accessfn = access_tda, -- .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr, -+ .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, - }; - - /* Note that all these register fields hold "number of Xs minus 1". */ -diff --git a/target/arm/internals.h b/target/arm/internals.h -index a72d0a6c..1d01ecc4 100644 ---- a/target/arm/internals.h -+++ b/target/arm/internals.h -@@ -867,7 +867,7 @@ static inline int arm_num_brps(ARMCPU *cpu) - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; - } else { -- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, BRPS) + 1; -+ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, BRPS) + 1; - } - } - -@@ -881,7 +881,7 @@ static inline int arm_num_wrps(ARMCPU *cpu) - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; - } else { -- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, WRPS) + 1; -+ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, WRPS) + 1; - } - } - -@@ -895,7 +895,7 @@ static inline int arm_num_ctx_cmps(ARMCPU *cpu) - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; - } else { -- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, CTX_CMPS) + 1; -+ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; - } - } - --- -2.25.1 - diff --git a/target-arm-Move-sve-probe-inside-kvm-4.15-branch.patch b/target-arm-Move-sve-probe-inside-kvm-4.15-branch.patch new file mode 100644 index 0000000000000000000000000000000000000000..3ee1d63cd2268f958971f09f45c1c361020aee09 --- /dev/null +++ b/target-arm-Move-sve-probe-inside-kvm-4.15-branch.patch @@ -0,0 +1,54 @@ +From d52674bfb6241316e436c8fe40dd5312950194dd Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 1 Aug 2022 16:21:18 +0100 +Subject: [PATCH 3/5] target/arm: Move sve probe inside kvm >= 4.15 branch + +The test for the IF block indicates no ID registers are exposed, much +less host support for SVE. Move the SVE probe into the ELSE block. + +Signed-off-by: Richard Henderson +Message-id: 20220726045828.53697-4-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Kunkun Jiang +--- + target/arm/kvm64.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 5b15d0582d..0f67b8ba96 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -654,18 +654,18 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + dbgdidr |= (1 << 15); /* RES1 bit */ + ahcf->isar.regs[DBGDIDR] = dbgdidr; + } +- } + +- if (sve_supported) { +- /* +- * There is a range of kernels between kernel commit 73433762fcae +- * and f81cb2c3ad41 which have a bug where the kernel doesn't expose +- * SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled +- * SVE support, which resulted in an error rather than RAZ. +- * So only read the register if we set KVM_ARM_VCPU_SVE above. +- */ +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ZFR0], +- ARM64_SYS_REG(3, 0, 0, 4, 4)); ++ if (sve_supported) { ++ /* ++ * There is a range of kernels between kernel commit 73433762fcae ++ * and f81cb2c3ad41 which have a bug where the kernel doesn't ++ * expose SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has ++ * enabled SVE support, which resulted in an error rather than RAZ. ++ * So only read the register if we set KVM_ARM_VCPU_SVE above. ++ */ ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ZFR0], ++ ARM64_SYS_REG(3, 0, 0, 4, 4)); ++ } + } + + kvm_arm_destroy_scratch_host_vcpu(fdarray); +-- +2.27.0 + diff --git a/target-arm-Read-debug-related-ID-registers-from-KVM.patch b/target-arm-Read-debug-related-ID-registers-from-KVM.patch deleted file mode 100644 index 1be7cd1713a456204efcb412c1d76398991ef77d..0000000000000000000000000000000000000000 --- a/target-arm-Read-debug-related-ID-registers-from-KVM.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 9cda8af5af9e95e7b0ff683d0fb661c1ffcba8d8 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:07 +0000 -Subject: [PATCH 11/13] target/arm: Read debug-related ID registers from KVM - -Now we have isar_feature test functions that look at fields in the -ID_AA64DFR0_EL1 and ID_DFR0 ID registers, add the code that reads -these register values from KVM so that the checks behave correctly -when we're using KVM. - -No isar_feature function tests ID_AA64DFR1_EL1 or DBGDIDR yet, but we -add it to maintain the invariant that every field in the -ARMISARegisters struct is populated for a KVM CPU and can be relied -on. This requirement isn't actually written down yet, so add a note -to the relevant comment. - -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Message-id: 20200214175116.9164-13-peter.maydell@linaro.org ---- - target/arm/cpu.h | 5 +++++ - target/arm/kvm32.c | 8 ++++++++ - target/arm/kvm64.c | 36 ++++++++++++++++++++++++++++++++++++ - 3 files changed, 49 insertions(+) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index a78c30c3..56d8cd8c 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -848,6 +848,11 @@ struct ARMCPU { - * prefix means a constant register. - * Some of these registers are split out into a substructure that - * is shared with the translators to control the ISA. -+ * -+ * Note that if you add an ID register to the ARMISARegisters struct -+ * you need to also update the 32-bit and 64-bit versions of the -+ * kvm_arm_get_host_cpu_features() function to correctly populate the -+ * field by reading the value from the KVM vCPU. - */ - struct ARMISARegisters { - uint32_t id_isar0; -diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c -index 2247148e..e984d52d 100644 ---- a/target/arm/kvm32.c -+++ b/target/arm/kvm32.c -@@ -93,6 +93,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - ahcf->isar.id_isar6 = 0; - } - -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, -+ ARM_CP15_REG32(0, 0, 1, 2)); -+ - err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, - KVM_REG_ARM | KVM_REG_SIZE_U32 | - KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR0); -@@ -121,6 +124,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - ahcf->isar.id_mmfr4 = 0; - } - -+ /* -+ * There is no way to read DBGDIDR, because currently 32-bit KVM -+ * doesn't implement debug at all. Leave it at zero. -+ */ -+ - kvm_arm_destroy_scratch_host_vcpu(fdarray); - - if (err < 0) { -diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index 276d1466..2a88b8df 100644 ---- a/target/arm/kvm64.c -+++ b/target/arm/kvm64.c -@@ -533,6 +533,10 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - } else { - err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, - ARM64_SYS_REG(3, 0, 0, 4, 1)); -+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, -+ ARM64_SYS_REG(3, 0, 0, 5, 0)); -+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, -+ ARM64_SYS_REG(3, 0, 0, 5, 1)); - err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, - ARM64_SYS_REG(3, 0, 0, 6, 0)); - err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, -@@ -551,6 +555,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - * than skipping the reads and leaving 0, as we must avoid - * considering the values in every case. - */ -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, -+ ARM64_SYS_REG(3, 0, 0, 1, 2)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, - ARM64_SYS_REG(3, 0, 0, 1, 4)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, -@@ -582,6 +588,36 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - ARM64_SYS_REG(3, 0, 0, 3, 1)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, - ARM64_SYS_REG(3, 0, 0, 3, 2)); -+ -+ /* -+ * DBGDIDR is a bit complicated because the kernel doesn't -+ * provide an accessor for it in 64-bit mode, which is what this -+ * scratch VM is in, and there's no architected "64-bit sysreg -+ * which reads the same as the 32-bit register" the way there is -+ * for other ID registers. Instead we synthesize a value from the -+ * AArch64 ID_AA64DFR0, the same way the kernel code in -+ * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does. -+ * We only do this if the CPU supports AArch32 at EL1. -+ */ -+ if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) { -+ int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); -+ int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); -+ int ctx_cmps = -+ FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); -+ int version = 6; /* ARMv8 debug architecture */ -+ bool has_el3 = -+ !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3); -+ uint32_t dbgdidr = 0; -+ -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, BRPS, brps); -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, CTX_CMPS, ctx_cmps); -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, VERSION, version); -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3); -+ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3); -+ dbgdidr |= (1 << 15); /* RES1 bit */ -+ ahcf->isar.dbgdidr = dbgdidr; -+ } - } - - kvm_arm_destroy_scratch_host_vcpu(fdarray); --- -2.25.1 - diff --git a/target-arm-Set-KVM_ARM_VCPU_SVE-while-probing-the-ho.patch b/target-arm-Set-KVM_ARM_VCPU_SVE-while-probing-the-ho.patch new file mode 100644 index 0000000000000000000000000000000000000000..e00097e947a4a8e6aba91a545ef0a527c5f65535 --- /dev/null +++ b/target-arm-Set-KVM_ARM_VCPU_SVE-while-probing-the-ho.patch @@ -0,0 +1,79 @@ +From c9b226f4a56bb13d4f0924ea3ce4b334e65e6db2 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 1 Aug 2022 16:21:18 +0100 +Subject: [PATCH 2/5] target/arm: Set KVM_ARM_VCPU_SVE while probing the host + +Because we weren't setting this flag, our probe of ID_AA64ZFR0 +was always returning zero. This also obviates the adjustment +of ID_AA64PFR0, which had sanitized the SVE field. + +The effects of the bug are not visible, because the only thing that +ID_AA64ZFR0 is used for within qemu at present is tcg translation. +The other tests for SVE within KVM are via ID_AA64PFR0.SVE. + +Reported-by: Zenghui Yu +Signed-off-by: Richard Henderson +Message-id: 20220726045828.53697-3-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Kunkun Jiang +--- + target/arm/kvm64.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index b7e34a4580..5b15d0582d 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -501,7 +501,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + int fdarray[3]; + bool sve_supported; + uint64_t features = 0; +- uint64_t t; + int err; + + /* Old kernels may not know about the PREFERRED_TARGET ioctl: however +@@ -521,6 +520,15 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + */ + struct kvm_vcpu_init init = { .target = -1, }; + ++ /* ++ * Ask for SVE if supported, so that we can query ID_AA64ZFR0, ++ * which is otherwise RAZ. ++ */ ++ sve_supported = kvm_arm_sve_supported(); ++ if (sve_supported) { ++ init.features[0] |= 1 << KVM_ARM_VCPU_SVE; ++ } ++ + if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) { + return false; + } +@@ -648,19 +656,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + } + } + +- sve_supported = kvm_arm_sve_supported(); +- +- /* Add feature bits that can't appear until after VCPU init. */ + if (sve_supported) { +- t = ahcf->isar.regs[ID_AA64PFR0]; +- t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); +- ahcf->isar.regs[ID_AA64PFR0] = t; +- + /* +- * Before v5.1, KVM did not support SVE and did not expose +- * ID_AA64ZFR0_EL1 even as RAZ. After v5.1, KVM still does +- * not expose the register to "user" requests like this +- * unless the host supports SVE. ++ * There is a range of kernels between kernel commit 73433762fcae ++ * and f81cb2c3ad41 which have a bug where the kernel doesn't expose ++ * SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled ++ * SVE support, which resulted in an error rather than RAZ. ++ * So only read the register if we set KVM_ARM_VCPU_SVE above. + */ + err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ZFR0], + ARM64_SYS_REG(3, 0, 0, 4, 4)); +-- +2.27.0 + diff --git a/target-arm-Stop-assuming-DBGDIDR-always-exists.patch b/target-arm-Stop-assuming-DBGDIDR-always-exists.patch deleted file mode 100644 index c7648c5430ebd61b2267a184ad16828dd8d25015..0000000000000000000000000000000000000000 --- a/target-arm-Stop-assuming-DBGDIDR-always-exists.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 1d4d4cda9637ec09f8cf30785f68b58cd46815c8 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:05 +0000 -Subject: [PATCH 07/13] target/arm: Stop assuming DBGDIDR always exists - -The AArch32 DBGDIDR defines properties like the number of -breakpoints, watchpoints and context-matching comparators. On an -AArch64 CPU, the register may not even exist if AArch32 is not -supported at EL1. - -Currently we hard-code use of DBGDIDR to identify the number of -breakpoints etc; this works for all our TCG CPUs, but will break if -we ever add an AArch64-only CPU. We also have an assert() that the -AArch32 and AArch64 registers match, which currently works only by -luck for KVM because we don't populate either of these ID registers -from the KVM vCPU and so they are both zero. - -Clean this up so we have functions for finding the number -of breakpoints, watchpoints and context comparators which look -in the appropriate ID register. - -This allows us to drop the "check that AArch64 and AArch32 agree -on the number of breakpoints etc" asserts: - * we no longer look at the AArch32 versions unless that's the - right place to be looking - * it's valid to have a CPU (eg AArch64-only) where they don't match - * we shouldn't have been asserting the validity of ID registers - in a codepath used with KVM anyway - -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Message-id: 20200214175116.9164-11-peter.maydell@linaro.org ---- - target/arm/cpu.h | 7 +++++++ - target/arm/debug_helper.c | 6 +++--- - target/arm/helper.c | 21 +++++--------------- - target/arm/internals.h | 42 +++++++++++++++++++++++++++++++++++++++ - 4 files changed, 57 insertions(+), 19 deletions(-) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 230130be..4b1ae32b 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -1798,6 +1798,13 @@ FIELD(ID_DFR0, MPROFDBG, 20, 4) - FIELD(ID_DFR0, PERFMON, 24, 4) - FIELD(ID_DFR0, TRACEFILT, 28, 4) - -+FIELD(DBGDIDR, SE_IMP, 12, 1) -+FIELD(DBGDIDR, NSUHD_IMP, 14, 1) -+FIELD(DBGDIDR, VERSION, 16, 4) -+FIELD(DBGDIDR, CTX_CMPS, 20, 4) -+FIELD(DBGDIDR, BRPS, 24, 4) -+FIELD(DBGDIDR, WRPS, 28, 4) -+ - FIELD(MVFR0, SIMDREG, 0, 4) - FIELD(MVFR0, FPSP, 4, 4) - FIELD(MVFR0, FPDP, 8, 4) -diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c -index dde80273..3f8f667d 100644 ---- a/target/arm/debug_helper.c -+++ b/target/arm/debug_helper.c -@@ -16,8 +16,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) - { - CPUARMState *env = &cpu->env; - uint64_t bcr = env->cp15.dbgbcr[lbn]; -- int brps = extract32(cpu->dbgdidr, 24, 4); -- int ctx_cmps = extract32(cpu->dbgdidr, 20, 4); -+ int brps = arm_num_brps(cpu); -+ int ctx_cmps = arm_num_ctx_cmps(cpu); - int bt; - uint32_t contextidr; - -@@ -28,7 +28,7 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) - * case DBGWCR_EL1.LBN must indicate that breakpoint). - * We choose the former. - */ -- if (lbn > brps || lbn < (brps - ctx_cmps)) { -+ if (lbn >= brps || lbn < (brps - ctx_cmps)) { - return false; - } - -diff --git a/target/arm/helper.c b/target/arm/helper.c -index a71f4ef6..c1ff4b6b 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -5601,23 +5601,12 @@ static void define_debug_regs(ARMCPU *cpu) - }; - - /* Note that all these register fields hold "number of Xs minus 1". */ -- brps = extract32(cpu->dbgdidr, 24, 4); -- wrps = extract32(cpu->dbgdidr, 28, 4); -- ctx_cmps = extract32(cpu->dbgdidr, 20, 4); -+ brps = arm_num_brps(cpu); -+ wrps = arm_num_wrps(cpu); -+ ctx_cmps = arm_num_ctx_cmps(cpu); - - assert(ctx_cmps <= brps); - -- /* The DBGDIDR and ID_AA64DFR0_EL1 define various properties -- * of the debug registers such as number of breakpoints; -- * check that if they both exist then they agree. -- */ -- if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); -- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); -- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) -- == ctx_cmps); -- } -- - define_one_arm_cp_reg(cpu, &dbgdidr); - define_arm_cp_regs(cpu, debug_cp_reginfo); - -@@ -5625,7 +5614,7 @@ static void define_debug_regs(ARMCPU *cpu) - define_arm_cp_regs(cpu, debug_lpae_cp_reginfo); - } - -- for (i = 0; i < brps + 1; i++) { -+ for (i = 0; i < brps; i++) { - ARMCPRegInfo dbgregs[] = { - { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, -@@ -5644,7 +5633,7 @@ static void define_debug_regs(ARMCPU *cpu) - define_arm_cp_regs(cpu, dbgregs); - } - -- for (i = 0; i < wrps + 1; i++) { -+ for (i = 0; i < wrps; i++) { - ARMCPRegInfo dbgregs[] = { - { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, -diff --git a/target/arm/internals.h b/target/arm/internals.h -index 232d9638..a72d0a6c 100644 ---- a/target/arm/internals.h -+++ b/target/arm/internals.h -@@ -857,6 +857,48 @@ static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) - } - } - -+/** -+ * arm_num_brps: Return number of implemented breakpoints. -+ * Note that the ID register BRPS field is "number of bps - 1", -+ * and we return the actual number of breakpoints. -+ */ -+static inline int arm_num_brps(ARMCPU *cpu) -+{ -+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -+ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; -+ } else { -+ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, BRPS) + 1; -+ } -+} -+ -+/** -+ * arm_num_wrps: Return number of implemented watchpoints. -+ * Note that the ID register WRPS field is "number of wps - 1", -+ * and we return the actual number of watchpoints. -+ */ -+static inline int arm_num_wrps(ARMCPU *cpu) -+{ -+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -+ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; -+ } else { -+ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, WRPS) + 1; -+ } -+} -+ -+/** -+ * arm_num_ctx_cmps: Return number of implemented context comparators. -+ * Note that the ID register CTX_CMPS field is "number of cmps - 1", -+ * and we return the actual number of comparators. -+ */ -+static inline int arm_num_ctx_cmps(ARMCPU *cpu) -+{ -+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { -+ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; -+ } else { -+ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, CTX_CMPS) + 1; -+ } -+} -+ - /* Note make_memop_idx reserves 4 bits for mmu_idx, and MO_BSWAP is bit 3. - * Thus a TCGMemOpIdx, without any MO_ALIGN bits, fits in 8 bits. - */ --- -2.25.1 - diff --git a/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch b/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch deleted file mode 100644 index ecbaf7750c42aab1efade6d50e53fd7e92762883..0000000000000000000000000000000000000000 --- a/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch +++ /dev/null @@ -1,453 +0,0 @@ -From 2bc630dc858bd0c010b7c375ebf1e8f4b4e0e346 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:13 +0000 -Subject: [PATCH 10/13] target/arm: Test correct register in aa32_pan and - aa32_ats1e1 checks - -The isar_feature_aa32_pan and isar_feature_aa32_ats1e1 functions -are supposed to be testing fields in ID_MMFR3; but a cut-and-paste -error meant we were looking at MVFR0 instead. - -Fix the functions to look at the right register; this requires -us to move at least id_mmfr3 to the ARMISARegisters struct; we -choose to move all the ID_MMFRn registers for consistency. - -Fixes: 3d6ad6bb466f -Signed-off-by: Peter Maydell -Reviewed-by: Richard Henderson -Message-id: 20200214175116.9164-19-peter.maydell@linaro.org ---- - hw/intc/armv7m_nvic.c | 8 ++-- - target/arm/cpu.c | 96 +++++++++++++++++++++---------------------- - target/arm/cpu.h | 14 +++---- - target/arm/cpu64.c | 28 ++++++------- - target/arm/helper.c | 12 +++--- - target/arm/kvm32.c | 17 ++++++++ - target/arm/kvm64.c | 10 +++++ - 7 files changed, 106 insertions(+), 79 deletions(-) - -diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c -index 0741db7b..f7ef6ad1 100644 ---- a/hw/intc/armv7m_nvic.c -+++ b/hw/intc/armv7m_nvic.c -@@ -1227,13 +1227,13 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) - case 0xd4c: /* AFR0. */ - return cpu->id_afr0; - case 0xd50: /* MMFR0. */ -- return cpu->id_mmfr0; -+ return cpu->isar.id_mmfr0; - case 0xd54: /* MMFR1. */ -- return cpu->id_mmfr1; -+ return cpu->isar.id_mmfr1; - case 0xd58: /* MMFR2. */ -- return cpu->id_mmfr2; -+ return cpu->isar.id_mmfr2; - case 0xd5c: /* MMFR3. */ -- return cpu->id_mmfr3; -+ return cpu->isar.id_mmfr3; - case 0xd60: /* ISAR0. */ - return cpu->isar.id_isar0; - case 0xd64: /* ISAR1. */ -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 119bd275..c3728e3d 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -1764,9 +1764,9 @@ static void arm1136_r2_initfn(Object *obj) - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; -- cpu->id_mmfr0 = 0x01130003; -- cpu->id_mmfr1 = 0x10030302; -- cpu->id_mmfr2 = 0x01222110; -+ cpu->isar.id_mmfr0 = 0x01130003; -+ cpu->isar.id_mmfr1 = 0x10030302; -+ cpu->isar.id_mmfr2 = 0x01222110; - cpu->isar.id_isar0 = 0x00140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231111; -@@ -1796,9 +1796,9 @@ static void arm1136_initfn(Object *obj) - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; -- cpu->id_mmfr0 = 0x01130003; -- cpu->id_mmfr1 = 0x10030302; -- cpu->id_mmfr2 = 0x01222110; -+ cpu->isar.id_mmfr0 = 0x01130003; -+ cpu->isar.id_mmfr1 = 0x10030302; -+ cpu->isar.id_mmfr2 = 0x01222110; - cpu->isar.id_isar0 = 0x00140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231111; -@@ -1829,9 +1829,9 @@ static void arm1176_initfn(Object *obj) - cpu->id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x33; - cpu->id_afr0 = 0; -- cpu->id_mmfr0 = 0x01130003; -- cpu->id_mmfr1 = 0x10030302; -- cpu->id_mmfr2 = 0x01222100; -+ cpu->isar.id_mmfr0 = 0x01130003; -+ cpu->isar.id_mmfr1 = 0x10030302; -+ cpu->isar.id_mmfr2 = 0x01222100; - cpu->isar.id_isar0 = 0x0140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231121; -@@ -1859,9 +1859,9 @@ static void arm11mpcore_initfn(Object *obj) - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0; - cpu->id_afr0 = 0x2; -- cpu->id_mmfr0 = 0x01100103; -- cpu->id_mmfr1 = 0x10020302; -- cpu->id_mmfr2 = 0x01222000; -+ cpu->isar.id_mmfr0 = 0x01100103; -+ cpu->isar.id_mmfr1 = 0x10020302; -+ cpu->isar.id_mmfr2 = 0x01222000; - cpu->isar.id_isar0 = 0x00100011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11221011; -@@ -1891,10 +1891,10 @@ static void cortex_m3_initfn(Object *obj) - cpu->id_pfr1 = 0x00000200; - cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x00000030; -- cpu->id_mmfr1 = 0x00000000; -- cpu->id_mmfr2 = 0x00000000; -- cpu->id_mmfr3 = 0x00000000; -+ cpu->isar.id_mmfr0 = 0x00000030; -+ cpu->isar.id_mmfr1 = 0x00000000; -+ cpu->isar.id_mmfr2 = 0x00000000; -+ cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01141110; - cpu->isar.id_isar1 = 0x02111000; - cpu->isar.id_isar2 = 0x21112231; -@@ -1922,10 +1922,10 @@ static void cortex_m4_initfn(Object *obj) - cpu->id_pfr1 = 0x00000200; - cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x00000030; -- cpu->id_mmfr1 = 0x00000000; -- cpu->id_mmfr2 = 0x00000000; -- cpu->id_mmfr3 = 0x00000000; -+ cpu->isar.id_mmfr0 = 0x00000030; -+ cpu->isar.id_mmfr1 = 0x00000000; -+ cpu->isar.id_mmfr2 = 0x00000000; -+ cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01141110; - cpu->isar.id_isar1 = 0x02111000; - cpu->isar.id_isar2 = 0x21112231; -@@ -1955,10 +1955,10 @@ static void cortex_m33_initfn(Object *obj) - cpu->id_pfr1 = 0x00000210; - cpu->isar.id_dfr0 = 0x00200000; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x00101F40; -- cpu->id_mmfr1 = 0x00000000; -- cpu->id_mmfr2 = 0x01000000; -- cpu->id_mmfr3 = 0x00000000; -+ cpu->isar.id_mmfr0 = 0x00101F40; -+ cpu->isar.id_mmfr1 = 0x00000000; -+ cpu->isar.id_mmfr2 = 0x01000000; -+ cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01101110; - cpu->isar.id_isar1 = 0x02212000; - cpu->isar.id_isar2 = 0x20232232; -@@ -2006,10 +2006,10 @@ static void cortex_r5_initfn(Object *obj) - cpu->id_pfr1 = 0x001; - cpu->isar.id_dfr0 = 0x010400; - cpu->id_afr0 = 0x0; -- cpu->id_mmfr0 = 0x0210030; -- cpu->id_mmfr1 = 0x00000000; -- cpu->id_mmfr2 = 0x01200000; -- cpu->id_mmfr3 = 0x0211; -+ cpu->isar.id_mmfr0 = 0x0210030; -+ cpu->isar.id_mmfr1 = 0x00000000; -+ cpu->isar.id_mmfr2 = 0x01200000; -+ cpu->isar.id_mmfr3 = 0x0211; - cpu->isar.id_isar0 = 0x02101111; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232141; -@@ -2061,10 +2061,10 @@ static void cortex_a8_initfn(Object *obj) - cpu->id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x400; - cpu->id_afr0 = 0; -- cpu->id_mmfr0 = 0x31100003; -- cpu->id_mmfr1 = 0x20000000; -- cpu->id_mmfr2 = 0x01202000; -- cpu->id_mmfr3 = 0x11; -+ cpu->isar.id_mmfr0 = 0x31100003; -+ cpu->isar.id_mmfr1 = 0x20000000; -+ cpu->isar.id_mmfr2 = 0x01202000; -+ cpu->isar.id_mmfr3 = 0x11; - cpu->isar.id_isar0 = 0x00101111; - cpu->isar.id_isar1 = 0x12112111; - cpu->isar.id_isar2 = 0x21232031; -@@ -2134,10 +2134,10 @@ static void cortex_a9_initfn(Object *obj) - cpu->id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x000; - cpu->id_afr0 = 0; -- cpu->id_mmfr0 = 0x00100103; -- cpu->id_mmfr1 = 0x20000000; -- cpu->id_mmfr2 = 0x01230000; -- cpu->id_mmfr3 = 0x00002111; -+ cpu->isar.id_mmfr0 = 0x00100103; -+ cpu->isar.id_mmfr1 = 0x20000000; -+ cpu->isar.id_mmfr2 = 0x01230000; -+ cpu->isar.id_mmfr3 = 0x00002111; - cpu->isar.id_isar0 = 0x00101111; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232041; -@@ -2199,10 +2199,10 @@ static void cortex_a7_initfn(Object *obj) - cpu->id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x10101105; -- cpu->id_mmfr1 = 0x40000000; -- cpu->id_mmfr2 = 0x01240000; -- cpu->id_mmfr3 = 0x02102211; -+ cpu->isar.id_mmfr0 = 0x10101105; -+ cpu->isar.id_mmfr1 = 0x40000000; -+ cpu->isar.id_mmfr2 = 0x01240000; -+ cpu->isar.id_mmfr3 = 0x02102211; - /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but - * table 4-41 gives 0x02101110, which includes the arm div insns. - */ -@@ -2245,10 +2245,10 @@ static void cortex_a15_initfn(Object *obj) - cpu->id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x10201105; -- cpu->id_mmfr1 = 0x20000000; -- cpu->id_mmfr2 = 0x01240000; -- cpu->id_mmfr3 = 0x02102211; -+ cpu->isar.id_mmfr0 = 0x10201105; -+ cpu->isar.id_mmfr1 = 0x20000000; -+ cpu->isar.id_mmfr2 = 0x01240000; -+ cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232041; -@@ -2484,13 +2484,13 @@ static void arm_max_initfn(Object *obj) - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - -- t = cpu->id_mmfr3; -+ t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ -- cpu->id_mmfr3 = t; -+ cpu->isar.id_mmfr3 = t; - -- t = cpu->id_mmfr4; -+ t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ -- cpu->id_mmfr4 = t; -+ cpu->isar.id_mmfr4 = t; - } - #endif - } -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 3040aa40..a78c30c3 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -857,6 +857,11 @@ struct ARMCPU { - uint32_t id_isar4; - uint32_t id_isar5; - uint32_t id_isar6; -+ uint32_t id_mmfr0; -+ uint32_t id_mmfr1; -+ uint32_t id_mmfr2; -+ uint32_t id_mmfr3; -+ uint32_t id_mmfr4; - uint32_t mvfr0; - uint32_t mvfr1; - uint32_t mvfr2; -@@ -882,11 +887,6 @@ struct ARMCPU { - uint64_t pmceid0; - uint64_t pmceid1; - uint32_t id_afr0; -- uint32_t id_mmfr0; -- uint32_t id_mmfr1; -- uint32_t id_mmfr2; -- uint32_t id_mmfr3; -- uint32_t id_mmfr4; - uint64_t id_aa64afr0; - uint64_t id_aa64afr1; - uint32_t clidr; -@@ -3490,12 +3490,12 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) - - static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) - { -- return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) != 0; -+ return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; - } - - static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) - { -- return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; -+ return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; - } - - static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index a0d07fd7..d450b8c8 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -125,10 +125,10 @@ static void aarch64_a57_initfn(Object *obj) - cpu->id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x10101105; -- cpu->id_mmfr1 = 0x40000000; -- cpu->id_mmfr2 = 0x01260000; -- cpu->id_mmfr3 = 0x02102211; -+ cpu->isar.id_mmfr0 = 0x10101105; -+ cpu->isar.id_mmfr1 = 0x40000000; -+ cpu->isar.id_mmfr2 = 0x01260000; -+ cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; -@@ -179,10 +179,10 @@ static void aarch64_a53_initfn(Object *obj) - cpu->id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x10101105; -- cpu->id_mmfr1 = 0x40000000; -- cpu->id_mmfr2 = 0x01260000; -- cpu->id_mmfr3 = 0x02102211; -+ cpu->isar.id_mmfr0 = 0x10101105; -+ cpu->isar.id_mmfr1 = 0x40000000; -+ cpu->isar.id_mmfr2 = 0x01260000; -+ cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; -@@ -233,10 +233,10 @@ static void aarch64_a72_initfn(Object *obj) - cpu->id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; -- cpu->id_mmfr0 = 0x10201105; -- cpu->id_mmfr1 = 0x40000000; -- cpu->id_mmfr2 = 0x01260000; -- cpu->id_mmfr3 = 0x02102211; -+ cpu->isar.id_mmfr0 = 0x10201105; -+ cpu->isar.id_mmfr1 = 0x40000000; -+ cpu->isar.id_mmfr2 = 0x01260000; -+ cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; -@@ -383,9 +383,9 @@ static void aarch64_max_initfn(Object *obj) - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - cpu->isar.id_isar6 = u; - -- u = cpu->id_mmfr3; -+ u = cpu->isar.id_mmfr3; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ -- cpu->id_mmfr3 = u; -+ cpu->isar.id_mmfr3 = u; - - /* - * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, -diff --git a/target/arm/helper.c b/target/arm/helper.c -index 60ff7c0f..49cd7a7e 100644 ---- a/target/arm/helper.c -+++ b/target/arm/helper.c -@@ -5906,19 +5906,19 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_MMFR0", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_mmfr0 }, -+ .resetvalue = cpu->isar.id_mmfr0 }, - { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_mmfr1 }, -+ .resetvalue = cpu->isar.id_mmfr1 }, - { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_mmfr2 }, -+ .resetvalue = cpu->isar.id_mmfr2 }, - { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_mmfr3 }, -+ .resetvalue = cpu->isar.id_mmfr3 }, - { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, - .access = PL1_R, .type = ARM_CP_CONST, -@@ -5946,7 +5946,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, - .access = PL1_R, .type = ARM_CP_CONST, -- .resetvalue = cpu->id_mmfr4 }, -+ .resetvalue = cpu->isar.id_mmfr4 }, - { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, - .access = PL1_R, .type = ARM_CP_CONST, -@@ -6426,7 +6426,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); - define_arm_cp_regs(cpu, vmsa_cp_reginfo); - /* TTCBR2 is introduced with ARMv8.2-A32HPD. */ -- if (FIELD_EX32(cpu->id_mmfr4, ID_MMFR4, HPDS) != 0) { -+ if (FIELD_EX32(cpu->isar.id_mmfr4, ID_MMFR4, HPDS) != 0) { - define_one_arm_cp_reg(cpu, &ttbcr2_reginfo); - } - } -diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c -index ee158830..2247148e 100644 ---- a/target/arm/kvm32.c -+++ b/target/arm/kvm32.c -@@ -104,6 +104,23 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - * Fortunately there is not yet anything in there that affects migration. - */ - -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, -+ ARM_CP15_REG32(0, 0, 1, 4)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, -+ ARM_CP15_REG32(0, 0, 1, 5)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, -+ ARM_CP15_REG32(0, 0, 1, 6)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, -+ ARM_CP15_REG32(0, 0, 1, 7)); -+ if (read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, -+ ARM_CP15_REG32(0, 0, 2, 6))) { -+ /* -+ * Older kernels don't support reading ID_MMFR4 (a new in v8 -+ * register); assume it's zero. -+ */ -+ ahcf->isar.id_mmfr4 = 0; -+ } -+ - kvm_arm_destroy_scratch_host_vcpu(fdarray); - - if (err < 0) { -diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index b794108a..276d1466 100644 ---- a/target/arm/kvm64.c -+++ b/target/arm/kvm64.c -@@ -551,6 +551,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - * than skipping the reads and leaving 0, as we must avoid - * considering the values in every case. - */ -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, -+ ARM64_SYS_REG(3, 0, 0, 1, 4)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, -+ ARM64_SYS_REG(3, 0, 0, 1, 5)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, -+ ARM64_SYS_REG(3, 0, 0, 1, 6)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, -+ ARM64_SYS_REG(3, 0, 0, 1, 7)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, - ARM64_SYS_REG(3, 0, 0, 2, 0)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, -@@ -563,6 +571,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - ARM64_SYS_REG(3, 0, 0, 2, 4)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, - ARM64_SYS_REG(3, 0, 0, 2, 5)); -+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, -+ ARM64_SYS_REG(3, 0, 0, 2, 6)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, - ARM64_SYS_REG(3, 0, 0, 2, 7)); - --- -2.25.1 - diff --git a/target-arm-Update-ID-fields.patch b/target-arm-Update-ID-fields.patch deleted file mode 100644 index 94ed8027c9e238f384e767bc88c209749eee234e..0000000000000000000000000000000000000000 --- a/target-arm-Update-ID-fields.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 47c76d73a435884b66ce6417cb853893099be5eb Mon Sep 17 00:00:00 2001 -From: Peng Liang -Date: Tue, 11 Aug 2020 10:18:57 +0800 -Subject: [PATCH 8/9] target/arm: Update ID fields - -Update definitions for ID fields, up to ARMv8.6. - -Signed-off-by: zhanghailiang -Signed-off-by: Peng Liang ---- - target/arm/cpu.h | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 068c3fa2..eb875e11 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -1691,6 +1691,8 @@ FIELD(ID_ISAR6, DP, 4, 4) - FIELD(ID_ISAR6, FHM, 8, 4) - FIELD(ID_ISAR6, SB, 12, 4) - FIELD(ID_ISAR6, SPECRES, 16, 4) -+FIELD(ID_ISAR6, BF16, 20, 4) -+FIELD(ID_ISAR6, I8MM, 24, 4) - - FIELD(ID_MMFR3, CMAINTVA, 0, 4) - FIELD(ID_MMFR3, CMAINTSW, 4, 4) -@@ -1736,6 +1738,9 @@ FIELD(ID_AA64ISAR1, GPI, 28, 4) - FIELD(ID_AA64ISAR1, FRINTTS, 32, 4) - FIELD(ID_AA64ISAR1, SB, 36, 4) - FIELD(ID_AA64ISAR1, SPECRES, 40, 4) -+FIELD(ID_AA64ISAR1, BF16, 44, 4) -+FIELD(ID_AA64ISAR1, DGH, 48, 4) -+FIELD(ID_AA64ISAR1, I8MM, 52, 4) - - FIELD(ID_AA64PFR0, EL0, 0, 4) - FIELD(ID_AA64PFR0, EL1, 4, 4) -@@ -1746,11 +1751,18 @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4) - FIELD(ID_AA64PFR0, GIC, 24, 4) - FIELD(ID_AA64PFR0, RAS, 28, 4) - FIELD(ID_AA64PFR0, SVE, 32, 4) -+FIELD(ID_AA64PFR0, SEL2, 36, 4) -+FIELD(ID_AA64PFR0, MPAM, 40, 4) -+FIELD(ID_AA64PFR0, AMU, 44, 4) -+FIELD(ID_AA64PFR0, DIT, 44, 4) -+FIELD(ID_AA64PFR0, CSV2, 56, 4) -+FIELD(ID_AA64PFR0, CSV3, 60, 4) - - FIELD(ID_AA64PFR1, BT, 0, 4) - FIELD(ID_AA64PFR1, SBSS, 4, 4) - FIELD(ID_AA64PFR1, MTE, 8, 4) - FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4) -+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4) - - FIELD(ID_AA64MMFR0, PARANGE, 0, 4) - FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4) -@@ -1764,6 +1776,8 @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4) - FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4) - FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4) - FIELD(ID_AA64MMFR0, EXS, 44, 4) -+FIELD(ID_AA64MMFR0, FGT, 56, 4) -+FIELD(ID_AA64MMFR0, ECV, 60, 4) - - FIELD(ID_AA64MMFR1, HAFDBS, 0, 4) - FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4) -@@ -1773,6 +1787,8 @@ FIELD(ID_AA64MMFR1, LO, 16, 4) - FIELD(ID_AA64MMFR1, PAN, 20, 4) - FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) - FIELD(ID_AA64MMFR1, XNX, 28, 4) -+FIELD(ID_AA64MMFR1, TWED, 32, 4) -+FIELD(ID_AA64MMFR1, ETS, 36, 4) - - FIELD(ID_AA64MMFR2, CNP, 0, 4) - FIELD(ID_AA64MMFR2, UAO, 4, 4) -@@ -1799,6 +1815,7 @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) - FIELD(ID_AA64DFR0, PMSVER, 32, 4) - FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) - FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) -+FIELD(ID_AA64DFR0, MUPMU, 48, 4) - - FIELD(ID_DFR0, COPDBG, 0, 4) - FIELD(ID_DFR0, COPSDBG, 4, 4) --- -2.25.1 - diff --git a/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch b/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch index 586dcbb1998a3e0e910feec54d326f577154711e..b632a31c8a51205849560417d40db9ce0a8c5c39 100644 --- a/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch +++ b/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch @@ -1,4 +1,4 @@ -From b54ca94f19a9b22537712638ae05d2095258eb80 Mon Sep 17 00:00:00 2001 +From e2cb8b57278357c0a42cf7722b8c28b6f8d7585c Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Sat, 19 Sep 2020 09:04:45 +0800 Subject: [PATCH] target/arm: Update the ID registers of Kunpeng-920 @@ -8,15 +8,16 @@ Let's update them. The values are read from Kunpeng-920 by calling read_sysreg_s. Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu64.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 726d123d8e..a1649f8844 100644 +index 287e7ac91c..3ec788fc29 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -275,10 +275,33 @@ static void aarch64_kunpeng_920_initfn(Object *obj) +@@ -262,10 +262,33 @@ static void aarch64_kunpeng_920_initfn(Object *obj) cpu->midr = 0x480fd010; cpu->ctr = 0x84448004; @@ -39,8 +40,8 @@ index 726d123d8e..a1649f8844 100644 + cpu->isar.regs[MVFR2] = 0; + cpu->isar.regs[MVFR2] = 0; + cpu->isar.regs[MVFR2] = 0; -+ cpu->id_pfr0 = 0; -+ cpu->id_pfr1 = 0; ++ cpu->isar.regs[ID_PFR0] = 0; ++ cpu->isar.regs[ID_PFR1] = 0; + cpu->isar.regs[ID_AA64PFR0] = 0x0000010011111111; cpu->isar.regs[ID_AA64DFR0] = 0x110305408; - cpu->isar.regs[ID_AA64ISAR0] = 0x10211120; @@ -51,7 +52,7 @@ index 726d123d8e..a1649f8844 100644 + cpu->isar.regs[ID_AA64MMFR2] = 0x00001011; } - static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) -- -2.23.0 +2.27.0 diff --git a/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch b/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch deleted file mode 100644 index 0e32f85104cb492dba2d0e72aa6138342ef960db..0000000000000000000000000000000000000000 --- a/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f54cdca97bf86f5ca1df8471bc229b89797b287e Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 14 Feb 2020 17:51:02 +0000 -Subject: [PATCH 04/13] target/arm: Use FIELD macros for clearing ID_DFR0 - PERFMON field -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We already define FIELD macros for ID_DFR0, so use them in the -one place where we're doing direct bit value manipulation. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Richard Henderson -Signed-off-by: Peter Maydell -Message-id: 20200214175116.9164-8-peter.maydell@linaro.org ---- - target/arm/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index dbd05e01..6ad211b1 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -1523,7 +1523,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - #endif - } else { - cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); -- cpu->id_dfr0 &= ~(0xf << 24); -+ cpu->id_dfr0 = FIELD_DP32(cpu->id_dfr0, ID_DFR0, PERFMON, 0); - cpu->pmceid0 = 0; - cpu->pmceid1 = 0; - } --- -2.25.1 - diff --git a/target-arm-Use-kvm_arm_sve_supported-in-kvm_arm_get_.patch b/target-arm-Use-kvm_arm_sve_supported-in-kvm_arm_get_.patch new file mode 100644 index 0000000000000000000000000000000000000000..9c5a9a3273233deef37fd3679a3ab578671a9686 --- /dev/null +++ b/target-arm-Use-kvm_arm_sve_supported-in-kvm_arm_get_.patch @@ -0,0 +1,34 @@ +From 110206cee2cf58b6ce4119e230b142192f7b52ac Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 1 Aug 2022 16:21:17 +0100 +Subject: [PATCH 1/5] target/arm: Use kvm_arm_sve_supported in + kvm_arm_get_host_cpu_features + +Indication for support for SVE will not depend on whether we +perform the query on the main kvm_state or the temp vcpu. + +Signed-off-by: Richard Henderson +Message-id: 20220726045828.53697-2-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Kunkun Jiang +--- + target/arm/kvm64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index b34a87fd24..b7e34a4580 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -648,7 +648,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + } + } + +- sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0; ++ sve_supported = kvm_arm_sve_supported(); + + /* Add feature bits that can't appear until after VCPU init. */ + if (sve_supported) { +-- +2.27.0 + diff --git a/target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch b/target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch index 455dc843c105743750f7bc573b6fb86f3a5861b8..a8d5ac0be9b6943904393406d3104f1a7a9353e1 100644 --- a/target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch +++ b/target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch @@ -1,4 +1,4 @@ -From ad6ce039cab07b6a99ccaa36fbb0043ae85a74c9 Mon Sep 17 00:00:00 2001 +From 20bd52038a960e0c959af38a5d3d7a6601db8e8b Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Mon, 21 Sep 2020 22:14:20 +0800 Subject: [PATCH] target/arm: clear EL2 and EL3 only when kvm is not enabled @@ -11,24 +11,25 @@ effect. Hence, clear EL2 and EL3 only when kvm is not enabled for backwards compatibility. Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 7ae2d3da56..3f62336acf 100644 +index 1c1647a0a8..65163f5135 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1996,7 +1996,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -2283,7 +2283,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -- if (!cpu->has_el3) { -+ if (!cpu->has_el3 && !kvm_enabled()) { +- if (!arm_feature(env, ARM_FEATURE_M) && !cpu->has_el3) { ++ if (!arm_feature(env, ARM_FEATURE_M) && !cpu->has_el3 && !kvm_enabled()) { /* If the has_el3 CPU property is disabled then we need to disable the * feature. */ -@@ -2037,7 +2037,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -2324,7 +2324,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->pmceid1 = 0; } @@ -38,5 +39,5 @@ index 7ae2d3da56..3f62336acf 100644 * registers if we don't have EL2. These are id_pfr1[15:12] and * id_aa64pfr0_el1[11:8]. -- -2.23.0 +2.27.0 diff --git a/target-arm-convert-isar-regs-to-array.patch b/target-arm-convert-isar-regs-to-array.patch index 528371212aad42f034db62858b1a2da2cdcba79d..14e9a0865434bed3b0bba3038a3fb1540bbb29b8 100644 --- a/target-arm-convert-isar-regs-to-array.patch +++ b/target-arm-convert-isar-regs-to-array.patch @@ -1,7 +1,7 @@ -From ac92f0f7bbf7cf063ba45fbfaf7e7970dd76544a Mon Sep 17 00:00:00 2001 +From bd8514594f0226b4599019ff123321138bb04d39 Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:25 +0800 -Subject: [PATCH 1/9] target/arm: convert isar regs to array +Subject: [PATCH] target/arm: convert isar regs to array The isar in ARMCPU is a struct, each field of which represents an ID register. It's not convenient for us to support CPU feature in AArch64. @@ -12,62 +12,108 @@ AArch32 to 64-bits. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- - hw/intc/armv7m_nvic.c | 28 +-- - target/arm/cpu.c | 440 +++++++++++++++++++++-------------------- - target/arm/cpu.h | 178 +++++++++-------- - target/arm/cpu64.c | 158 +++++++-------- - target/arm/helper.c | 54 ++--- - target/arm/internals.h | 15 +- - target/arm/kvm64.c | 68 +++---- - 7 files changed, 478 insertions(+), 463 deletions(-) + hw/intc/armv7m_nvic.c | 32 +-- + target/arm/cpu.c | 105 ++++----- + target/arm/cpu.h | 298 ++++++++++++------------ + target/arm/cpu64.c | 234 +++++++++---------- + target/arm/cpu_tcg.c | 503 +++++++++++++++++++++-------------------- + target/arm/helper.c | 64 +++--- + target/arm/hvf/hvf.c | 20 +- + target/arm/internals.h | 14 +- + target/arm/kvm64.c | 81 +++---- + 9 files changed, 683 insertions(+), 668 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c -index f7ef6ad1..5013ec97 100644 +index 13df002ce4..4b12b209b7 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c -@@ -1223,29 +1223,29 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) +@@ -1273,17 +1273,17 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_pfr0; ++ return cpu->isar.regs[ID_PFR0]; case 0xd44: /* PFR1. */ - return cpu->id_pfr1; + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_pfr1; ++ return cpu->isar.regs[ID_PFR1]; case 0xd48: /* DFR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_dfr0; + return cpu->isar.regs[ID_DFR0]; case 0xd4c: /* AFR0. */ - return cpu->id_afr0; - case 0xd50: /* MMFR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; +@@ -1293,52 +1293,52 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_mmfr0; + return cpu->isar.regs[ID_MMFR0]; case 0xd54: /* MMFR1. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_mmfr1; + return cpu->isar.regs[ID_MMFR1]; case 0xd58: /* MMFR2. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_mmfr2; + return cpu->isar.regs[ID_MMFR2]; case 0xd5c: /* MMFR3. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_mmfr3; + return cpu->isar.regs[ID_MMFR3]; case 0xd60: /* ISAR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar0; + return cpu->isar.regs[ID_ISAR0]; case 0xd64: /* ISAR1. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar1; + return cpu->isar.regs[ID_ISAR1]; case 0xd68: /* ISAR2. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar2; + return cpu->isar.regs[ID_ISAR2]; case 0xd6c: /* ISAR3. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar3; + return cpu->isar.regs[ID_ISAR3]; case 0xd70: /* ISAR4. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar4; + return cpu->isar.regs[ID_ISAR4]; case 0xd74: /* ISAR5. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } - return cpu->isar.id_isar5; + return cpu->isar.regs[ID_ISAR5]; case 0xd78: /* CLIDR */ return cpu->clidr; case 0xd7c: /* CTR */ -@@ -1450,11 +1450,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) +@@ -1548,11 +1548,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return cpu->env.v7m.fpdscr[attrs.secure]; case 0xf40: /* MVFR0 */ @@ -83,10 +129,10 @@ index f7ef6ad1..5013ec97 100644 bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset); diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index c3728e3d..5bcdad0c 100644 +index a211804fd3..f1ce0474a3 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -170,9 +170,9 @@ static void arm_cpu_reset(CPUState *s) +@@ -176,9 +176,9 @@ static void arm_cpu_reset(DeviceState *dev) g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu); env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; @@ -97,11 +143,11 @@ index c3728e3d..5bcdad0c 100644 + env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.regs[MVFR1]; + env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.regs[MVFR2]; - cpu->power_state = cpu->start_powered_off ? PSCI_OFF : PSCI_ON; - s->halted = cpu->start_powered_off; -@@ -1251,19 +1251,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - unset_feature(env, ARM_FEATURE_VFP3); - unset_feature(env, ARM_FEATURE_VFP4); + cpu->power_state = s->start_powered_off ? PSCI_OFF : PSCI_ON; + +@@ -1520,20 +1520,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + uint64_t t; + uint32_t u; - t = cpu->isar.id_aa64isar1; + t = cpu->isar.regs[ID_AA64ISAR1]; @@ -118,6 +164,7 @@ index c3728e3d..5bcdad0c 100644 - u = cpu->isar.id_isar6; + u = cpu->isar.regs[ID_ISAR6]; u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0); + u = FIELD_DP32(u, ID_ISAR6, BF16, 0); - cpu->isar.id_isar6 = u; + cpu->isar.regs[ID_ISAR6] = u; @@ -125,11 +172,11 @@ index c3728e3d..5bcdad0c 100644 + u = cpu->isar.regs[MVFR0]; u = FIELD_DP32(u, MVFR0, FPSP, 0); u = FIELD_DP32(u, MVFR0, FPDP, 0); - u = FIELD_DP32(u, MVFR0, FPTRAP, 0); -@@ -1271,17 +1271,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - u = FIELD_DP32(u, MVFR0, FPSQRT, 0); - u = FIELD_DP32(u, MVFR0, FPSHVEC, 0); - u = FIELD_DP32(u, MVFR0, FPROUND, 0); + u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0); +@@ -1543,20 +1543,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + u = FIELD_DP32(u, MVFR0, FPTRAP, 0); + u = FIELD_DP32(u, MVFR0, FPSHVEC, 0); + } - cpu->isar.mvfr0 = u; + cpu->isar.regs[MVFR0] = u; @@ -138,6 +185,9 @@ index c3728e3d..5bcdad0c 100644 u = FIELD_DP32(u, MVFR1, FPFTZ, 0); u = FIELD_DP32(u, MVFR1, FPDNAN, 0); u = FIELD_DP32(u, MVFR1, FPHP, 0); + if (arm_feature(env, ARM_FEATURE_M)) { + u = FIELD_DP32(u, MVFR1, FP16, 0); + } - cpu->isar.mvfr1 = u; + cpu->isar.regs[MVFR1] = u; @@ -149,7 +199,7 @@ index c3728e3d..5bcdad0c 100644 } if (!cpu->has_neon) { -@@ -1290,56 +1290,56 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -1565,43 +1565,43 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) unset_feature(env, ARM_FEATURE_NEON); @@ -162,6 +212,8 @@ index c3728e3d..5bcdad0c 100644 - t = cpu->isar.id_aa64isar1; + t = cpu->isar.regs[ID_AA64ISAR1]; t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0); + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 0); + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 0); - cpu->isar.id_aa64isar1 = t; + cpu->isar.regs[ID_AA64ISAR1] = t; @@ -182,27 +234,30 @@ index c3728e3d..5bcdad0c 100644 + u = cpu->isar.regs[ID_ISAR6]; u = FIELD_DP32(u, ID_ISAR6, DP, 0); u = FIELD_DP32(u, ID_ISAR6, FHM, 0); + u = FIELD_DP32(u, ID_ISAR6, BF16, 0); + u = FIELD_DP32(u, ID_ISAR6, I8MM, 0); - cpu->isar.id_isar6 = u; + cpu->isar.regs[ID_ISAR6] = u; -- u = cpu->isar.mvfr1; -+ u = cpu->isar.regs[MVFR1]; - u = FIELD_DP32(u, MVFR1, SIMDLS, 0); - u = FIELD_DP32(u, MVFR1, SIMDINT, 0); - u = FIELD_DP32(u, MVFR1, SIMDSP, 0); - u = FIELD_DP32(u, MVFR1, SIMDHP, 0); - u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0); -- cpu->isar.mvfr1 = u; -+ cpu->isar.regs[MVFR1] = u; - -- u = cpu->isar.mvfr2; -+ u = cpu->isar.regs[MVFR2]; - u = FIELD_DP32(u, MVFR2, SIMDMISC, 0); -- cpu->isar.mvfr2 = u; -+ cpu->isar.regs[MVFR2] = u; + if (!arm_feature(env, ARM_FEATURE_M)) { +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, SIMDLS, 0); + u = FIELD_DP32(u, MVFR1, SIMDINT, 0); + u = FIELD_DP32(u, MVFR1, SIMDSP, 0); + u = FIELD_DP32(u, MVFR1, SIMDHP, 0); +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; + +- u = cpu->isar.mvfr2; ++ u = cpu->isar.regs[MVFR2]; + u = FIELD_DP32(u, MVFR2, SIMDMISC, 0); +- cpu->isar.mvfr2 = u; ++ cpu->isar.regs[MVFR2] = u; + } } - if (!cpu->has_neon && !cpu->has_vfp) { +@@ -1609,22 +1609,22 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) uint64_t t; uint32_t u; @@ -223,10 +278,17 @@ index c3728e3d..5bcdad0c 100644 u = FIELD_DP32(u, MVFR0, SIMDREG, 0); - cpu->isar.mvfr0 = u; + cpu->isar.regs[MVFR0] = u; + + /* Despite the name, this field covers both VFP and Neon */ +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0); +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; } if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) { -@@ -1347,19 +1347,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -1632,19 +1632,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) unset_feature(env, ARM_FEATURE_THUMB_DSP); @@ -252,16 +314,18 @@ index c3728e3d..5bcdad0c 100644 } /* Some features automatically imply others: */ -@@ -1499,7 +1499,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -1785,8 +1785,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + /* Disable the security extension feature bits in the processor feature * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. */ - cpu->id_pfr1 &= ~0xf0; +- cpu->isar.id_pfr1 &= ~0xf0; - cpu->isar.id_aa64pfr0 &= ~0xf000; ++ cpu->isar.regs[ID_PFR1] &= ~0xf0; + cpu->isar.regs[ID_AA64PFR0] &= ~0xf000; } if (!cpu->has_el2) { -@@ -1522,9 +1522,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -1809,9 +1809,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu); #endif } else { @@ -275,794 +339,375 @@ index c3728e3d..5bcdad0c 100644 cpu->pmceid0 = 0; cpu->pmceid1 = 0; } -@@ -1534,7 +1535,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) +@@ -1821,8 +1822,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) * registers if we don't have EL2. These are id_pfr1[15:12] and * id_aa64pfr0_el1[11:8]. */ - cpu->isar.id_aa64pfr0 &= ~0xf00; +- cpu->isar.id_pfr1 &= ~0xf000; + cpu->isar.regs[ID_AA64PFR0] &= ~0xf00; - cpu->id_pfr1 &= ~0xf000; ++ cpu->isar.regs[ID_PFR1] &= ~0xf000; } -@@ -1675,13 +1676,15 @@ static void arm926_initfn(Object *obj) - * ARMv5 does not have the ID_ISAR registers, but we can still - * set the field to indicate Jazelle support within QEMU. - */ -- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); -+ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, -+ JAZELLE, 1); - /* - * Similarly, we need to set MVFR0 fields to enable double precision - * and short vector support even though ARMv5 doesn't have this register. + #ifndef CONFIG_USER_ONLY +@@ -1831,8 +1832,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * Disable the MTE feature bits if we do not have tag-memory + * provided by the machine. + */ +- cpu->isar.id_aa64pfr1 = +- FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0); ++ cpu->isar.regs[ID_AA64PFR1] = ++ FIELD_DP64(cpu->isar.regs[ID_AA64PFR1], ID_AA64PFR1, MTE, 0); + } + #endif + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index e33f37b70a..3dda33f347 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -69,6 +69,41 @@ + #define ARMV7M_EXCP_PENDSV 14 + #define ARMV7M_EXCP_SYSTICK 15 + ++typedef enum CPUIDReg { ++ MIDR_EL1, ++ ID_ISAR0, ++ ID_ISAR1, ++ ID_ISAR2, ++ ID_ISAR3, ++ ID_ISAR4, ++ ID_ISAR5, ++ ID_ISAR6, ++ ID_PFR0, ++ ID_PFR1, ++ ID_PFR2, ++ ID_MMFR0, ++ ID_MMFR1, ++ ID_MMFR2, ++ ID_MMFR3, ++ ID_MMFR4, ++ ID_AA64ISAR0, ++ ID_AA64ISAR1, ++ ID_AA64PFR0, ++ ID_AA64PFR1, ++ ID_AA64MMFR0, ++ ID_AA64MMFR1, ++ ID_AA64MMFR2, ++ ID_AA64DFR0, ++ ID_AA64DFR1, ++ ID_AA64ZFR0, ++ ID_DFR0, ++ MVFR0, ++ MVFR1, ++ MVFR2, ++ DBGDIDR, ++ ID_MAX, ++} CPUIDReg; ++ + /* For M profile, some registers are banked secure vs non-secure; + * these are represented as a 2-element array where the first element + * is the non-secure copy and the second is the secure copy. +@@ -922,36 +957,7 @@ struct ARMCPU { + * field by reading the value from the KVM vCPU. */ -- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); -- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); -+ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, -+ FPSHVEC, 1); -+ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); + struct ARMISARegisters { +- uint32_t id_isar0; +- uint32_t id_isar1; +- uint32_t id_isar2; +- uint32_t id_isar3; +- uint32_t id_isar4; +- uint32_t id_isar5; +- uint32_t id_isar6; +- uint32_t id_mmfr0; +- uint32_t id_mmfr1; +- uint32_t id_mmfr2; +- uint32_t id_mmfr3; +- uint32_t id_mmfr4; +- uint32_t id_pfr0; +- uint32_t id_pfr1; +- uint32_t id_pfr2; +- uint32_t mvfr0; +- uint32_t mvfr1; +- uint32_t mvfr2; +- uint32_t id_dfr0; +- uint32_t dbgdidr; +- uint64_t id_aa64isar0; +- uint64_t id_aa64isar1; +- uint64_t id_aa64pfr0; +- uint64_t id_aa64pfr1; +- uint64_t id_aa64mmfr0; +- uint64_t id_aa64mmfr1; +- uint64_t id_aa64mmfr2; +- uint64_t id_aa64dfr0; +- uint64_t id_aa64dfr1; +- uint64_t id_aa64zfr0; ++ uint64_t regs[ID_MAX]; + } isar; + uint64_t midr; + uint32_t revidr; +@@ -3729,103 +3735,103 @@ static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x) + */ + static inline bool isar_feature_aa32_thumb_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) != 0; } - static void arm946_initfn(Object *obj) -@@ -1717,13 +1720,15 @@ static void arm1026_initfn(Object *obj) - * ARMv5 does not have the ID_ISAR registers, but we can still - * set the field to indicate Jazelle support within QEMU. - */ -- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); -+ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, -+ JAZELLE, 1); - /* - * Similarly, we need to set MVFR0 fields to enable double precision - * and short vector support even though ARMv5 doesn't have this register. - */ -- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); -- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); -+ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, -+ FPSHVEC, 1); -+ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); + static inline bool isar_feature_aa32_arm_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) > 1; + } - { - /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ -@@ -1756,22 +1761,22 @@ static void arm1136_r2_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = 0x4107b362; - cpu->reset_fpsid = 0x410120b4; -- cpu->isar.mvfr0 = 0x11111111; -- cpu->isar.mvfr1 = 0x00000000; -+ cpu->isar.regs[MVFR0] = 0x11111111; -+ cpu->isar.regs[MVFR1] = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->isar.id_dfr0 = 0x2; -+ cpu->isar.regs[ID_DFR0] = 0x2; - cpu->id_afr0 = 0x3; -- cpu->isar.id_mmfr0 = 0x01130003; -- cpu->isar.id_mmfr1 = 0x10030302; -- cpu->isar.id_mmfr2 = 0x01222110; -- cpu->isar.id_isar0 = 0x00140011; -- cpu->isar.id_isar1 = 0x12002111; -- cpu->isar.id_isar2 = 0x11231111; -- cpu->isar.id_isar3 = 0x01102131; -- cpu->isar.id_isar4 = 0x141; -+ cpu->isar.regs[ID_MMFR0] = 0x01130003; -+ cpu->isar.regs[ID_MMFR1] = 0x10030302; -+ cpu->isar.regs[ID_MMFR2] = 0x01222110; -+ cpu->isar.regs[ID_ISAR0] = 0x00140011; -+ cpu->isar.regs[ID_ISAR1] = 0x12002111; -+ cpu->isar.regs[ID_ISAR2] = 0x11231111; -+ cpu->isar.regs[ID_ISAR3] = 0x01102131; -+ cpu->isar.regs[ID_ISAR4] = 0x141; - cpu->reset_auxcr = 7; + static inline bool isar_feature_aa32_lob(const ARMISARegisters *id) + { + /* (M-profile) low-overhead loops and branch future */ +- return FIELD_EX32(id->id_isar0, ID_ISAR0, CMPBRANCH) >= 3; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, CMPBRANCH) >= 3; } -@@ -1788,22 +1793,22 @@ static void arm1136_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = 0x4117b363; - cpu->reset_fpsid = 0x410120b4; -- cpu->isar.mvfr0 = 0x11111111; -- cpu->isar.mvfr1 = 0x00000000; -+ cpu->isar.regs[MVFR0] = 0x11111111; -+ cpu->isar.regs[MVFR1] = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->isar.id_dfr0 = 0x2; -+ cpu->isar.regs[ID_DFR0] = 0x2; - cpu->id_afr0 = 0x3; -- cpu->isar.id_mmfr0 = 0x01130003; -- cpu->isar.id_mmfr1 = 0x10030302; -- cpu->isar.id_mmfr2 = 0x01222110; -- cpu->isar.id_isar0 = 0x00140011; -- cpu->isar.id_isar1 = 0x12002111; -- cpu->isar.id_isar2 = 0x11231111; -- cpu->isar.id_isar3 = 0x01102131; -- cpu->isar.id_isar4 = 0x141; -+ cpu->isar.regs[ID_MMFR0] = 0x01130003; -+ cpu->isar.regs[ID_MMFR1] = 0x10030302; -+ cpu->isar.regs[ID_MMFR2] = 0x01222110; -+ cpu->isar.regs[ID_ISAR0] = 0x00140011; -+ cpu->isar.regs[ID_ISAR1] = 0x12002111; -+ cpu->isar.regs[ID_ISAR2] = 0x11231111; -+ cpu->isar.regs[ID_ISAR3] = 0x01102131; -+ cpu->isar.regs[ID_ISAR4] = 0x141; - cpu->reset_auxcr = 7; + static inline bool isar_feature_aa32_jazelle(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR1], ID_ISAR1, JAZELLE) != 0; } -@@ -1821,22 +1826,22 @@ static void arm1176_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_EL3); - cpu->midr = 0x410fb767; - cpu->reset_fpsid = 0x410120b5; -- cpu->isar.mvfr0 = 0x11111111; -- cpu->isar.mvfr1 = 0x00000000; -+ cpu->isar.regs[MVFR0] = 0x11111111; -+ cpu->isar.regs[MVFR1] = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x11; -- cpu->isar.id_dfr0 = 0x33; -+ cpu->isar.regs[ID_DFR0] = 0x33; - cpu->id_afr0 = 0; -- cpu->isar.id_mmfr0 = 0x01130003; -- cpu->isar.id_mmfr1 = 0x10030302; -- cpu->isar.id_mmfr2 = 0x01222100; -- cpu->isar.id_isar0 = 0x0140011; -- cpu->isar.id_isar1 = 0x12002111; -- cpu->isar.id_isar2 = 0x11231121; -- cpu->isar.id_isar3 = 0x01102131; -- cpu->isar.id_isar4 = 0x01141; -+ cpu->isar.regs[ID_MMFR0] = 0x01130003; -+ cpu->isar.regs[ID_MMFR1] = 0x10030302; -+ cpu->isar.regs[ID_MMFR2] = 0x01222100; -+ cpu->isar.regs[ID_ISAR0] = 0x0140011; -+ cpu->isar.regs[ID_ISAR1] = 0x12002111; -+ cpu->isar.regs[ID_ISAR2] = 0x11231121; -+ cpu->isar.regs[ID_ISAR3] = 0x01102131; -+ cpu->isar.regs[ID_ISAR4] = 0x01141; - cpu->reset_auxcr = 7; + static inline bool isar_feature_aa32_aes(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) != 0; } -@@ -1852,21 +1857,21 @@ static void arm11mpcore_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = 0x410fb022; - cpu->reset_fpsid = 0x410120b4; -- cpu->isar.mvfr0 = 0x11111111; -- cpu->isar.mvfr1 = 0x00000000; -+ cpu->isar.regs[MVFR0] = 0x11111111; -+ cpu->isar.regs[MVFR1] = 0x00000000; - cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; -- cpu->isar.id_dfr0 = 0; -+ cpu->isar.regs[ID_DFR0] = 0; - cpu->id_afr0 = 0x2; -- cpu->isar.id_mmfr0 = 0x01100103; -- cpu->isar.id_mmfr1 = 0x10020302; -- cpu->isar.id_mmfr2 = 0x01222000; -- cpu->isar.id_isar0 = 0x00100011; -- cpu->isar.id_isar1 = 0x12002111; -- cpu->isar.id_isar2 = 0x11221011; -- cpu->isar.id_isar3 = 0x01102131; -- cpu->isar.id_isar4 = 0x141; -+ cpu->isar.regs[ID_MMFR0] = 0x01100103; -+ cpu->isar.regs[ID_MMFR1] = 0x10020302; -+ cpu->isar.regs[ID_MMFR2] = 0x01222000; -+ cpu->isar.regs[ID_ISAR0] = 0x00100011; -+ cpu->isar.regs[ID_ISAR1] = 0x12002111; -+ cpu->isar.regs[ID_ISAR2] = 0x11221011; -+ cpu->isar.regs[ID_ISAR3] = 0x01102131; -+ cpu->isar.regs[ID_ISAR4] = 0x141; - cpu->reset_auxcr = 1; + static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) > 1; } -@@ -1889,19 +1894,19 @@ static void cortex_m3_initfn(Object *obj) - cpu->pmsav7_dregion = 8; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; -- cpu->isar.id_dfr0 = 0x00100000; -+ cpu->isar.regs[ID_DFR0] = 0x00100000; - cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x00000030; -- cpu->isar.id_mmfr1 = 0x00000000; -- cpu->isar.id_mmfr2 = 0x00000000; -- cpu->isar.id_mmfr3 = 0x00000000; -- cpu->isar.id_isar0 = 0x01141110; -- cpu->isar.id_isar1 = 0x02111000; -- cpu->isar.id_isar2 = 0x21112231; -- cpu->isar.id_isar3 = 0x01111110; -- cpu->isar.id_isar4 = 0x01310102; -- cpu->isar.id_isar5 = 0x00000000; -- cpu->isar.id_isar6 = 0x00000000; -+ cpu->isar.regs[ID_MMFR0] = 0x00000030; -+ cpu->isar.regs[ID_MMFR1] = 0x00000000; -+ cpu->isar.regs[ID_MMFR2] = 0x00000000; -+ cpu->isar.regs[ID_MMFR3] = 0x00000000; -+ cpu->isar.regs[ID_ISAR0] = 0x01141110; -+ cpu->isar.regs[ID_ISAR1] = 0x02111000; -+ cpu->isar.regs[ID_ISAR2] = 0x21112231; -+ cpu->isar.regs[ID_ISAR3] = 0x01111110; -+ cpu->isar.regs[ID_ISAR4] = 0x01310102; -+ cpu->isar.regs[ID_ISAR5] = 0x00000000; -+ cpu->isar.regs[ID_ISAR6] = 0x00000000; + static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA1) != 0; } - static void cortex_m4_initfn(Object *obj) -@@ -1915,24 +1920,24 @@ static void cortex_m4_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_VFP4); - cpu->midr = 0x410fc240; /* r0p0 */ - cpu->pmsav7_dregion = 8; -- cpu->isar.mvfr0 = 0x10110021; -- cpu->isar.mvfr1 = 0x11000011; -- cpu->isar.mvfr2 = 0x00000000; -+ cpu->isar.regs[MVFR0] = 0x10110021; -+ cpu->isar.regs[MVFR1] = 0x11000011; -+ cpu->isar.regs[MVFR2] = 0x00000000; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; -- cpu->isar.id_dfr0 = 0x00100000; -+ cpu->isar.regs[ID_DFR0] = 0x00100000; - cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x00000030; -- cpu->isar.id_mmfr1 = 0x00000000; -- cpu->isar.id_mmfr2 = 0x00000000; -- cpu->isar.id_mmfr3 = 0x00000000; -- cpu->isar.id_isar0 = 0x01141110; -- cpu->isar.id_isar1 = 0x02111000; -- cpu->isar.id_isar2 = 0x21112231; -- cpu->isar.id_isar3 = 0x01111110; -- cpu->isar.id_isar4 = 0x01310102; -- cpu->isar.id_isar5 = 0x00000000; -- cpu->isar.id_isar6 = 0x00000000; -+ cpu->isar.regs[ID_MMFR0] = 0x00000030; -+ cpu->isar.regs[ID_MMFR1] = 0x00000000; -+ cpu->isar.regs[ID_MMFR2] = 0x00000000; -+ cpu->isar.regs[ID_MMFR3] = 0x00000000; -+ cpu->isar.regs[ID_ISAR0] = 0x01141110; -+ cpu->isar.regs[ID_ISAR1] = 0x02111000; -+ cpu->isar.regs[ID_ISAR2] = 0x21112231; -+ cpu->isar.regs[ID_ISAR3] = 0x01111110; -+ cpu->isar.regs[ID_ISAR4] = 0x01310102; -+ cpu->isar.regs[ID_ISAR5] = 0x00000000; -+ cpu->isar.regs[ID_ISAR6] = 0x00000000; + static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA2) != 0; } - static void cortex_m33_initfn(Object *obj) -@@ -1948,24 +1953,24 @@ static void cortex_m33_initfn(Object *obj) - cpu->midr = 0x410fd213; /* r0p3 */ - cpu->pmsav7_dregion = 16; - cpu->sau_sregion = 8; -- cpu->isar.mvfr0 = 0x10110021; -- cpu->isar.mvfr1 = 0x11000011; -- cpu->isar.mvfr2 = 0x00000040; -+ cpu->isar.regs[MVFR0] = 0x10110021; -+ cpu->isar.regs[MVFR1] = 0x11000011; -+ cpu->isar.regs[MVFR2] = 0x00000040; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000210; -- cpu->isar.id_dfr0 = 0x00200000; -+ cpu->isar.regs[ID_DFR0] = 0x00200000; - cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x00101F40; -- cpu->isar.id_mmfr1 = 0x00000000; -- cpu->isar.id_mmfr2 = 0x01000000; -- cpu->isar.id_mmfr3 = 0x00000000; -- cpu->isar.id_isar0 = 0x01101110; -- cpu->isar.id_isar1 = 0x02212000; -- cpu->isar.id_isar2 = 0x20232232; -- cpu->isar.id_isar3 = 0x01111131; -- cpu->isar.id_isar4 = 0x01310132; -- cpu->isar.id_isar5 = 0x00000000; -- cpu->isar.id_isar6 = 0x00000000; -+ cpu->isar.regs[ID_MMFR0] = 0x00101F40; -+ cpu->isar.regs[ID_MMFR1] = 0x00000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01000000; -+ cpu->isar.regs[ID_MMFR3] = 0x00000000; -+ cpu->isar.regs[ID_ISAR0] = 0x01101110; -+ cpu->isar.regs[ID_ISAR1] = 0x02212000; -+ cpu->isar.regs[ID_ISAR2] = 0x20232232; -+ cpu->isar.regs[ID_ISAR3] = 0x01111131; -+ cpu->isar.regs[ID_ISAR4] = 0x01310132; -+ cpu->isar.regs[ID_ISAR5] = 0x00000000; -+ cpu->isar.regs[ID_ISAR6] = 0x00000000; - cpu->clidr = 0x00000000; - cpu->ctr = 0x8000c000; + static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, CRC32) != 0; } -@@ -2004,19 +2009,19 @@ static void cortex_r5_initfn(Object *obj) - cpu->midr = 0x411fc153; /* r1p3 */ - cpu->id_pfr0 = 0x0131; - cpu->id_pfr1 = 0x001; -- cpu->isar.id_dfr0 = 0x010400; -+ cpu->isar.regs[ID_DFR0] = 0x010400; - cpu->id_afr0 = 0x0; -- cpu->isar.id_mmfr0 = 0x0210030; -- cpu->isar.id_mmfr1 = 0x00000000; -- cpu->isar.id_mmfr2 = 0x01200000; -- cpu->isar.id_mmfr3 = 0x0211; -- cpu->isar.id_isar0 = 0x02101111; -- cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232141; -- cpu->isar.id_isar3 = 0x01112131; -- cpu->isar.id_isar4 = 0x0010142; -- cpu->isar.id_isar5 = 0x0; -- cpu->isar.id_isar6 = 0x0; -+ cpu->isar.regs[ID_MMFR0] = 0x0210030; -+ cpu->isar.regs[ID_MMFR1] = 0x00000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01200000; -+ cpu->isar.regs[ID_MMFR3] = 0x0211; -+ cpu->isar.regs[ID_ISAR0] = 0x02101111; -+ cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232141; -+ cpu->isar.regs[ID_ISAR3] = 0x01112131; -+ cpu->isar.regs[ID_ISAR4] = 0x0010142; -+ cpu->isar.regs[ID_ISAR5] = 0x0; -+ cpu->isar.regs[ID_ISAR6] = 0x0; - cpu->mp_is_up = true; - cpu->pmsav7_dregion = 16; - define_arm_cp_regs(cpu, cortexr5_cp_reginfo); -@@ -2028,8 +2033,8 @@ static void cortex_r5f_initfn(Object *obj) - cortex_r5_initfn(obj); - set_feature(&cpu->env, ARM_FEATURE_VFP3); -- cpu->isar.mvfr0 = 0x10110221; -- cpu->isar.mvfr1 = 0x00000011; -+ cpu->isar.regs[MVFR0] = 0x10110221; -+ cpu->isar.regs[MVFR1] = 0x00000011; + static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, RDM) != 0; } - static const ARMCPRegInfo cortexa8_cp_reginfo[] = { -@@ -2053,24 +2058,24 @@ static void cortex_a8_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_EL3); - cpu->midr = 0x410fc080; - cpu->reset_fpsid = 0x410330c0; -- cpu->isar.mvfr0 = 0x11110222; -- cpu->isar.mvfr1 = 0x00011111; -+ cpu->isar.regs[MVFR0] = 0x11110222; -+ cpu->isar.regs[MVFR1] = 0x00011111; - cpu->ctr = 0x82048004; - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x1031; - cpu->id_pfr1 = 0x11; -- cpu->isar.id_dfr0 = 0x400; -+ cpu->isar.regs[ID_DFR0] = 0x400; - cpu->id_afr0 = 0; -- cpu->isar.id_mmfr0 = 0x31100003; -- cpu->isar.id_mmfr1 = 0x20000000; -- cpu->isar.id_mmfr2 = 0x01202000; -- cpu->isar.id_mmfr3 = 0x11; -- cpu->isar.id_isar0 = 0x00101111; -- cpu->isar.id_isar1 = 0x12112111; -- cpu->isar.id_isar2 = 0x21232031; -- cpu->isar.id_isar3 = 0x11112131; -- cpu->isar.id_isar4 = 0x00111142; -- cpu->isar.dbgdidr = 0x15141000; -+ cpu->isar.regs[ID_MMFR0] = 0x31100003; -+ cpu->isar.regs[ID_MMFR1] = 0x20000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01202000; -+ cpu->isar.regs[ID_MMFR3] = 0x11; -+ cpu->isar.regs[ID_ISAR0] = 0x00101111; -+ cpu->isar.regs[ID_ISAR1] = 0x12112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232031; -+ cpu->isar.regs[ID_ISAR3] = 0x11112131; -+ cpu->isar.regs[ID_ISAR4] = 0x00111142; -+ cpu->isar.regs[DBGDIDR] = 0x15141000; - cpu->clidr = (1 << 27) | (2 << 24) | 3; - cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ -@@ -2126,24 +2131,24 @@ static void cortex_a9_initfn(Object *obj) - set_feature(&cpu->env, ARM_FEATURE_CBAR); - cpu->midr = 0x410fc090; - cpu->reset_fpsid = 0x41033090; -- cpu->isar.mvfr0 = 0x11110222; -- cpu->isar.mvfr1 = 0x01111111; -+ cpu->isar.regs[MVFR0] = 0x11110222; -+ cpu->isar.regs[MVFR1] = 0x01111111; - cpu->ctr = 0x80038003; - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x1031; - cpu->id_pfr1 = 0x11; -- cpu->isar.id_dfr0 = 0x000; -+ cpu->isar.regs[ID_DFR0] = 0x000; - cpu->id_afr0 = 0; -- cpu->isar.id_mmfr0 = 0x00100103; -- cpu->isar.id_mmfr1 = 0x20000000; -- cpu->isar.id_mmfr2 = 0x01230000; -- cpu->isar.id_mmfr3 = 0x00002111; -- cpu->isar.id_isar0 = 0x00101111; -- cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232041; -- cpu->isar.id_isar3 = 0x11112131; -- cpu->isar.id_isar4 = 0x00111142; -- cpu->isar.dbgdidr = 0x35141000; -+ cpu->isar.regs[ID_MMFR0] = 0x00100103; -+ cpu->isar.regs[ID_MMFR1] = 0x20000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01230000; -+ cpu->isar.regs[ID_MMFR3] = 0x00002111; -+ cpu->isar.regs[ID_ISAR0] = 0x00101111; -+ cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232041; -+ cpu->isar.regs[ID_ISAR3] = 0x11112131; -+ cpu->isar.regs[ID_ISAR4] = 0x00111142; -+ cpu->isar.regs[DBGDIDR] = 0x35141000; - cpu->clidr = (1 << 27) | (1 << 24) | 3; - cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ -@@ -2191,27 +2196,27 @@ static void cortex_a7_initfn(Object *obj) - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; - cpu->midr = 0x410fc075; - cpu->reset_fpsid = 0x41023075; -- cpu->isar.mvfr0 = 0x10110222; -- cpu->isar.mvfr1 = 0x11111111; -+ cpu->isar.regs[MVFR0] = 0x10110222; -+ cpu->isar.regs[MVFR1] = 0x11111111; - cpu->ctr = 0x84448003; - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x00001131; - cpu->id_pfr1 = 0x00011011; -- cpu->isar.id_dfr0 = 0x02010555; -+ cpu->isar.regs[ID_DFR0] = 0x02010555; - cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x10101105; -- cpu->isar.id_mmfr1 = 0x40000000; -- cpu->isar.id_mmfr2 = 0x01240000; -- cpu->isar.id_mmfr3 = 0x02102211; -+ cpu->isar.regs[ID_MMFR0] = 0x10101105; -+ cpu->isar.regs[ID_MMFR1] = 0x40000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01240000; -+ cpu->isar.regs[ID_MMFR3] = 0x02102211; - /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but - * table 4-41 gives 0x02101110, which includes the arm div insns. - */ -- cpu->isar.id_isar0 = 0x02101110; -- cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232041; -- cpu->isar.id_isar3 = 0x11112131; -- cpu->isar.id_isar4 = 0x10011142; -- cpu->isar.dbgdidr = 0x3515f005; -+ cpu->isar.regs[ID_ISAR0] = 0x02101110; -+ cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232041; -+ cpu->isar.regs[ID_ISAR3] = 0x11112131; -+ cpu->isar.regs[ID_ISAR4] = 0x10011142; -+ cpu->isar.regs[DBGDIDR] = 0x3515f005; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ -@@ -2237,24 +2242,24 @@ static void cortex_a15_initfn(Object *obj) - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; - cpu->midr = 0x412fc0f1; - cpu->reset_fpsid = 0x410430f0; -- cpu->isar.mvfr0 = 0x10110222; -- cpu->isar.mvfr1 = 0x11111111; -+ cpu->isar.regs[MVFR0] = 0x10110222; -+ cpu->isar.regs[MVFR1] = 0x11111111; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50078; - cpu->id_pfr0 = 0x00001131; - cpu->id_pfr1 = 0x00011011; -- cpu->isar.id_dfr0 = 0x02010555; -+ cpu->isar.regs[ID_DFR0] = 0x02010555; - cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x10201105; -- cpu->isar.id_mmfr1 = 0x20000000; -- cpu->isar.id_mmfr2 = 0x01240000; -- cpu->isar.id_mmfr3 = 0x02102211; -- cpu->isar.id_isar0 = 0x02101110; -- cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232041; -- cpu->isar.id_isar3 = 0x11112131; -- cpu->isar.id_isar4 = 0x10011142; -- cpu->isar.dbgdidr = 0x3515f021; -+ cpu->isar.regs[ID_MMFR0] = 0x10201105; -+ cpu->isar.regs[ID_MMFR1] = 0x20000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01240000; -+ cpu->isar.regs[ID_MMFR3] = 0x02102211; -+ cpu->isar.regs[ID_ISAR0] = 0x02101110; -+ cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232041; -+ cpu->isar.regs[ID_ISAR3] = 0x11112131; -+ cpu->isar.regs[ID_ISAR4] = 0x10011142; -+ cpu->isar.regs[DBGDIDR] = 0x3515f021; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ -@@ -2447,7 +2452,8 @@ static void arm_max_initfn(Object *obj) - cortex_a15_initfn(obj); - - /* old-style VFP short-vector support */ -- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); -+ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, -+ FPSHVEC, 1); - - #ifdef CONFIG_USER_ONLY - /* We don't set these in system emulation mode for the moment, -@@ -2458,39 +2464,39 @@ static void arm_max_initfn(Object *obj) - { - uint32_t t; - -- t = cpu->isar.id_isar5; -+ t = cpu->isar.regs[ID_ISAR5]; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); -- cpu->isar.id_isar5 = t; -+ cpu->isar.regs[ID_ISAR5] = t; - -- t = cpu->isar.id_isar6; -+ t = cpu->isar.regs[ID_ISAR6]; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); -- cpu->isar.id_isar6 = t; -+ cpu->isar.regs[ID_ISAR6] = t; - -- t = cpu->isar.mvfr1; -+ t = cpu->isar.regs[MVFR1]; - t = FIELD_DP32(t, MVFR1, FPHP, 2); /* v8.0 FP support */ -- cpu->isar.mvfr1 = t; -+ cpu->isar.regs[MVFR1] = t; - -- t = cpu->isar.mvfr2; -+ t = cpu->isar.regs[MVFR2]; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ -- cpu->isar.mvfr2 = t; -+ cpu->isar.regs[MVFR2] = t; - -- t = cpu->isar.id_mmfr3; -+ t = cpu->isar.regs[ID_MMFR3]; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ -- cpu->isar.id_mmfr3 = t; -+ cpu->isar.regs[ID_MMFR3] = t; - -- t = cpu->isar.id_mmfr4; -+ t = cpu->isar.regs[ID_MMFR4]; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ -- cpu->isar.id_mmfr4 = t; -+ cpu->isar.regs[ID_MMFR4] = t; - } - #endif - } -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 56d8cd8c..7bb481fb 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -63,6 +63,37 @@ - #define ARMV7M_EXCP_PENDSV 14 - #define ARMV7M_EXCP_SYSTICK 15 - -+typedef enum CPUIDReg { -+ MIDR_EL1, -+ ID_ISAR0, -+ ID_ISAR1, -+ ID_ISAR2, -+ ID_ISAR3, -+ ID_ISAR4, -+ ID_ISAR5, -+ ID_ISAR6, -+ ID_MMFR0, -+ ID_MMFR1, -+ ID_MMFR2, -+ ID_MMFR3, -+ ID_MMFR4, -+ ID_AA64ISAR0, -+ ID_AA64ISAR1, -+ ID_AA64PFR0, -+ ID_AA64PFR1, -+ ID_AA64MMFR0, -+ ID_AA64MMFR1, -+ ID_AA64MMFR2, -+ ID_AA64DFR0, -+ ID_AA64DFR1, -+ ID_DFR0, -+ MVFR0, -+ MVFR1, -+ MVFR2, -+ DBGDIDR, -+ ID_MAX, -+} CPUIDReg; -+ - /* For M profile, some registers are banked secure vs non-secure; - * these are represented as a 2-element array where the first element - * is the non-secure copy and the second is the secure copy. -@@ -855,32 +886,7 @@ struct ARMCPU { - * field by reading the value from the KVM vCPU. - */ - struct ARMISARegisters { -- uint32_t id_isar0; -- uint32_t id_isar1; -- uint32_t id_isar2; -- uint32_t id_isar3; -- uint32_t id_isar4; -- uint32_t id_isar5; -- uint32_t id_isar6; -- uint32_t id_mmfr0; -- uint32_t id_mmfr1; -- uint32_t id_mmfr2; -- uint32_t id_mmfr3; -- uint32_t id_mmfr4; -- uint32_t mvfr0; -- uint32_t mvfr1; -- uint32_t mvfr2; -- uint32_t id_dfr0; -- uint32_t dbgdidr; -- uint64_t id_aa64isar0; -- uint64_t id_aa64isar1; -- uint64_t id_aa64pfr0; -- uint64_t id_aa64pfr1; -- uint64_t id_aa64mmfr0; -- uint64_t id_aa64mmfr1; -- uint64_t id_aa64mmfr2; -- uint64_t id_aa64dfr0; -- uint64_t id_aa64dfr1; -+ uint64_t regs[ID_MAX]; - } isar; - uint32_t midr; - uint32_t revidr; -@@ -3358,77 +3364,77 @@ extern const uint64_t pred_esz_masks[4]; - */ - static inline bool isar_feature_thumb_div(const ARMISARegisters *id) + static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) != 0; +- return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, VCMA) != 0; } - static inline bool isar_feature_arm_div(const ARMISARegisters *id) + static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1; -+ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) > 1; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, JSCVT) != 0; } - static inline bool isar_feature_jazelle(const ARMISARegisters *id) + static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR1], ID_ISAR1, JAZELLE) != 0; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, DP) != 0; } - static inline bool isar_feature_aa32_aes(const ARMISARegisters *id) + static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) != 0; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, FHM) != 0; } - static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id) + static inline bool isar_feature_aa32_sb(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) > 1; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SB) != 0; } - static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id) + static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA1) != 0; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SPECRES) != 0; } - static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id) + static inline bool isar_feature_aa32_bf16(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA2) != 0; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, BF16) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, BF16) != 0; } - static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id) + static inline bool isar_feature_aa32_i8mm(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, CRC32) != 0; +- return FIELD_EX32(id->id_isar6, ID_ISAR6, I8MM) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, I8MM) != 0; } - static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id) + static inline bool isar_feature_aa32_ras(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, RDM) != 0; +- return FIELD_EX32(id->id_pfr0, ID_PFR0, RAS) != 0; ++ return FIELD_EX32(id->regs[ID_PFR0], ID_PFR0, RAS) != 0; } - static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) + static inline bool isar_feature_aa32_mprofile(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, VCMA) != 0; +- return FIELD_EX32(id->id_pfr1, ID_PFR1, MPROGMOD) != 0; ++ return FIELD_EX32(id->regs[ID_PFR1], ID_PFR1, MPROGMOD) != 0; } - static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) + static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) +@@ -3834,16 +3840,16 @@ static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) + * Return true if M-profile state handling insns + * (VSCCLRM, CLRM, FPCTX access insns) are implemented + */ +- return FIELD_EX32(id->id_pfr1, ID_PFR1, SECURITY) >= 3; ++ return FIELD_EX32(id->regs[ID_PFR1], ID_PFR1, SECURITY) >= 3; + } + + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, JSCVT) != 0; + /* Sadly this is encoded differently for A-profile and M-profile */ + if (isar_feature_aa32_mprofile(id)) { +- return FIELD_EX32(id->mvfr1, MVFR1, FP16) > 0; ++ return FIELD_EX32(id->regs[MVFR1], MVFR1, FP16) > 0; + } else { +- return FIELD_EX32(id->mvfr1, MVFR1, FPHP) >= 3; ++ return FIELD_EX32(id->regs[MVFR1], MVFR1, FPHP) >= 3; + } + } + +@@ -3855,7 +3861,7 @@ static inline bool isar_feature_aa32_mve(const ARMISARegisters *id) + * else for A-profile. + */ + return isar_feature_aa32_mprofile(id) && +- FIELD_EX32(id->mvfr1, MVFR1, MVE) > 0; ++ FIELD_EX32(id->regs[MVFR1], MVFR1, MVE) > 0; } - static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) - { -- return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, DP) != 0; + static inline bool isar_feature_aa32_mve_fp(const ARMISARegisters *id) +@@ -3866,7 +3872,7 @@ static inline bool isar_feature_aa32_mve_fp(const ARMISARegisters *id) + * else for A-profile. + */ + return isar_feature_aa32_mprofile(id) && +- FIELD_EX32(id->mvfr1, MVFR1, MVE) >= 2; ++ FIELD_EX32(id->regs[MVFR1], MVFR1, MVE) >= 2; } - static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) - { -- return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, FHM) != 0; + static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id) +@@ -3875,42 +3881,42 @@ static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id) + * Return true if either VFP or SIMD is implemented. + * In this case, a minimum of VFP w/ D0-D15. + */ +- return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, SIMDREG) > 0; } - static inline bool isar_feature_aa32_sb(const ARMISARegisters *id) + static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SB) != 0; + /* Return true if D16-D31 are implemented */ +- return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) >= 2; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, SIMDREG) >= 2; } - static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id) + static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) { -- return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0; -+ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SPECRES) != 0; +- return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, FPSHVEC) > 0; } - static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) -@@ -3438,24 +3444,24 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) - * the ARMv8.2-FP16 extension is implemented for aa32 mode. - * At which point we can properly set and check MVFR1.FPHP. - */ -- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; -+ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) == 1; + static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id) + { + /* Return true if CPU supports single precision floating point, VFPv2 */ +- return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, FPSP) > 0; } - static inline bool isar_feature_aa32_fp_d32(const ARMISARegisters *id) + static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id) { - /* Return true if D16-D31 are implemented */ -- return FIELD_EX64(id->mvfr0, MVFR0, SIMDREG) >= 2; -+ return FIELD_EX64(id->regs[MVFR0], MVFR0, SIMDREG) >= 2; + /* Return true if CPU supports single precision floating point, VFPv3 */ +- return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, FPSP) >= 2; } - static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) + static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr0, MVFR0, FPSHVEC) > 0; -+ return FIELD_EX64(id->regs[MVFR0], MVFR0, FPSHVEC) > 0; + /* Return true if CPU supports double precision floating point, VFPv2 */ +- return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, FPDP) > 0; } - static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id) + static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id) { - /* Return true if CPU supports double precision floating point */ -- return FIELD_EX64(id->mvfr0, MVFR0, FPDP) > 0; -+ return FIELD_EX64(id->regs[MVFR0], MVFR0, FPDP) > 0; + /* Return true if CPU supports double precision floating point, VFPv3 */ +- return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2; ++ return FIELD_EX32(id->regs[MVFR0], MVFR0, FPDP) >= 2; } - /* -@@ -3465,49 +3471,49 @@ static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id) + static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id) +@@ -3925,12 +3931,12 @@ static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id) */ static inline bool isar_feature_aa32_fp16_spconv(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 0; -+ return FIELD_EX64(id->regs[MVFR1], MVFR1, FPHP) > 0; +- return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 0; ++ return FIELD_EX32(id->regs[MVFR1], MVFR1, FPHP) > 0; } static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 1; -+ return FIELD_EX64(id->regs[MVFR1], MVFR1, FPHP) > 1; +- return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1; ++ return FIELD_EX32(id->regs[MVFR1], MVFR1, FPHP) > 1; + } + + /* +@@ -3942,86 +3948,86 @@ static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) + */ + static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id) + { +- return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0; ++ return FIELD_EX32(id->regs[MVFR1], MVFR1, SIMDFMAC) != 0; } static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 1; -+ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 1; +- return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1; ++ return FIELD_EX32(id->regs[MVFR2], MVFR2, FPMISC) >= 1; } static inline bool isar_feature_aa32_vcvt_dr(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 2; -+ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 2; +- return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 2; ++ return FIELD_EX32(id->regs[MVFR2], MVFR2, FPMISC) >= 2; } static inline bool isar_feature_aa32_vrint(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 3; -+ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 3; +- return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 3; ++ return FIELD_EX32(id->regs[MVFR2], MVFR2, FPMISC) >= 3; } static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) { -- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4; -+ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 4; +- return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 4; ++ return FIELD_EX32(id->regs[MVFR2], MVFR2, FPMISC) >= 4; + } + + static inline bool isar_feature_aa32_pxn(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr0, ID_MMFR0, VMSA) >= 4; ++ return FIELD_EX32(id->regs[ID_MMFR0], ID_MMFR0, VMSA) >= 4; } static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) @@ -1086,8 +731,53 @@ index 56d8cd8c..7bb481fb 100644 + FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) != 0xf; } + static inline bool isar_feature_aa32_pmu_8_4(const ARMISARegisters *id) + { + /* 0xf means "non-standard IMPDEF PMU" */ +- return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 && +- FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++ return FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) >= 5 && ++ FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) != 0xf; + } + + static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR4], ID_MMFR4, HPDS) != 0; + } + + static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR4], ID_MMFR4, AC2) != 0; + } + + static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR4], ID_MMFR4, CCIDX) != 0; + } + + static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR4], ID_MMFR4, XNX) != 0; + } + + static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0; ++ return FIELD_EX32(id->regs[ID_PFR0], ID_PFR0, DIT) != 0; + } + + static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0; ++ return FIELD_EX32(id->regs[ID_PFR2], ID_PFR2, SSBS) != 0; + } + /* -@@ -3515,92 +3521,92 @@ static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) +@@ -4029,92 +4035,92 @@ static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) */ static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) { @@ -1161,391 +851,1462 @@ index 56d8cd8c..7bb481fb 100644 + return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, DP) != 0; } - static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) + static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, FHM) != 0; + } + + static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) != 0; + } + + static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) >= 2; + } + + static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, RNDR) != 0; + } + + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, JSCVT) != 0; + } + + static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FCMA) != 0; + } + + static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) +@@ -4123,7 +4129,7 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) + * Return true if any form of pauth is enabled, as this + * predicate controls migration of the 128-bit keys. + */ +- return (id->id_aa64isar1 & ++ return (id->regs[ID_AA64ISAR1] & + (FIELD_DP64(0, ID_AA64ISAR1, APA, 0xf) | + FIELD_DP64(0, ID_AA64ISAR1, API, 0xf) | + FIELD_DP64(0, ID_AA64ISAR1, GPA, 0xf) | +@@ -4136,221 +4142,221 @@ static inline bool isar_feature_aa64_pauth_arch(const ARMISARegisters *id) + * Return true if pauth is enabled with the architected QARMA algorithm. + * QEMU will always set APA+GPA to the same value. + */ +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, APA) != 0; + } + + static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) == 2; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TLB) == 2; + } + + static inline bool isar_feature_aa64_tlbios(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TLB) != 0; + } + + static inline bool isar_feature_aa64_sb(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SB) != 0; + } + + static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SPECRES) != 0; + } + + static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FRINTTS) != 0; + } + + static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, DPB) != 0; + } + + static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, DPB) >= 2; + } + + static inline bool isar_feature_aa64_bf16(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, BF16) != 0; + } + + static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id) + { + /* We always set the AdvSIMD and FP fields identically. */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) != 0xf; + } + + static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) + { + /* We always set the AdvSIMD and FP fields identically wrt FP16. */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) == 1; + } + + static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, EL0) >= 2; + } + + static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, EL1) >= 2; + } + + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, SVE) != 0; + } + + static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, SEL2) != 0; + } + + static inline bool isar_feature_aa64_vh(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, VH) != 0; + } + + static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, LO) != 0; + } + + static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) != 0; + } + + static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) >= 2; + } + + static inline bool isar_feature_aa64_uao(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR2], ID_AA64MMFR2, UAO) != 0; + } + + static inline bool isar_feature_aa64_st(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR2], ID_AA64MMFR2, ST) != 0; + } + + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, BT) != 0; + } + + static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, MTE) != 0; + } + + static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, MTE) >= 2; + } + + static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) >= 4 && ++ FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) >= 5 && ++ FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, LRCPC) != 0; + } + + static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, LRCPC) >= 2; + } + + static inline bool isar_feature_aa64_i8mm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, I8MM) != 0; + } + + static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR2], ID_AA64MMFR2, CCIDX) != 0; + } + + static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, XNX) != 0; + } + + static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, DIT) != 0; + } + + static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, SSBS) != 0; + } + + static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, SVEVER) != 0; + } + + static inline bool isar_feature_aa64_sve2_aes(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, AES) != 0; + } + + static inline bool isar_feature_aa64_sve2_pmull128(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, AES) >= 2; + } + + static inline bool isar_feature_aa64_sve2_bitperm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BITPERM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, BITPERM) != 0; + } + + static inline bool isar_feature_aa64_sve_bf16(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BFLOAT16) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, BFLOAT16) != 0; + } + + static inline bool isar_feature_aa64_sve2_sha3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SHA3) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, SHA3) != 0; + } + + static inline bool isar_feature_aa64_sve2_sm4(const ARMISARegisters *id) { -- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, FHM) != 0; +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SM4) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, SM4) != 0; } - static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id) + static inline bool isar_feature_aa64_sve_i8mm(const ARMISARegisters *id) { -- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) != 0; +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, I8MM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, I8MM) != 0; } - static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id) + static inline bool isar_feature_aa64_sve_f32mm(const ARMISARegisters *id) { -- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2; -+ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) >= 2; +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F32MM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, F32MM) != 0; } - static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) + static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) { -- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, RNDR) != 0; +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ZFR0], ID_AA64ZFR0, F64MM) != 0; } - static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, JSCVT) != 0; + /* +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 1b56261964..96a49a3158 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -108,31 +108,31 @@ static void aarch64_a57_initfn(Object *obj) + cpu->midr = 0x411fd070; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[ID_PFR0] = 0x00000131; ++ cpu->isar.regs[ID_PFR1] = 0x00011011; ++ cpu->isar.regs[ID_DFR0] = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_isar6 = 0; +- cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10101105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_ISAR6] = 0; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ +@@ -161,31 +161,31 @@ static void aarch64_a53_initfn(Object *obj) + cpu->midr = 0x410fd034; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[ID_PFR0] = 0x00000131; ++ cpu->isar.regs[ID_PFR1] = 0x00011011; ++ cpu->isar.regs[ID_DFR0] = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_isar6 = 0; +- cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10101105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_ISAR6] = 0; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001122; /* 40 bit physical addr */ ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ +@@ -214,30 +214,30 @@ static void aarch64_a72_initfn(Object *obj) + cpu->midr = 0x410fd083; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034080; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[ID_PFR0] = 0x00000131; ++ cpu->isar.regs[ID_PFR1] = 0x00011011; ++ cpu->isar.regs[ID_DFR0] = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10201105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ +@@ -262,10 +262,10 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; +- cpu->isar.id_aa64pfr0 = 0x11001111; +- cpu->isar.id_aa64dfr0 = 0x110305408; +- cpu->isar.id_aa64isar0 = 0x10211120; +- cpu->isar.id_aa64mmfr0 = 0x101125; ++ cpu->isar.regs[ID_AA64PFR0] = 0x11001111; ++ cpu->isar.regs[ID_AA64DFR0] = 0x110305408; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x10211120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x101125; } - static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FCMA) != 0; + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) +@@ -566,9 +566,9 @@ static void cpu_arm_set_sve(Object *obj, bool value, Error **errp) + return; + } + +- t = cpu->isar.id_aa64pfr0; ++ t = cpu->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, value); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; } - static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) -@@ -3611,7 +3617,7 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) - * defined algorithms, and thus API+GPI, and this predicate controls - * migration of the 128-bit keys. - */ -- return (id->id_aa64isar1 & -+ return (id->regs[ID_AA64ISAR1] & - (FIELD_DP64(0, ID_AA64ISAR1, APA, 0xf) | - FIELD_DP64(0, ID_AA64ISAR1, API, 0xf) | - FIELD_DP64(0, ID_AA64ISAR1, GPA, 0xf) | -@@ -3620,59 +3626,59 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) + #ifdef CONFIG_USER_ONLY +@@ -662,12 +662,12 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) + error_append_hint(errp, "Add pauth=on to the CPU property list.\n"); + } + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, APA, arch_val); + t = FIELD_DP64(t, ID_AA64ISAR1, GPA, arch_val); + t = FIELD_DP64(t, ID_AA64ISAR1, API, impdef_val); + t = FIELD_DP64(t, ID_AA64ISAR1, GPI, impdef_val); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + } + + static Property arm_cpu_pauth_property = +@@ -736,7 +736,7 @@ static void aarch64_max_initfn(Object *obj) + t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); + cpu->midr = t; + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[ID_AA64ISAR0]; + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ +@@ -751,9 +751,9 @@ static void aarch64_max_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); +- cpu->isar.id_aa64isar0 = t; ++ cpu->isar.regs[ID_AA64ISAR0] = t; + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); +@@ -763,17 +763,17 @@ static void aarch64_max_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- t = cpu->isar.id_aa64pfr0; ++ t = cpu->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- t = cpu->isar.id_aa64pfr1; ++ t = cpu->isar.regs[ID_AA64PFR1]; + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); + /* +@@ -782,28 +782,28 @@ static void aarch64_max_initfn(Object *obj) + * we do for EL2 with the virtualization=on property. + */ + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); +- cpu->isar.id_aa64pfr1 = t; ++ cpu->isar.regs[ID_AA64PFR1] = t; + +- t = cpu->isar.id_aa64mmfr0; ++ t = cpu->isar.regs[ID_AA64MMFR0]; + t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 5); /* PARange: 48 bits */ +- cpu->isar.id_aa64mmfr0 = t; ++ cpu->isar.regs[ID_AA64MMFR0] = t; + +- t = cpu->isar.id_aa64mmfr1; ++ t = cpu->isar.regs[ID_AA64MMFR1]; + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ + t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); + t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ +- cpu->isar.id_aa64mmfr1 = t; ++ cpu->isar.regs[ID_AA64MMFR1] = t; + +- t = cpu->isar.id_aa64mmfr2; ++ t = cpu->isar.regs[ID_AA64MMFR2]; + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ +- cpu->isar.id_aa64mmfr2 = t; ++ cpu->isar.regs[ID_AA64MMFR2] = t; + +- t = cpu->isar.id_aa64zfr0; ++ t = cpu->isar.regs[ID_AA64ZFR0]; + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); +@@ -813,19 +813,19 @@ static void aarch64_max_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); +- cpu->isar.id_aa64zfr0 = t; ++ cpu->isar.regs[ID_AA64ZFR0] = t; + + /* Replicate the same data to the 32-bit id registers. */ +- u = cpu->isar.id_isar5; ++ u = cpu->isar.regs[ID_ISAR5]; + u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ + u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); + u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); + u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); + u = FIELD_DP32(u, ID_ISAR5, RDM, 1); + u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); +- cpu->isar.id_isar5 = u; ++ cpu->isar.regs[ID_ISAR5] = u; + +- u = cpu->isar.id_isar6; ++ u = cpu->isar.regs[ID_ISAR6]; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); + u = FIELD_DP32(u, ID_ISAR6, DP, 1); + u = FIELD_DP32(u, ID_ISAR6, FHM, 1); +@@ -833,39 +833,39 @@ static void aarch64_max_initfn(Object *obj) + u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); + u = FIELD_DP32(u, ID_ISAR6, BF16, 1); + u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); +- cpu->isar.id_isar6 = u; ++ cpu->isar.regs[ID_ISAR6] = u; - static inline bool isar_feature_aa64_sb(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SB) != 0; - } +- u = cpu->isar.id_pfr0; ++ u = cpu->isar.regs[ID_PFR0]; + u = FIELD_DP32(u, ID_PFR0, DIT, 1); +- cpu->isar.id_pfr0 = u; ++ cpu->isar.regs[ID_PFR0] = u; - static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SPECRES) != 0; - } +- u = cpu->isar.id_pfr2; ++ u = cpu->isar.regs[ID_PFR2]; + u = FIELD_DP32(u, ID_PFR2, SSBS, 1); +- cpu->isar.id_pfr2 = u; ++ cpu->isar.regs[ID_PFR2] = u; - static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; -+ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FRINTTS) != 0; - } +- u = cpu->isar.id_mmfr3; ++ u = cpu->isar.regs[ID_MMFR3]; + u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->isar.id_mmfr3 = u; ++ cpu->isar.regs[ID_MMFR3] = u; - static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) - { - /* We always set the AdvSIMD and FP fields identically wrt FP16. */ -- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; -+ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) == 1; - } +- u = cpu->isar.id_mmfr4; ++ u = cpu->isar.regs[ID_MMFR4]; + u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ + u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ + u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ +- cpu->isar.id_mmfr4 = u; ++ cpu->isar.regs[ID_MMFR4] = u; + +- t = cpu->isar.id_aa64dfr0; ++ t = cpu->isar.regs[ID_AA64DFR0]; + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ +- cpu->isar.id_aa64dfr0 = t; ++ cpu->isar.regs[ID_AA64DFR0] = t; + +- u = cpu->isar.id_dfr0; ++ u = cpu->isar.regs[ID_DFR0]; + u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ +- cpu->isar.id_dfr0 = u; ++ cpu->isar.regs[ID_DFR0] = u; - static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2; -+ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, EL0) >= 2; - } +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ + u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; - static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; -+ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, SVE) != 0; + #ifdef CONFIG_USER_ONLY + /* For usermode -cpu max we can use a larger and more efficient DCZ +@@ -903,18 +903,18 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->revidr = 0x00000000; + cpu->ctr = 0x86668006; + cpu->reset_sctlr = 0x30000180; +- cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000000; +- cpu->isar.id_aa64dfr0 = 0x0000000010305408; +- cpu->isar.id_aa64dfr1 = 0x0000000000000000; ++ cpu->isar.regs[ID_AA64PFR0] = 0x0000000101111111; /* No RAS Extensions */ ++ cpu->isar.regs[ID_AA64PFR1] = 0x0000000000000000; ++ cpu->isar.regs[ID_AA64DFR0] = 0x0000000010305408; ++ cpu->isar.regs[ID_AA64DFR1] = 0x0000000000000000; + cpu->id_aa64afr0 = 0x0000000000000000; + cpu->id_aa64afr1 = 0x0000000000000000; +- cpu->isar.id_aa64mmfr0 = 0x0000000000001122; +- cpu->isar.id_aa64mmfr1 = 0x0000000011212100; +- cpu->isar.id_aa64mmfr2 = 0x0000000000001011; +- cpu->isar.id_aa64isar0 = 0x0000000010211120; +- cpu->isar.id_aa64isar1 = 0x0000000000010001; +- cpu->isar.id_aa64zfr0 = 0x0000000000000000; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x0000000000001122; ++ cpu->isar.regs[ID_AA64MMFR1] = 0x0000000011212100; ++ cpu->isar.regs[ID_AA64MMFR2] = 0x0000000000001011; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x0000000010211120; ++ cpu->isar.regs[ID_AA64ISAR1] = 0x0000000000010001; ++ cpu->isar.regs[ID_AA64ZFR0] = 0x0000000000000000; + cpu->clidr = 0x0000000080000023; + cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ +diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c +index 13d0e9b195..be9c3166fb 100644 +--- a/target/arm/cpu_tcg.c ++++ b/target/arm/cpu_tcg.c +@@ -65,14 +65,16 @@ static void arm926_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, ++ JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. + */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPSHVEC, ++ 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPSP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); } - static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; -+ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, LO) != 0; - } + static void arm946_initfn(Object *obj) +@@ -107,14 +109,16 @@ static void arm1026_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, ++ JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. + */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPSHVEC, ++ 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPSP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); - static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; -+ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) != 0; + { + /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ +@@ -147,22 +151,22 @@ static void arm1136_r2_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4107b362; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0x2; ++ cpu->isar.regs[ID_PFR0] = 0x111; ++ cpu->isar.regs[ID_PFR1] = 0x1; ++ cpu->isar.regs[ID_DFR0] = 0x2; + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222110; ++ cpu->isar.regs[ID_ISAR0] = 0x00140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231111; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 7; } - static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; -+ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) >= 2; +@@ -178,22 +182,22 @@ static void arm1136_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4117b363; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0x2; ++ cpu->isar.regs[ID_PFR0] = 0x111; ++ cpu->isar.regs[ID_PFR1] = 0x1; ++ cpu->isar.regs[ID_DFR0] = 0x2; + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222110; ++ cpu->isar.regs[ID_ISAR0] = 0x00140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231111; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 7; } - static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; -+ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, BT) != 0; +@@ -210,22 +214,22 @@ static void arm1176_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fb767; + cpu->reset_fpsid = 0x410120b5; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x33; ++ cpu->isar.regs[ID_PFR0] = 0x111; ++ cpu->isar.regs[ID_PFR1] = 0x11; ++ cpu->isar.regs[ID_DFR0] = 0x33; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222100; +- cpu->isar.id_isar0 = 0x0140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231121; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x01141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222100; ++ cpu->isar.regs[ID_ISAR0] = 0x0140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231121; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x01141; + cpu->reset_auxcr = 7; } - static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) - { -- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && -- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; -+ return FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) >= 4 && -+ FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) != 0xf; +@@ -240,21 +244,21 @@ static void arm11mpcore_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x410fb022; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0; ++ cpu->isar.regs[ID_PFR0] = 0x111; ++ cpu->isar.regs[ID_PFR1] = 0x1; ++ cpu->isar.regs[ID_DFR0] = 0; + cpu->id_afr0 = 0x2; +- cpu->isar.id_mmfr0 = 0x01100103; +- cpu->isar.id_mmfr1 = 0x10020302; +- cpu->isar.id_mmfr2 = 0x01222000; +- cpu->isar.id_isar0 = 0x00100011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11221011; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01100103; ++ cpu->isar.regs[ID_MMFR1] = 0x10020302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222000; ++ cpu->isar.regs[ID_ISAR0] = 0x00100011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11221011; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 1; } - static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index d450b8c8..fe648752 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -116,31 +116,31 @@ static void aarch64_a57_initfn(Object *obj) - cpu->midr = 0x411fd070; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034070; +@@ -278,24 +282,24 @@ static void cortex_a8_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fc080; + cpu->reset_fpsid = 0x410330c0; +- cpu->isar.mvfr0 = 0x11110222; +- cpu->isar.mvfr1 = 0x00011111; ++ cpu->isar.regs[MVFR0] = 0x11110222; ++ cpu->isar.regs[MVFR1] = 0x00011111; + cpu->ctr = 0x82048004; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x1031; +- cpu->isar.id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x400; ++ cpu->isar.regs[ID_PFR0] = 0x1031; ++ cpu->isar.regs[ID_PFR1] = 0x11; ++ cpu->isar.regs[ID_DFR0] = 0x400; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x31100003; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01202000; +- cpu->isar.id_mmfr3 = 0x11; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x12112111; +- cpu->isar.id_isar2 = 0x21232031; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; +- cpu->isar.dbgdidr = 0x15141000; ++ cpu->isar.regs[ID_MMFR0] = 0x31100003; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01202000; ++ cpu->isar.regs[ID_MMFR3] = 0x11; ++ cpu->isar.regs[ID_ISAR0] = 0x00101111; ++ cpu->isar.regs[ID_ISAR1] = 0x12112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232031; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00111142; ++ cpu->isar.regs[DBGDIDR] = 0x15141000; + cpu->clidr = (1 << 27) | (2 << 24) | 3; + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ +@@ -352,24 +356,24 @@ static void cortex_a9_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CBAR); + cpu->midr = 0x410fc090; + cpu->reset_fpsid = 0x41033090; +- cpu->isar.mvfr0 = 0x11110222; +- cpu->isar.mvfr1 = 0x01111111; ++ cpu->isar.regs[MVFR0] = 0x11110222; ++ cpu->isar.regs[MVFR1] = 0x01111111; + cpu->ctr = 0x80038003; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x1031; +- cpu->isar.id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x000; ++ cpu->isar.regs[ID_PFR0] = 0x1031; ++ cpu->isar.regs[ID_PFR1] = 0x11; ++ cpu->isar.regs[ID_DFR0] = 0x000; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x00100103; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01230000; +- cpu->isar.id_mmfr3 = 0x00002111; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; +- cpu->isar.dbgdidr = 0x35141000; ++ cpu->isar.regs[ID_MMFR0] = 0x00100103; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01230000; ++ cpu->isar.regs[ID_MMFR3] = 0x00002111; ++ cpu->isar.regs[ID_ISAR0] = 0x00101111; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00111142; ++ cpu->isar.regs[DBGDIDR] = 0x35141000; + cpu->clidr = (1 << 27) | (1 << 24) | 3; + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ +@@ -417,28 +421,28 @@ static void cortex_a7_initfn(Object *obj) + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; + cpu->midr = 0x410fc075; + cpu->reset_fpsid = 0x41023075; - cpu->isar.mvfr0 = 0x10110222; -- cpu->isar.mvfr1 = 0x12111111; -- cpu->isar.mvfr2 = 0x00000043; +- cpu->isar.mvfr1 = 0x11111111; + cpu->isar.regs[MVFR0] = 0x10110222; -+ cpu->isar.regs[MVFR1] = 0x12111111; -+ cpu->isar.regs[MVFR2] = 0x00000043; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->isar.id_dfr0 = 0x03010066; -+ cpu->isar.regs[ID_DFR0] = 0x03010066; ++ cpu->isar.regs[MVFR1] = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x00001131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x02010555; ++ cpu->isar.regs[ID_PFR0] = 0x00001131; ++ cpu->isar.regs[ID_PFR1] = 0x00011011; ++ cpu->isar.regs[ID_DFR0] = 0x02010555; cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10101105; - cpu->isar.id_mmfr1 = 0x40000000; -- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr2 = 0x01240000; - cpu->isar.id_mmfr3 = 0x02102211; -- cpu->isar.id_isar0 = 0x02101110; -- cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232042; -- cpu->isar.id_isar3 = 0x01112131; -- cpu->isar.id_isar4 = 0x00011142; -- cpu->isar.id_isar5 = 0x00011121; -- cpu->isar.id_isar6 = 0; -- cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->isar.id_aa64dfr0 = 0x10305106; -- cpu->isar.id_aa64isar0 = 0x00011120; -- cpu->isar.id_aa64mmfr0 = 0x00001124; -- cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.regs[ID_MMFR0] = 0x10101105; + cpu->isar.regs[ID_MMFR1] = 0x40000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR2] = 0x01240000; + cpu->isar.regs[ID_MMFR3] = 0x02102211; + /* + * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; +- cpu->isar.dbgdidr = 0x3515f005; + cpu->isar.regs[ID_ISAR0] = 0x02101110; + cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232042; -+ cpu->isar.regs[ID_ISAR3] = 0x01112131; -+ cpu->isar.regs[ID_ISAR4] = 0x00011142; -+ cpu->isar.regs[ID_ISAR5] = 0x00011121; -+ cpu->isar.regs[ID_ISAR6] = 0; -+ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; -+ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; -+ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; -+ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; -+ cpu->isar.regs[DBGDIDR] = 0x3516d000; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x10011142; ++ cpu->isar.regs[DBGDIDR] = 0x3515f005; cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ -@@ -170,31 +170,31 @@ static void aarch64_a53_initfn(Object *obj) - cpu->midr = 0x410fd034; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034070; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +@@ -463,24 +467,24 @@ static void cortex_a15_initfn(Object *obj) + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; + cpu->midr = 0x412fc0f1; + cpu->reset_fpsid = 0x410430f0; - cpu->isar.mvfr0 = 0x10110222; -- cpu->isar.mvfr1 = 0x12111111; -- cpu->isar.mvfr2 = 0x00000043; +- cpu->isar.mvfr1 = 0x11111111; + cpu->isar.regs[MVFR0] = 0x10110222; -+ cpu->isar.regs[MVFR1] = 0x12111111; -+ cpu->isar.regs[MVFR2] = 0x00000043; - cpu->ctr = 0x84448004; /* L1Ip = VIPT */ - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->isar.id_dfr0 = 0x03010066; -+ cpu->isar.regs[ID_DFR0] = 0x03010066; ++ cpu->isar.regs[MVFR1] = 0x11111111; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x00001131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x02010555; ++ cpu->isar.regs[ID_PFR0] = 0x00001131; ++ cpu->isar.regs[ID_PFR1] = 0x00011011; ++ cpu->isar.regs[ID_DFR0] = 0x02010555; cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x10101105; -- cpu->isar.id_mmfr1 = 0x40000000; -- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01240000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232042; -- cpu->isar.id_isar3 = 0x01112131; -- cpu->isar.id_isar4 = 0x00011142; -- cpu->isar.id_isar5 = 0x00011121; -- cpu->isar.id_isar6 = 0; -- cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->isar.id_aa64dfr0 = 0x10305106; -- cpu->isar.id_aa64isar0 = 0x00011120; -- cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ -- cpu->isar.dbgdidr = 0x3516d000; -+ cpu->isar.regs[ID_MMFR0] = 0x10101105; -+ cpu->isar.regs[ID_MMFR1] = 0x40000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01260000; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; +- cpu->isar.dbgdidr = 0x3515f021; ++ cpu->isar.regs[ID_MMFR0] = 0x10201105; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01240000; + cpu->isar.regs[ID_MMFR3] = 0x02102211; + cpu->isar.regs[ID_ISAR0] = 0x02101110; + cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232042; -+ cpu->isar.regs[ID_ISAR3] = 0x01112131; -+ cpu->isar.regs[ID_ISAR4] = 0x00011142; -+ cpu->isar.regs[ID_ISAR5] = 0x00011121; -+ cpu->isar.regs[ID_ISAR6] = 0; -+ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; -+ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; -+ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; -+ cpu->isar.regs[ID_AA64MMFR0] = 0x00001122; /* 40 bit physical addr */ -+ cpu->isar.regs[DBGDIDR] = 0x3516d000; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x10011142; ++ cpu->isar.regs[DBGDIDR] = 0x3515f021; cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ -@@ -224,30 +224,30 @@ static void aarch64_a72_initfn(Object *obj) - cpu->midr = 0x410fd083; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034080; -- cpu->isar.mvfr0 = 0x10110222; -- cpu->isar.mvfr1 = 0x12111111; -- cpu->isar.mvfr2 = 0x00000043; -+ cpu->isar.regs[MVFR0] = 0x10110222; -+ cpu->isar.regs[MVFR1] = 0x12111111; -+ cpu->isar.regs[MVFR2] = 0x00000043; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50838; - cpu->id_pfr0 = 0x00000131; - cpu->id_pfr1 = 0x00011011; -- cpu->isar.id_dfr0 = 0x03010066; -+ cpu->isar.regs[ID_DFR0] = 0x03010066; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +@@ -504,21 +508,21 @@ static void cortex_m0_initfn(Object *obj) + * by looking at ID register fields. We use the same values as + * for the M3. + */ +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[ID_PFR0] = 0x00000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000200; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00000030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x00000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01141110; ++ cpu->isar.regs[ID_ISAR1] = 0x02111000; ++ cpu->isar.regs[ID_ISAR2] = 0x21112231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111110; ++ cpu->isar.regs[ID_ISAR4] = 0x01310102; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m3_initfn(Object *obj) +@@ -529,21 +533,21 @@ static void cortex_m3_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + cpu->midr = 0x410fc231; + cpu->pmsav7_dregion = 8; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[ID_PFR0] = 0x00000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000200; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00000030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x00000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01141110; ++ cpu->isar.regs[ID_ISAR1] = 0x02111000; ++ cpu->isar.regs[ID_ISAR2] = 0x21112231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111110; ++ cpu->isar.regs[ID_ISAR4] = 0x01310102; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m4_initfn(Object *obj) +@@ -556,24 +560,24 @@ static void cortex_m4_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x410fc240; /* r0p0 */ + cpu->pmsav7_dregion = 8; +- cpu->isar.mvfr0 = 0x10110021; +- cpu->isar.mvfr1 = 0x11000011; +- cpu->isar.mvfr2 = 0x00000000; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[MVFR0] = 0x10110021; ++ cpu->isar.regs[MVFR1] = 0x11000011; ++ cpu->isar.regs[MVFR2] = 0x00000000; ++ cpu->isar.regs[ID_PFR0] = 0x00000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000200; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00000030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x00000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01141110; ++ cpu->isar.regs[ID_ISAR1] = 0x02111000; ++ cpu->isar.regs[ID_ISAR2] = 0x21112231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111110; ++ cpu->isar.regs[ID_ISAR4] = 0x01310102; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m7_initfn(Object *obj) +@@ -586,24 +590,24 @@ static void cortex_m7_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x411fc272; /* r1p2 */ + cpu->pmsav7_dregion = 8; +- cpu->isar.mvfr0 = 0x10110221; +- cpu->isar.mvfr1 = 0x12000011; +- cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[MVFR0] = 0x10110221; ++ cpu->isar.regs[MVFR1] = 0x12000011; ++ cpu->isar.regs[MVFR2] = 0x00000040; ++ cpu->isar.regs[ID_PFR0] = 0x00000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000200; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; cpu->id_afr0 = 0x00000000; -- cpu->isar.id_mmfr0 = 0x10201105; -- cpu->isar.id_mmfr1 = 0x40000000; -- cpu->isar.id_mmfr2 = 0x01260000; -- cpu->isar.id_mmfr3 = 0x02102211; -- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_mmfr0 = 0x00100030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01101110; +- cpu->isar.id_isar1 = 0x02112000; +- cpu->isar.id_isar2 = 0x20232231; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00100030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01101110; ++ cpu->isar.regs[ID_ISAR1] = 0x02112000; ++ cpu->isar.regs[ID_ISAR2] = 0x20232231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111131; ++ cpu->isar.regs[ID_ISAR4] = 0x01310132; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m33_initfn(Object *obj) +@@ -618,24 +622,24 @@ static void cortex_m33_initfn(Object *obj) + cpu->midr = 0x410fd213; /* r0p3 */ + cpu->pmsav7_dregion = 16; + cpu->sau_sregion = 8; +- cpu->isar.mvfr0 = 0x10110021; +- cpu->isar.mvfr1 = 0x11000011; +- cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000210; +- cpu->isar.id_dfr0 = 0x00200000; ++ cpu->isar.regs[MVFR0] = 0x10110021; ++ cpu->isar.regs[MVFR1] = 0x11000011; ++ cpu->isar.regs[MVFR2] = 0x00000040; ++ cpu->isar.regs[ID_PFR0] = 0x00000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000210; ++ cpu->isar.regs[ID_DFR0] = 0x00200000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00101F40; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01101110; +- cpu->isar.id_isar1 = 0x02212000; +- cpu->isar.id_isar2 = 0x20232232; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00101F40; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01101110; ++ cpu->isar.regs[ID_ISAR1] = 0x02212000; ++ cpu->isar.regs[ID_ISAR2] = 0x20232232; ++ cpu->isar.regs[ID_ISAR3] = 0x01111131; ++ cpu->isar.regs[ID_ISAR4] = 0x01310132; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + cpu->clidr = 0x00000000; + cpu->ctr = 0x8000c000; + } +@@ -655,24 +659,24 @@ static void cortex_m55_initfn(Object *obj) + cpu->pmsav7_dregion = 16; + cpu->sau_sregion = 8; + /* These are the MVFR* values for the FPU + full MVE configuration */ +- cpu->isar.mvfr0 = 0x10110221; +- cpu->isar.mvfr1 = 0x12100211; +- cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x20000030; +- cpu->isar.id_pfr1 = 0x00000230; +- cpu->isar.id_dfr0 = 0x10200000; ++ cpu->isar.regs[MVFR0] = 0x10110221; ++ cpu->isar.regs[MVFR1] = 0x12100211; ++ cpu->isar.regs[MVFR2] = 0x00000040; ++ cpu->isar.regs[ID_PFR0] = 0x20000030; ++ cpu->isar.regs[ID_PFR1] = 0x00000230; ++ cpu->isar.regs[ID_DFR0] = 0x10200000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00111040; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000011; +- cpu->isar.id_isar0 = 0x01103110; +- cpu->isar.id_isar1 = 0x02212000; +- cpu->isar.id_isar2 = 0x20232232; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00111040; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000011; ++ cpu->isar.regs[ID_ISAR0] = 0x01103110; ++ cpu->isar.regs[ID_ISAR1] = 0x02212000; ++ cpu->isar.regs[ID_ISAR2] = 0x20232232; ++ cpu->isar.regs[ID_ISAR3] = 0x01111131; ++ cpu->isar.regs[ID_ISAR4] = 0x01310132; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + cpu->clidr = 0x00000000; /* caches not implemented */ + cpu->ctr = 0x8303c003; + } +@@ -697,21 +701,21 @@ static void cortex_r5_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_PMSA); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x411fc153; /* r1p3 */ +- cpu->isar.id_pfr0 = 0x0131; +- cpu->isar.id_pfr1 = 0x001; +- cpu->isar.id_dfr0 = 0x010400; ++ cpu->isar.regs[ID_PFR0] = 0x0131; ++ cpu->isar.regs[ID_PFR1] = 0x001; ++ cpu->isar.regs[ID_DFR0] = 0x010400; + cpu->id_afr0 = 0x0; +- cpu->isar.id_mmfr0 = 0x0210030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01200000; +- cpu->isar.id_mmfr3 = 0x0211; +- cpu->isar.id_isar0 = 0x02101111; - cpu->isar.id_isar1 = 0x13112111; -- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar2 = 0x21232141; - cpu->isar.id_isar3 = 0x01112131; -- cpu->isar.id_isar4 = 0x00011142; -- cpu->isar.id_isar5 = 0x00011121; -- cpu->isar.id_aa64pfr0 = 0x00002222; -- cpu->isar.id_aa64dfr0 = 0x10305106; -- cpu->isar.id_aa64isar0 = 0x00011120; -- cpu->isar.id_aa64mmfr0 = 0x00001124; -- cpu->isar.dbgdidr = 0x3516d000; -+ cpu->isar.regs[ID_MMFR0] = 0x10201105; -+ cpu->isar.regs[ID_MMFR1] = 0x40000000; -+ cpu->isar.regs[ID_MMFR2] = 0x01260000; -+ cpu->isar.regs[ID_MMFR3] = 0x02102211; -+ cpu->isar.regs[ID_ISAR0] = 0x02101110; +- cpu->isar.id_isar4 = 0x0010142; +- cpu->isar.id_isar5 = 0x0; +- cpu->isar.id_isar6 = 0x0; ++ cpu->isar.regs[ID_MMFR0] = 0x0210030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01200000; ++ cpu->isar.regs[ID_MMFR3] = 0x0211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101111; + cpu->isar.regs[ID_ISAR1] = 0x13112111; -+ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR2] = 0x21232141; + cpu->isar.regs[ID_ISAR3] = 0x01112131; -+ cpu->isar.regs[ID_ISAR4] = 0x00011142; -+ cpu->isar.regs[ID_ISAR5] = 0x00011121; -+ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; -+ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; -+ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; -+ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; -+ cpu->isar.regs[DBGDIDR] = 0x3516d000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ -@@ -275,10 +275,10 @@ static void aarch64_kunpeng_920_initfn(Object *obj) ++ cpu->isar.regs[ID_ISAR4] = 0x0010142; ++ cpu->isar.regs[ID_ISAR5] = 0x0; ++ cpu->isar.regs[ID_ISAR6] = 0x0; + cpu->mp_is_up = true; + cpu->pmsav7_dregion = 16; + define_arm_cp_regs(cpu, cortexr5_cp_reginfo); +@@ -722,8 +726,8 @@ static void cortex_r5f_initfn(Object *obj) + ARMCPU *cpu = ARM_CPU(obj); - cpu->midr = 0x480fd010; - cpu->ctr = 0x84448004; -- cpu->isar.id_aa64pfr0 = 0x11001111; -- cpu->isar.id_aa64dfr0 = 0x110305408; -- cpu->isar.id_aa64isar0 = 0x10211120; -- cpu->isar.id_aa64mmfr0 = 0x101125; -+ cpu->isar.regs[ID_AA64PFR0] = 0x11001111; -+ cpu->isar.regs[ID_AA64DFR0] = 0x110305408; -+ cpu->isar.regs[ID_AA64ISAR0] = 0x10211120; -+ cpu->isar.regs[ID_AA64MMFR0] = 0x101125; + cortex_r5_initfn(obj); +- cpu->isar.mvfr0 = 0x10110221; +- cpu->isar.mvfr1 = 0x00000011; ++ cpu->isar.regs[MVFR0] = 0x10110221; ++ cpu->isar.regs[MVFR1] = 0x00000011; } - static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, -@@ -321,7 +321,7 @@ static void aarch64_max_initfn(Object *obj) - uint32_t u; - aarch64_a57_initfn(obj); - -- t = cpu->isar.id_aa64isar0; -+ t = cpu->isar.regs[ID_AA64ISAR0]; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ -@@ -335,9 +335,9 @@ static void aarch64_max_initfn(Object *obj) - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); -- cpu->isar.id_aa64isar0 = t; -+ cpu->isar.regs[ID_AA64ISAR0] = t; - -- t = cpu->isar.id_aa64isar1; -+ t = cpu->isar.regs[ID_AA64ISAR1]; - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */ -@@ -347,45 +347,45 @@ static void aarch64_max_initfn(Object *obj) - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); -- cpu->isar.id_aa64isar1 = t; -+ cpu->isar.regs[ID_AA64ISAR1] = t; - -- t = cpu->isar.id_aa64pfr0; -+ t = cpu->isar.regs[ID_AA64PFR0]; - t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); -- cpu->isar.id_aa64pfr0 = t; -+ cpu->isar.regs[ID_AA64PFR0] = t; - -- t = cpu->isar.id_aa64pfr1; -+ t = cpu->isar.regs[ID_AA64PFR1]; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); -- cpu->isar.id_aa64pfr1 = t; -+ cpu->isar.regs[ID_AA64PFR1] = t; - -- t = cpu->isar.id_aa64mmfr1; -+ t = cpu->isar.regs[ID_AA64MMFR1]; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ -- cpu->isar.id_aa64mmfr1 = t; -+ cpu->isar.regs[ID_AA64MMFR1] = t; - - /* Replicate the same data to the 32-bit id registers. */ -- u = cpu->isar.id_isar5; -+ u = cpu->isar.regs[ID_ISAR5]; - u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ - u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); - u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); - u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); - u = FIELD_DP32(u, ID_ISAR5, RDM, 1); - u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); -- cpu->isar.id_isar5 = u; -+ cpu->isar.regs[ID_ISAR5] = u; - -- u = cpu->isar.id_isar6; -+ u = cpu->isar.regs[ID_ISAR6]; - u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); - u = FIELD_DP32(u, ID_ISAR6, DP, 1); - u = FIELD_DP32(u, ID_ISAR6, FHM, 1); - u = FIELD_DP32(u, ID_ISAR6, SB, 1); - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); -- cpu->isar.id_isar6 = u; -+ cpu->isar.regs[ID_ISAR6] = u; + static void ti925t_initfn(Object *obj) +@@ -942,7 +946,8 @@ static void arm_max_initfn(Object *obj) + cortex_a15_initfn(obj); -- u = cpu->isar.id_mmfr3; -+ u = cpu->isar.regs[ID_MMFR3]; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ -- cpu->isar.id_mmfr3 = u; -+ cpu->isar.regs[ID_MMFR3] = u; + /* old-style VFP short-vector support */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPSHVEC, ++ 1); - /* - * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, + #ifdef CONFIG_USER_ONLY + /* +@@ -954,16 +959,16 @@ static void arm_max_initfn(Object *obj) + { + uint32_t t; + +- t = cpu->isar.id_isar5; ++ t = cpu->isar.regs[ID_ISAR5]; + t = FIELD_DP32(t, ID_ISAR5, AES, 2); + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); +- cpu->isar.id_isar5 = t; ++ cpu->isar.regs[ID_ISAR5] = t; + +- t = cpu->isar.id_isar6; ++ t = cpu->isar.regs[ID_ISAR6]; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); + t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); +@@ -971,36 +976,36 @@ static void arm_max_initfn(Object *obj) + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); +- cpu->isar.id_isar6 = t; ++ cpu->isar.regs[ID_ISAR6] = t; + +- t = cpu->isar.mvfr1; ++ t = cpu->isar.regs[MVFR1]; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ +- cpu->isar.mvfr1 = t; ++ cpu->isar.regs[MVFR1] = t; + +- t = cpu->isar.mvfr2; ++ t = cpu->isar.regs[MVFR2]; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ +- cpu->isar.mvfr2 = t; ++ cpu->isar.regs[MVFR2] = t; + +- t = cpu->isar.id_mmfr3; ++ t = cpu->isar.regs[ID_MMFR3]; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->isar.id_mmfr3 = t; ++ cpu->isar.regs[ID_MMFR3] = t; + +- t = cpu->isar.id_mmfr4; ++ t = cpu->isar.regs[ID_MMFR4]; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ +- cpu->isar.id_mmfr4 = t; ++ cpu->isar.regs[ID_MMFR4] = t; + +- t = cpu->isar.id_pfr0; ++ t = cpu->isar.regs[ID_PFR0]; + t = FIELD_DP32(t, ID_PFR0, DIT, 1); +- cpu->isar.id_pfr0 = t; ++ cpu->isar.regs[ID_PFR0] = t; + +- t = cpu->isar.id_pfr2; ++ t = cpu->isar.regs[ID_PFR2]; + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); +- cpu->isar.id_pfr2 = t; ++ cpu->isar.regs[ID_PFR2] = t; + } + #endif /* CONFIG_USER_ONLY */ + } diff --git a/target/arm/helper.c b/target/arm/helper.c -index 49cd7a7e..459af431 100644 +index 9b317899a6..b8ea1dc1f6 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c -@@ -5597,7 +5597,7 @@ static void define_debug_regs(ARMCPU *cpu) - ARMCPRegInfo dbgdidr = { - .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL0_R, .accessfn = access_tda, -- .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, -+ .type = ARM_CP_CONST, .resetvalue = cpu->isar.regs[DBGDIDR], - }; +@@ -6547,12 +6547,12 @@ static void define_debug_regs(ARMCPU *cpu) + * use AArch32. Given that bit 15 is RES1, if the value is 0 then + * the register must not exist for this cpu. + */ +- if (cpu->isar.dbgdidr != 0) { ++ if (cpu->isar.regs[DBGDIDR] != 0) { + ARMCPRegInfo dbgdidr = { + .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, + .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tda, +- .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, ++ .type = ARM_CP_CONST, .resetvalue = cpu->isar.regs[DBGDIDR], + }; + define_one_arm_cp_reg(cpu, &dbgdidr); + } +@@ -6707,7 +6707,7 @@ static void define_pmu_regs(ARMCPU *cpu) + static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) + { + ARMCPU *cpu = env_archcpu(env); +- uint64_t pfr1 = cpu->isar.id_pfr1; ++ uint64_t pfr1 = cpu->isar.regs[ID_PFR1]; - /* Note that all these register fields hold "number of Xs minus 1". */ -@@ -5672,7 +5672,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) + if (env->gicv3state) { + pfr1 |= 1 << 28; +@@ -6719,7 +6719,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = env_archcpu(env); @@ -1554,168 +2315,250 @@ index 49cd7a7e..459af431 100644 if (env->gicv3state) { pfr0 |= 1 << 24; -@@ -5898,7 +5898,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, +@@ -7501,7 +7501,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_pfr0 }, ++ .resetvalue = cpu->isar.regs[ID_PFR0] }, + /* ID_PFR1 is not a plain ARM_CP_CONST because we don't know + * the value of the GIC field until after we define these regs. + */ +@@ -7515,7 +7515,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_dfr0 }, + .resetvalue = cpu->isar.regs[ID_DFR0] }, { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, -@@ -5906,51 +5906,51 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_MMFR0", .state = ARM_CP_STATE_BOTH, +@@ -7525,62 +7525,62 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_mmfr0 }, + .resetvalue = cpu->isar.regs[ID_MMFR0] }, { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_mmfr1 }, + .resetvalue = cpu->isar.regs[ID_MMFR1] }, { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_mmfr2 }, + .resetvalue = cpu->isar.regs[ID_MMFR2] }, { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_mmfr3 }, + .resetvalue = cpu->isar.regs[ID_MMFR3] }, { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar0 }, + .resetvalue = cpu->isar.regs[ID_ISAR0] }, { .name = "ID_ISAR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar1 }, + .resetvalue = cpu->isar.regs[ID_ISAR1] }, { .name = "ID_ISAR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar2 }, + .resetvalue = cpu->isar.regs[ID_ISAR2] }, { .name = "ID_ISAR3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar3 }, + .resetvalue = cpu->isar.regs[ID_ISAR3] }, { .name = "ID_ISAR4", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar4 }, + .resetvalue = cpu->isar.regs[ID_ISAR4] }, { .name = "ID_ISAR5", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar5 }, + .resetvalue = cpu->isar.regs[ID_ISAR5] }, { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_mmfr4 }, + .resetvalue = cpu->isar.regs[ID_MMFR4] }, { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, - .resetvalue = cpu->isar.id_isar6 }, + .resetvalue = cpu->isar.regs[ID_ISAR6] }, REGINFO_SENTINEL }; define_arm_cp_regs(cpu, v6_idregs); -@@ -6074,7 +6074,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64, +@@ -7630,7 +7630,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .access = PL1_R, + #ifdef CONFIG_USER_ONLY + .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64pfr0 ++ .resetvalue = cpu->isar.regs[ID_AA64PFR0] + #else + .type = ARM_CP_NO_RAW, + .accessfn = access_aa64_tid3, +@@ -7642,7 +7642,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64pfr1}, + .resetvalue = cpu->isar.regs[ID_AA64PFR1]}, { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, -@@ -6103,11 +6103,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64, +@@ -7657,7 +7657,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64zfr0 }, ++ .resetvalue = cpu->isar.regs[ID_AA64ZFR0] }, + { .name = "ID_AA64PFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -7677,12 +7677,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64dfr0 }, + .resetvalue = cpu->isar.regs[ID_AA64DFR0] }, { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64dfr1 }, + .resetvalue = cpu->isar.regs[ID_AA64DFR1] }, { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, -@@ -6135,11 +6135,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64, +@@ -7717,12 +7717,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64isar0 }, + .resetvalue = cpu->isar.regs[ID_AA64ISAR0] }, { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64isar1 }, + .resetvalue = cpu->isar.regs[ID_AA64ISAR1] }, { .name = "ID_AA64ISAR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, -@@ -6167,15 +6167,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64, +@@ -7757,17 +7757,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64mmfr0 }, + .resetvalue = cpu->isar.regs[ID_AA64MMFR0] }, { .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64mmfr1 }, + .resetvalue = cpu->isar.regs[ID_AA64MMFR1] }, { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.id_aa64mmfr2 }, + .resetvalue = cpu->isar.regs[ID_AA64MMFR2] }, { .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, -@@ -6199,15 +6199,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) - { .name = "MVFR0_EL1", .state = ARM_CP_STATE_AA64, +@@ -7797,17 +7797,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.mvfr0 }, + .resetvalue = cpu->isar.regs[MVFR0] }, { .name = "MVFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.mvfr1 }, + .resetvalue = cpu->isar.regs[MVFR1] }, { .name = "MVFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, - .resetvalue = cpu->isar.mvfr2 }, + .resetvalue = cpu->isar.regs[MVFR2] }, { .name = "MVFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, -@@ -6426,7 +6426,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) - define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); - define_arm_cp_regs(cpu, vmsa_cp_reginfo); - /* TTCBR2 is introduced with ARMv8.2-A32HPD. */ -- if (FIELD_EX32(cpu->isar.id_mmfr4, ID_MMFR4, HPDS) != 0) { -+ if (FIELD_EX32(cpu->isar.regs[ID_MMFR4], ID_MMFR4, HPDS) != 0) { - define_one_arm_cp_reg(cpu, &ttbcr2_reginfo); - } - } +@@ -7817,7 +7817,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_pfr2 }, ++ .resetvalue = cpu->isar.regs[ID_PFR2] }, + { .name = "MVFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index 0dc96560d3..66ad698df1 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -449,15 +449,15 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + int reg; + uint64_t *val; + } regs[] = { +- { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.id_aa64pfr0 }, +- { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 }, +- { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 }, +- { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 }, +- { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.id_aa64isar0 }, +- { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 }, +- { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 }, +- { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 }, +- { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.id_aa64mmfr2 }, ++ { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.regs[ID_AA64PFR0] }, ++ { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.regs[ID_AA64PFR1] }, ++ { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.regs[ID_AA64DFR0] }, ++ { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.regs[ID_AA64DFR1] }, ++ { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.regs[ID_AA64ISAR0] }, ++ { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.regs[ID_AA64ISAR1] }, ++ { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.regs[ID_AA64MMFR0] }, ++ { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.regs[ID_AA64MMFR1] }, ++ { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.regs[ID_AA64MMFR2] }, + }; + hv_vcpu_t fd; + hv_return_t r = HV_SUCCESS; +@@ -593,7 +593,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) + + /* We're limited to underlying hardware caps, override internal versions */ + ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64MMFR0_EL1, +- &arm_cpu->isar.id_aa64mmfr0); ++ &arm_cpu->isar.regs[ID_AA64MMFR0]); + assert_hvf_ok(ret); + + return 0; diff --git a/target/arm/internals.h b/target/arm/internals.h -index 1d01ecc4..2da13ba8 100644 +index 89f7610ebc..0ea225e480 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h -@@ -237,7 +237,7 @@ static inline unsigned int arm_pamax(ARMCPU *cpu) +@@ -254,7 +254,7 @@ static inline unsigned int arm_pamax(ARMCPU *cpu) [5] = 48, }; unsigned int parange = @@ -1724,7 +2567,7 @@ index 1d01ecc4..2da13ba8 100644 /* id_aa64mmfr0 is a read-only register so values outside of the * supported mappings can be considered an implementation error. */ -@@ -865,9 +865,9 @@ static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) +@@ -808,9 +808,9 @@ static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) static inline int arm_num_brps(ARMCPU *cpu) { if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { @@ -1736,7 +2579,7 @@ index 1d01ecc4..2da13ba8 100644 } } -@@ -879,9 +879,9 @@ static inline int arm_num_brps(ARMCPU *cpu) +@@ -822,9 +822,9 @@ static inline int arm_num_brps(ARMCPU *cpu) static inline int arm_num_wrps(ARMCPU *cpu) { if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { @@ -1748,13 +2591,12 @@ index 1d01ecc4..2da13ba8 100644 } } -@@ -893,9 +893,10 @@ static inline int arm_num_wrps(ARMCPU *cpu) +@@ -836,9 +836,9 @@ static inline int arm_num_wrps(ARMCPU *cpu) static inline int arm_num_ctx_cmps(ARMCPU *cpu) { if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; -+ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, -+ CTX_CMPS) + 1; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, CTX_CMPS) + 1; } else { - return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; + return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, CTX_CMPS) + 1; @@ -1762,11 +2604,11 @@ index 1d01ecc4..2da13ba8 100644 } diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index 2a88b8df..06cf31e8 100644 +index e790d6c9a5..4f97e516c2 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c -@@ -455,7 +455,7 @@ static inline void unset_feature(uint64_t *features, int feature) - *features &= ~(1ULL << feature); +@@ -468,7 +468,7 @@ void kvm_arm_pvtime_init(CPUState *cs, uint64_t ipa) + } } -static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) @@ -1774,7 +2616,7 @@ index 2a88b8df..06cf31e8 100644 { uint64_t ret; struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)&ret }; -@@ -509,7 +509,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) +@@ -528,7 +528,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ahcf->target = init.target; ahcf->dtb_compatible = "arm,arm-v8"; @@ -1783,7 +2625,7 @@ index 2a88b8df..06cf31e8 100644 ARM64_SYS_REG(3, 0, 0, 4, 0)); if (unlikely(err < 0)) { /* -@@ -528,24 +528,24 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) +@@ -547,24 +547,24 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * ??? Either of these sounds like too much effort just * to work around running a modern host kernel. */ @@ -1817,10 +2659,19 @@ index 2a88b8df..06cf31e8 100644 ARM64_SYS_REG(3, 0, 0, 7, 2)); /* -@@ -555,38 +555,38 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) +@@ -574,44 +574,44 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * than skipping the reads and leaving 0, as we must avoid * considering the values in every case. */ +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_PFR0], + ARM64_SYS_REG(3, 0, 0, 1, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_PFR1], + ARM64_SYS_REG(3, 0, 0, 1, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_PFR2], + ARM64_SYS_REG(3, 0, 0, 3, 4)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, + err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_DFR0], ARM64_SYS_REG(3, 0, 0, 1, 2)); @@ -1872,7 +2723,7 @@ index 2a88b8df..06cf31e8 100644 ARM64_SYS_REG(3, 0, 0, 3, 2)); /* -@@ -599,14 +599,16 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) +@@ -624,14 +624,17 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does. * We only do this if the CPU supports AArch32 at EL1. */ @@ -1880,13 +2731,14 @@ index 2a88b8df..06cf31e8 100644 - int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); - int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); + if (FIELD_EX32(ahcf->isar.regs[ID_AA64PFR0], ID_AA64PFR0, EL1) >= 2) { -+ int wrps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], -+ ID_AA64DFR0, WRPS); -+ int brps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], -+ ID_AA64DFR0, BRPS); ++ int wrps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ID_AA64DFR0, ++ WRPS); ++ int brps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ID_AA64DFR0, ++ BRPS); int ctx_cmps = - FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); -+ FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ID_AA64DFR0, CTX_CMPS); ++ FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ID_AA64DFR0, ++ CTX_CMPS); int version = 6; /* ARMv8 debug architecture */ bool has_el3 = - !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3); @@ -1894,7 +2746,7 @@ index 2a88b8df..06cf31e8 100644 uint32_t dbgdidr = 0; dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); -@@ -616,7 +618,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) +@@ -641,7 +644,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3); dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3); dbgdidr |= (1 << 15); /* RES1 bit */ @@ -1903,6 +2755,27 @@ index 2a88b8df..06cf31e8 100644 } } +@@ -649,9 +652,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + + /* Add feature bits that can't appear until after VCPU init. */ + if (sve_supported) { +- t = ahcf->isar.id_aa64pfr0; ++ t = ahcf->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); +- ahcf->isar.id_aa64pfr0 = t; ++ ahcf->isar.regs[ID_AA64PFR0] = t; + + /* + * Before v5.1, KVM did not support SVE and did not expose +@@ -659,7 +662,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * not expose the register to "user" requests like this + * unless the host supports SVE. + */ +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ZFR0], + ARM64_SYS_REG(3, 0, 0, 4, 4)); + } + -- -2.25.1 +2.27.0 diff --git a/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch b/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch deleted file mode 100644 index 41c67cf1b8024af9f48888ecd782e9927a2f166e..0000000000000000000000000000000000000000 --- a/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 860035652c7866b033762f6d90f81d5ddedf855c Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 22 Apr 2020 17:08:43 +0800 -Subject: [PATCH] target/arm/cpu: Add the kvm-no-adjvtime CPU property - -kvm-no-adjvtime is a KVM specific CPU property and a first of its -kind. To accommodate it we also add kvm_arm_add_vcpu_properties() -and a KVM specific CPU properties description to the CPU features -document. - -Signed-off-by: Andrew Jones -Message-id: 20200120101023.16030-7-drjones@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index e9a2a959..cfda6cc5 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -1748,6 +1748,11 @@ static void machvirt_init(MachineState *machine) - } - } - -+ if (vmc->kvm_no_adjvtime && -+ object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { -+ object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); -+ } -+ - if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { - object_property_set_bool(cpuobj, false, "pmu", NULL); - } -diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 43a6ce91..a9d6977a 100644 ---- a/include/hw/arm/virt.h -+++ b/include/hw/arm/virt.h -@@ -107,6 +107,7 @@ typedef struct { - bool claim_edge_triggered_timers; - bool smbios_old_sys_ver; - bool no_highmem_ecam; -+ bool kvm_no_adjvtime; - } VirtMachineClass; - - typedef struct { -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index bc3da9a3..39bbe7e2 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -2441,6 +2441,7 @@ static void arm_max_initfn(Object *obj) - - if (kvm_enabled()) { - kvm_arm_set_cpu_features_from_host(cpu); -+ kvm_arm_add_vcpu_properties(obj); - } else { - cortex_a15_initfn(obj); - -@@ -2629,6 +2630,7 @@ static void arm_host_initfn(Object *obj) - ARMCPU *cpu = ARM_CPU(obj); - - kvm_arm_set_cpu_features_from_host(cpu); -+ kvm_arm_add_vcpu_properties(obj); - arm_cpu_post_init(obj); - } - -diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index dbf44b92..b30ca7c9 100644 ---- a/target/arm/cpu64.c -+++ b/target/arm/cpu64.c -@@ -312,6 +312,7 @@ static void aarch64_max_initfn(Object *obj) - - if (kvm_enabled()) { - kvm_arm_set_cpu_features_from_host(cpu); -+ kvm_arm_add_vcpu_properties(obj); - } else { - uint64_t t; - uint32_t u; -diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index 21fb7ecd..327b3bc3 100644 ---- a/target/arm/kvm.c -+++ b/target/arm/kvm.c -@@ -16,6 +16,8 @@ - #include "qemu-common.h" - #include "qemu/timer.h" - #include "qemu/error-report.h" -+#include "qom/object.h" -+#include "qapi/error.h" - #include "sysemu/sysemu.h" - #include "sysemu/kvm.h" - #include "sysemu/kvm_int.h" -@@ -162,6 +164,32 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) - env->features = arm_host_cpu_features.features; - } - -+static bool kvm_no_adjvtime_get(Object *obj, Error **errp) -+{ -+ return !ARM_CPU(obj)->kvm_adjvtime; -+} -+ -+static void kvm_no_adjvtime_set(Object *obj, bool value, Error **errp) -+{ -+ ARM_CPU(obj)->kvm_adjvtime = !value; -+} -+ -+/* KVM VCPU properties should be prefixed with "kvm-". */ -+void kvm_arm_add_vcpu_properties(Object *obj) -+{ -+ if (!kvm_enabled()) { -+ return; -+ } -+ -+ ARM_CPU(obj)->kvm_adjvtime = true; -+ object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get, -+ kvm_no_adjvtime_set, &error_abort); -+ object_property_set_description(obj, "kvm-no-adjvtime", -+ "Set on to disable the adjustment of " -+ "the virtual counter. VM stopped time " -+ "will be counted.", &error_abort); -+} -+ - int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - { - KVMState *s = KVM_STATE(ms->accelerator); -diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 97560d4e..0de5f83e 100644 ---- a/target/arm/kvm_arm.h -+++ b/target/arm/kvm_arm.h -@@ -230,6 +230,15 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); - */ - void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); - -+/** -+ * kvm_arm_add_vcpu_properties: -+ * @obj: The CPU object to add the properties to -+ * -+ * Add all KVM specific CPU properties to the CPU object. These -+ * are the CPU properties with "kvm-" prefixed names. -+ */ -+void kvm_arm_add_vcpu_properties(Object *obj); -+ - /** - * kvm_arm_get_max_vm_ipa_size: - * @ms: Machine state handle -@@ -294,6 +303,8 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) - cpu->host_cpu_probe_failed = true; - } - -+static inline void kvm_arm_add_vcpu_properties(Object *obj) {} -+ - static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - { - return -ENOENT; --- -2.23.0 diff --git a/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch b/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch index cf9bb73b8f5bf63c5e073042ca137266fd28e894..edb4ea44c77e024c9104895c149040f364c11f79 100644 --- a/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch +++ b/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch @@ -1,4 +1,4 @@ -From dfedc889fafd35efd4f8382b7672bf0e556f9f45 Mon Sep 17 00:00:00 2001 +From 4558dc5590b89b1252baea2734c2b3668566e5cb Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Mon, 7 Sep 2020 14:07:07 +0800 Subject: [PATCH] target/arm: ignore evtstrm and cpuid CPU features @@ -14,16 +14,17 @@ However, they are exposed by getauxval() and /proc/cpuinfo. Hence, let's report and ignore the CPU features if someone set them. Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu64.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index 7de20848..726d123d 100644 +index 9e5179afbe..287e7ac91c 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -506,10 +506,37 @@ static void arm_cpu_parse_featurestr(const char *typename, char *features, - } +@@ -982,10 +982,37 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) + return g_strdup("aarch64"); } +static const char *unconfigurable_feats[] = { @@ -62,5 +63,5 @@ index 7de20848..726d123d 100644 prop->property = g_strdup(name); prop->value = g_strdup(val); -- -2.28.0 +2.27.0 diff --git a/target-arm-introduce-CPU-feature-dependency-mechanis.patch b/target-arm-introduce-CPU-feature-dependency-mechanis.patch index 8c47cba243d4890cfc205c6c9b5b04b37705664f..aecfbf8991d1fc259c2efe06cf4a32bec39ac1e0 100644 --- a/target-arm-introduce-CPU-feature-dependency-mechanis.patch +++ b/target-arm-introduce-CPU-feature-dependency-mechanis.patch @@ -1,7 +1,7 @@ -From da538bb9d1acc22543a2b7b07ae35a62386bf226 Mon Sep 17 00:00:00 2001 +From 632d58d1b908ee979074b589417f446c0a3be35d Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:46 +0800 -Subject: [PATCH 5/9] target/arm: introduce CPU feature dependency mechanism +Subject: [PATCH] target/arm: introduce CPU feature dependency mechanism Some CPU features are dependent on other CPU features. For example, ID_AA64PFR0_EL1.FP field and ID_AA64PFR0_EL1.AdvSIMD must have the same @@ -21,15 +21,16 @@ user, then b and c is disabled automatically. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 3f63312c..d5576538 100644 +index c081ecc12b..ee09642dae 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1306,6 +1306,103 @@ static struct CPUFeatureInfo cpu_features[] = { +@@ -1483,6 +1483,103 @@ static struct CPUFeatureInfo cpu_features[] = { }, }; @@ -133,7 +134,7 @@ index 3f63312c..d5576538 100644 static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { -@@ -1342,13 +1439,45 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, +@@ -1519,13 +1616,45 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, } if (value) { @@ -150,7 +151,7 @@ index 3f63312c..d5576538 100644 + continue; + } + -+ object_property_set_bool(obj, true, d->from.name, &local_err); ++ object_property_set_bool(obj, d->from.name, true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; @@ -170,7 +171,7 @@ index 3f63312c..d5576538 100644 + continue; + } + -+ object_property_set_bool(obj, false, d->to.name, &local_err); ++ object_property_set_bool(obj, d->to.name, false, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; @@ -180,5 +181,5 @@ index 3f63312c..d5576538 100644 } -- -2.25.1 +2.27.0 diff --git a/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch index 0477419196061a5e452363845ffd4591bfc5ef21..d5bc0e88ed89005c6d4cf66d4c90eafb314bc048 100644 --- a/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch +++ b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch @@ -1,13 +1,14 @@ -From 7ed595242f52d0654982d41a9c2a63be2bc3378e Mon Sep 17 00:00:00 2001 +From 536aa9ecc3cb25c81c2df56230c690257189d4ef Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:55 +0800 -Subject: [PATCH 6/9] target/arm: introduce KVM_CAP_ARM_CPU_FEATURE +Subject: [PATCH] target/arm: introduce KVM_CAP_ARM_CPU_FEATURE Introduce KVM_CAP_ARM_CPU_FEATURE to check whether KVM supports to set CPU features in ARM. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- linux-headers/linux/kvm.h | 2 ++ target/arm/cpu.c | 5 +++++ @@ -16,12 +17,12 @@ Signed-off-by: Peng Liang 4 files changed, 28 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 744e888e..4844edc3 100644 +index bcaf66cc4d..5d8e42b8f8 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h -@@ -995,6 +995,8 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171 - #define KVM_CAP_ARM_PTRAUTH_GENERIC 172 +@@ -1113,6 +1113,8 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 + #define KVM_CAP_ARM_MTE 205 +#define KVM_CAP_ARM_CPU_FEATURE 555 + @@ -29,10 +30,10 @@ index 744e888e..4844edc3 100644 struct kvm_irq_routing_irqchip { diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index d5576538..db46afba 100644 +index ee09642dae..3024f4a3f5 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1427,6 +1427,11 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, +@@ -1604,6 +1604,11 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; bool value; @@ -45,11 +46,11 @@ index d5576538..db46afba 100644 qdev_prop_set_after_realize(dev, name, errp); return; diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index 06cf31e8..05345556 100644 +index 4f97e516c2..b34a87fd24 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c -@@ -644,6 +644,20 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - return true; +@@ -827,6 +827,20 @@ static int kvm_arm_sve_set_vls(CPUState *cs) + return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } +bool kvm_arm_cpu_feature_supported(void) @@ -70,12 +71,12 @@ index 06cf31e8..05345556 100644 int kvm_arch_init_vcpu(CPUState *cs) diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 9b7104d6..49e80878 100644 +index f8e0e64363..82145607ec 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h -@@ -239,6 +239,13 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); +@@ -306,6 +306,13 @@ bool kvm_arm_pmu_supported(void); */ - void kvm_arm_add_vcpu_properties(Object *obj); + bool kvm_arm_sve_supported(void); +/** + * kvm_arm_cpu_feature_supported: @@ -88,5 +89,5 @@ index 9b7104d6..49e80878 100644 * kvm_arm_get_max_vm_ipa_size: * @ms: Machine state handle -- -2.25.1 +2.27.0 diff --git a/target-arm-kvm-Implement-virtual-time-adjustment.patch b/target-arm-kvm-Implement-virtual-time-adjustment.patch deleted file mode 100644 index 86450c4d8f1739527a7065ec9242706605487b0e..0000000000000000000000000000000000000000 --- a/target-arm-kvm-Implement-virtual-time-adjustment.patch +++ /dev/null @@ -1,290 +0,0 @@ -From 77ee224418fac859acecd9aca4d18555ced42db6 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 21 Apr 2020 17:32:31 +0800 -Subject: [PATCH 3/4] target/arm/kvm: Implement virtual time adjustment - -When a VM is stopped (such as when it's paused) guest virtual time -should stop counting. Otherwise, when the VM is resumed it will -experience time jumps and its kernel may report soft lockups. Not -counting virtual time while the VM is stopped has the side effect -of making the guest's time appear to lag when compared with real -time, and even with time derived from the physical counter. For -this reason, this change, which is enabled by default, comes with -a KVM CPU feature allowing it to be disabled, restoring legacy -behavior. - -This patch only provides the implementation of the virtual time -adjustment. A subsequent patch will provide the CPU property -allowing the change to be enabled and disabled. - -Reported-by: Bijan Mottahedeh -Signed-off-by: Andrew Jones -Message-id: 20200120101023.16030-6-drjones@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell ---- - target/arm/cpu.h | 7 ++++ - target/arm/kvm.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ - target/arm/kvm32.c | 2 + - target/arm/kvm64.c | 2 + - target/arm/kvm_arm.h | 37 ++++++++++++++++++ - target/arm/machine.c | 7 ++++ - 6 files changed, 147 insertions(+) - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 94c990cd..e19531a7 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -816,6 +816,13 @@ struct ARMCPU { - /* KVM init features for this CPU */ - uint32_t kvm_init_features[7]; - -+ /* KVM CPU state */ -+ -+ /* KVM virtual time adjustment */ -+ bool kvm_adjvtime; -+ bool kvm_vtime_dirty; -+ uint64_t kvm_vtime; -+ - /* Uniprocessor system with MP extensions */ - bool mp_is_up; - -diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index cc7a46df..21fb7ecd 100644 ---- a/target/arm/kvm.c -+++ b/target/arm/kvm.c -@@ -336,6 +336,22 @@ static int compare_u64(const void *a, const void *b) - return 0; - } - -+/* -+ * cpreg_values are sorted in ascending order by KVM register ID -+ * (see kvm_arm_init_cpreg_list). This allows us to cheaply find -+ * the storage for a KVM register by ID with a binary search. -+ */ -+static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx) -+{ -+ uint64_t *res; -+ -+ res = bsearch(®idx, cpu->cpreg_indexes, cpu->cpreg_array_len, -+ sizeof(uint64_t), compare_u64); -+ assert(res); -+ -+ return &cpu->cpreg_values[res - cpu->cpreg_indexes]; -+} -+ - /* Initialize the ARMCPU cpreg list according to the kernel's - * definition of what CPU registers it knows about (and throw away - * the previous TCG-created cpreg list). -@@ -489,6 +505,23 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) - return ok; - } - -+void kvm_arm_cpu_pre_save(ARMCPU *cpu) -+{ -+ /* KVM virtual time adjustment */ -+ if (cpu->kvm_vtime_dirty) { -+ *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT) = cpu->kvm_vtime; -+ } -+} -+ -+void kvm_arm_cpu_post_load(ARMCPU *cpu) -+{ -+ /* KVM virtual time adjustment */ -+ if (cpu->kvm_adjvtime) { -+ cpu->kvm_vtime = *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT); -+ cpu->kvm_vtime_dirty = true; -+ } -+} -+ - void kvm_arm_reset_vcpu(ARMCPU *cpu) - { - int ret; -@@ -556,6 +589,50 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu) - return 0; - } - -+void kvm_arm_get_virtual_time(CPUState *cs) -+{ -+ ARMCPU *cpu = ARM_CPU(cs); -+ struct kvm_one_reg reg = { -+ .id = KVM_REG_ARM_TIMER_CNT, -+ .addr = (uintptr_t)&cpu->kvm_vtime, -+ }; -+ int ret; -+ -+ if (cpu->kvm_vtime_dirty) { -+ return; -+ } -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); -+ if (ret) { -+ error_report("Failed to get KVM_REG_ARM_TIMER_CNT"); -+ abort(); -+ } -+ -+ cpu->kvm_vtime_dirty = true; -+} -+ -+void kvm_arm_put_virtual_time(CPUState *cs) -+{ -+ ARMCPU *cpu = ARM_CPU(cs); -+ struct kvm_one_reg reg = { -+ .id = KVM_REG_ARM_TIMER_CNT, -+ .addr = (uintptr_t)&cpu->kvm_vtime, -+ }; -+ int ret; -+ -+ if (!cpu->kvm_vtime_dirty) { -+ return; -+ } -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); -+ if (ret) { -+ error_report("Failed to set KVM_REG_ARM_TIMER_CNT"); -+ abort(); -+ } -+ -+ cpu->kvm_vtime_dirty = false; -+} -+ - int kvm_put_vcpu_events(ARMCPU *cpu) - { - CPUARMState *env = &cpu->env; -@@ -667,6 +744,21 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) - return MEMTXATTRS_UNSPECIFIED; - } - -+void kvm_arm_vm_state_change(void *opaque, int running, RunState state) -+{ -+ CPUState *cs = opaque; -+ ARMCPU *cpu = ARM_CPU(cs); -+ -+ if (running) { -+ if (cpu->kvm_adjvtime) { -+ kvm_arm_put_virtual_time(cs); -+ } -+ } else { -+ if (cpu->kvm_adjvtime) { -+ kvm_arm_get_virtual_time(cs); -+ } -+ } -+} - - int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) - { -diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c -index 51f78f72..ee158830 100644 ---- a/target/arm/kvm32.c -+++ b/target/arm/kvm32.c -@@ -195,6 +195,8 @@ int kvm_arch_init_vcpu(CPUState *cs) - return -EINVAL; - } - -+ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs); -+ - /* Determine init features for this CPU */ - memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); - if (cpu->start_powered_off) { -diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index f2f0a92e..4f0bf000 100644 ---- a/target/arm/kvm64.c -+++ b/target/arm/kvm64.c -@@ -609,6 +609,8 @@ int kvm_arch_init_vcpu(CPUState *cs) - return -EINVAL; - } - -+ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs); -+ - /* Determine init features for this CPU */ - memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); - if (cpu->start_powered_off) { -diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index 32d97ce5..97560d4e 100644 ---- a/target/arm/kvm_arm.h -+++ b/target/arm/kvm_arm.h -@@ -113,6 +113,23 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level); - */ - bool write_kvmstate_to_list(ARMCPU *cpu); - -+/** -+ * kvm_arm_cpu_pre_save: -+ * @cpu: ARMCPU -+ * -+ * Called after write_kvmstate_to_list() from cpu_pre_save() to update -+ * the cpreg list with KVM CPU state. -+ */ -+void kvm_arm_cpu_pre_save(ARMCPU *cpu); -+ -+/** -+ * kvm_arm_cpu_post_load: -+ * @cpu: ARMCPU -+ * -+ * Called from cpu_post_load() to update KVM CPU state from the cpreg list. -+ */ -+void kvm_arm_cpu_post_load(ARMCPU *cpu); -+ - /** - * kvm_arm_reset_vcpu: - * @cpu: ARMCPU -@@ -241,6 +258,24 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu); - */ - int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); - -+/** -+ * kvm_arm_get_virtual_time: -+ * @cs: CPUState -+ * -+ * Gets the VCPU's virtual counter and stores it in the KVM CPU state. -+ */ -+void kvm_arm_get_virtual_time(CPUState *cs); -+ -+/** -+ * kvm_arm_put_virtual_time: -+ * @cs: CPUState -+ * -+ * Sets the VCPU's virtual counter to the value stored in the KVM CPU state. -+ */ -+void kvm_arm_put_virtual_time(CPUState *cs); -+ -+void kvm_arm_vm_state_change(void *opaque, int running, RunState state); -+ - int kvm_arm_vgic_probe(void); - - void kvm_arm_pmu_set_irq(CPUState *cs, int irq); -@@ -272,6 +307,8 @@ static inline int kvm_arm_vgic_probe(void) - static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {} - static inline void kvm_arm_pmu_init(CPUState *cs) {} - -+static inline void kvm_arm_get_virtual_time(CPUState *cs) {} -+static inline void kvm_arm_put_virtual_time(CPUState *cs) {} - #endif - - static inline const char *gic_class_name(void) -diff --git a/target/arm/machine.c b/target/arm/machine.c -index 3fd319a3..ee3c59a6 100644 ---- a/target/arm/machine.c -+++ b/target/arm/machine.c -@@ -644,6 +644,12 @@ static int cpu_pre_save(void *opaque) - /* This should never fail */ - abort(); - } -+ -+ /* -+ * kvm_arm_cpu_pre_save() must be called after -+ * write_kvmstate_to_list() -+ */ -+ kvm_arm_cpu_pre_save(cpu); - } else { - if (!write_cpustate_to_list(cpu, false)) { - /* This should never fail. */ -@@ -746,6 +752,7 @@ static int cpu_post_load(void *opaque, int version_id) - * we're using it. - */ - write_list_to_cpustate(cpu); -+ kvm_arm_cpu_post_load(cpu); - } else { - if (!write_list_to_cpustate(cpu)) { - return -1; --- -2.23.0 diff --git a/target-arm-kvm-trivial-Clean-up-header-documentation.patch b/target-arm-kvm-trivial-Clean-up-header-documentation.patch deleted file mode 100644 index 8c28c63b1e9fa89ace5860f635f07e2d9b221bbe..0000000000000000000000000000000000000000 --- a/target-arm-kvm-trivial-Clean-up-header-documentation.patch +++ /dev/null @@ -1,144 +0,0 @@ -From c057499f90af4be8b26f57f8755aca0ddfcf9467 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 21 Apr 2020 16:52:07 +0800 -Subject: [PATCH 1/4] target/arm/kvm: trivial: Clean up header documentation - -Signed-off-by: Andrew Jones -Message-id: 20200120101023.16030-2-drjones@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell ---- - target/arm/kvm_arm.h | 38 +++++++++++++++++++++++--------------- - 1 file changed, 23 insertions(+), 15 deletions(-) - -diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h -index a9f3ccab..32d97ce5 100644 ---- a/target/arm/kvm_arm.h -+++ b/target/arm/kvm_arm.h -@@ -61,8 +61,8 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, - int kvm_arm_init_cpreg_list(ARMCPU *cpu); - - /** -- * kvm_arm_reg_syncs_via_cpreg_list -- * regidx: KVM register index -+ * kvm_arm_reg_syncs_via_cpreg_list: -+ * @regidx: KVM register index - * - * Return true if this KVM register should be synchronized via the - * cpreg list of arbitrary system registers, false if it is synchronized -@@ -71,8 +71,8 @@ int kvm_arm_init_cpreg_list(ARMCPU *cpu); - bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx); - - /** -- * kvm_arm_cpreg_level -- * regidx: KVM register index -+ * kvm_arm_cpreg_level: -+ * @regidx: KVM register index - * - * Return the level of this coprocessor/system register. Return value is - * either KVM_PUT_RUNTIME_STATE, KVM_PUT_RESET_STATE, or KVM_PUT_FULL_STATE. -@@ -134,6 +134,8 @@ void kvm_arm_init_serror_injection(CPUState *cs); - * @cpu: ARMCPU - * - * Get VCPU related state from kvm. -+ * -+ * Returns: 0 if success else < 0 error code - */ - int kvm_get_vcpu_events(ARMCPU *cpu); - -@@ -142,6 +144,8 @@ int kvm_get_vcpu_events(ARMCPU *cpu); - * @cpu: ARMCPU - * - * Put VCPU related state to kvm. -+ * -+ * Returns: 0 if success else < 0 error code - */ - int kvm_put_vcpu_events(ARMCPU *cpu); - -@@ -191,10 +195,12 @@ typedef struct ARMHostCPUFeatures { - - /** - * kvm_arm_get_host_cpu_features: -- * @ahcc: ARMHostCPUClass to fill in -+ * @ahcf: ARMHostCPUClass to fill in - * - * Probe the capabilities of the host kernel's preferred CPU and fill - * in the ARMHostCPUClass struct accordingly. -+ * -+ * Returns true on success and false otherwise. - */ - bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); - -@@ -208,26 +214,30 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); - void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); - - /** -- * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the -- * IPA address space supported by KVM -- * -+ * kvm_arm_get_max_vm_ipa_size: - * @ms: Machine state handle -+ * -+ * Returns the number of bits in the IPA address space supported by KVM - */ - int kvm_arm_get_max_vm_ipa_size(MachineState *ms); - - /** -- * kvm_arm_sync_mpstate_to_kvm -+ * kvm_arm_sync_mpstate_to_kvm: - * @cpu: ARMCPU - * - * If supported set the KVM MP_STATE based on QEMU's model. -+ * -+ * Returns 0 on success and -1 on failure. - */ - int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu); - - /** -- * kvm_arm_sync_mpstate_to_qemu -+ * kvm_arm_sync_mpstate_to_qemu: - * @cpu: ARMCPU - * - * If supported get the MP_STATE from KVM and store in QEMU's model. -+ * -+ * Returns 0 on success and aborts on failure. - */ - int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); - -@@ -241,7 +251,8 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); - - static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) - { -- /* This should never actually be called in the "not KVM" case, -+ /* -+ * This should never actually be called in the "not KVM" case, - * but set up the fields to indicate an error anyway. - */ - cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE; -@@ -310,23 +321,20 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit); - * - * Return: TRUE if any hardware breakpoints in use. - */ -- - bool kvm_arm_hw_debug_active(CPUState *cs); - - /** - * kvm_arm_copy_hw_debug_data: -- * - * @ptr: kvm_guest_debug_arch structure - * - * Copy the architecture specific debug registers into the - * kvm_guest_debug ioctl structure. - */ - struct kvm_guest_debug_arch; -- - void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr); - - /** -- * its_class_name -+ * its_class_name: - * - * Return the ITS class name to use depending on whether KVM acceleration - * and KVM CAP_SIGNAL_MSI are supported --- -2.23.0 diff --git a/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch b/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch deleted file mode 100644 index b8cec1bd36e2da9526a643229252ac6760eebecf..0000000000000000000000000000000000000000 --- a/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 07bd62920f968da7d1d8962cc7fd3d29652d25f4 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 21 Apr 2020 17:04:13 +0800 -Subject: [PATCH 2/4] target/arm/kvm64: kvm64 cpus have timer registers - -Add the missing GENERIC_TIMER feature to kvm64 cpus. - -We don't currently use these registers when KVM is enabled, but it's -probably best we add the feature flag for consistency and potential -future use. There's also precedent, as we add the PMU feature flag to -KVM enabled guests, even though we don't use those registers either. - -This change was originally posted as a hunk of a different, never -merged patch from Bijan Mottahedeh. - -Signed-off-by: Andrew Jones -Reviewed-by: Richard Henderson -Message-id: 20200120101023.16030-4-drjones@redhat.com -Signed-off-by: Peter Maydell ---- - target/arm/kvm64.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c -index 22d19c9a..f2f0a92e 100644 ---- a/target/arm/kvm64.c -+++ b/target/arm/kvm64.c -@@ -587,6 +587,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) - set_feature(&features, ARM_FEATURE_NEON); - set_feature(&features, ARM_FEATURE_AARCH64); - set_feature(&features, ARM_FEATURE_PMU); -+ set_feature(&features, ARM_FEATURE_GENERIC_TIMER); - - ahcf->features = features; - --- -2.23.0 diff --git a/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch b/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch deleted file mode 100644 index 30f14bafcc5b70310e462e9b4f5ca5cb91708cef..0000000000000000000000000000000000000000 --- a/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch +++ /dev/null @@ -1,373 +0,0 @@ -From c527fa45dd0bb03c7f35b79ff53f127297f96314 Mon Sep 17 00:00:00 2001 -From: Andrew Jones -Date: Thu, 31 Oct 2019 15:27:26 +0100 -Subject: [PATCH 12/13] target/arm/monitor: Introduce - qmp_query_cpu_model_expansion - -Add support for the query-cpu-model-expansion QMP command to Arm. We -do this selectively, only exposing CPU properties which represent -optional CPU features which the user may want to enable/disable. -Additionally we restrict the list of queryable cpu models to 'max', -'host', or the current type when KVM is in use. And, finally, we only -implement expansion type 'full', as Arm does not yet have a "base" -CPU type. More details and example queries are described in a new -document (docs/arm-cpu-features.rst). - -Note, certainly more features may be added to the list of advertised -features, e.g. 'vfp' and 'neon'. The only requirement is that we can -detect invalid configurations and emit failures at QMP query time. -For 'vfp' and 'neon' this will require some refactoring to share a -validation function between the QMP query and the CPU realize -functions. - -Signed-off-by: Andrew Jones -Reviewed-by: Richard Henderson -Reviewed-by: Eric Auger -Reviewed-by: Beata Michalska -Message-id: 20191031142734.8590-2-drjones@redhat.com -Signed-off-by: Peter Maydell ---- - docs/arm-cpu-features.rst | 137 +++++++++++++++++++++++++++++++++++ - qapi/machine-target.json | 6 +- - target/arm/monitor.c | 145 ++++++++++++++++++++++++++++++++++++++ - 3 files changed, 285 insertions(+), 3 deletions(-) - create mode 100644 docs/arm-cpu-features.rst - -diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst -new file mode 100644 -index 00000000..c79dcffb ---- /dev/null -+++ b/docs/arm-cpu-features.rst -@@ -0,0 +1,137 @@ -+================ -+ARM CPU Features -+================ -+ -+Examples of probing and using ARM CPU features -+ -+Introduction -+============ -+ -+CPU features are optional features that a CPU of supporting type may -+choose to implement or not. In QEMU, optional CPU features have -+corresponding boolean CPU proprieties that, when enabled, indicate -+that the feature is implemented, and, conversely, when disabled, -+indicate that it is not implemented. An example of an ARM CPU feature -+is the Performance Monitoring Unit (PMU). CPU types such as the -+Cortex-A15 and the Cortex-A57, which respectively implement ARM -+architecture reference manuals ARMv7-A and ARMv8-A, may both optionally -+implement PMUs. For example, if a user wants to use a Cortex-A15 without -+a PMU, then the `-cpu` parameter should contain `pmu=off` on the QEMU -+command line, i.e. `-cpu cortex-a15,pmu=off`. -+ -+As not all CPU types support all optional CPU features, then whether or -+not a CPU property exists depends on the CPU type. For example, CPUs -+that implement the ARMv8-A architecture reference manual may optionally -+support the AArch32 CPU feature, which may be enabled by disabling the -+`aarch64` CPU property. A CPU type such as the Cortex-A15, which does -+not implement ARMv8-A, will not have the `aarch64` CPU property. -+ -+QEMU's support may be limited for some CPU features, only partially -+supporting the feature or only supporting the feature under certain -+configurations. For example, the `aarch64` CPU feature, which, when -+disabled, enables the optional AArch32 CPU feature, is only supported -+when using the KVM accelerator and when running on a host CPU type that -+supports the feature. -+ -+CPU Feature Probing -+=================== -+ -+Determining which CPU features are available and functional for a given -+CPU type is possible with the `query-cpu-model-expansion` QMP command. -+Below are some examples where `scripts/qmp/qmp-shell` (see the top comment -+block in the script for usage) is used to issue the QMP commands. -+ -+(1) Determine which CPU features are available for the `max` CPU type -+ (Note, we started QEMU with qemu-system-aarch64, so `max` is -+ implementing the ARMv8-A reference manual in this case):: -+ -+ (QEMU) query-cpu-model-expansion type=full model={"name":"max"} -+ { "return": { -+ "model": { "name": "max", "props": { -+ "pmu": true, "aarch64": true -+ }}}} -+ -+We see that the `max` CPU type has the `pmu` and `aarch64` CPU features. -+We also see that the CPU features are enabled, as they are all `true`. -+ -+(2) Let's try to disable the PMU:: -+ -+ (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}} -+ { "return": { -+ "model": { "name": "max", "props": { -+ "pmu": false, "aarch64": true -+ }}}} -+ -+We see it worked, as `pmu` is now `false`. -+ -+(3) Let's try to disable `aarch64`, which enables the AArch32 CPU feature:: -+ -+ (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"aarch64":false}} -+ {"error": { -+ "class": "GenericError", "desc": -+ "'aarch64' feature cannot be disabled unless KVM is enabled and 32-bit EL1 is supported" -+ }} -+ -+It looks like this feature is limited to a configuration we do not -+currently have. -+ -+(4) Let's try probing CPU features for the Cortex-A15 CPU type:: -+ -+ (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"} -+ {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}} -+ -+Only the `pmu` CPU feature is available. -+ -+A note about CPU feature dependencies -+------------------------------------- -+ -+It's possible for features to have dependencies on other features. I.e. -+it may be possible to change one feature at a time without error, but -+when attempting to change all features at once an error could occur -+depending on the order they are processed. It's also possible changing -+all at once doesn't generate an error, because a feature's dependencies -+are satisfied with other features, but the same feature cannot be changed -+independently without error. For these reasons callers should always -+attempt to make their desired changes all at once in order to ensure the -+collection is valid. -+ -+A note about CPU models and KVM -+------------------------------- -+ -+Named CPU models generally do not work with KVM. There are a few cases -+that do work, e.g. using the named CPU model `cortex-a57` with KVM on a -+seattle host, but mostly if KVM is enabled the `host` CPU type must be -+used. This means the guest is provided all the same CPU features as the -+host CPU type has. And, for this reason, the `host` CPU type should -+enable all CPU features that the host has by default. Indeed it's even -+a bit strange to allow disabling CPU features that the host has when using -+the `host` CPU type, but in the absence of CPU models it's the best we can -+do if we want to launch guests without all the host's CPU features enabled. -+ -+Enabling KVM also affects the `query-cpu-model-expansion` QMP command. The -+affect is not only limited to specific features, as pointed out in example -+(3) of "CPU Feature Probing", but also to which CPU types may be expanded. -+When KVM is enabled, only the `max`, `host`, and current CPU type may be -+expanded. This restriction is necessary as it's not possible to know all -+CPU types that may work with KVM, but it does impose a small risk of users -+experiencing unexpected errors. For example on a seattle, as mentioned -+above, the `cortex-a57` CPU type is also valid when KVM is enabled. -+Therefore a user could use the `host` CPU type for the current type, but -+then attempt to query `cortex-a57`, however that query will fail with our -+restrictions. This shouldn't be an issue though as management layers and -+users have been preferring the `host` CPU type for use with KVM for quite -+some time. Additionally, if the KVM-enabled QEMU instance running on a -+seattle host is using the `cortex-a57` CPU type, then querying `cortex-a57` -+will work. -+ -+Using CPU Features -+================== -+ -+After determining which CPU features are available and supported for a -+given CPU type, then they may be selectively enabled or disabled on the -+QEMU command line with that CPU type:: -+ -+ $ qemu-system-aarch64 -M virt -cpu max,pmu=off -+ -+The example above disables the PMU for the `max` CPU type. -+ -diff --git a/qapi/machine-target.json b/qapi/machine-target.json -index 55310a6a..04623224 100644 ---- a/qapi/machine-target.json -+++ b/qapi/machine-target.json -@@ -212,7 +212,7 @@ - ## - { 'struct': 'CpuModelExpansionInfo', - 'data': { 'model': 'CpuModelInfo' }, -- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } -+ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' } - - ## - # @query-cpu-model-expansion: -@@ -237,7 +237,7 @@ - # query-cpu-model-expansion while using these is not advised. - # - # Some architectures may not support all expansion types. s390x supports --# "full" and "static". -+# "full" and "static". Arm only supports "full". - # - # Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is - # not supported, if the model cannot be expanded, if the model contains -@@ -251,7 +251,7 @@ - 'data': { 'type': 'CpuModelExpansionType', - 'model': 'CpuModelInfo' }, - 'returns': 'CpuModelExpansionInfo', -- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } -+ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' } - - ## - # @CpuDefinitionInfo: -diff --git a/target/arm/monitor.c b/target/arm/monitor.c -index 6ec6dd04..560970de 100644 ---- a/target/arm/monitor.c -+++ b/target/arm/monitor.c -@@ -23,7 +23,14 @@ - #include "qemu/osdep.h" - #include "hw/boards.h" - #include "kvm_arm.h" -+#include "qapi/error.h" -+#include "qapi/visitor.h" -+#include "qapi/qobject-input-visitor.h" -+#include "qapi/qapi-commands-machine-target.h" - #include "qapi/qapi-commands-misc-target.h" -+#include "qapi/qmp/qerror.h" -+#include "qapi/qmp/qdict.h" -+#include "qom/qom-qobject.h" - - static GICCapability *gic_cap_new(int version) - { -@@ -82,3 +89,141 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp) - - return head; - } -+ -+/* -+ * These are cpu model features we want to advertise. The order here -+ * matters as this is the order in which qmp_query_cpu_model_expansion -+ * will attempt to set them. If there are dependencies between features, -+ * then the order that considers those dependencies must be used. -+ */ -+static const char *cpu_model_advertised_features[] = { -+ "aarch64", "pmu", -+ NULL -+}; -+ -+CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, -+ CpuModelInfo *model, -+ Error **errp) -+{ -+ CpuModelExpansionInfo *expansion_info; -+ const QDict *qdict_in = NULL; -+ QDict *qdict_out; -+ ObjectClass *oc; -+ Object *obj; -+ const char *name; -+ int i; -+ -+ if (type != CPU_MODEL_EXPANSION_TYPE_FULL) { -+ error_setg(errp, "The requested expansion type is not supported"); -+ return NULL; -+ } -+ -+ if (!kvm_enabled() && !strcmp(model->name, "host")) { -+ error_setg(errp, "The CPU type '%s' requires KVM", model->name); -+ return NULL; -+ } -+ -+ oc = cpu_class_by_name(TYPE_ARM_CPU, model->name); -+ if (!oc) { -+ error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type", -+ model->name); -+ return NULL; -+ } -+ -+ if (kvm_enabled()) { -+ const char *cpu_type = current_machine->cpu_type; -+ int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); -+ bool supported = false; -+ -+ if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { -+ /* These are kvmarm's recommended cpu types */ -+ supported = true; -+ } else if (strlen(model->name) == len && -+ !strncmp(model->name, cpu_type, len)) { -+ /* KVM is enabled and we're using this type, so it works. */ -+ supported = true; -+ } -+ if (!supported) { -+ error_setg(errp, "We cannot guarantee the CPU type '%s' works " -+ "with KVM on this host", model->name); -+ return NULL; -+ } -+ } -+ -+ if (model->props) { -+ qdict_in = qobject_to(QDict, model->props); -+ if (!qdict_in) { -+ error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); -+ return NULL; -+ } -+ } -+ -+ obj = object_new(object_class_get_name(oc)); -+ -+ if (qdict_in) { -+ Visitor *visitor; -+ Error *err = NULL; -+ -+ visitor = qobject_input_visitor_new(model->props); -+ visit_start_struct(visitor, NULL, NULL, 0, &err); -+ if (err) { -+ visit_free(visitor); -+ object_unref(obj); -+ error_propagate(errp, err); -+ return NULL; -+ } -+ -+ i = 0; -+ while ((name = cpu_model_advertised_features[i++]) != NULL) { -+ if (qdict_get(qdict_in, name)) { -+ object_property_set(obj, visitor, name, &err); -+ if (err) { -+ break; -+ } -+ } -+ } -+ -+ if (!err) { -+ visit_check_struct(visitor, &err); -+ } -+ visit_end_struct(visitor, NULL); -+ visit_free(visitor); -+ if (err) { -+ object_unref(obj); -+ error_propagate(errp, err); -+ return NULL; -+ } -+ } -+ -+ expansion_info = g_new0(CpuModelExpansionInfo, 1); -+ expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); -+ expansion_info->model->name = g_strdup(model->name); -+ -+ qdict_out = qdict_new(); -+ -+ i = 0; -+ while ((name = cpu_model_advertised_features[i++]) != NULL) { -+ ObjectProperty *prop = object_property_find(obj, name, NULL); -+ if (prop) { -+ Error *err = NULL; -+ QObject *value; -+ -+ assert(prop->get); -+ value = object_property_get_qobject(obj, name, &err); -+ assert(!err); -+ -+ qdict_put_obj(qdict_out, name, value); -+ } -+ } -+ -+ if (!qdict_size(qdict_out)) { -+ qobject_unref(qdict_out); -+ } else { -+ expansion_info->model->props = QOBJECT(qdict_out); -+ expansion_info->model->has_props = true; -+ } -+ -+ object_unref(obj); -+ -+ return expansion_info; -+} --- -2.25.1 - diff --git a/target-arm-monitor-query-cpu-model-expansion-crashed.patch b/target-arm-monitor-query-cpu-model-expansion-crashed.patch deleted file mode 100644 index 60973a7c2233a8e57f23d89c69a0c3a972835e8b..0000000000000000000000000000000000000000 --- a/target-arm-monitor-query-cpu-model-expansion-crashed.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 5d75b922480f3fbefe83b5bb5e241e56a16e1e3e Mon Sep 17 00:00:00 2001 -From: Liang Yan -Date: Fri, 7 Feb 2020 14:04:21 +0000 -Subject: [PATCH 13/13] target/arm/monitor: query-cpu-model-expansion crashed - qemu when using machine type none - -Commit e19afd566781 mentioned that target-arm only supports queryable -cpu models 'max', 'host', and the current type when KVM is in use. -The logic works well until using machine type none. - -For machine type none, cpu_type will be null if cpu option is not -set by command line, strlen(cpu_type) will terminate process. -So We add a check above it. - -This won't affect i386 and s390x since they do not use current_cpu. - -Signed-off-by: Liang Yan -Message-id: 20200203134251.12986-1-lyan@suse.com -Reviewed-by: Andrew Jones -Tested-by: Andrew Jones -Signed-off-by: Peter Maydell ---- - target/arm/monitor.c | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - -diff --git a/target/arm/monitor.c b/target/arm/monitor.c -index 560970de..e2b1d117 100644 ---- a/target/arm/monitor.c -+++ b/target/arm/monitor.c -@@ -131,17 +131,20 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, - } - - if (kvm_enabled()) { -- const char *cpu_type = current_machine->cpu_type; -- int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); - bool supported = false; - - if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { - /* These are kvmarm's recommended cpu types */ - supported = true; -- } else if (strlen(model->name) == len && -- !strncmp(model->name, cpu_type, len)) { -- /* KVM is enabled and we're using this type, so it works. */ -- supported = true; -+ } else if (current_machine->cpu_type) { -+ const char *cpu_type = current_machine->cpu_type; -+ int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); -+ -+ if (strlen(model->name) == len && -+ !strncmp(model->name, cpu_type, len)) { -+ /* KVM is enabled and we're using this type, so it works. */ -+ supported = true; -+ } - } - if (!supported) { - error_setg(errp, "We cannot guarantee the CPU type '%s' works " --- -2.25.1 - diff --git a/target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch b/target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch index 91702dbe0cbcc5fff7a113ff2b75a90026521500..a9be076ecc13826d1f57e1fcd525721cee216342 100644 --- a/target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch +++ b/target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch @@ -1,4 +1,4 @@ -From 88e3146118230de8b99280db219a6a6c47bebce1 Mon Sep 17 00:00:00 2001 +From 3371917ea92265377f87692a717397267416c4aa Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Wed, 16 Sep 2020 19:40:28 +0800 Subject: [PATCH] target/arm: only set ID_PFR1_EL1.GIC for AArch32 guest @@ -9,17 +9,18 @@ in AArch64 mode. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c -index 97b6b86197..b262f5d6c5 100644 +index 79f77705c3..4c7b4cadfa 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c -@@ -5672,7 +5672,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) +@@ -6718,7 +6718,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) ARMCPU *cpu = env_archcpu(env); - uint64_t pfr1 = cpu->id_pfr1; + uint64_t pfr1 = cpu->isar.regs[ID_PFR1]; - if (env->gicv3state) { + if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && env->gicv3state) { @@ -27,5 +28,5 @@ index 97b6b86197..b262f5d6c5 100644 } return pfr1; -- -2.23.0 +2.27.0 diff --git a/target-arm-parse-cpu-feature-related-options.patch b/target-arm-parse-cpu-feature-related-options.patch index 066e231af6266d21eecaf5d0c519b8a6aa4069d6..b90027bc6316da9de2144979f3af20cc6fdf7777 100644 --- a/target-arm-parse-cpu-feature-related-options.patch +++ b/target-arm-parse-cpu-feature-related-options.patch @@ -1,7 +1,7 @@ -From dca1df05ce3d6b17d03203fc6fd94e23548216c7 Mon Sep 17 00:00:00 2001 +From abd51f8d46b916efb37cb2c8face176bc83c0d5d Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:35 +0800 -Subject: [PATCH 2/9] target/arm: parse cpu feature related options +Subject: [PATCH] target/arm: parse cpu feature related options The implementation of CPUClass::parse_features only supports CPU features in "feature=value" format. However, libvirt maybe send us a @@ -14,16 +14,17 @@ X86CPUClass::parse_features. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu64.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c -index fe648752..7de20848 100644 +index 96a49a3158..9e5179afbe 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c -@@ -506,6 +506,88 @@ static void arm_cpu_parse_featurestr(const char *typename, char *features, - } +@@ -982,6 +982,88 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) + return g_strdup("aarch64"); } +static void @@ -111,14 +112,14 @@ index fe648752..7de20848 100644 static void aarch64_cpu_class_init(ObjectClass *oc, void *data) { CPUClass *cc = CPU_CLASS(oc); -@@ -517,6 +599,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) +@@ -991,6 +1073,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = 34; cc->gdb_core_xml_file = "aarch64-core.xml"; cc->gdb_arch_name = aarch64_gdb_arch_name; + cc->parse_features = aarch64_cpu_parse_features; - } - static void aarch64_cpu_instance_init(Object *obj) + object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, + aarch64_cpu_set_aarch64); -- -2.25.1 +2.27.0 diff --git a/target-arm-register-CPU-features-for-property.patch b/target-arm-register-CPU-features-for-property.patch index ea42a63ea7620fc790d01ae94590fb4336e12c32..3d60d68c8cd96cca6e8c22d212b81f2c8378a637 100644 --- a/target-arm-register-CPU-features-for-property.patch +++ b/target-arm-register-CPU-features-for-property.patch @@ -1,7 +1,7 @@ -From f169b1f76cad9f727c701df853b05ad5e8d7f927 Mon Sep 17 00:00:00 2001 +From 9fd09aabba558b39ca949ef376d05bc0779fdda6 Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Thu, 6 Aug 2020 16:14:37 +0800 -Subject: [PATCH 3/9] target/arm: register CPU features for property +Subject: [PATCH] target/arm: register CPU features for property The Arm architecture specifies a number of ID registers that are characterized as comprising a set of 4-bit ID fields. Each ID field @@ -28,16 +28,17 @@ not-implemented value) to disable a CPU feature safely. Signed-off-by: zhanghailiang Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun --- target/arm/cpu.c | 343 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 5bcdad0c..3f63312c 100644 +index f1ce0474a3..c081ecc12b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1034,6 +1034,347 @@ static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name, - visit_type_uint32(v, name, &cpu->init_svtor, errp); +@@ -1211,6 +1211,347 @@ unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) + NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1; } +/** @@ -224,7 +225,7 @@ index 5bcdad0c..3f63312c 100644 + FIELD_INFO("sve", ID_AA64PFR0, SVE, false, 1, 0, false), + + FIELD_INFO("bti", ID_AA64PFR1, BT, false, 1, 0, false), -+ FIELD_INFO("sbss", ID_AA64PFR1, SBSS, false, 1, 0, false), ++ FIELD_INFO("ssbs", ID_AA64PFR1, SSBS, false, 1, 0, false), + FIELD_INFO("mte", ID_AA64PFR1, MTE, false, 1, 0, false), + FIELD_INFO("ras_frac", ID_AA64PFR1, RAS_FRAC, false, 1, 0, false), + @@ -371,12 +372,12 @@ index 5bcdad0c..3f63312c 100644 + cpu_features[i].is_32bit)) { + continue; + } -+ op = object_property_find(OBJECT(cpu), cpu_features[i].name, NULL); ++ op = object_property_find(OBJECT(cpu), cpu_features[i].name); + if (!op) { + object_property_add(OBJECT(cpu), cpu_features[i].name, "bool", + arm_cpu_get_bit_prop, + arm_cpu_set_bit_prop, -+ NULL, &cpu_features[i], &error_abort); ++ NULL, &cpu_features[i]); + } + } +} @@ -384,15 +385,15 @@ index 5bcdad0c..3f63312c 100644 void arm_cpu_post_init(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); -@@ -1150,6 +1491,8 @@ void arm_cpu_post_init(Object *obj) +@@ -1319,6 +1660,8 @@ void arm_cpu_post_init(Object *obj) - qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, - &error_abort); -+ -+ arm_cpu_register_feature_props(cpu); - } + qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property); - static void arm_cpu_finalizefn(Object *obj) ++ arm_cpu_register_feature_props(cpu); ++ + if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) { + qdev_property_add_static(DEVICE(cpu), &arm_cpu_gt_cntfrq_property); + } -- -2.25.1 +2.27.0 diff --git a/target-hppa-Fix-deposit-assert-from-trans_shrpw_imm.patch b/target-hppa-Fix-deposit-assert-from-trans_shrpw_imm.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea5d8de6cd65aa554bc1c883c24a7e4118204df1 --- /dev/null +++ b/target-hppa-Fix-deposit-assert-from-trans_shrpw_imm.patch @@ -0,0 +1,88 @@ +From 8964f3516cab9ed0183407136aa9f0dae87c49e3 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 15:38:38 -0800 +Subject: [PATCH 12/29] target/hppa: Fix deposit assert from trans_shrpw_imm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit 05bfd4db08608bc4c22de729780c1f74612fbc0e +category: bugfix + +---------------------------------------------- + +Because sa may be 0, + + tcg_gen_deposit_reg(dest, t0, cpu_gr[a->r1], 32 - sa, sa); + +may attempt a zero-width deposit at bit 32, which will assert +for TARGET_REGISTER_BITS == 32. + +Use the newer extract2 when possible, which itself includes the +rotri special case; otherwise mirror the code from trans_shrpw_sar, +using concat and shri. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/635 +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + target/hppa/translate.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/target/hppa/translate.c b/target/hppa/translate.c +index 3b9744deb4..952027a28e 100644 +--- a/target/hppa/translate.c ++++ b/target/hppa/translate.c +@@ -140,6 +140,7 @@ + #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i64 + #define tcg_gen_extract_reg tcg_gen_extract_i64 + #define tcg_gen_sextract_reg tcg_gen_sextract_i64 ++#define tcg_gen_extract2_reg tcg_gen_extract2_i64 + #define tcg_const_reg tcg_const_i64 + #define tcg_const_local_reg tcg_const_local_i64 + #define tcg_constant_reg tcg_constant_i64 +@@ -234,6 +235,7 @@ + #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i32 + #define tcg_gen_extract_reg tcg_gen_extract_i32 + #define tcg_gen_sextract_reg tcg_gen_sextract_i32 ++#define tcg_gen_extract2_reg tcg_gen_extract2_i32 + #define tcg_const_reg tcg_const_i32 + #define tcg_const_local_reg tcg_const_local_i32 + #define tcg_constant_reg tcg_constant_i32 +@@ -3204,19 +3206,22 @@ static bool trans_shrpw_imm(DisasContext *ctx, arg_shrpw_imm *a) + + dest = dest_gpr(ctx, a->t); + t2 = load_gpr(ctx, a->r2); +- if (a->r1 == a->r2) { ++ if (a->r1 == 0) { ++ tcg_gen_extract_reg(dest, t2, sa, 32 - sa); ++ } else if (TARGET_REGISTER_BITS == 32) { ++ tcg_gen_extract2_reg(dest, t2, cpu_gr[a->r1], sa); ++ } else if (a->r1 == a->r2) { + TCGv_i32 t32 = tcg_temp_new_i32(); + tcg_gen_trunc_reg_i32(t32, t2); + tcg_gen_rotri_i32(t32, t32, sa); + tcg_gen_extu_i32_reg(dest, t32); + tcg_temp_free_i32(t32); +- } else if (a->r1 == 0) { +- tcg_gen_extract_reg(dest, t2, sa, 32 - sa); + } else { +- TCGv_reg t0 = tcg_temp_new(); +- tcg_gen_extract_reg(t0, t2, sa, 32 - sa); +- tcg_gen_deposit_reg(dest, t0, cpu_gr[a->r1], 32 - sa, sa); +- tcg_temp_free(t0); ++ TCGv_i64 t64 = tcg_temp_new_i64(); ++ tcg_gen_concat_reg_i64(t64, t2, cpu_gr[a->r1]); ++ tcg_gen_shri_i64(t64, t64, sa); ++ tcg_gen_trunc_i64_reg(dest, t64); ++ tcg_temp_free_i64(t64); + } + save_gpr(ctx, a->t, dest); + +-- +2.27.0 + diff --git a/target-i386-Add-SGX-aex-notify-and-EDECCSSA-support.patch b/target-i386-Add-SGX-aex-notify-and-EDECCSSA-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf32c05515dd4bfcbc74a8de8a7b3c583133a7e1 --- /dev/null +++ b/target-i386-Add-SGX-aex-notify-and-EDECCSSA-support.patch @@ -0,0 +1,64 @@ +From b4657a1cf12f3a0a650498d87f4e91aae76cc840 Mon Sep 17 00:00:00 2001 +From: Kai Huang +Date: Wed, 9 Nov 2022 15:48:34 +1300 +Subject: [PATCH] target/i386: Add SGX aex-notify and EDECCSSA support + +from mainline-v8.0.0-rc0 +commit d45f24fe7525d8a8aaa4ca6d9d214dc41819caa5 +category: feature +feature: SGX aex-notify and EDECCSSA support +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Y4W4 + +Intel-SIG: commit d45f24fe7525 ("target/i386: Add SGX aex-notify and EDECCSSA support") + +----------------------------------------------------------- + +The new SGX Asynchronous Exit (AEX) notification mechanism (AEX-notify) +allows one enclave to receive a notification in the ERESUME after the +enclave exit due to an AEX. EDECCSSA is a new SGX user leaf function +(ENCLU[EDECCSSA]) to facilitate the AEX notification handling. + +Whether the hardware supports to create enclave with AEX-notify support +is enumerated via CPUID.(EAX=0x12,ECX=0x1):EAX[10]. The new EDECCSSA +user leaf function is enumerated via CPUID.(EAX=0x12,ECX=0x0):EAX[11]. + +Add support to allow to expose the new SGX AEX-notify feature and the +new EDECCSSA user leaf function to KVM guest. + +Link: https://lore.kernel.org/lkml/166760360549.4906.809756297092548496.tip-bot2@tip-bot2/ +Link: https://lore.kernel.org/lkml/166760360934.4906.2427175408052308969.tip-bot2@tip-bot2/ +Reviewed-by: Yang Zhong +Signed-off-by: Kai Huang +Message-Id: <20221109024834.172705-1-kai.huang@intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 61cd7abcaa..df475f27d3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1205,7 +1205,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .feat_names = { + "sgx1", "sgx2", NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, "sgx-edeccssa", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +@@ -1245,7 +1245,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .feat_names = { + NULL, "sgx-debug", "sgx-mode64", NULL, + "sgx-provisionkey", "sgx-tokenkey", NULL, "sgx-kss", +- NULL, NULL, NULL, NULL, ++ NULL, NULL, "sgx-aex-notify", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +-- +2.27.0 + diff --git a/target-i386-Add-Snowridge-v2-no-MPX-CPU-model.patch b/target-i386-Add-Snowridge-v2-no-MPX-CPU-model.patch deleted file mode 100644 index eedd3356bf33b6fd02950740fa81330cbbed2895..0000000000000000000000000000000000000000 --- a/target-i386-Add-Snowridge-v2-no-MPX-CPU-model.patch +++ /dev/null @@ -1,43 +0,0 @@ -From ce4bb30a650773833cd1e86afcaa30e47259085c Mon Sep 17 00:00:00 2001 -From: Xiaoyao Li -Date: Sat, 12 Oct 2019 10:47:48 +0800 -Subject: [PATCH] target/i386: Add Snowridge-v2 (no MPX) CPU model - -Add new version of Snowridge CPU model that removes MPX feature. - -MPX support is being phased out by Intel. GCC has dropped it, Linux kernel -and KVM are also going to do that in the future. - -Signed-off-by: Xiaoyao Li -Message-Id: <20191012024748.127135-1-xiaoyao.li@intel.com> -Signed-off-by: Eduardo Habkost ---- - target/i386/cpu.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index d3742ef4ac..f09612f9da 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2668,6 +2668,18 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_6_EAX_ARAT, - .xlevel = 0x80000008, - .model_id = "Intel Atom Processor (SnowRidge)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { -+ .version = 2, -+ .props = (PropValue[]) { -+ { "mpx", "off" }, -+ { "model-id", "Intel Atom Processor (Snowridge, no MPX)" }, -+ { /* end of list */ }, -+ }, -+ }, -+ { /* end of list */ }, -+ }, - }, - { - .name = "KnightsMill", --- -2.27.0 - diff --git a/target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch b/target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch new file mode 100644 index 0000000000000000000000000000000000000000..0db8839a414c5e161fa4150d46bd38bc3460d7d5 --- /dev/null +++ b/target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch @@ -0,0 +1,53 @@ +From 732cb06c9b652cf899e9f329ad74ec3dae3d18b2 Mon Sep 17 00:00:00 2001 +From: Lei Wang +Date: Thu, 6 Jul 2023 13:49:48 +0800 +Subject: [PATCH] target/i386: Add few security fix bits in ARCH_CAPABILITIES + into SapphireRapids CPU model + +commit 3baf7ae63505eb1652d1e52d65798307fead8539 upstream. + +SapphireRapids has bit 13, 14 and 15 of MSR_IA32_ARCH_CAPABILITIES +enabled, which are related to some security fixes. + +Add version 2 of SapphireRapids CPU model with those bits enabled also. + +Intel-SIG: commit 3baf7ae63505 ("target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model") +Backport support of SapphireRapids CPU Model version 2 + +Signed-off-by: Lei Wang +Signed-off-by: Tao Su +Message-ID: <20230706054949.66556-6-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 685bfca37e..eb911b12fa 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3675,8 +3675,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { + .model_id = "Intel Xeon Processor (SapphireRapids)", + .versions = (X86CPUVersionDefinition[]) { + { .version = 1 }, +- { /* end of list */ }, +- }, ++ { ++ .version = 2, ++ .props = (PropValue[]) { ++ { "sbdr-ssdp-no", "on" }, ++ { "fbsdp-no", "on" }, ++ { "psdp-no", "on" }, ++ { /* end of list */ } ++ } ++ }, ++ { /* end of list */ } ++ } + }, + { + .name = "Denverton", +-- +2.41.0.windows.1 + diff --git a/target-i386-Add-missed-security-features-to-Cooperla.patch b/target-i386-Add-missed-security-features-to-Cooperla.patch deleted file mode 100644 index d17e0c00e9a638c2c1dd715a7c6f1f1eb5a14474..0000000000000000000000000000000000000000 --- a/target-i386-Add-missed-security-features-to-Cooperla.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 97d5c6c621569b011a2122423d0f630bd71de5ff Mon Sep 17 00:00:00 2001 -From: Jingyi Wang -Date: Fri, 9 Jul 2021 11:17:19 +0800 -Subject: [PATCH] target/i386: Add missed security features to Cooperlake CPU - model - -It lacks two security feature bits in MSR_IA32_ARCH_CAPABILITIES in -current Cooperlake CPU model, so add them. - -This is part of uptream commit 2dea9d9 - -Signed-off-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 5329d73316..50d6ef9de4 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2420,7 +2420,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_7_0_EDX_SPEC_CTRL_SSBD | CPUID_7_0_EDX_ARCH_CAPABILITIES, - .features[FEAT_ARCH_CAPABILITIES] = - MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -- MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO, -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO, - .features[FEAT_7_1_EAX] = - CPUID_7_1_EAX_AVX512_BF16, - /* --- -2.27.0 - diff --git a/target-i386-Add-new-CPU-model-GraniteRapids.patch b/target-i386-Add-new-CPU-model-GraniteRapids.patch new file mode 100644 index 0000000000000000000000000000000000000000..24672e94aebfec3f6b06df7769652ea1098a2b43 --- /dev/null +++ b/target-i386-Add-new-CPU-model-GraniteRapids.patch @@ -0,0 +1,183 @@ +From 7ebcbfb9ac1d53ea46bfd86fa7f0a90a4012412e Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:49 +0800 +Subject: [PATCH] target/i386: Add new CPU model GraniteRapids + +commit 6d5e9694ef374159072984c0958c3eaab6dd1d52 upstream. + +The GraniteRapids CPU model mainly adds the following new features +based on SapphireRapids: +- PREFETCHITI CPUID.(EAX=7,ECX=1):EDX[bit 14] +- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] + +And adds the following security fix for corresponding vulnerabilities: +- MCDT_NO CPUID.(EAX=7,ECX=2):EDX[bit 5] +- SBDR_SSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 13] +- FBSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 14] +- PSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 15] +- PBRSB_NO MSR_IA32_ARCH_CAPABILITIES[bit 24] + +Intel-SIG: commit 6d5e9694ef37 target/i386: Add new CPU model GraniteRapids. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Tao Su +Tested-by: Xuelian Guo +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-7-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 136 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ee243693e3..efe0c2b46c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3707,6 +3707,142 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .name = "GraniteRapids", ++ .level = 0x20, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 173, ++ .stepping = 0, ++ /* ++ * please keep the ascending order so that we can have a clear view of ++ * bit position of each feature. ++ */ ++ .features[FEAT_1_EDX] = ++ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | ++ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | ++ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | ++ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | ++ CPUID_SSE | CPUID_SSE2, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | ++ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | ++ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | ++ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | ++ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_WBNOINVD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | ++ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | ++ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | ++ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | ++ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | ++ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | ++ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | ++ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | ++ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | ++ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | ++ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | ++ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | ++ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, ++ .features[FEAT_ARCH_CAPABILITIES] = ++ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | ++ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | ++ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO | ++ MSR_ARCH_CAP_SBDR_SSDP_NO | MSR_ARCH_CAP_FBSDP_NO | ++ MSR_ARCH_CAP_PSDP_NO | MSR_ARCH_CAP_PBRSB_NO, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | ++ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC | ++ CPUID_7_1_EAX_AMX_FP16, ++ .features[FEAT_7_1_EDX] = ++ CPUID_7_1_EDX_PREFETCHITI, ++ .features[FEAT_7_2_EDX] = ++ CPUID_7_2_EDX_MCDT_NO, ++ .features[FEAT_VMX_BASIC] = ++ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, ++ .features[FEAT_VMX_ENTRY_CTLS] = ++ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | ++ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, ++ .features[FEAT_VMX_EPT_VPID_CAPS] = ++ MSR_VMX_EPT_EXECONLY | ++ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | ++ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | ++ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | ++ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | ++ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, ++ .features[FEAT_VMX_EXIT_CTLS] = ++ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | ++ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | ++ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | ++ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, ++ .features[FEAT_VMX_MISC] = ++ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | ++ MSR_VMX_MISC_VMWRITE_VMEXIT, ++ .features[FEAT_VMX_PINBASED_CTLS] = ++ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | ++ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | ++ VMX_PIN_BASED_POSTED_INTR, ++ .features[FEAT_VMX_PROCBASED_CTLS] = ++ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | ++ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | ++ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | ++ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | ++ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | ++ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | ++ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | ++ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | ++ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | ++ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | ++ VMX_CPU_BASED_PAUSE_EXITING | ++ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, ++ .features[FEAT_VMX_SECONDARY_CTLS] = ++ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | ++ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | ++ VMX_SECONDARY_EXEC_RDTSCP | ++ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | ++ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | ++ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | ++ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | ++ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | ++ VMX_SECONDARY_EXEC_RDRAND_EXITING | ++ VMX_SECONDARY_EXEC_ENABLE_INVPCID | ++ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | ++ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | ++ VMX_SECONDARY_EXEC_XSAVES, ++ .features[FEAT_VMX_VMFUNC] = ++ MSR_VMX_VMFUNC_EPT_SWITCHING, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (GraniteRapids)", ++ .versions = (X86CPUVersionDefinition[]) { ++ { .version = 1 }, ++ { /* end of list */ }, ++ }, ++ }, + { + .name = "Denverton", + .level = 21, +-- +2.27.0 + diff --git a/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch b/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch index 3aff7ea35f37047933f6f4464b513feaa242cf69..b0b81164ab851c0f1c1838d997b52b4b0044408e 100644 --- a/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch +++ b/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch @@ -1,47 +1,43 @@ -From 05b13a8de90abc6c1cfeca8b9c436e60e6d3142e Mon Sep 17 00:00:00 2001 -From: Xiaoyao Li -Date: Wed, 25 Dec 2019 14:30:17 +0800 +From cdd89390a5e8fb55515798ab4ec5ec5fd6fed32b Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:47 +0800 Subject: [PATCH] target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES -The bit 6, 7 and 8 of MSR_IA32_ARCH_CAPABILITIES are recently disclosed -for some security issues. Add the definitions for them to be used by named -CPU models. +commit 6c43ec3b206956a8a3008accafe9eb2dfd885190 upstream. -Signed-off-by: Xiaoyao Li -Message-Id: <20191225063018.20038-2-xiaoyao.li@intel.com> -Signed-off-by: Paolo Bonzini +Currently, bit 13, 14, 15 and 24 of MSR_IA32_ARCH_CAPABILITIES are +disclosed for fixing security issues, so add those bit definitions. + +Intel-SIG: commit 6c43ec3b2069 ("target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES") +Backport new bit definitions of MSR_IA32_ARCH_CAPABILITIES -Signed-off-by: Jingyi Wang +Signed-off-by: Tao Su +Reviewed-by: Igor Mammedov +Message-ID: <20230706054949.66556-5-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng --- - target/i386/cpu.h | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) + target/i386/cpu.h | 4 ++++ + 1 file changed, 4 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 58d8c48964..7ff8ddd464 100644 +index edbaba0d62..37c687d4d8 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h -@@ -743,12 +743,15 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_TOPOLOGY_LEVEL_DIE (5U << 8) - - /* MSR Feature Bits */ --#define MSR_ARCH_CAP_RDCL_NO (1U << 0) --#define MSR_ARCH_CAP_IBRS_ALL (1U << 1) --#define MSR_ARCH_CAP_RSBA (1U << 2) -+#define MSR_ARCH_CAP_RDCL_NO (1U << 0) -+#define MSR_ARCH_CAP_IBRS_ALL (1U << 1) -+#define MSR_ARCH_CAP_RSBA (1U << 2) - #define MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY (1U << 3) --#define MSR_ARCH_CAP_SSB_NO (1U << 4) --#define MSR_ARCH_CAP_MDS_NO (1U << 5) -+#define MSR_ARCH_CAP_SSB_NO (1U << 4) -+#define MSR_ARCH_CAP_MDS_NO (1U << 5) -+#define MSR_ARCH_CAP_PSCHANGE_MC_NO (1U << 6) -+#define MSR_ARCH_CAP_TSX_CTRL_MSR (1U << 7) -+#define MSR_ARCH_CAP_TAA_NO (1U << 8) +@@ -966,7 +966,11 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define MSR_ARCH_CAP_PSCHANGE_MC_NO (1U << 6) + #define MSR_ARCH_CAP_TSX_CTRL_MSR (1U << 7) + #define MSR_ARCH_CAP_TAA_NO (1U << 8) ++#define MSR_ARCH_CAP_SBDR_SSDP_NO (1U << 13) ++#define MSR_ARCH_CAP_FBSDP_NO (1U << 14) ++#define MSR_ARCH_CAP_PSDP_NO (1U << 15) + #define MSR_ARCH_CAP_FB_CLEAR (1U << 17) ++#define MSR_ARCH_CAP_PBRSB_NO (1U << 24) #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) -- -2.27.0 +2.41.0.windows.1 diff --git a/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch b/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch new file mode 100644 index 0000000000000000000000000000000000000000..27cdfaf249c65be4ea1ac7a5c5940b3f7300bd51 --- /dev/null +++ b/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch @@ -0,0 +1,62 @@ +From c362956eb88558991bee59e43d7db52c8bc7e5f5 Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:09 +0800 +Subject: [PATCH] target/i386: Add support for AMX-FP16 in CPUID enumeration + +commit 99ed8445ea27742a4df40f51a3a5fbd6f8e76fa5 upstream. + +Latest Intel platform Granite Rapids has introduced a new instruction - +AMX-FP16, which performs dot-products of two FP16 tiles and accumulates +the results into a packed single precision tile. AMX-FP16 adds FP16 +capability and allows a FP16 GPU trained model to run faster without +loss of accuracy or added SW overhead. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 21] + +Add CPUID definition for AMX-FP16. + +Intel-SIG: commit 99ed8445ea27 target/i386: Add support for AMX-FP16 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-3-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 47c2d9da80..3fc3b8041a 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "amx-fp16", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 4a7362ee07..c747e68a7a 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -891,6 +891,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_FSRS (1U << 11) + /* Fast Short REP CMPS/SCAS */ + #define CPUID_7_1_EAX_FSRC (1U << 12) ++/* Support Tile Computational Operations on FP16 Numbers */ ++#define CPUID_7_1_EAX_AMX_FP16 (1U << 21) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch b/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b99815a4c1a33bdf4ce9d0825bf04c3a746c6e4 --- /dev/null +++ b/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch @@ -0,0 +1,60 @@ +From 8fe9899c39d86f9e0baf832744a7cfe19642a3fd Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:10 +0800 +Subject: [PATCH] target/i386: Add support for AVX-IFMA in CPUID enumeration + +commit a957a88416ecbec51e147cba9fe89b93f6646b3b upstream. + +AVX-IFMA is a new instruction in the latest Intel platform Sierra +Forest. This instruction packed multiplies unsigned 52-bit integers and +adds the low/high 52-bit products to Qword Accumulators. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 23] + +Add CPUID definition for AVX-IFMA. + +Intel-SIG: commit a957a88416ec target/i386: Add support for AVX-IFMA in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-4-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3fc3b8041a..b19fb0cf87 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, "amx-fp16", NULL, NULL, ++ NULL, "amx-fp16", NULL, "avx-ifma", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index c747e68a7a..2bcc127fac 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -893,6 +893,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_FSRC (1U << 12) + /* Support Tile Computational Operations on FP16 Numbers */ + #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) ++/* Support for VPMADD52[H,L]UQ */ ++#define CPUID_7_1_EAX_AVX_IFMA (1U << 23) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch b/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch new file mode 100644 index 0000000000000000000000000000000000000000..0eb1635b4d3fdc20048e7357ed1187e0dce8e058 --- /dev/null +++ b/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch @@ -0,0 +1,62 @@ +From 165d587b52f7c8459d9a9deca389610f9165b33a Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:44:56 +0800 +Subject: [PATCH] target/i386: Add support for AVX-NE-CONVERT in CPUID + enumeration + +commit ecd2e6ca037d7bf3673c5478590d686d5cd6135a upstream. + +AVX-NE-CONVERT is a new set of instructions which can convert low +precision floating point like BF16/FP16 to high precision floating point +FP32, as well as convert FP32 elements to BF16. This instruction allows +the platform to have improved AI capabilities and better compatibility. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 5] + +Add CPUID definition for AVX-NE-CONVERT. + +Intel-SIG: commit ecd2e6ca037d target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-6-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a14284a81b..d36174d689 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -911,7 +911,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, +- "avx-vnni-int8", NULL, NULL, NULL, ++ "avx-vnni-int8", "avx-ne-convert", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index b81d77084c..93c8bd6a13 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -898,6 +898,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) + /* Support for VPDPB[SU,UU,SS]D[,S] */ + #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) ++/* AVX NE CONVERT Instructions */ ++#define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch b/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6fc1d0e249f9faa13f70b838153db3f5dc370b7 --- /dev/null +++ b/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch @@ -0,0 +1,110 @@ +From 71b820dc04fbe04342d5a05be3d774c704b682ec Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:43:11 +0800 +Subject: [PATCH] target/i386: Add support for AVX-VNNI-INT8 in CPUID + enumeration + +commit eaaa197d5b112ea2758b54df58881a2626de3af5 upstream. + +AVX-VNNI-INT8 is a new set of instructions in the latest Intel platform +Sierra Forest, aims for the platform to have superior AI capabilities. +This instruction multiplies the individual bytes of two unsigned or +unsigned source operands, then adds and accumulates the results into the +destination dword element size operand. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 4] + +AVX-VNNI-INT8 is on a new feature bits leaf. Add a CPUID feature word +FEAT_7_1_EDX for this leaf. + +Add CPUID definition for AVX-VNNI-INT8. + +Intel-SIG: commit eaaa197d5b11 target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-5-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 22 +++++++++++++++++++++- + target/i386/cpu.h | 3 +++ + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b19fb0cf87..a14284a81b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -663,6 +663,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM + #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ + CPUID_7_1_EAX_FSRC) ++#define TCG_7_1_EDX_FEATURES 0 + #define TCG_7_2_EDX_FEATURES 0 + #define TCG_APM_FEATURES 0 + #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT +@@ -906,6 +907,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + }, + .tcg_features = TCG_7_2_EDX_FEATURES, + }, ++ [FEAT_7_1_EDX] = { ++ .type = CPUID_FEATURE_WORD, ++ .feat_names = { ++ NULL, NULL, NULL, NULL, ++ "avx-vnni-int8", NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ }, ++ .cpuid = { ++ .eax = 7, ++ .needs_ecx = true, .ecx = 1, ++ .reg = R_EDX, ++ }, ++ .tcg_features = TCG_7_1_EDX_FEATURES, ++ }, + [FEAT_8000_0007_EDX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { +@@ -5557,9 +5577,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } else if (count == 1) { + *eax = env->features[FEAT_7_1_EAX]; ++ *edx = env->features[FEAT_7_1_EDX]; + *ebx = 0; + *ecx = 0; +- *edx = 0; + } else if (count == 2) { + *edx = env->features[FEAT_7_2_EDX]; + *eax = 0; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 2bcc127fac..b81d77084c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -601,6 +601,7 @@ typedef enum FeatureWord { + FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ + FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ + FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ ++ FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ + FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ + FEATURE_WORDS, + } FeatureWord; +@@ -895,6 +896,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) + /* Support for VPMADD52[H,L]UQ */ + #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) ++/* Support for VPDPB[SU,UU,SS]D[,S] */ ++#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch b/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch new file mode 100644 index 0000000000000000000000000000000000000000..d1633122ee5d8dfc1129f1881de2ff4eb2beed84 --- /dev/null +++ b/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch @@ -0,0 +1,61 @@ +From 25d08629eab566f5a47bf915a86e20318ee1cf08 Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:08 +0800 +Subject: [PATCH] target/i386: Add support for CMPCCXADD in CPUID enumeration + +commit a9ce107fd0f2017af84255a9cf6542fa3eb3e214 upstream. + +CMPccXADD is a new set of instructions in the latest Intel platform +Sierra Forest. This new instruction set includes a semaphore operation +that can compare and add the operands if condition is met, which can +improve database performance. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 7] + +Add CPUID definition for CMPCCXADD. + +Intel-SIG: commit a9ce107fd0f2 target/i386: Add support for CMPCCXADD in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-2-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 58124071da..47c2d9da80 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -872,7 +872,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, +- "avx-vnni", "avx512-bf16", NULL, NULL, ++ "avx-vnni", "avx512-bf16", NULL, "cmpccxadd", + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 37c687d4d8..4a7362ee07 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -883,6 +883,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) + /* AVX512 BFloat16 Instruction */ + #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) ++/* CMPCCXADD Instructions */ ++#define CPUID_7_1_EAX_CMPCCXADD (1U << 7) + /* Fast Zero REP MOVS */ + #define CPUID_7_1_EAX_FZRM (1U << 10) + /* Fast Short REP STOS */ +-- +2.27.0 + diff --git a/target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch b/target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch new file mode 100644 index 0000000000000000000000000000000000000000..0dbfc10a7f56394119868f1a33fe7f891497e035 --- /dev/null +++ b/target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch @@ -0,0 +1,112 @@ +From a7329b80a2c8a50e53da17aa4eff0ef50aa21413 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:45 +0800 +Subject: [PATCH] target/i386: Add support for MCDT_NO in CPUID enumeration + +commit 9dd8b71091f47bac395f543779269c14d8d93c60 upstream. + +CPUID.(EAX=7,ECX=2):EDX[bit 5] enumerates MCDT_NO. Processors enumerate +this bit as 1 do not exhibit MXCSR Configuration Dependent Timing (MCDT) +behavior and do not need to be mitigated to avoid data-dependent behavior +for certain instructions. + +Since MCDT_NO is in a new sub-leaf, add a new CPUID feature word +FEAT_7_2_EDX. Also update cpuid_level_func7 by FEAT_7_2_EDX. + +Intel-SIG: commit 9dd8b71091f4 ("target/i386: Add support for MCDT_NO in CPUID enumeration") +Backport support for MCDT_NO in CPUID enumeration + +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-3-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ jason: resolve conflict with FEAT_7_1_EDX which not backported yet ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 26 ++++++++++++++++++++++++++ + target/i386/cpu.h | 4 ++++ + 2 files changed, 30 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b878a1bf20..685bfca37e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -663,6 +663,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM + #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ + CPUID_7_1_EAX_FSRC) ++#define TCG_7_2_EDX_FEATURES 0 + #define TCG_APM_FEATURES 0 + #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT + #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) +@@ -886,6 +887,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + }, + .tcg_features = TCG_7_1_EAX_FEATURES, + }, ++ [FEAT_7_2_EDX] = { ++ .type = CPUID_FEATURE_WORD, ++ .feat_names = { ++ NULL, NULL, NULL, NULL, ++ NULL, "mcdt-no", NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ }, ++ .cpuid = { ++ .eax = 7, ++ .needs_ecx = true, .ecx = 2, ++ .reg = R_EDX, ++ }, ++ .tcg_features = TCG_7_2_EDX_FEATURES, ++ }, + [FEAT_8000_0007_EDX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { +@@ -5531,6 +5551,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ebx = 0; + *ecx = 0; + *edx = 0; ++ } else if (count == 2) { ++ *edx = env->features[FEAT_7_2_EDX]; ++ *eax = 0; ++ *ebx = 0; ++ *ecx = 0; + } else { + *eax = 0; + *ebx = 0; +@@ -6361,6 +6386,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); ++ x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index d9aac5acd2..edbaba0d62 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -601,6 +601,7 @@ typedef enum FeatureWord { + FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ + FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ + FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ ++ FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ + FEATURE_WORDS, + } FeatureWord; + +@@ -889,6 +890,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + /* Fast Short REP CMPS/SCAS */ + #define CPUID_7_1_EAX_FSRC (1U << 12) + ++/* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ ++#define CPUID_7_2_EDX_MCDT_NO (1U << 5) ++ + /* XFD Extend Feature Disabled */ + #define CPUID_D_1_EAX_XFD (1U << 4) + +-- +2.41.0.windows.1 + diff --git a/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch b/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch new file mode 100644 index 0000000000000000000000000000000000000000..59053fd787257ca0e120a32b0d398f10b81f2616 --- /dev/null +++ b/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch @@ -0,0 +1,61 @@ +From 9a56c714caaf3bf31430a769befdf92e79388dda Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:46:00 +0800 +Subject: [PATCH] target/i386: Add support for PREFETCHIT0/1 in CPUID + enumeration + +commit d1a1111514333e46a98b136235f71eef90d610fa upstream. + +Latest Intel platform Granite Rapids has introduced a new instruction - +PREFETCHIT0/1, which moves code to memory (cache) closer to the +processor depending on specific hints. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 14] + +Add CPUID definition for PREFETCHIT0/1. + +Intel-SIG: commit d1a111151433 target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-7-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d36174d689..ee243693e3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -913,7 +913,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, NULL, NULL, + "avx-vnni-int8", "avx-ne-convert", NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, "prefetchiti", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 93c8bd6a13..32ecec5fa7 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -900,6 +900,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) + /* AVX NE CONVERT Instructions */ + #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) ++/* PREFETCHIT0/1 Instructions */ ++#define CPUID_7_1_EDX_PREFETCHITI (1U << 14) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Adjust-feature-level-according-to-FEAT_7.patch b/target-i386-Adjust-feature-level-according-to-FEAT_7.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c238c62f69f25e0943d4d95f2f6933361564b69 --- /dev/null +++ b/target-i386-Adjust-feature-level-according-to-FEAT_7.patch @@ -0,0 +1,46 @@ +From 52d000a4043f3000f880bb5c75a298f57b8e0fe0 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:44 +0800 +Subject: [PATCH] target/i386: Adjust feature level according to FEAT_7_1_EDX + +commit 8731336e90dea3dd04948127e775c9f087f97a4c upstream. + +If FEAT_7_1_EAX is 0 and FEAT_7_1_EDX is non-zero, as is the case +with a Granite Rapids host and +'-cpu host,-avx-vnni,-avx512-bf16,-fzrm,-fsrs,-fsrc,-amx-fp16', we can't +get CPUID_7_1 leaf even though CPUID_7_1_EDX has non-zero value. + +Update cpuid_level_func7 according to CPUID_7_1_EDX, otherwise +guest may report wrong maximum number sub-leaves in leaf 07H. + +Fixes: eaaa197d5b11 ("target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration") + +Intel-SIG: commit 8731336e90de target/i386: Adjust feature level according to FEAT_7_1_EDX. +Backport GNR and SRF ISA into QEMU-6.2 + +Cc: qemu-stable@nongnu.org +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-2-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index efe0c2b46c..6aaa730a0d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6551,6 +6551,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); ++ x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); +-- +2.27.0 + diff --git a/target-i386-Allow-MCDT_NO-if-host-supports.patch b/target-i386-Allow-MCDT_NO-if-host-supports.patch new file mode 100644 index 0000000000000000000000000000000000000000..a95c27ea6ffc34d275cb1df8cd45420c1de83195 --- /dev/null +++ b/target-i386-Allow-MCDT_NO-if-host-supports.patch @@ -0,0 +1,43 @@ +From 6beadcde4d28a1e4ad3267b7702162ecf9d4541b Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:46 +0800 +Subject: [PATCH] target/i386: Allow MCDT_NO if host supports + +commit ba3709feaab44631315e02cd793cfccae4c6bd2a upstream. + +MCDT_NO bit indicates HW contains the security fix and doesn't need to +be mitigated to avoid data-dependent behaviour for certain instructions. +It needs no hypervisor support. Treat it as supported regardless of what +KVM reports. + +Intel-SIG: commit ba3709feaab4 ("target/i386: Allow MCDT_NO if host supports") +Backport allowing MCDT_NO if host supports + +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-4-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/kvm/kvm.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index d323d08dcb..55ee75e844 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -424,6 +424,10 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + uint32_t eax; + host_cpuid(7, 1, &eax, &unused, &unused, &unused); + ret |= eax & (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC); ++ } else if (function == 7 && index == 2 && reg == R_EDX) { ++ uint32_t edx; ++ host_cpuid(7, 2, &unused, &unused, &unused, &edx); ++ ret |= edx & CPUID_7_2_EDX_MCDT_NO; + } else if (function == 0xd && index == 0 && + (reg == R_EAX || reg == R_EDX)) { + /* +-- +2.41.0.windows.1 + diff --git a/target-i386-Export-GDS_NO-bit-to-guests.patch b/target-i386-Export-GDS_NO-bit-to-guests.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b6e5f10815daeed3d809ead15b6141330f6f877 --- /dev/null +++ b/target-i386-Export-GDS_NO-bit-to-guests.patch @@ -0,0 +1,46 @@ +From 3cea2c36571b39a6fa956abe66507c04283ad614 Mon Sep 17 00:00:00 2001 +From: Pawan Gupta +Date: Mon, 14 Aug 2023 21:54:27 -0700 +Subject: [PATCH] target/i386: Export GDS_NO bit to guests + +commit 3a2a1f97ea349745094e789e6b0768dbd92d0dcd upstream. + +Gather Data Sampling (GDS) is a side-channel attack using Gather +instructions. Some Intel processors will set ARCH_CAP_GDS_NO bit in +MSR IA32_ARCH_CAPABILITIES to report that they are not vulnerable to +GDS. + +Make this bit available to guests. + +Intel-SIG: commit 3a2a1f97ea34 ("target/i386: Export GDS_NO bit to guests") +Backport to export GDS_NO bit to guests(CVE-2022-40982). + +Closes: https://lore.kernel.org/qemu-devel/CAMGffEmG6TNq0n3+4OJAgXc8J0OevY60KHZekXCBs3LoK9vehA@mail.gmail.com/ +Reported-by: Jack Wang +Signed-off-by: Pawan Gupta +Tested-by: Jack Wang +Tested-by: Daniel Sneddon +Message-ID: +Signed-off-by: Paolo Bonzini +[ Aichun Shi: amend commit log ] +Signed-off-by: Aichun Shi +--- + target/i386/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index eb911b12fa..58124071da 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1004,7 +1004,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", + NULL, "fb-clear", NULL, NULL, + NULL, NULL, NULL, NULL, +- "pbrsb-no", NULL, NULL, NULL, ++ "pbrsb-no", NULL, "gds-no", NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { +-- +2.27.0 + diff --git a/target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch b/target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac4e016198be24f07fe83f1265440b45d0cbf963 --- /dev/null +++ b/target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch @@ -0,0 +1,47 @@ +From 93551bb8747ffc9ef26fc3ced7be310d9aa805d6 Mon Sep 17 00:00:00 2001 +From: Pawan Gupta +Date: Fri, 23 Jun 2023 13:26:25 -0700 +Subject: [PATCH] target/i386: Export MSR_ARCH_CAPABILITIES bits to guests + +commit 5bef742cc4f0e21c80a31611af7881ba811e507f upstream. + +On Intel CPUs there are certain bits in MSR_ARCH_CAPABILITIES that +indicates if the CPU is not affected by a vulnerability. Without these +bits guests may try to deploy the mitigation even if the CPU is not +affected. + +Export the bits to guests that indicate immunity to hardware +vulnerabilities. + +Intel-SIG: commit 5bef742cc4f0 ("target/i386: Export MSR_ARCH_CAPABILITIES bits to guests") +Backport exporting MSR_ARCH_CAPABILITIES bits to guests + +Signed-off-by: Pawan Gupta +Message-ID: <63d85cc76d4cdc51e6c732478b81d8f13be11e5a.1687551881.git.pawan.kumar.gupta@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 8adc84b7f9..b878a1bf20 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -981,10 +981,10 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "rdctl-no", "ibrs-all", "rsba", "skip-l1dfl-vmentry", + "ssb-no", "mds-no", "pschange-mc-no", "tsx-ctrl", + "taa-no", NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", + NULL, "fb-clear", NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ "pbrsb-no", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { +-- +2.41.0.windows.1 + diff --git a/target-i386-Export-TAA_NO-bit-to-guests.patch b/target-i386-Export-TAA_NO-bit-to-guests.patch deleted file mode 100644 index 8d995dc840bbace44c4d59b61f70167e960e2699..0000000000000000000000000000000000000000 --- a/target-i386-Export-TAA_NO-bit-to-guests.patch +++ /dev/null @@ -1,36 +0,0 @@ -From c828229e1dc4a3d0837071db4c08f7860dc24755 Mon Sep 17 00:00:00 2001 -From: Pawan Gupta -Date: Mon, 18 Nov 2019 23:23:27 -0800 -Subject: [PATCH] target/i386: Export TAA_NO bit to guests - -TSX Async Abort (TAA) is a side channel attack on internal buffers in -some Intel processors similar to Microachitectural Data Sampling (MDS). - -Some future Intel processors will use the ARCH_CAP_TAA_NO bit in the -IA32_ARCH_CAPABILITIES MSR to report that they are not vulnerable to -TAA. Make this bit available to guests. - -Signed-off-by: Pawan Gupta -Signed-off-by: Paolo Bonzini - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 29836cb2a5..5af4fca350 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1209,7 +1209,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .feat_names = { - "rdctl-no", "ibrs-all", "rsba", "skip-l1dfl-vmentry", - "ssb-no", "mds-no", "pschange-mc-no", NULL, -- NULL, NULL, NULL, NULL, -+ "taa-no", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, --- -2.27.0 - diff --git a/target-i386-Fix-sanity-check-on-max-APIC-ID-X2APIC-e.patch b/target-i386-Fix-sanity-check-on-max-APIC-ID-X2APIC-e.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9dec7a58afd2459ee8f09d0db9a693b8dde62a1 --- /dev/null +++ b/target-i386-Fix-sanity-check-on-max-APIC-ID-X2APIC-e.patch @@ -0,0 +1,109 @@ +From 197ebfabf4319c3dff79f06822d98304df2a3110 Mon Sep 17 00:00:00 2001 +From: David Woodhouse +Date: Mon, 14 Mar 2022 14:25:41 +0000 +Subject: [PATCH] target/i386: Fix sanity check on max APIC ID / X2APIC + enablement + +from mainline-v7.1.0-rc0 +commit dc89f32d92bba795b0665f075b78d8881cf67ab3 +category: feature +feature: Optimization of IPI virtualization +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Y34T + +Intel-SIG: commit dc89f32d92bb ("target/i386: Fix sanity check on max APIC ID / X2APIC enablement") + +------------------------------------------------ + +The check on x86ms->apic_id_limit in pc_machine_done() had two problems. + +Firstly, we need KVM to support the X2APIC API in order to allow IRQ +delivery to APICs >= 255. So we need to call/check kvm_enable_x2apic(), +which was done elsewhere in *some* cases but not all. + +Secondly, microvm needs the same check. So move it from pc_machine_done() +to x86_cpus_init() where it will work for both. + +The check in kvm_cpu_instance_init() is now redundant and can be dropped. + +Signed-off-by: David Woodhouse +Acked-by: Claudio Fontana +Message-Id: <20220314142544.150555-1-dwmw2@infradead.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + hw/i386/pc.c | 8 -------- + hw/i386/x86.c | 16 ++++++++++++++++ + target/i386/kvm/kvm-cpu.c | 2 +- + 3 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 4870ce0f96..c5f430f83d 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -736,14 +736,6 @@ void pc_machine_done(Notifier *notifier, void *data) + /* update FW_CFG_NB_CPUS to account for -device added CPUs */ + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); + } +- +- +- if (x86ms->apic_id_limit > 255 && !xen_enabled() && +- !kvm_irqchip_in_kernel()) { +- error_report("current -smp configuration requires kernel " +- "irqchip support."); +- exit(EXIT_FAILURE); +- } + } + + void pc_guest_info_init(PCMachineState *pcms) +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index b84840a1bb..f64639b873 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -39,6 +39,7 @@ + #include "sysemu/replay.h" + #include "sysemu/sysemu.h" + #include "sysemu/cpu-timers.h" ++#include "sysemu/xen.h" + #include "trace.h" + + #include "hw/i386/x86.h" +@@ -136,6 +137,21 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) + */ + x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms, + ms->smp.max_cpus - 1) + 1; ++ ++ /* ++ * Can we support APIC ID 255 or higher? ++ * ++ * Under Xen: yes. ++ * With userspace emulated lapic: no ++ * With KVM's in-kernel lapic: only if X2APIC API is enabled. ++ */ ++ if (x86ms->apic_id_limit > 255 && !xen_enabled() && ++ (!kvm_irqchip_in_kernel() || !kvm_enable_x2apic())) { ++ error_report("current -smp configuration requires kernel " ++ "irqchip and X2APIC API support."); ++ exit(EXIT_FAILURE); ++ } ++ + possible_cpus = mc->possible_cpu_arch_ids(ms); + for (i = 0; i < ms->smp.cpus; i++) { + x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index 5eb955ce9a..7237378a7d 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -171,7 +171,7 @@ static void kvm_cpu_instance_init(CPUState *cs) + /* only applies to builtin_x86_defs cpus */ + if (!kvm_irqchip_in_kernel()) { + x86_cpu_change_kvm_default("x2apic", "off"); +- } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { ++ } else if (kvm_irqchip_is_split()) { + x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); + } + +-- +2.27.0 + diff --git a/target-i386-Fix-the-RES-memory-inc-which-caused-by-t.patch b/target-i386-Fix-the-RES-memory-inc-which-caused-by-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..ae16318772e2e2e2ff67042f20aebc4467b56c34 --- /dev/null +++ b/target-i386-Fix-the-RES-memory-inc-which-caused-by-t.patch @@ -0,0 +1,30 @@ +From 6e070be26502e171fd5d43a128dea99f1d34429b Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 10 Feb 2022 21:41:06 +0800 +Subject: [PATCH] target-i386: Fix the RES memory inc which caused by the + coroutine created + +for better performance, change the POOL_BATCH_SIZE from 64 to 128. + +Signed-off-by: caojinhua +Signed-off-by: jiangdongxu +--- + util/qemu-coroutine.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c +index 38fb6d3084..b9586d6929 100644 +--- a/util/qemu-coroutine.c ++++ b/util/qemu-coroutine.c +@@ -21,7 +21,7 @@ + #include "block/aio.h" + + enum { +- POOL_BATCH_SIZE = 64, ++ POOL_BATCH_SIZE = 128, + }; + + /** Free list to speed up creation */ +-- +2.27.0 + diff --git a/target-i386-Introduce-Denverton-CPU-model.patch b/target-i386-Introduce-Denverton-CPU-model.patch deleted file mode 100644 index 3e9debe339e6d1b0f7c0ca0ad019129de668363b..0000000000000000000000000000000000000000 --- a/target-i386-Introduce-Denverton-CPU-model.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 7d602cefa04f4992d913683c1a5826abc4806e41 Mon Sep 17 00:00:00 2001 -From: Tao Xu -Date: Thu, 18 Jul 2019 15:34:05 +0800 -Subject: [PATCH] target/i386: Introduce Denverton CPU model - -Denverton is the Atom Processor of Intel Harrisonville platform. - -For more information: -https://ark.intel.com/content/www/us/en/ark/products/\ -codename/63508/denverton.html - -Signed-off-by: Tao Xu -Message-Id: <20190718073405.28301-1-tao3.xu@intel.com> -Signed-off-by: Eduardo Habkost ---- - target/i386/cpu.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 47 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 5af4fca350..d3742ef4ac 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2552,6 +2552,53 @@ static X86CPUDefinition builtin_x86_defs[] = { - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Icelake)", - }, -+ { -+ .name = "Denverton", -+ .level = 21, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 95, -+ .stepping = 1, -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_MONITOR | -+ CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | -+ CPUID_EXT_AES | CPUID_EXT_XSAVE | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_ERMS | -+ CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_SMAP | -+ CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_SHA_NI, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES | -+ CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ /* -+ * Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component, -+ * and the only one defined in Skylake (processor tracing) -+ * probably will block migration anyway. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Atom Processor (Denverton)", -+ }, - { - .name = "Snowridge", - .level = 27, --- -2.27.0 - diff --git a/target-i386-KVM-allow-fast-string-operations-if-host.patch b/target-i386-KVM-allow-fast-string-operations-if-host.patch new file mode 100644 index 0000000000000000000000000000000000000000..7015ee27a6800a4c358ca751402a2b890c5906b7 --- /dev/null +++ b/target-i386-KVM-allow-fast-string-operations-if-host.patch @@ -0,0 +1,81 @@ +From 52ee6f565f4b4a0ca3325e94dcb44ce68ca61eee Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 27 Feb 2023 10:41:46 +0100 +Subject: [PATCH] target/i386: KVM: allow fast string operations if host + supports them + +mainline inclusion +from mainline-v8.0.0-rc0 +commit 3023c9b4d1092eb27a523c08d9e78cbaec67b59b +category: feature +feature: Intel fast REP string operations support +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6ZGIX + +Intel-SIG: commit 3023c9b4d109 ("target/i386: KVM: allow fast string operations if host supports them") + +------------------------------------- + +target/i386: KVM: allow fast string operations if host supports them + +These are just a flag that documents the performance characteristic of +an instruction; it needs no hypervisor support. So include them even +if KVM does not show them. In particular, FZRM/FSRS/FSRC have only +been added very recently, but they are available on Sapphire Rapids +processors. + +Reviewed-by: Xiaoyao Li +Signed-off-by: Paolo Bonzini +Signed-off-by: Aichun Shi +--- + target/i386/kvm/kvm.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index b8257e7e5f..6fa3bd9694 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -350,7 +350,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + { + struct kvm_cpuid2 *cpuid; + uint32_t ret = 0; +- uint32_t cpuid_1_edx; ++ uint32_t cpuid_1_edx, unused; + uint64_t bitmask; + + cpuid = get_supported_cpuid(s); +@@ -397,10 +397,20 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + } else if (function == 6 && reg == R_EAX) { + ret |= CPUID_6_EAX_ARAT; /* safe to allow because of emulated APIC */ + } else if (function == 7 && index == 0 && reg == R_EBX) { ++ /* Not new instructions, just an optimization. */ ++ uint32_t ebx; ++ host_cpuid(7, 0, &unused, &ebx, &unused, &unused); ++ ret |= ebx & CPUID_7_0_EBX_ERMS; ++ + if (host_tsx_broken()) { + ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE); + } + } else if (function == 7 && index == 0 && reg == R_EDX) { ++ /* Not new instructions, just an optimization. */ ++ uint32_t edx; ++ host_cpuid(7, 0, &unused, &unused, &unused, &edx); ++ ret |= edx & CPUID_7_0_EDX_FSRM; ++ + /* + * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. + * We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is +@@ -409,6 +419,11 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + if (!has_msr_arch_capabs) { + ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; + } ++ } else if (function == 7 && index == 1 && reg == R_EAX) { ++ /* Not new instructions, just an optimization. */ ++ uint32_t eax; ++ host_cpuid(7, 1, &eax, &unused, &unused, &unused); ++ ret |= eax & (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC); + } else if (function == 0xd && index == 0 && + (reg == R_EAX || reg == R_EDX)) { + /* +-- +2.27.0 + diff --git a/target-i386-Modify-the-VM-s-physical-bits-value-set-.patch b/target-i386-Modify-the-VM-s-physical-bits-value-set-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a490b614796ce0d33f645039c057ca8950187be --- /dev/null +++ b/target-i386-Modify-the-VM-s-physical-bits-value-set-.patch @@ -0,0 +1,116 @@ +From a09c3928b33b0c53831bd9eeb56f8171c26057bc Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Tue, 8 Feb 2022 09:46:53 +0800 +Subject: [PATCH 2/2] target-i386: Modify the VM's physical bits value set + policy. + +To resolve the problem that a VM with large memory capacity fails +to be live migrated, determine whether the VM is a large memory +capacity based on the memory size (4 TB). If yes, set the bus width +of the VM address to 46 bits. If no, set the bus width to 42 bits. + +Signed-off-by: Jinhua Cao +Signed-off-by: Jiajie Li +--- + target/i386/cpu.c | 19 ++++++++++++++++++- + target/i386/cpu.h | 6 ++++++ + target/i386/host-cpu.c | 13 +++++++------ + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index aa9e636800..868cf3e7e8 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6678,6 +6678,23 @@ static void x86_cpu_set_pc(CPUState *cs, vaddr value) + cpu->env.eip = value; + } + ++/* At present, we check the vm is *LARGE* or not, i.e. whether ++ * the memory size is more than 4T or not. ++ */ ++const uint64_t large_vm_mem_size = 0x40000000000UL; ++void x86_cpu_adjuest_by_ram_size(ram_addr_t ram_size, X86CPU *cpu) ++{ ++ /* If there is not a large vm, we set the phys_bits to 42 bits, ++ * otherwise, we increase the phys_bits to 46 bits. ++ */ ++ if (ram_size < large_vm_mem_size) { ++ cpu->phys_bits = DEFAULT_VM_CPU_PHYS_BITS; ++ } else { ++ cpu->phys_bits = LARGE_VM_CPU_PHYS_BITS; ++ cpu->fill_mtrr_mask = true; ++ } ++} ++ + int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request) + { + X86CPU *cpu = X86_CPU(cs); +@@ -6862,7 +6879,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0), + DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), + DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), +- DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), ++ DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, false), + DEFINE_PROP_UINT32("level-func7", X86CPU, env.cpuid_level_func7, + UINT32_MAX), + DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 04f2b790c9..6f777fd6ca 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -24,6 +24,7 @@ + #include "cpu-qom.h" + #include "kvm/hyperv-proto.h" + #include "exec/cpu-defs.h" ++#include "exec/cpu-common.h" + #include "qapi/qapi-types-common.h" + + /* The x86 has a strong memory model with some store-after-load re-ordering */ +@@ -1841,6 +1842,11 @@ struct X86CPU { + extern const VMStateDescription vmstate_x86_cpu; + #endif + ++#define DEFAULT_VM_CPU_PHYS_BITS 42 ++#define LARGE_VM_CPU_PHYS_BITS 46 ++ ++void x86_cpu_adjuest_by_ram_size(ram_addr_t ram_size, X86CPU *cpu); ++ + int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request); + + int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, +diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c +index 10f8aba86e..5a1bbefa36 100644 +--- a/target/i386/host-cpu.c ++++ b/target/i386/host-cpu.c +@@ -12,6 +12,7 @@ + #include "host-cpu.h" + #include "qapi/error.h" + #include "sysemu/sysemu.h" ++#include "hw/boards.h" + + /* Note: Only safe for use on x86(-64) hosts */ + static uint32_t host_cpu_phys_bits(void) +@@ -56,14 +57,14 @@ static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu) + uint32_t phys_bits = cpu->phys_bits; + static bool warned; + +- /* +- * Print a warning if the user set it to a value that's not the +- * host value. +- */ +- if (phys_bits != host_phys_bits && phys_bits != 0 && ++ /* adjust x86 cpu phys_bits according to ram_size. */ ++ x86_cpu_adjuest_by_ram_size(current_machine->ram_size, cpu); ++ ++ /* Print a warning if the host value less than the user set. */ ++ if (phys_bits > host_phys_bits && phys_bits != 0 && + !warned) { + warn_report("Host physical bits (%u)" +- " does not match phys-bits property (%u)", ++ " less than phys-bits property (%u)", + host_phys_bits, phys_bits); + warned = true; + } +-- +2.27.0 + diff --git a/target-i386-Set-maximum-APIC-ID-to-KVM-prior-to-vCPU.patch b/target-i386-Set-maximum-APIC-ID-to-KVM-prior-to-vCPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..04d6bb61193c1b89f1886f97bcc6ef54e7cad8b7 --- /dev/null +++ b/target-i386-Set-maximum-APIC-ID-to-KVM-prior-to-vCPU.patch @@ -0,0 +1,95 @@ +From db3e0a8dd430a11e8dde6aee4e1f9cca4af0e015 Mon Sep 17 00:00:00 2001 +From: Zeng Guang +Date: Thu, 25 Aug 2022 10:52:46 +0800 +Subject: [PATCH] target/i386: Set maximum APIC ID to KVM prior to vCPU + creation + +from mainline-v7.2.0-rc0 +commit 19e2a9fb9da067acba95b3be83588bda5a3f6a99 +category: feature +feature: Optimization of IPI virtualization +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6Y34T + +Intel-SIG: commit 19e2a9fb9da0 ("target/i386: Set maximum APIC ID to KVM prior to vCPU creation") + +------------------------------------------------ + +Specify maximum possible APIC ID assigned for current VM session to KVM +prior to the creation of vCPUs. By this setting, KVM can set up VM-scoped +data structure indexed by the APIC ID, e.g. Posted-Interrupt Descriptor +pointer table to support Intel IPI virtualization, with the most optimal +memory footprint. + +It can be achieved by calling KVM_ENABLE_CAP for KVM_CAP_MAX_VCPU_ID +capability once KVM has enabled it. Ignoring the return error if KVM +doesn't support this capability yet. + +Signed-off-by: Zeng Guang +Acked-by: Peter Xu +Acked-by: Michael S. Tsirkin +Message-Id: <20220825025246.26618-1-guang.zeng@intel.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + hw/i386/x86.c | 4 ++++ + target/i386/kvm/kvm-stub.c | 5 +++++ + target/i386/kvm/kvm.c | 5 +++++ + target/i386/kvm/kvm_i386.h | 2 ++ + 4 files changed, 16 insertions(+) + +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index f64639b873..a3258d78fa 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -152,6 +152,10 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) + exit(EXIT_FAILURE); + } + ++ if (kvm_enabled()) { ++ kvm_set_max_apic_id(x86ms->apic_id_limit); ++ } ++ + possible_cpus = mc->possible_cpu_arch_ids(ms); + for (i = 0; i < ms->smp.cpus; i++) { + x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); +diff --git a/target/i386/kvm/kvm-stub.c b/target/i386/kvm/kvm-stub.c +index f6e7e4466e..e052f1c7b0 100644 +--- a/target/i386/kvm/kvm-stub.c ++++ b/target/i386/kvm/kvm-stub.c +@@ -44,3 +44,8 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) + { + abort(); + } ++ ++void kvm_set_max_apic_id(uint32_t max_apic_id) ++{ ++ return; ++} +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index b8257e7e5f..7212ed98a9 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5270,3 +5270,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc) + "Clock cycles without an event window " + "after which a notification VM exit occurs"); + } ++ ++void kvm_set_max_apic_id(uint32_t max_apic_id) ++{ ++ kvm_vm_enable_cap(kvm_state, KVM_CAP_MAX_VCPU_ID, 0, max_apic_id); ++} +diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h +index 4124912c20..58590138e5 100644 +--- a/target/i386/kvm/kvm_i386.h ++++ b/target/i386/kvm/kvm_i386.h +@@ -54,4 +54,6 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); + bool kvm_enable_sgx_provisioning(KVMState *s); + void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); + ++void kvm_set_max_apic_id(uint32_t max_apic_id); ++ + #endif +-- +2.27.0 + diff --git a/target-i386-add-FSRM-to-TCG.patch b/target-i386-add-FSRM-to-TCG.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3536ace803173dbde26d5a60a2aa30a3f95f9c3 --- /dev/null +++ b/target-i386-add-FSRM-to-TCG.patch @@ -0,0 +1,44 @@ +From 2a2b5f93c2ee2071eb32c65f925974d02c11808d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 27 Feb 2023 10:57:09 +0100 +Subject: [PATCH] target/i386: add FSRM to TCG + +mainline inclusion +from mainline-v8.0.0-rc0 +commit c0728d4e3d23356691e4182eac54c67e1ca26618 +category: feature +feature: Intel fast REP string operations support +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I6ZGIX + +Intel-SIG: commit c0728d4e3d23 ("target/i386: add FSRM to TCG") + +------------------------------------- + +target/i386: add FSRM to TCG + +Fast short REP MOVS can be added to TCG, since a trivial translation +of string operation is a good option for short lengths. + +Reviewed-by: Xiaoyao Li +Signed-off-by: Paolo Bonzini +Signed-off-by: Aichun Shi +--- + target/i386/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 61cd7abcaa..13dcd4c720 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -660,7 +660,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ + /* CPUID_7_0_ECX_OSPKE is dynamic */ \ + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) +-#define TCG_7_0_EDX_FEATURES 0 ++#define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM + #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ + CPUID_7_1_EAX_FSRC) + #define TCG_APM_FEATURES 0 +-- +2.27.0 + diff --git a/target-i386-add-FZRM-FSRS-FSRC.patch b/target-i386-add-FZRM-FSRS-FSRC.patch new file mode 100644 index 0000000000000000000000000000000000000000..2077add338175e88fc5cd3752be19d82c076d2ee --- /dev/null +++ b/target-i386-add-FZRM-FSRS-FSRC.patch @@ -0,0 +1,62 @@ +From 37ef938fd9cdea1c9f87b17f49a935f729374f1d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 27 Feb 2023 10:55:46 +0100 +Subject: [PATCH] target/i386: add FZRM, FSRS, FSRC + +These are three more markers for string operation optimizations. +They can all be added to TCG, whose string operations are more or +less as fast as they can be for short lengths. + +Reviewed-by: Xiaoyao Li +Signed-off-by: Paolo Bonzini +--- + target/i386/cpu.c | 7 ++++--- + target/i386/cpu.h | 7 +++++++ + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e3cea8397c..7122af303d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -661,7 +661,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + /* CPUID_7_0_ECX_OSPKE is dynamic */ \ + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) + #define TCG_7_0_EDX_FEATURES 0 +-#define TCG_7_1_EAX_FEATURES 0 ++#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ ++ CPUID_7_1_EAX_FSRC) + #define TCG_APM_FEATURES 0 + #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT + #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) +@@ -871,8 +872,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .feat_names = { + NULL, NULL, NULL, NULL, + "avx-vnni", "avx512-bf16", NULL, NULL, +- NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, "fzrm", "fsrs", ++ "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 4f7fa87b95..7a32dabf12 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -876,6 +876,13 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) + /* AVX512 BFloat16 Instruction */ + #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) ++/* Fast Zero REP MOVS */ ++#define CPUID_7_1_EAX_FZRM (1U << 10) ++/* Fast Short REP STOS */ ++#define CPUID_7_1_EAX_FSRS (1U << 11) ++/* Fast Short REP CMPS/SCAS */ ++#define CPUID_7_1_EAX_FSRC (1U << 12) ++ + /* XFD Extend Feature Disabled */ + #define CPUID_D_1_EAX_XFD (1U << 4) + +-- +2.27.0 + diff --git a/target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch b/target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch deleted file mode 100644 index 6cba87b020b3f5a01fbc2f74958d8e9c03a9d1a2..0000000000000000000000000000000000000000 --- a/target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 4372535d5f2f50b24d14ec8a3393aebec938fb61 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 13 Nov 2019 15:54:35 +0100 -Subject: [PATCH] target/i386: add PSCHANGE_NO bit for the ARCH_CAPABILITIES - MSR - -This is required to disable ITLB multihit mitigations in nested -hypervisors. - -Signed-off-by: Paolo Bonzini - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 50d6ef9de4..29836cb2a5 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1208,7 +1208,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .type = MSR_FEATURE_WORD, - .feat_names = { - "rdctl-no", "ibrs-all", "rsba", "skip-l1dfl-vmentry", -- "ssb-no", "mds-no", NULL, NULL, -+ "ssb-no", "mds-no", "pschange-mc-no", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, --- -2.27.0 - diff --git a/target-i386-add-VMX-definitions.patch b/target-i386-add-VMX-definitions.patch deleted file mode 100644 index 4365e3a7a1082abf15b5e9c51a7c3801e27ee806..0000000000000000000000000000000000000000 --- a/target-i386-add-VMX-definitions.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 9fb16fc548fca297086be0efe20345160660f340 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 1 Jul 2019 18:24:52 +0200 -Subject: [PATCH] target/i386: add VMX definitions - -These will be used to compile the list of VMX features for named -CPU models, and/or by the code that sets up the VMX MSRs. - -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.h | 130 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 130 insertions(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 9a105b2251..b4be6ffb1f 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -452,6 +452,25 @@ typedef enum X86Seg { - #define MSR_IA32_BNDCFGS 0x00000d90 - #define MSR_IA32_XSS 0x00000da0 - -+#define MSR_IA32_VMX_BASIC 0x00000480 -+#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 -+#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 -+#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 -+#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 -+#define MSR_IA32_VMX_MISC 0x00000485 -+#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 -+#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 -+#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 -+#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 -+#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a -+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b -+#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c -+#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d -+#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e -+#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f -+#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 -+#define MSR_IA32_VMX_VMFUNC 0x00000491 -+ - #define XSTATE_FP_BIT 0 - #define XSTATE_SSE_BIT 1 - #define XSTATE_YMM_BIT 2 -@@ -757,6 +776,117 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; - - #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) - -+/* VMX MSR features */ -+#define MSR_VMX_BASIC_VMCS_REVISION_MASK 0x7FFFFFFFull -+#define MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK (0x00001FFFull << 32) -+#define MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK (0x003C0000ull << 32) -+#define MSR_VMX_BASIC_DUAL_MONITOR (1ULL << 49) -+#define MSR_VMX_BASIC_INS_OUTS (1ULL << 54) -+#define MSR_VMX_BASIC_TRUE_CTLS (1ULL << 55) -+ -+#define MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK 0x1Full -+#define MSR_VMX_MISC_STORE_LMA (1ULL << 5) -+#define MSR_VMX_MISC_ACTIVITY_HLT (1ULL << 6) -+#define MSR_VMX_MISC_ACTIVITY_SHUTDOWN (1ULL << 7) -+#define MSR_VMX_MISC_ACTIVITY_WAIT_SIPI (1ULL << 8) -+#define MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK 0x0E000000ull -+#define MSR_VMX_MISC_VMWRITE_VMEXIT (1ULL << 29) -+#define MSR_VMX_MISC_ZERO_LEN_INJECT (1ULL << 30) -+ -+#define MSR_VMX_EPT_EXECONLY (1ULL << 0) -+#define MSR_VMX_EPT_PAGE_WALK_LENGTH_4 (1ULL << 6) -+#define MSR_VMX_EPT_PAGE_WALK_LENGTH_5 (1ULL << 7) -+#define MSR_VMX_EPT_UC (1ULL << 8) -+#define MSR_VMX_EPT_WB (1ULL << 14) -+#define MSR_VMX_EPT_2MB (1ULL << 16) -+#define MSR_VMX_EPT_1GB (1ULL << 17) -+#define MSR_VMX_EPT_INVEPT (1ULL << 20) -+#define MSR_VMX_EPT_AD_BITS (1ULL << 21) -+#define MSR_VMX_EPT_ADVANCED_VMEXIT_INFO (1ULL << 22) -+#define MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT (1ULL << 25) -+#define MSR_VMX_EPT_INVEPT_ALL_CONTEXT (1ULL << 26) -+#define MSR_VMX_EPT_INVVPID (1ULL << 32) -+#define MSR_VMX_EPT_INVVPID_SINGLE_ADDR (1ULL << 40) -+#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT (1ULL << 41) -+#define MSR_VMX_EPT_INVVPID_ALL_CONTEXT (1ULL << 42) -+#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS (1ULL << 43) -+ -+#define MSR_VMX_VMFUNC_EPT_SWITCHING (1ULL << 0) -+ -+ -+/* VMX controls */ -+#define VMX_CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 -+#define VMX_CPU_BASED_USE_TSC_OFFSETING 0x00000008 -+#define VMX_CPU_BASED_HLT_EXITING 0x00000080 -+#define VMX_CPU_BASED_INVLPG_EXITING 0x00000200 -+#define VMX_CPU_BASED_MWAIT_EXITING 0x00000400 -+#define VMX_CPU_BASED_RDPMC_EXITING 0x00000800 -+#define VMX_CPU_BASED_RDTSC_EXITING 0x00001000 -+#define VMX_CPU_BASED_CR3_LOAD_EXITING 0x00008000 -+#define VMX_CPU_BASED_CR3_STORE_EXITING 0x00010000 -+#define VMX_CPU_BASED_CR8_LOAD_EXITING 0x00080000 -+#define VMX_CPU_BASED_CR8_STORE_EXITING 0x00100000 -+#define VMX_CPU_BASED_TPR_SHADOW 0x00200000 -+#define VMX_CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 -+#define VMX_CPU_BASED_MOV_DR_EXITING 0x00800000 -+#define VMX_CPU_BASED_UNCOND_IO_EXITING 0x01000000 -+#define VMX_CPU_BASED_USE_IO_BITMAPS 0x02000000 -+#define VMX_CPU_BASED_MONITOR_TRAP_FLAG 0x08000000 -+#define VMX_CPU_BASED_USE_MSR_BITMAPS 0x10000000 -+#define VMX_CPU_BASED_MONITOR_EXITING 0x20000000 -+#define VMX_CPU_BASED_PAUSE_EXITING 0x40000000 -+#define VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 -+ -+#define VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 -+#define VMX_SECONDARY_EXEC_ENABLE_EPT 0x00000002 -+#define VMX_SECONDARY_EXEC_DESC 0x00000004 -+#define VMX_SECONDARY_EXEC_RDTSCP 0x00000008 -+#define VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010 -+#define VMX_SECONDARY_EXEC_ENABLE_VPID 0x00000020 -+#define VMX_SECONDARY_EXEC_WBINVD_EXITING 0x00000040 -+#define VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 -+#define VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100 -+#define VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200 -+#define VMX_SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 -+#define VMX_SECONDARY_EXEC_RDRAND_EXITING 0x00000800 -+#define VMX_SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 -+#define VMX_SECONDARY_EXEC_ENABLE_VMFUNC 0x00002000 -+#define VMX_SECONDARY_EXEC_SHADOW_VMCS 0x00004000 -+#define VMX_SECONDARY_EXEC_ENCLS_EXITING 0x00008000 -+#define VMX_SECONDARY_EXEC_RDSEED_EXITING 0x00010000 -+#define VMX_SECONDARY_EXEC_ENABLE_PML 0x00020000 -+#define VMX_SECONDARY_EXEC_XSAVES 0x00100000 -+ -+#define VMX_PIN_BASED_EXT_INTR_MASK 0x00000001 -+#define VMX_PIN_BASED_NMI_EXITING 0x00000008 -+#define VMX_PIN_BASED_VIRTUAL_NMIS 0x00000020 -+#define VMX_PIN_BASED_VMX_PREEMPTION_TIMER 0x00000040 -+#define VMX_PIN_BASED_POSTED_INTR 0x00000080 -+ -+#define VMX_VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000004 -+#define VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 -+#define VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL 0x00001000 -+#define VMX_VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 -+#define VMX_VM_EXIT_SAVE_IA32_PAT 0x00040000 -+#define VMX_VM_EXIT_LOAD_IA32_PAT 0x00080000 -+#define VMX_VM_EXIT_SAVE_IA32_EFER 0x00100000 -+#define VMX_VM_EXIT_LOAD_IA32_EFER 0x00200000 -+#define VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000 -+#define VMX_VM_EXIT_CLEAR_BNDCFGS 0x00800000 -+#define VMX_VM_EXIT_PT_CONCEAL_PIP 0x01000000 -+#define VMX_VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000 -+ -+#define VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000004 -+#define VMX_VM_ENTRY_IA32E_MODE 0x00000200 -+#define VMX_VM_ENTRY_SMM 0x00000400 -+#define VMX_VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 -+#define VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000 -+#define VMX_VM_ENTRY_LOAD_IA32_PAT 0x00004000 -+#define VMX_VM_ENTRY_LOAD_IA32_EFER 0x00008000 -+#define VMX_VM_ENTRY_LOAD_BNDCFGS 0x00010000 -+#define VMX_VM_ENTRY_PT_CONCEAL_PIP 0x00020000 -+#define VMX_VM_ENTRY_LOAD_IA32_RTIT_CTL 0x00040000 -+ - /* Supported Hyper-V Enlightenments */ - #define HYPERV_FEAT_RELAXED 0 - #define HYPERV_FEAT_VAPIC 1 --- -2.27.0 - diff --git a/target-i386-add-VMX-features-to-named-CPU-models.patch b/target-i386-add-VMX-features-to-named-CPU-models.patch deleted file mode 100644 index ab42b83785e5e5fd463f64415611b98ebe06066b..0000000000000000000000000000000000000000 --- a/target-i386-add-VMX-features-to-named-CPU-models.patch +++ /dev/null @@ -1,980 +0,0 @@ -From 5a63a16d709c89b25a0a9c3c7fdf765f26dac312 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 20 Nov 2019 18:37:53 +0100 -Subject: [PATCH] target/i386: add VMX features to named CPU models - -This allows using "-cpu Haswell,+vmx", which we did not really want to -support in QEMU but was produced by Libvirt when using the "host-model" -CPU model. Without this patch, no VMX feature is _actually_ supported -(only the basic instruction set extensions are) and KVM fails to load -in the guest. - -This was produced from the output of scripts/kvm/vmxcap using the following -very ugly Python script: - - bits = { - 'INS/OUTS instruction information': ['FEAT_VMX_BASIC', 'MSR_VMX_BASIC_INS_OUTS'], - 'IA32_VMX_TRUE_*_CTLS support': ['FEAT_VMX_BASIC', 'MSR_VMX_BASIC_TRUE_CTLS'], - 'External interrupt exiting': ['FEAT_VMX_PINBASED_CTLS', 'VMX_PIN_BASED_EXT_INTR_MASK'], - 'NMI exiting': ['FEAT_VMX_PINBASED_CTLS', 'VMX_PIN_BASED_NMI_EXITING'], - 'Virtual NMIs': ['FEAT_VMX_PINBASED_CTLS', 'VMX_PIN_BASED_VIRTUAL_NMIS'], - 'Activate VMX-preemption timer': ['FEAT_VMX_PINBASED_CTLS', 'VMX_PIN_BASED_VMX_PREEMPTION_TIMER'], - 'Process posted interrupts': ['FEAT_VMX_PINBASED_CTLS', 'VMX_PIN_BASED_POSTED_INTR'], - 'Interrupt window exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_VIRTUAL_INTR_PENDING'], - 'Use TSC offsetting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_USE_TSC_OFFSETING'], - 'HLT exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_HLT_EXITING'], - 'INVLPG exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_INVLPG_EXITING'], - 'MWAIT exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_MWAIT_EXITING'], - 'RDPMC exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_RDPMC_EXITING'], - 'RDTSC exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_RDTSC_EXITING'], - 'CR3-load exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_CR3_LOAD_EXITING'], - 'CR3-store exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_CR3_STORE_EXITING'], - 'CR8-load exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_CR8_LOAD_EXITING'], - 'CR8-store exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_CR8_STORE_EXITING'], - 'Use TPR shadow': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_TPR_SHADOW'], - 'NMI-window exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_VIRTUAL_NMI_PENDING'], - 'MOV-DR exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_MOV_DR_EXITING'], - 'Unconditional I/O exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_UNCOND_IO_EXITING'], - 'Use I/O bitmaps': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_USE_IO_BITMAPS'], - 'Monitor trap flag': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_MONITOR_TRAP_FLAG'], - 'Use MSR bitmaps': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_USE_MSR_BITMAPS'], - 'MONITOR exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_MONITOR_EXITING'], - 'PAUSE exiting': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_PAUSE_EXITING'], - 'Activate secondary control': ['FEAT_VMX_PROCBASED_CTLS', 'VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS'], - 'Virtualize APIC accesses': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES'], - 'Enable EPT': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_ENABLE_EPT'], - 'Descriptor-table exiting': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_DESC'], - 'Enable RDTSCP': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_RDTSCP'], - 'Virtualize x2APIC mode': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE'], - 'Enable VPID': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_ENABLE_VPID'], - 'WBINVD exiting': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_WBINVD_EXITING'], - 'Unrestricted guest': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST'], - 'APIC register emulation': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT'], - 'Virtual interrupt delivery': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY'], - 'PAUSE-loop exiting': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_PAUSE_LOOP_EXITING'], - 'RDRAND exiting': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_RDRAND_EXITING'], - 'Enable INVPCID': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_ENABLE_INVPCID'], - 'Enable VM functions': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_ENABLE_VMFUNC'], - 'VMCS shadowing': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_SHADOW_VMCS'], - 'RDSEED exiting': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_RDSEED_EXITING'], - 'Enable PML': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_ENABLE_PML'], - 'Enable XSAVES/XRSTORS': ['FEAT_VMX_SECONDARY_CTLS', 'VMX_SECONDARY_EXEC_XSAVES'], - 'Save debug controls': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_SAVE_DEBUG_CONTROLS'], - 'Load IA32_PERF_GLOBAL_CTRL': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL'], - 'Acknowledge interrupt on exit': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_ACK_INTR_ON_EXIT'], - 'Save IA32_PAT': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_SAVE_IA32_PAT'], - 'Load IA32_PAT': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_LOAD_IA32_PAT'], - 'Save IA32_EFER': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_SAVE_IA32_EFER'], - 'Load IA32_EFER': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_LOAD_IA32_EFER'], - 'Save VMX-preemption timer value': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER'], - 'Clear IA32_BNDCFGS': ['FEAT_VMX_EXIT_CTLS', 'VMX_VM_EXIT_CLEAR_BNDCFGS'], - 'Load debug controls': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS'], - 'IA-32e mode guest': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_IA32E_MODE'], - 'Load IA32_PERF_GLOBAL_CTRL': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL'], - 'Load IA32_PAT': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_LOAD_IA32_PAT'], - 'Load IA32_EFER': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_LOAD_IA32_EFER'], - 'Load IA32_BNDCFGS': ['FEAT_VMX_ENTRY_CTLS', 'VMX_VM_ENTRY_LOAD_BNDCFGS'], - 'Store EFER.LMA into IA-32e mode guest control': ['FEAT_VMX_MISC', 'MSR_VMX_MISC_STORE_LMA'], - 'HLT activity state': ['FEAT_VMX_MISC', 'MSR_VMX_MISC_ACTIVITY_HLT'], - 'VMWRITE to VM-exit information fields': ['FEAT_VMX_MISC', 'MSR_VMX_MISC_VMWRITE_VMEXIT'], - 'Inject event with insn length=0': ['FEAT_VMX_MISC', 'MSR_VMX_MISC_ZERO_LEN_INJECT'], - 'Execute-only EPT translations': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_EXECONLY'], - 'Page-walk length 4': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_PAGE_WALK_LENGTH_4'], - 'Paging-structure memory type WB': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_WB'], - '2MB EPT pages': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB'], - 'INVEPT supported': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVEPT'], - 'EPT accessed and dirty flags': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_AD_BITS'], - 'Single-context INVEPT': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT'], - 'All-context INVEPT': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVEPT_ALL_CONTEXT'], - 'INVVPID supported': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVVPID'], - 'Individual-address INVVPID': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVVPID_SINGLE_ADDR'], - 'Single-context INVVPID': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT'], - 'All-context INVVPID': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVVPID_ALL_CONTEXT'], - 'Single-context-retaining-globals INVVPID': ['FEAT_VMX_EPT_VPID_CAPS', 'MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS'], - 'EPTP Switching': ['FEAT_VMX_VMFUNC', 'MSR_VMX_VMFUNC_EPT_SWITCHING'] - } - - import sys - import textwrap - - out = {} - for l in sys.stdin.readlines(): - l = l.rstrip() - if l.endswith('!!'): - l = l[:-2].rstrip() - if l.startswith(' ') and (l.endswith('default') or l.endswith('yes')): - l = l[4:] - for key, value in bits.items(): - if l.startswith(key): - ctl, bit = value - if ctl in out: - out[ctl] = out[ctl] + ' | ' - else: - out[ctl] = ' [%s] = ' % ctl - out[ctl] = out[ctl] + bit - - for x in sorted(out.keys()): - print("\n ".join(textwrap.wrap(out[x] + ","))) - -Note that the script has a bug in that some keys apply to both VM entry -and VM exit controls ("load IA32_PERF_GLOBAL_CTRL", "load IA32_EFER", -"load IA32_PAT". Those have to be fixed by hand. - -Reviewed-by: Eduardo Habkost -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 705 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 705 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index fd248a78db..2f32d67aa5 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1799,6 +1799,34 @@ static CPUCaches epyc_cache_info = { - }, - }; - -+/* The following VMX features are not supported by KVM and are left out in the -+ * CPU definitions: -+ * -+ * Dual-monitor support (all processors) -+ * Entry to SMM -+ * Deactivate dual-monitor treatment -+ * Number of CR3-target values -+ * Shutdown activity state -+ * Wait-for-SIPI activity state -+ * PAUSE-loop exiting (Westmere and newer) -+ * EPT-violation #VE (Broadwell and newer) -+ * Inject event with insn length=0 (Skylake and newer) -+ * Conceal non-root operation from PT -+ * Conceal VM exits from PT -+ * Conceal VM entries from PT -+ * Enable ENCLS exiting -+ * Mode-based execute control (XS/XU) -+ s TSC scaling (Skylake Server and newer) -+ * GPA translation for PT (IceLake and newer) -+ * User wait and pause -+ * ENCLV exiting -+ * Load IA32_RTIT_CTL -+ * Clear IA32_RTIT_CTL -+ * Advanced VM-exit information for EPT violations -+ * Sub-page write permissions -+ * PT in VMX operation -+ */ -+ - static X86CPUDefinition builtin_x86_defs[] = { - { - .name = "qemu64", -@@ -1873,6 +1901,24 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_LAHF_LM, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES, - .xlevel = 0x80000008, - .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz", - }, -@@ -1900,6 +1946,20 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */ - .features[FEAT_8000_0001_ECX] = - 0, -+ /* VMX features from Cedar Mill/Prescott */ -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING, - .xlevel = 0x80000008, - .model_id = "Common KVM processor" - }, -@@ -1931,6 +1991,19 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT_SSE3, - .features[FEAT_8000_0001_ECX] = - 0, -+ /* VMX features from Yonah */ -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | VMX_CPU_BASED_USE_MSR_BITMAPS, - .xlevel = 0x80000008, - .model_id = "Common 32-bit KVM processor" - }, -@@ -1952,6 +2025,18 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT_SSE3 | CPUID_EXT_MONITOR, - .features[FEAT_8000_0001_EDX] = - CPUID_EXT2_NX, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | VMX_CPU_BASED_USE_MSR_BITMAPS, - .xlevel = 0x80000008, - .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz", - }, -@@ -2062,6 +2147,24 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_LAHF_LM, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES, - .xlevel = 0x80000008, - .model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)", - }, -@@ -2085,6 +2188,27 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_LAHF_LM, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, -+ .features[FEAT_VMX_EXIT_CTLS] = VMX_VM_EXIT_ACK_INTR_ON_EXIT | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING, - .xlevel = 0x80000008, - .model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)", - }, -@@ -2108,6 +2232,46 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_LAHF_LM, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID, - .xlevel = 0x80000008, - .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2148,6 +2312,47 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_EXT3_LAHF_LM, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST, - .xlevel = 0x80000008, - .model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2193,6 +2398,47 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XSAVEOPT, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST, - .xlevel = 0x80000008, - .model_id = "Intel Xeon E312xx (Sandy Bridge)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2241,6 +2487,50 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XSAVEOPT, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING, - .xlevel = 0x80000008, - .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2292,6 +2582,52 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XSAVEOPT, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Haswell)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2376,6 +2712,53 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XSAVEOPT, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Broadwell)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2460,6 +2843,51 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Skylake)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2524,6 +2952,52 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Skylake)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2594,6 +3068,52 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Cascadelake)", - .versions = (X86CPUVersionDefinition[]) { -@@ -2724,6 +3244,51 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Icelake)", - }, -@@ -2782,6 +3347,52 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Icelake)", - }, -@@ -2829,6 +3440,53 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_6_EAX_ARAT, - .features[FEAT_ARCH_CAPABILITIES] = - MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Atom Processor (Denverton)", - }, -@@ -2899,6 +3557,53 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, -+ .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | -+ MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | -+ MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | -+ VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | -+ VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | -+ VMX_PIN_BASED_VMX_PREEMPTION_TIMER | VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | -+ VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | -+ VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | -+ VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, -+ .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Atom Processor (SnowRidge)", - .versions = (X86CPUVersionDefinition[]) { --- -2.27.0 - diff --git a/target-i386-add-VMX-features.patch b/target-i386-add-VMX-features.patch deleted file mode 100644 index 50457d7f2125e4db535a18c4798e6bab48d68393..0000000000000000000000000000000000000000 --- a/target-i386-add-VMX-features.patch +++ /dev/null @@ -1,492 +0,0 @@ -From 290ed17e639a67a9faf4a18b1b5973f9535bace4 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 1 Jul 2019 18:32:17 +0200 -Subject: [PATCH] target/i386: add VMX features - -Add code to convert the VMX feature words back into MSR values, -allowing the user to enable/disable VMX features as they wish. The same -infrastructure enables support for limiting VMX features in named -CPU models. - -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++ - target/i386/cpu.h | 9 ++ - target/i386/kvm.c | 162 ++++++++++++++++++++++++++++++++- - 3 files changed, 394 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 3d6541c4a8..fd248a78db 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1232,6 +1232,163 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .index = MSR_IA32_CORE_CAPABILITY, - }, - }, -+ -+ [FEAT_VMX_PROCBASED_CTLS] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, "vmx-vintr-pending", "vmx-tsc-offset", -+ NULL, NULL, NULL, "vmx-hlt-exit", -+ NULL, "vmx-invlpg-exit", "vmx-mwait-exit", "vmx-rdpmc-exit", -+ "vmx-rdtsc-exit", NULL, NULL, "vmx-cr3-load-noexit", -+ "vmx-cr3-store-noexit", NULL, NULL, "vmx-cr8-load-exit", -+ "vmx-cr8-store-exit", "vmx-flexpriority", "vmx-vnmi-pending", "vmx-movdr-exit", -+ "vmx-io-exit", "vmx-io-bitmap", NULL, "vmx-mtf", -+ "vmx-msr-bitmap", "vmx-monitor-exit", "vmx-pause-exit", "vmx-secondary-ctls", -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, -+ } -+ }, -+ -+ [FEAT_VMX_SECONDARY_CTLS] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ "vmx-apicv-xapic", "vmx-ept", "vmx-desc-exit", "vmx-rdtscp-exit", -+ "vmx-apicv-x2apic", "vmx-vpid", "vmx-wbinvd-exit", "vmx-unrestricted-guest", -+ "vmx-apicv-register", "vmx-apicv-vid", "vmx-ple", "vmx-rdrand-exit", -+ "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit", -+ "vmx-rdseed-exit", "vmx-pml", NULL, NULL, -+ "vmx-xsaves", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_PROCBASED_CTLS2, -+ } -+ }, -+ -+ [FEAT_VMX_PINBASED_CTLS] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ "vmx-intr-exit", NULL, NULL, "vmx-nmi-exit", -+ NULL, "vmx-vnmi", "vmx-preemption-timer", "vmx-posted-intr", -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_TRUE_PINBASED_CTLS, -+ } -+ }, -+ -+ [FEAT_VMX_EXIT_CTLS] = { -+ .type = MSR_FEATURE_WORD, -+ /* -+ * VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE is copied from -+ * the LM CPUID bit. -+ */ -+ .feat_names = { -+ NULL, NULL, "vmx-exit-nosave-debugctl", NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL /* vmx-exit-host-addr-space-size */, NULL, NULL, -+ "vmx-exit-load-perf-global-ctrl", NULL, NULL, "vmx-exit-ack-intr", -+ NULL, NULL, "vmx-exit-save-pat", "vmx-exit-load-pat", -+ "vmx-exit-save-efer", "vmx-exit-load-efer", -+ "vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs", -+ NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_TRUE_EXIT_CTLS, -+ } -+ }, -+ -+ [FEAT_VMX_ENTRY_CTLS] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, "vmx-entry-noload-debugctl", NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, "vmx-entry-ia32e-mode", NULL, NULL, -+ NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer", -+ "vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_TRUE_ENTRY_CTLS, -+ } -+ }, -+ -+ [FEAT_VMX_MISC] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ NULL, "vmx-store-lma", "vmx-activity-hlt", "vmx-activity-shutdown", -+ "vmx-activity-wait-sipi", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, "vmx-vmwrite-vmexit-fields", "vmx-zero-len-inject", NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_MISC, -+ } -+ }, -+ -+ [FEAT_VMX_EPT_VPID_CAPS] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ "vmx-ept-execonly", NULL, NULL, NULL, -+ NULL, NULL, "vmx-page-walk-4", "vmx-page-walk-5", -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ "vmx-ept-2mb", "vmx-ept-1gb", NULL, NULL, -+ "vmx-invept", "vmx-eptad", "vmx-ept-advanced-exitinfo", NULL, -+ NULL, "vmx-invept-single-context", "vmx-invept-all-context", NULL, -+ NULL, NULL, NULL, NULL, -+ "vmx-invvpid", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ "vmx-invvpid-single-addr", "vmx-invept-single-context", -+ "vmx-invvpid-all-context", "vmx-invept-single-context-noglobals", -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_EPT_VPID_CAP, -+ } -+ }, -+ -+ [FEAT_VMX_BASIC] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ [54] = "vmx-ins-outs", -+ [55] = "vmx-true-ctls", -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_BASIC, -+ }, -+ /* Just to be safe - we don't support setting the MSEG version field. */ -+ .no_autoenable_flags = MSR_VMX_BASIC_DUAL_MONITOR, -+ }, -+ -+ [FEAT_VMX_VMFUNC] = { -+ .type = MSR_FEATURE_WORD, -+ .feat_names = { -+ [0] = "vmx-eptp-switching", -+ }, -+ .msr = { -+ .index = MSR_IA32_VMX_VMFUNC, -+ } -+ }, -+ - }; - - typedef struct FeatureMask { -@@ -1252,6 +1409,74 @@ static FeatureDep feature_dependencies[] = { - .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY }, - .to = { FEAT_CORE_CAPABILITY, ~0ull }, - }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_PROCBASED_CTLS, ~0ull }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_PINBASED_CTLS, ~0ull }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_EXIT_CTLS, ~0ull }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_ENTRY_CTLS, ~0ull }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_MISC, ~0ull }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_VMX }, -+ .to = { FEAT_VMX_BASIC, ~0ull }, -+ }, -+ { -+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_LM }, -+ .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_IA32E_MODE }, -+ }, -+ { -+ .from = { FEAT_VMX_PROCBASED_CTLS, VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, ~0ull }, -+ }, -+ { -+ .from = { FEAT_XSAVE, CPUID_XSAVE_XSAVES }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_XSAVES }, -+ }, -+ { -+ .from = { FEAT_1_ECX, CPUID_EXT_RDRAND }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDRAND_EXITING }, -+ }, -+ { -+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID }, -+ }, -+ { -+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING }, -+ }, -+ { -+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_RDTSCP }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDTSCP }, -+ }, -+ { -+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT }, -+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull }, -+ }, -+ { -+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT }, -+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST }, -+ }, -+ { -+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VPID }, -+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull << 32 }, -+ }, -+ { -+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC }, -+ .to = { FEAT_VMX_VMFUNC, ~0ull }, -+ }, - }; - - typedef struct X86RegisterInfo32 { -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index b4be6ffb1f..0b57b915af 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -518,6 +518,15 @@ typedef enum FeatureWord { - FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ - FEAT_ARCH_CAPABILITIES, - FEAT_CORE_CAPABILITY, -+ FEAT_VMX_PROCBASED_CTLS, -+ FEAT_VMX_SECONDARY_CTLS, -+ FEAT_VMX_PINBASED_CTLS, -+ FEAT_VMX_EXIT_CTLS, -+ FEAT_VMX_ENTRY_CTLS, -+ FEAT_VMX_MISC, -+ FEAT_VMX_EPT_VPID_CAPS, -+ FEAT_VMX_BASIC, -+ FEAT_VMX_VMFUNC, - FEATURE_WORDS, - } FeatureWord; - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index e9a6293ab2..fafb9fb26d 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -96,6 +96,7 @@ static bool has_msr_virt_ssbd; - static bool has_msr_smi_count; - static bool has_msr_arch_capabs; - static bool has_msr_core_capabs; -+static bool has_msr_vmx_vmfunc; - - static uint32_t has_architectural_pmu_version; - static uint32_t num_architectural_pmu_gp_counters; -@@ -443,7 +444,8 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data; -- uint32_t ret; -+ uint64_t value; -+ uint32_t ret, can_be_one, must_be_one; - - if (kvm_feature_msrs == NULL) { /* Host doesn't support feature MSRs */ - return 0; -@@ -469,7 +471,25 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) - exit(1); - } - -- return msr_data.entries[0].data; -+ value = msr_data.entries[0].data; -+ switch (index) { -+ case MSR_IA32_VMX_PROCBASED_CTLS2: -+ case MSR_IA32_VMX_TRUE_PINBASED_CTLS: -+ case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: -+ case MSR_IA32_VMX_TRUE_ENTRY_CTLS: -+ case MSR_IA32_VMX_TRUE_EXIT_CTLS: -+ /* -+ * Return true for bits that can be one, but do not have to be one. -+ * The SDM tells us which bits could have a "must be one" setting, -+ * so we can do the opposite transformation in make_vmx_msr_value. -+ */ -+ must_be_one = (uint32_t)value; -+ can_be_one = (uint32_t)(value >> 32); -+ return can_be_one & ~must_be_one; -+ -+ default: -+ return value; -+ } - } - - -@@ -1933,6 +1953,9 @@ static int kvm_get_supported_msrs(KVMState *s) - case MSR_IA32_CORE_CAPABILITY: - has_msr_core_capabs = true; - break; -+ case MSR_IA32_VMX_VMFUNC: -+ has_msr_vmx_vmfunc = true; -+ break; - } - } - } -@@ -2407,6 +2430,132 @@ static int kvm_put_msr_feature_control(X86CPU *cpu) - return 0; - } - -+static uint64_t make_vmx_msr_value(uint32_t index, uint32_t features) -+{ -+ uint32_t default1, can_be_one, can_be_zero; -+ uint32_t must_be_one; -+ -+ switch (index) { -+ case MSR_IA32_VMX_TRUE_PINBASED_CTLS: -+ default1 = 0x00000016; -+ break; -+ case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: -+ default1 = 0x0401e172; -+ break; -+ case MSR_IA32_VMX_TRUE_ENTRY_CTLS: -+ default1 = 0x000011ff; -+ break; -+ case MSR_IA32_VMX_TRUE_EXIT_CTLS: -+ default1 = 0x00036dff; -+ break; -+ case MSR_IA32_VMX_PROCBASED_CTLS2: -+ default1 = 0; -+ break; -+ default: -+ abort(); -+ } -+ -+ /* If a feature bit is set, the control can be either set or clear. -+ * Otherwise the value is limited to either 0 or 1 by default1. -+ */ -+ can_be_one = features | default1; -+ can_be_zero = features | ~default1; -+ must_be_one = ~can_be_zero; -+ -+ /* -+ * Bit 0:31 -> 0 if the control bit can be zero (i.e. 1 if it must be one). -+ * Bit 32:63 -> 1 if the control bit can be one. -+ */ -+ return must_be_one | (((uint64_t)can_be_one) << 32); -+} -+ -+#define VMCS12_MAX_FIELD_INDEX (0x17) -+ -+static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f) -+{ -+ uint64_t kvm_vmx_basic = -+ kvm_arch_get_supported_msr_feature(kvm_state, -+ MSR_IA32_VMX_BASIC); -+ uint64_t kvm_vmx_misc = -+ kvm_arch_get_supported_msr_feature(kvm_state, -+ MSR_IA32_VMX_MISC); -+ uint64_t kvm_vmx_ept_vpid = -+ kvm_arch_get_supported_msr_feature(kvm_state, -+ MSR_IA32_VMX_EPT_VPID_CAP); -+ -+ /* -+ * If the guest is 64-bit, a value of 1 is allowed for the host address -+ * space size vmexit control. -+ */ -+ uint64_t fixed_vmx_exit = f[FEAT_8000_0001_EDX] & CPUID_EXT2_LM -+ ? (uint64_t)VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE << 32 : 0; -+ -+ /* -+ * Bits 0-30, 32-44 and 50-53 come from the host. KVM should -+ * not change them for backwards compatibility. -+ */ -+ uint64_t fixed_vmx_basic = kvm_vmx_basic & -+ (MSR_VMX_BASIC_VMCS_REVISION_MASK | -+ MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK | -+ MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK); -+ -+ /* -+ * Same for bits 0-4 and 25-27. Bits 16-24 (CR3 target count) can -+ * change in the future but are always zero for now, clear them to be -+ * future proof. Bits 32-63 in theory could change, though KVM does -+ * not support dual-monitor treatment and probably never will; mask -+ * them out as well. -+ */ -+ uint64_t fixed_vmx_misc = kvm_vmx_misc & -+ (MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK | -+ MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK); -+ -+ /* -+ * EPT memory types should not change either, so we do not bother -+ * adding features for them. -+ */ -+ uint64_t fixed_vmx_ept_mask = -+ (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_ENABLE_EPT ? -+ MSR_VMX_EPT_UC | MSR_VMX_EPT_WB : 0); -+ uint64_t fixed_vmx_ept_vpid = kvm_vmx_ept_vpid & fixed_vmx_ept_mask; -+ -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, -+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_PROCBASED_CTLS, -+ f[FEAT_VMX_PROCBASED_CTLS])); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PINBASED_CTLS, -+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_PINBASED_CTLS, -+ f[FEAT_VMX_PINBASED_CTLS])); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_EXIT_CTLS, -+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_EXIT_CTLS, -+ f[FEAT_VMX_EXIT_CTLS]) | fixed_vmx_exit); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS, -+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_ENTRY_CTLS, -+ f[FEAT_VMX_ENTRY_CTLS])); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_PROCBASED_CTLS2, -+ make_vmx_msr_value(MSR_IA32_VMX_PROCBASED_CTLS2, -+ f[FEAT_VMX_SECONDARY_CTLS])); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_EPT_VPID_CAP, -+ f[FEAT_VMX_EPT_VPID_CAPS] | fixed_vmx_ept_vpid); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_BASIC, -+ f[FEAT_VMX_BASIC] | fixed_vmx_basic); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_MISC, -+ f[FEAT_VMX_MISC] | fixed_vmx_misc); -+ if (has_msr_vmx_vmfunc) { -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMFUNC, f[FEAT_VMX_VMFUNC]); -+ } -+ -+ /* -+ * Just to be safe, write these with constant values. The CRn_FIXED1 -+ * MSRs are generated by KVM based on the vCPU's CPUID. -+ */ -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR0_FIXED0, -+ CR0_PE_MASK | CR0_PG_MASK | CR0_NE_MASK); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR4_FIXED0, -+ CR4_VMXE_MASK); -+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM, -+ VMCS12_MAX_FIELD_INDEX << 1); -+} -+ - static int kvm_put_msrs(X86CPU *cpu, int level) - { - CPUX86State *env = &cpu->env; -@@ -2646,7 +2795,16 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - - /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see - * kvm_put_msr_feature_control. */ -+ -+ /* -+ * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but -+ * all kernels with MSR features should have them. -+ */ -+ if (kvm_feature_msrs && cpu_has_vmx(env)) { -+ kvm_msr_entry_add_vmx(cpu, env->features); -+ } - } -+ - if (env->mcg_cap) { - int i; - --- -2.27.0 - diff --git a/target-i386-add-a-ucode-rev-property.patch b/target-i386-add-a-ucode-rev-property.patch deleted file mode 100644 index 8a3ff6fd91f67dc93e12e75f9c84ce30dd7725f1..0000000000000000000000000000000000000000 --- a/target-i386-add-a-ucode-rev-property.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 9b3b22bfe87be7eec126056b96f7cea7e3ab9257 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 17 Feb 2020 16:23:12 +0000 -Subject: [PATCH] target/i386: add a ucode-rev property - -RH-Author: Paolo Bonzini -Message-id: <20200217162316.2464-3-pbonzini@redhat.com> -Patchwork-id: 93909 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 2/6] target/i386: add a ucode-rev property -Bugzilla: 1791648 -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Maxim Levitsky -RH-Acked-by: Dr. David Alan Gilbert - -Add the property and plumb it in TCG and HVF (the latter of which -tried to support returning a constant value but used the wrong MSR). - -Signed-off-by: Paolo Bonzini -Message-Id: <1579544504-3616-3-git-send-email-pbonzini@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 4e45aff398cd1542c2a384a2a3b8600f23337d86) -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/cpu.c | 10 ++++++++++ - target/i386/cpu.h | 3 +++ - target/i386/hvf/x86_emu.c | 4 +--- - target/i386/misc_helper.c | 4 ++++ - 4 files changed, 18 insertions(+), 3 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 35a33db39a..ec8bc9957e 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6332,6 +6332,15 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - } - } - -+ if (cpu->ucode_rev == 0) { -+ /* The default is the same as KVM's. */ -+ if (IS_AMD_CPU(env)) { -+ cpu->ucode_rev = 0x01000065; -+ } else { -+ cpu->ucode_rev = 0x100000000ULL; -+ } -+ } -+ - /* mwait extended info: needed for Core compatibility */ - /* We always wake on interrupt even if host does not have the capability */ - cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; -@@ -7011,6 +7020,7 @@ static Property x86_cpu_properties[] = { - DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0), - DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0), - DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0), -+ DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0), - DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true), - DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id), - DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 0b57b915af..ca7de143af 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -345,6 +345,7 @@ typedef enum X86Seg { - #define MSR_IA32_SPEC_CTRL 0x48 - #define MSR_VIRT_SSBD 0xc001011f - #define MSR_IA32_PRED_CMD 0x49 -+#define MSR_IA32_UCODE_REV 0x8b - #define MSR_IA32_CORE_CAPABILITY 0xcf - #define MSR_IA32_ARCH_CAPABILITIES 0x10a - #define MSR_IA32_TSCDEADLINE 0x6e0 -@@ -1562,6 +1563,8 @@ struct X86CPU { - CPUNegativeOffsetState neg; - CPUX86State env; - -+ uint64_t ucode_rev; -+ - uint32_t hyperv_spinlock_attempts; - char *hyperv_vendor_id; - bool hyperv_synic_kvm_only; -diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c -index 1b04bd7e94..cd40520c16 100644 ---- a/target/i386/hvf/x86_emu.c -+++ b/target/i386/hvf/x86_emu.c -@@ -664,8 +664,6 @@ static void exec_lods(struct CPUX86State *env, struct x86_decode *decode) - RIP(env) += decode->len; - } - --#define MSR_IA32_UCODE_REV 0x00000017 -- - void simulate_rdmsr(struct CPUState *cpu) - { - X86CPU *x86_cpu = X86_CPU(cpu); -@@ -681,7 +679,7 @@ void simulate_rdmsr(struct CPUState *cpu) - val = cpu_get_apic_base(X86_CPU(cpu)->apic_state); - break; - case MSR_IA32_UCODE_REV: -- val = (0x100000000ULL << 32) | 0x100000000ULL; -+ val = x86_cpu->ucode_rev; - break; - case MSR_EFER: - val = rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER); -diff --git a/target/i386/misc_helper.c b/target/i386/misc_helper.c -index 3eff6885f8..aed16fe3f0 100644 ---- a/target/i386/misc_helper.c -+++ b/target/i386/misc_helper.c -@@ -229,6 +229,7 @@ void helper_rdmsr(CPUX86State *env) - #else - void helper_wrmsr(CPUX86State *env) - { -+ X86CPU *x86_cpu = env_archcpu(env); - uint64_t val; - - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); -@@ -371,6 +372,9 @@ void helper_wrmsr(CPUX86State *env) - env->msr_bndcfgs = val; - cpu_sync_bndcs_hflags(env); - break; -+ case MSR_IA32_UCODE_REV: -+ val = x86_cpu->ucode_rev; -+ break; - default: - if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL - && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + --- -2.27.0 - diff --git a/target-i386-add-support-for-FB_CLEAR-feature.patch b/target-i386-add-support-for-FB_CLEAR-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..621864375f71f8284080aba51d36ca69422836cb --- /dev/null +++ b/target-i386-add-support-for-FB_CLEAR-feature.patch @@ -0,0 +1,62 @@ +From fb84b9baa665ffa4596fd871537e0544d60e40fc Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Wed, 1 Feb 2023 08:57:59 -0500 +Subject: [PATCH] target/i386: add support for FB_CLEAR feature + +commit 22e1094ca82d5518c1b69aff3e87c550776ae1eb upstream. + +As reported by the Intel's doc: +"FB_CLEAR: The processor will overwrite fill buffer values as part of +MD_CLEAR operations with the VERW instruction. +On these processors, L1D_FLUSH does not overwrite fill buffer values." + +If this cpu feature is present in host, allow QEMU to choose whether to +show it to the guest too. +One disadvantage of not exposing it is that the guest will report +a non existing vulnerability in +/sys/devices/system/cpu/vulnerabilities/mmio_stale_data +because the mitigation is present only when the cpu has + (FLUSH_L1D and MD_CLEAR) or FB_CLEAR +features enabled. + +Intel-SIG: commit 22e1094ca82d ("target/i386: add support for FB_CLEAR feature") +Backport support for FB_CLEAR feature + +Signed-off-by: Emanuele Giuseppe Esposito +Message-Id: <20230201135759.555607-3-eesposit@redhat.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 512bec3ca3..8adc84b7f9 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -982,7 +982,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "ssb-no", "mds-no", "pschange-mc-no", "tsx-ctrl", + "taa-no", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "fb-clear", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 9e094ef934..d9aac5acd2 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -962,6 +962,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define MSR_ARCH_CAP_PSCHANGE_MC_NO (1U << 6) + #define MSR_ARCH_CAP_TSX_CTRL_MSR (1U << 7) + #define MSR_ARCH_CAP_TAA_NO (1U << 8) ++#define MSR_ARCH_CAP_FB_CLEAR (1U << 17) + + #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) + +-- +2.41.0.windows.1 + diff --git a/target-i386-add-support-for-FLUSH_L1D-feature.patch b/target-i386-add-support-for-FLUSH_L1D-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..1853829386d65154b5ae8260e2bb4833314feb08 --- /dev/null +++ b/target-i386-add-support-for-FLUSH_L1D-feature.patch @@ -0,0 +1,61 @@ +From dd635e4b0340a426333b466a2222e5848dfda42c Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Wed, 1 Feb 2023 08:57:58 -0500 +Subject: [PATCH] target/i386: add support for FLUSH_L1D feature + +commit 0e7e3bf1a552c178924867fa7c2f30ccc8a179e0 upstream. + +As reported by Intel's doc: +"L1D_FLUSH: Writeback and invalidate the L1 data cache" + +If this cpu feature is present in host, allow QEMU to choose whether to +show it to the guest too. +One disadvantage of not exposing it is that the guest will report +a non existing vulnerability in +/sys/devices/system/cpu/vulnerabilities/mmio_stale_data +because the mitigation is present only when the cpu has + (FLUSH_L1D and MD_CLEAR) or FB_CLEAR +features enabled. + +Intel-SIG: commit 0e7e3bf1a552 ("target/i386: add support for FLUSH_L1D feature") +Backport support for FLUSH_L1D feature + +Signed-off-by: Emanuele Giuseppe Esposito +Message-Id: <20230201135759.555607-2-eesposit@redhat.com> +Signed-off-by: Paolo Bonzini +[ jason: amend commit log ] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 66b5eaa14e..512bec3ca3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -858,7 +858,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, + NULL, NULL, "amx-bf16", "avx512-fp16", + "amx-tile", "amx-int8", "spec-ctrl", "stibp", +- NULL, "arch-capabilities", "core-capability", "ssbd", ++ "flush-l1d", "arch-capabilities", "core-capability", "ssbd", + }, + .cpuid = { + .eax = 7, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index d0c7791a1e..9e094ef934 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -869,6 +869,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) + /* Single Thread Indirect Branch Predictors */ + #define CPUID_7_0_EDX_STIBP (1U << 27) ++/* Flush L1D cache */ ++#define CPUID_7_0_EDX_FLUSH_L1D (1U << 28) + /* Arch Capabilities */ + #define CPUID_7_0_EDX_ARCH_CAPABILITIES (1U << 29) + /* Core Capability */ +-- +2.41.0.windows.1 + diff --git a/target-i386-add-two-missing-VMX-features-for-Skylake.patch b/target-i386-add-two-missing-VMX-features-for-Skylake.patch deleted file mode 100644 index fa3c6d8f39ad28cb75995e142697bee2bf48e97a..0000000000000000000000000000000000000000 --- a/target-i386-add-two-missing-VMX-features-for-Skylake.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 1faa48f4de44c123143d43e67cd5a478628a45a4 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 25 Nov 2019 19:12:16 +0100 -Subject: [PATCH] target/i386: add two missing VMX features for Skylake and - CascadeLake Server - -They are present in client (Core) Skylake but pasted wrong into the server -SKUs. - -Reported-by: Dr. David Alan Gilbert -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 2f32d67aa5..6f27a5170a 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2997,7 +2997,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | - VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | - VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -- VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Skylake)", - .versions = (X86CPUVersionDefinition[]) { -@@ -3113,7 +3114,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | - VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | - VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | -- VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS, -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, - .xlevel = 0x80000008, - .model_id = "Intel Xeon Processor (Cascadelake)", - .versions = (X86CPUVersionDefinition[]) { --- -2.27.0 - diff --git a/target-i386-check-for-availability-of-MSR_IA32_UCODE.patch b/target-i386-check-for-availability-of-MSR_IA32_UCODE.patch deleted file mode 100644 index 377226a4cbff7b6a4c83d410f8f78ff18bc97190..0000000000000000000000000000000000000000 --- a/target-i386-check-for-availability-of-MSR_IA32_UCODE.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0633e7684b4f4da858a3739d68cb57a1d49bdf01 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Tue, 11 Feb 2020 18:55:16 +0100 -Subject: [PATCH] target/i386: check for availability of MSR_IA32_UCODE_REV as - an emulated MSR - -Even though MSR_IA32_UCODE_REV has been available long before Linux 5.6, -which added it to the emulated MSR list, a bug caused the microcode -version to revert to 0x100000000 on INIT. As a result, processors other -than the bootstrap processor would not see the host microcode revision; -some Windows version complain loudly about this and crash with a -fairly explicit MICROCODE REVISION MISMATCH error. - -[If running 5.6 prereleases, the kernel fix "KVM: x86: do not reset - microcode version on INIT or RESET" should also be applied.] - -Reported-by: Alex Williamson -Message-id: <20200211175516.10716-1-pbonzini@redhat.com> -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 7437f86130..e49a2d2585 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -99,6 +99,7 @@ static bool has_msr_smi_count; - static bool has_msr_arch_capabs; - static bool has_msr_core_capabs; - static bool has_msr_vmx_vmfunc; -+static bool has_msr_ucode_rev; - static bool has_msr_vmx_procbased_ctls2; - - static uint32_t has_architectural_pmu_version; -@@ -1985,6 +1986,9 @@ static int kvm_get_supported_msrs(KVMState *s) - case MSR_IA32_VMX_VMFUNC: - has_msr_vmx_vmfunc = true; - break; -+ case MSR_IA32_UCODE_REV: -+ has_msr_ucode_rev = true; -+ break; - case MSR_IA32_VMX_PROCBASED_CTLS2: - has_msr_vmx_procbased_ctls2 = true; - break; -@@ -2628,8 +2632,7 @@ static void kvm_init_msrs(X86CPU *cpu) - env->features[FEAT_CORE_CAPABILITY]); - } - -- if (kvm_arch_get_supported_msr_feature(kvm_state, -- MSR_IA32_UCODE_REV)) { -+ if (has_msr_ucode_rev) { - kvm_msr_entry_add(cpu, MSR_IA32_UCODE_REV, cpu->ucode_rev); - } - --- -2.27.0 - diff --git a/target-i386-cpu-Improve-error-message-for-property-v.patch b/target-i386-cpu-Improve-error-message-for-property-v.patch new file mode 100644 index 0000000000000000000000000000000000000000..462d4877ef1b5836e15e636f41a5050972c2fdd0 --- /dev/null +++ b/target-i386-cpu-Improve-error-message-for-property-v.patch @@ -0,0 +1,45 @@ +From dca8f8c8bc4466d2502bcd305fcc8e84adf992da Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 10:20:40 +0800 +Subject: [PATCH] target/i386/cpu: Improve error message for property "vendor" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 298d8b122056052951bda487392d8aabbfd0f3e5 + +Improve + + $ qemu-system-x86_64 -device max-x86_64-cpu,vendor=me + qemu-system-x86_64: -device max-x86_64-cpu,vendor=me: Property '.vendor' doesn't take value 'me' + +to + + qemu-system-x86_64: -device max-x86_64-cpu,vendor=0123456789abc: value of property 'vendor' must consist of exactly 12 characters + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-8-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé + +Signed-off-by: boringandboring +--- + target/i386/cpu.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 6aaa730a0d..53a7484ca8 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4805,7 +4805,8 @@ static void x86_cpuid_set_vendor(Object *obj, const char *value, + int i; + + if (strlen(value) != CPUID_VENDOR_SZ) { +- error_setg(errp, QERR_PROPERTY_VALUE_BAD, "", "vendor", value); ++ error_setg(errp, "value of property 'vendor' must consist of" ++ " exactly " stringify(CPUID_VENDOR_SZ) " characters"); + return; + } + +-- +2.27.0 + diff --git a/target-i386-disable-VMX-features-if-nested-0.patch b/target-i386-disable-VMX-features-if-nested-0.patch deleted file mode 100644 index fa7edfdb2a7296a0039a44e2c4c1af9b5b324951..0000000000000000000000000000000000000000 --- a/target-i386-disable-VMX-features-if-nested-0.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 26f01427d155510edcab07e312a72f5bacddafb2 Mon Sep 17 00:00:00 2001 -From: Yang Zhong -Date: Fri, 6 Dec 2019 15:11:11 +0800 -Subject: [PATCH] target/i386: disable VMX features if nested=0 - -If kvm does not support VMX feature by nested=0, the kvm_vmx_basic -can't get the right value from MSR_IA32_VMX_BASIC register, which -make qemu coredump when qemu do KVM_SET_MSRS. - -The coredump info: -error: failed to set MSR 0x480 to 0x0 -kvm_put_msrs: Assertion `ret == cpu->kvm_msr_buf->nmsrs' failed. - -Signed-off-by: Yang Zhong -Message-Id: <20191206071111.12128-1-yang.zhong@intel.com> -Reported-by: Catherine Ho -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index b97f40df6b..5ee0c50d7c 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -2493,6 +2493,14 @@ static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f) - uint64_t kvm_vmx_basic = - kvm_arch_get_supported_msr_feature(kvm_state, - MSR_IA32_VMX_BASIC); -+ -+ if (!kvm_vmx_basic) { -+ /* If the kernel doesn't support VMX feature (kvm_intel.nested=0), -+ * then kvm_vmx_basic will be 0 and KVM_SET_MSR will fail. -+ */ -+ return; -+ } -+ - uint64_t kvm_vmx_misc = - kvm_arch_get_supported_msr_feature(kvm_state, - MSR_IA32_VMX_MISC); --- -2.27.0 - diff --git a/target-i386-do-not-set-unsupported-VMX-secondary-exe.patch b/target-i386-do-not-set-unsupported-VMX-secondary-exe.patch deleted file mode 100644 index 8eda458156b202ba7c5405bf1e261e56a7aa1771..0000000000000000000000000000000000000000 --- a/target-i386-do-not-set-unsupported-VMX-secondary-exe.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 472ccc3e48cab962ec9acf3f31e4467544b51705 Mon Sep 17 00:00:00 2001 -From: Vitaly Kuznetsov -Date: Tue, 31 Mar 2020 18:27:52 +0200 -Subject: [PATCH] target/i386: do not set unsupported VMX secondary execution - controls - -Commit 048c95163b4 ("target/i386: work around KVM_GET_MSRS bug for -secondary execution controls") added a workaround for KVM pre-dating -commit 6defc591846d ("KVM: nVMX: include conditional controls in /dev/kvm -KVM_GET_MSRS") which wasn't setting certain available controls. The -workaround uses generic CPUID feature bits to set missing VMX controls. - -It was found that in some cases it is possible to observe hosts which -have certain CPUID features but lack the corresponding VMX control. - -In particular, it was reported that Azure VMs have RDSEED but lack -VMX_SECONDARY_EXEC_RDSEED_EXITING; attempts to enable this feature -bit result in QEMU abort. - -Resolve the issue but not applying the workaround when we don't have -to. As there is no good way to find out if KVM has the fix itself, use -95c5c7c77c ("KVM: nVMX: list VMX MSRs in KVM_GET_MSR_INDEX_LIST") instead -as these [are supposed to] come together. - -Fixes: 048c95163b4 ("target/i386: work around KVM_GET_MSRS bug for secondary execution controls") -Suggested-by: Paolo Bonzini -Signed-off-by: Vitaly Kuznetsov -Message-Id: <20200331162752.1209928-1-vkuznets@redhat.com> -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm.c | 41 ++++++++++++++++++++++++++--------------- - 1 file changed, 26 insertions(+), 15 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 5ee0c50d7c..7328746d92 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -97,6 +97,7 @@ static bool has_msr_smi_count; - static bool has_msr_arch_capabs; - static bool has_msr_core_capabs; - static bool has_msr_vmx_vmfunc; -+static bool has_msr_vmx_procbased_ctls2; - - static uint32_t has_architectural_pmu_version; - static uint32_t num_architectural_pmu_gp_counters; -@@ -474,21 +475,28 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) - value = msr_data.entries[0].data; - switch (index) { - case MSR_IA32_VMX_PROCBASED_CTLS2: -- /* KVM forgot to add these bits for some time, do this ourselves. */ -- if (kvm_arch_get_supported_cpuid(s, 0xD, 1, R_ECX) & CPUID_XSAVE_XSAVES) { -- value |= (uint64_t)VMX_SECONDARY_EXEC_XSAVES << 32; -- } -- if (kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX) & CPUID_EXT_RDRAND) { -- value |= (uint64_t)VMX_SECONDARY_EXEC_RDRAND_EXITING << 32; -- } -- if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_INVPCID) { -- value |= (uint64_t)VMX_SECONDARY_EXEC_ENABLE_INVPCID << 32; -- } -- if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_RDSEED) { -- value |= (uint64_t)VMX_SECONDARY_EXEC_RDSEED_EXITING << 32; -- } -- if (kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) { -- value |= (uint64_t)VMX_SECONDARY_EXEC_RDTSCP << 32; -+ if (!has_msr_vmx_procbased_ctls2) { -+ /* KVM forgot to add these bits for some time, do this ourselves. */ -+ if (kvm_arch_get_supported_cpuid(s, 0xD, 1, R_ECX) & -+ CPUID_XSAVE_XSAVES) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_XSAVES << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX) & -+ CPUID_EXT_RDRAND) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDRAND_EXITING << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & -+ CPUID_7_0_EBX_INVPCID) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_ENABLE_INVPCID << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & -+ CPUID_7_0_EBX_RDSEED) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDSEED_EXITING << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX) & -+ CPUID_EXT2_RDTSCP) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDTSCP << 32; -+ } - } - /* fall through */ - case MSR_IA32_VMX_TRUE_PINBASED_CTLS: -@@ -1973,6 +1981,9 @@ static int kvm_get_supported_msrs(KVMState *s) - case MSR_IA32_VMX_VMFUNC: - has_msr_vmx_vmfunc = true; - break; -+ case MSR_IA32_VMX_PROCBASED_CTLS2: -+ has_msr_vmx_procbased_ctls2 = true; -+ break; - } - } - } --- -2.27.0 - diff --git a/target-i386-enable-monitor-and-ucode-revision-with-c.patch b/target-i386-enable-monitor-and-ucode-revision-with-c.patch deleted file mode 100644 index 398a79d1648aa2d595ad39098a49c00b7b8ab95a..0000000000000000000000000000000000000000 --- a/target-i386-enable-monitor-and-ucode-revision-with-c.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 8470399d9508b3b56d625866ea235c2a5b4cb39a Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 17 Feb 2020 16:23:16 +0000 -Subject: [PATCH] target/i386: enable monitor and ucode revision with -cpu max -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20200217162316.2464-7-pbonzini@redhat.com> -Patchwork-id: 93910 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 6/6] target/i386: enable monitor and ucode revision with -cpu max -Bugzilla: 1791648 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Maxim Levitsky -RH-Acked-by: Dr. David Alan Gilbert - -These two features were incorrectly tied to host_cpuid_required rather than -cpu->max_features. As a result, -cpu max was not enabling either MONITOR -features or ucode revision. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit be02cda3afde60d219786e23c3f8edb53aec8e17) - -[RHEL7: context, upstream uses g_autofree] - -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/cpu.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 22e0e89718..6147cd419a 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6317,7 +6317,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - g_free(name); - goto out; - } -+ } - -+ if (cpu->max_features && accel_uses_host_cpuid()) { - if (enable_cpu_pm) { - host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, - &cpu->mwait.ecx, &cpu->mwait.edx); --- -2.27.0 - diff --git a/target-i386-expand-feature-words-to-64-bits.patch b/target-i386-expand-feature-words-to-64-bits.patch deleted file mode 100644 index e4a06e5954aec3ec8d30e29c61234612ed36d0c7..0000000000000000000000000000000000000000 --- a/target-i386-expand-feature-words-to-64-bits.patch +++ /dev/null @@ -1,295 +0,0 @@ -From bec2d75a3d3c6405d0afe59c343d23199b009666 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 1 Jul 2019 17:38:54 +0200 -Subject: [PATCH] target/i386: expand feature words to 64 bits - -VMX requires 64-bit feature words for the IA32_VMX_EPT_VPID_CAP -and IA32_VMX_BASIC MSRs. (The VMX control MSRs are 64-bit wide but -actually have only 32 bits of information). - -Signed-off-by: Paolo Bonzini ---- - include/sysemu/kvm.h | 2 +- - target/i386/cpu.c | 71 +++++++++++++++++++++++--------------------- - target/i386/cpu.h | 2 +- - target/i386/kvm.c | 2 +- - 4 files changed, 40 insertions(+), 37 deletions(-) - -diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h -index 565adb4e2c..875b2bf10d 100644 ---- a/include/sysemu/kvm.h -+++ b/include/sysemu/kvm.h -@@ -464,7 +464,7 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension); - - uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function, - uint32_t index, int reg); --uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index); -+uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index); - - - void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len); -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index d4a435ba96..3d6541c4a8 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -789,7 +789,7 @@ typedef struct FeatureWordInfo { - * In cases of disagreement between feature naming conventions, - * aliases may be added. - */ -- const char *feat_names[32]; -+ const char *feat_names[64]; - union { - /* If type==CPUID_FEATURE_WORD */ - struct { -@@ -803,11 +803,11 @@ typedef struct FeatureWordInfo { - uint32_t index; - } msr; - }; -- uint32_t tcg_features; /* Feature flags supported by TCG */ -- uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */ -- uint32_t migratable_flags; /* Feature flags known to be migratable */ -+ uint64_t tcg_features; /* Feature flags supported by TCG */ -+ uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ -+ uint64_t migratable_flags; /* Feature flags known to be migratable */ - /* Features that shouldn't be auto-enabled by "-cpu host" */ -- uint32_t no_autoenable_flags; -+ uint64_t no_autoenable_flags; - } FeatureWordInfo; - - static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { -@@ -1236,7 +1236,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - - typedef struct FeatureMask { - FeatureWord index; -- uint32_t mask; -+ uint64_t mask; - } FeatureMask; - - typedef struct FeatureDep { -@@ -1246,11 +1246,11 @@ typedef struct FeatureDep { - static FeatureDep feature_dependencies[] = { - { - .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES }, -- .to = { FEAT_ARCH_CAPABILITIES, ~0u }, -+ .to = { FEAT_ARCH_CAPABILITIES, ~0ull }, - }, - { - .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY }, -- .to = { FEAT_CORE_CAPABILITY, ~0u }, -+ .to = { FEAT_CORE_CAPABILITY, ~0ull }, - }, - }; - -@@ -1362,14 +1362,14 @@ const char *get_register_name_32(unsigned int reg) - * Returns the set of feature flags that are supported and migratable by - * QEMU, for a given FeatureWord. - */ --static uint32_t x86_cpu_get_migratable_flags(FeatureWord w) -+static uint64_t x86_cpu_get_migratable_flags(FeatureWord w) - { - FeatureWordInfo *wi = &feature_word_info[w]; -- uint32_t r = 0; -+ uint64_t r = 0; - int i; - -- for (i = 0; i < 32; i++) { -- uint32_t f = 1U << i; -+ for (i = 0; i < 64; i++) { -+ uint64_t f = 1ULL << i; - - /* If the feature name is known, it is implicitly considered migratable, - * unless it is explicitly set in unmigratable_flags */ -@@ -3051,7 +3051,7 @@ void x86_cpu_change_kvm_default(const char *prop, const char *value) - assert(pv->prop); - } - --static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, -+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - bool migratable_only); - - static bool lmce_supported(void) -@@ -3237,7 +3237,7 @@ static bool x86_cpu_have_filtered_features(X86CPU *cpu) - return false; - } - --static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint32_t mask, -+static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, - const char *verbose_prefix) - { - CPUX86State *env = &cpu->env; -@@ -3254,8 +3254,8 @@ static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint32_t mask, - return; - } - -- for (i = 0; i < 32; ++i) { -- if ((1UL << i) & mask) { -+ for (i = 0; i < 64; ++i) { -+ if ((1ULL << i) & mask) { - feat_word_str = feature_word_description(f, i); - warn_report("%s: %s%s%s [bit %d]", - verbose_prefix, -@@ -3498,7 +3498,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) - { -- uint32_t *array = (uint32_t *)opaque; -+ uint64_t *array = (uint64_t *)opaque; - FeatureWord w; - X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { }; - X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { }; -@@ -3542,6 +3542,7 @@ static inline void feat2prop(char *s) - /* Return the feature property name for a feature flag bit */ - static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) - { -+ const char *name; - /* XSAVE components are automatically enabled by other features, - * so return the original feature name instead - */ -@@ -3555,9 +3556,11 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) - } - } - -- assert(bitnr < 32); -+ assert(bitnr < 64); - assert(w < FEATURE_WORDS); -- return feature_word_info[w].feat_names[bitnr]; -+ name = feature_word_info[w].feat_names[bitnr]; -+ assert(bitnr < 32 || !(name && feature_word_info[w].type == CPUID_FEATURE_WORD)); -+ return name; - } - - /* Compatibily hack to maintain legacy +-feat semantic, -@@ -3673,10 +3676,10 @@ static void x86_cpu_list_feature_names(FeatureWordArray features, - strList **next = feat_names; - - for (w = 0; w < FEATURE_WORDS; w++) { -- uint32_t filtered = features[w]; -+ uint64_t filtered = features[w]; - int i; -- for (i = 0; i < 32; i++) { -- if (filtered & (1UL << i)) { -+ for (i = 0; i < 64; i++) { -+ if (filtered & (1ULL << i)) { - strList *new = g_new0(strList, 1); - new->value = g_strdup(x86_cpu_feature_name(w, i)); - *next = new; -@@ -3845,7 +3848,7 @@ void x86_cpu_list(void) - names = NULL; - for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) { - FeatureWordInfo *fw = &feature_word_info[i]; -- for (j = 0; j < 32; j++) { -+ for (j = 0; j < 64; j++) { - if (fw->feat_names[j]) { - names = g_list_append(names, (gpointer)fw->feat_names[j]); - } -@@ -3900,11 +3903,11 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) - return cpu_list; - } - --static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, -+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - bool migratable_only) - { - FeatureWordInfo *wi = &feature_word_info[w]; -- uint32_t r = 0; -+ uint64_t r = 0; - - if (kvm_enabled()) { - switch (wi->type) { -@@ -4075,7 +4078,7 @@ static QDict *x86_cpu_static_props(void) - for (w = 0; w < FEATURE_WORDS; w++) { - FeatureWordInfo *fi = &feature_word_info[w]; - int bit; -- for (bit = 0; bit < 32; bit++) { -+ for (bit = 0; bit < 64; bit++) { - if (!fi->feat_names[bit]) { - continue; - } -@@ -5231,7 +5234,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { - FeatureDep *d = &feature_dependencies[i]; - if (!(env->features[d->from.index] & d->from.mask)) { -- uint32_t unavailable_features = env->features[d->to.index] & d->to.mask; -+ uint64_t unavailable_features = env->features[d->to.index] & d->to.mask; - - /* Not an error unless the dependent feature was added explicitly. */ - mark_unavailable_features(cpu, d->to.index, -@@ -5326,10 +5329,10 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool verbose) - } - - for (w = 0; w < FEATURE_WORDS; w++) { -- uint32_t host_feat = -+ uint64_t host_feat = - x86_cpu_get_supported_feature_word(w, false); -- uint32_t requested_features = env->features[w]; -- uint32_t unavailable_features = requested_features & ~host_feat; -+ uint64_t requested_features = env->features[w]; -+ uint64_t unavailable_features = requested_features & ~host_feat; - mark_unavailable_features(cpu, w, unavailable_features, prefix); - } - -@@ -5626,7 +5629,7 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) - - typedef struct BitProperty { - FeatureWord w; -- uint32_t mask; -+ uint64_t mask; - } BitProperty; - - static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, -@@ -5634,7 +5637,7 @@ static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, - { - X86CPU *cpu = X86_CPU(obj); - BitProperty *fp = opaque; -- uint32_t f = cpu->env.features[fp->w]; -+ uint64_t f = cpu->env.features[fp->w]; - bool value = (f & fp->mask) == fp->mask; - visit_type_bool(v, name, &value, errp); - } -@@ -5687,7 +5690,7 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu, - { - BitProperty *fp; - ObjectProperty *op; -- uint32_t mask = (1UL << bitnr); -+ uint64_t mask = (1ULL << bitnr); - - op = object_property_find(OBJECT(cpu), prop_name, NULL); - if (op) { -@@ -5821,7 +5824,7 @@ static void x86_cpu_initfn(Object *obj) - for (w = 0; w < FEATURE_WORDS; w++) { - int bitnr; - -- for (bitnr = 0; bitnr < 32; bitnr++) { -+ for (bitnr = 0; bitnr < 64; bitnr++) { - x86_cpu_register_feature_bit_props(cpu, w, bitnr); - } - } -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 24d489db0f..9a105b2251 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -502,7 +502,7 @@ typedef enum FeatureWord { - FEATURE_WORDS, - } FeatureWord; - --typedef uint32_t FeatureWordArray[FEATURE_WORDS]; -+typedef uint64_t FeatureWordArray[FEATURE_WORDS]; - - /* cpuid_features bits */ - #define CPUID_FP87 (1U << 0) -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index f55d4b4b97..e9a6293ab2 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -437,7 +437,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, - return ret; - } - --uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) -+uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) - { - struct { - struct kvm_msrs info; --- -2.27.0 - diff --git a/target-i386-fix-INVD-vmexit.patch b/target-i386-fix-INVD-vmexit.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e9a1601a4e22d2242cb440fe38f1a35f8c6c003 --- /dev/null +++ b/target-i386-fix-INVD-vmexit.patch @@ -0,0 +1,34 @@ +From b17eea58c7497f96cb66d31b8c59fdcdb06b6c40 Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Sun, 24 Sep 2023 19:43:41 +0800 +Subject: [PATCH] target/i386: fix INVD vmexit + +Due to a typo or perhaps a brain fart, the INVD vmexit was never generated. +Fix it (but not that fixing just the typo would break both INVD and WBINVD, +due to a case of two wrongs making a right). + +cheery-pick from 4d714d1a0bf1fca9576ee53a1a5dfa3fd5ddae99 + +Signed-off-by: jipengfei_yewu +Reviewed-by: Richard Henderson +Signed-off-by: Paolo Bonzini +--- + target/i386/tcg/translate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index e9e1451540..82f77b52fb 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -7773,7 +7773,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) + case 0x108: /* invd */ + case 0x109: /* wbinvd */ + if (check_cpl0(s)) { +- gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); ++ gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD); + /* nothing to do */ + } + break; +-- +2.41.0.windows.1 + diff --git a/target-i386-handle-filtered_features-in-a-new-functi.patch b/target-i386-handle-filtered_features-in-a-new-functi.patch deleted file mode 100644 index ba35948dd1e1c10f566c327750026c22b626a5f2..0000000000000000000000000000000000000000 --- a/target-i386-handle-filtered_features-in-a-new-functi.patch +++ /dev/null @@ -1,176 +0,0 @@ -From b9d29966103ca671718ef1eb5b68067b05fad340 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Tue, 2 Jul 2019 15:32:41 +0200 -Subject: [PATCH] target/i386: handle filtered_features in a new function - mark_unavailable_features - -The next patch will add a different reason for filtering features, unrelated -to host feature support. Extract a new function that takes care of disabling -the features and optionally reporting them. - -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 87 ++++++++++++++++++++++++++--------------------- - 1 file changed, 48 insertions(+), 39 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index e65f372f25..8798cafc7a 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3216,17 +3216,41 @@ static char *feature_word_description(FeatureWordInfo *f, uint32_t bit) - return NULL; - } - --static void report_unavailable_features(FeatureWord w, uint32_t mask) -+static bool x86_cpu_have_filtered_features(X86CPU *cpu) - { -+ FeatureWord w; -+ -+ for (w = 0; w < FEATURE_WORDS; w++) { -+ if (cpu->filtered_features[w]) { -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint32_t mask, -+ const char *verbose_prefix) -+{ -+ CPUX86State *env = &cpu->env; - FeatureWordInfo *f = &feature_word_info[w]; - int i; - char *feat_word_str; - -+ if (!cpu->force_features) { -+ env->features[w] &= ~mask; -+ } -+ cpu->filtered_features[w] |= mask; -+ -+ if (!verbose_prefix) { -+ return; -+ } -+ - for (i = 0; i < 32; ++i) { - if ((1UL << i) & mask) { - feat_word_str = feature_word_description(f, i); -- warn_report("%s doesn't support requested feature: %s%s%s [bit %d]", -- accel_uses_host_cpuid() ? "host" : "TCG", -+ warn_report("%s: %s%s%s [bit %d]", -+ verbose_prefix, - feat_word_str, - f->feat_names[i] ? "." : "", - f->feat_names[i] ? f->feat_names[i] : "", i); -@@ -3631,7 +3655,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, - } - - static void x86_cpu_expand_features(X86CPU *cpu, Error **errp); --static int x86_cpu_filter_features(X86CPU *cpu); -+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose); - - /* Build a list with the name of all features on a feature word array */ - static void x86_cpu_list_feature_names(FeatureWordArray features, -@@ -3696,7 +3720,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, - next = &new->next; - } - -- x86_cpu_filter_features(xc); -+ x86_cpu_filter_features(xc, false); - - x86_cpu_list_feature_names(xc->filtered_features, next); - -@@ -3904,15 +3928,6 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, - return r; - } - --static void x86_cpu_report_filtered_features(X86CPU *cpu) --{ -- FeatureWord w; -- -- for (w = 0; w < FEATURE_WORDS; w++) { -- report_unavailable_features(w, cpu->filtered_features[w]); -- } --} -- - static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) - { - PropValue *pv; -@@ -5274,24 +5289,24 @@ out: - * - * Returns: 0 if all flags are supported by the host, non-zero otherwise. - */ --static int x86_cpu_filter_features(X86CPU *cpu) -+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose) - { - CPUX86State *env = &cpu->env; - FeatureWord w; -- int rv = 0; -+ const char *prefix = NULL; -+ -+ if (verbose) { -+ prefix = accel_uses_host_cpuid() -+ ? "host doesn't support requested feature" -+ : "TCG doesn't support requested feature"; -+ } - - for (w = 0; w < FEATURE_WORDS; w++) { - uint32_t host_feat = - x86_cpu_get_supported_feature_word(w, false); - uint32_t requested_features = env->features[w]; -- uint32_t available_features = requested_features & host_feat; -- if (!cpu->force_features) { -- env->features[w] = available_features; -- } -- cpu->filtered_features[w] = requested_features & ~available_features; -- if (cpu->filtered_features[w]) { -- rv = 1; -- } -+ uint32_t unavailable_features = requested_features & ~host_feat; -+ mark_unavailable_features(cpu, w, unavailable_features, prefix); - } - - if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) && -@@ -5317,13 +5332,9 @@ static int x86_cpu_filter_features(X86CPU *cpu) - * host can't emulate the capabilities we report on - * cpu_x86_cpuid(), intel-pt can't be enabled on the current host. - */ -- env->features[FEAT_7_0_EBX] &= ~CPUID_7_0_EBX_INTEL_PT; -- cpu->filtered_features[FEAT_7_0_EBX] |= CPUID_7_0_EBX_INTEL_PT; -- rv = 1; -+ mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix); - } - } -- -- return rv; - } - - static void x86_cpu_realizefn(DeviceState *dev, Error **errp) -@@ -5364,16 +5375,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - goto out; - } - -- if (x86_cpu_filter_features(cpu) && -- (cpu->check_cpuid || cpu->enforce_cpuid)) { -- x86_cpu_report_filtered_features(cpu); -- if (cpu->enforce_cpuid) { -- error_setg(&local_err, -- accel_uses_host_cpuid() ? -- "Host doesn't support requested features" : -- "TCG doesn't support requested features"); -- goto out; -- } -+ x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); -+ -+ if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { -+ error_setg(&local_err, -+ accel_uses_host_cpuid() ? -+ "Host doesn't support requested features" : -+ "TCG doesn't support requested features"); -+ goto out; - } - - /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on --- -2.27.0 - diff --git a/target-i386-introduce-generic-feature-dependency-mec.patch b/target-i386-introduce-generic-feature-dependency-mec.patch deleted file mode 100644 index da374c58652d5559993c9a584d7c83377d6669cd..0000000000000000000000000000000000000000 --- a/target-i386-introduce-generic-feature-dependency-mec.patch +++ /dev/null @@ -1,146 +0,0 @@ -From ed8fa9d895a0e06434b4163405aeaacbe65bcf44 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 1 Jul 2019 17:26:45 +0200 -Subject: [PATCH] target/i386: introduce generic feature dependency mechanism - -Sometimes a CPU feature does not make sense unless another is -present. In the case of VMX features, KVM does not even allow -setting the VMX controls to some invalid combinations. - -Therefore, this patch adds a generic mechanism that looks for bits -that the user explicitly cleared, and uses them to remove other bits -from the expanded CPU definition. If these dependent bits were also -explicitly *set* by the user, this will be a warning for "-cpu check" -and an error for "-cpu enforce". If not, then the dependent bits are -cleared silently, for convenience. - -With VMX features, this will be used so that for example -"-cpu host,-rdrand" will also hide support for RDRAND exiting. - -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 72 +++++++++++++++++++++++++++++++---------------- - 1 file changed, 48 insertions(+), 24 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 8798cafc7a..d4a435ba96 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -801,10 +801,6 @@ typedef struct FeatureWordInfo { - /* If type==MSR_FEATURE_WORD */ - struct { - uint32_t index; -- struct { /*CPUID that enumerate this MSR*/ -- FeatureWord cpuid_class; -- uint32_t cpuid_flag; -- } cpuid_dep; - } msr; - }; - uint32_t tcg_features; /* Feature flags supported by TCG */ -@@ -1218,10 +1214,6 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .msr = { - .index = MSR_IA32_ARCH_CAPABILITIES, -- .cpuid_dep = { -- FEAT_7_0_EDX, -- CPUID_7_0_EDX_ARCH_CAPABILITIES -- } - }, - }, - [FEAT_CORE_CAPABILITY] = { -@@ -1238,14 +1230,30 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .msr = { - .index = MSR_IA32_CORE_CAPABILITY, -- .cpuid_dep = { -- FEAT_7_0_EDX, -- CPUID_7_0_EDX_CORE_CAPABILITY, -- }, - }, - }, - }; - -+typedef struct FeatureMask { -+ FeatureWord index; -+ uint32_t mask; -+} FeatureMask; -+ -+typedef struct FeatureDep { -+ FeatureMask from, to; -+} FeatureDep; -+ -+static FeatureDep feature_dependencies[] = { -+ { -+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES }, -+ .to = { FEAT_ARCH_CAPABILITIES, ~0u }, -+ }, -+ { -+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY }, -+ .to = { FEAT_CORE_CAPABILITY, ~0u }, -+ }, -+}; -+ - typedef struct X86RegisterInfo32 { - /* Name of register */ - const char *name; -@@ -5183,9 +5191,26 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - { - CPUX86State *env = &cpu->env; - FeatureWord w; -+ int i; - GList *l; - Error *local_err = NULL; - -+ for (l = plus_features; l; l = l->next) { -+ const char *prop = l->data; -+ object_property_set_bool(OBJECT(cpu), true, prop, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ } -+ -+ for (l = minus_features; l; l = l->next) { -+ const char *prop = l->data; -+ object_property_set_bool(OBJECT(cpu), false, prop, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ } -+ - /*TODO: Now cpu->max_features doesn't overwrite features - * set using QOM properties, and we can convert - * plus_features & minus_features to global properties -@@ -5203,19 +5228,18 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - } - } - -- for (l = plus_features; l; l = l->next) { -- const char *prop = l->data; -- object_property_set_bool(OBJECT(cpu), true, prop, &local_err); -- if (local_err) { -- goto out; -- } -- } -+ for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { -+ FeatureDep *d = &feature_dependencies[i]; -+ if (!(env->features[d->from.index] & d->from.mask)) { -+ uint32_t unavailable_features = env->features[d->to.index] & d->to.mask; - -- for (l = minus_features; l; l = l->next) { -- const char *prop = l->data; -- object_property_set_bool(OBJECT(cpu), false, prop, &local_err); -- if (local_err) { -- goto out; -+ /* Not an error unless the dependent feature was added explicitly. */ -+ mark_unavailable_features(cpu, d->to.index, -+ unavailable_features & env->user_features[d->to.index], -+ "This feature depends on other features that were not requested"); -+ -+ env->user_features[d->to.index] |= unavailable_features; -+ env->features[d->to.index] &= ~unavailable_features; - } - } - --- -2.27.0 - diff --git a/target-i386-kvm-do-not-access-uninitialized-variable.patch b/target-i386-kvm-do-not-access-uninitialized-variable.patch new file mode 100644 index 0000000000000000000000000000000000000000..3af5ef72f25d8be2045c59315c8cd84363d90e37 --- /dev/null +++ b/target-i386-kvm-do-not-access-uninitialized-variable.patch @@ -0,0 +1,77 @@ +From 550d43a946b61bdadb418e0f8bef8b98e646276d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 18 Mar 2022 16:23:47 +0100 +Subject: [PATCH 09/10] target/i386: kvm: do not access uninitialized variable + on older kernels + +from mainline-v7.0.0-rc1 +commit 3ec5ad40081b14af28496198b4d08dbe13386790 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 3ec5ad40081b ("target/i386: kvm: do not access +uninitialized variable on older kernels") + +--------------------------------------------------------- + +target/i386: kvm: do not access uninitialized variable on older kernels + +KVM support for AMX includes a new system attribute, KVM_X86_XCOMP_GUEST_SUPP. +Commit 19db68ca68 ("x86: Grant AMX permission for guest", 2022-03-15) however +did not fully consider the behavior on older kernels. First, it warns +too aggressively. Second, it invokes the KVM_GET_DEVICE_ATTR ioctl +unconditionally and then uses the "bitmask" variable, which remains +uninitialized if the ioctl fails. Third, kvm_ioctl returns -errno rather +than -1 on errors. + +While at it, explain why the ioctl is needed and KVM_GET_SUPPORTED_CPUID +is not enough. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/kvm/kvm.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 49fca5ea88..20e418463d 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -409,6 +409,12 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + } + } else if (function == 0xd && index == 0 && + (reg == R_EAX || reg == R_EDX)) { ++ /* ++ * The value returned by KVM_GET_SUPPORTED_CPUID does not include ++ * features that still have to be enabled with the arch_prctl ++ * system call. QEMU needs the full value, which is retrieved ++ * with KVM_GET_DEVICE_ATTR. ++ */ + struct kvm_device_attr attr = { + .group = 0, + .attr = KVM_X86_XCOMP_GUEST_SUPP, +@@ -417,13 +423,16 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + + bool sys_attr = kvm_check_extension(s, KVM_CAP_SYS_ATTRIBUTES); + if (!sys_attr) { +- warn_report("cannot get sys attribute capabilities %d", sys_attr); ++ return ret; + } + + int rc = kvm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr); +- if (rc == -1 && (errno == ENXIO || errno == EINVAL)) { +- warn_report("KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) " +- "error: %d", rc); ++ if (rc < 0) { ++ if (rc != -ENXIO) { ++ warn_report("KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) " ++ "error: %d", rc); ++ } ++ return ret; + } + ret = (reg == R_EAX) ? bitmask : bitmask >> 32; + } else if (function == 0x80000001 && reg == R_ECX) { +-- +2.27.0 + diff --git a/target-i386-kvm-fix-kvmclock_current_nsec-Assertion-.patch b/target-i386-kvm-fix-kvmclock_current_nsec-Assertion-.patch new file mode 100644 index 0000000000000000000000000000000000000000..5153ba71a68b4df62b1153d9a213c454c918ef63 --- /dev/null +++ b/target-i386-kvm-fix-kvmclock_current_nsec-Assertion-.patch @@ -0,0 +1,49 @@ +From f53c352a12a0785ff4e83aaeaec7245384538d6a Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Mon, 28 Nov 2022 03:10:06 +0000 +Subject: [PATCH 29/29] target/i386/kvm: fix kvmclock_current_nsec: Assertion + `time.tsc_timestamp <= migration_tsc' failed mainline inclusion from + mainline-v7.2.0-rc2 commit c4ef867f2949bf2a2ae18a4e27cf1a34bbc8aecb category: + bugfix + +-------------------------------- + +New KVM_CLOCK flags were added in the kernel.(c68dc1b577eabd5605c6c7c08f3e07ae18d30d5d) +``` ++ #define KVM_CLOCK_VALID_FLAGS \ ++ (KVM_CLOCK_TSC_STABLE | KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC) + + case KVM_CAP_ADJUST_CLOCK: +- r = KVM_CLOCK_TSC_STABLE; ++ r = KVM_CLOCK_VALID_FLAGS; +``` + +kvm_has_adjust_clock_stable needs to handle additional flags, +so that s->clock_is_reliable can be true and kvmclock_current_nsec doesn't need to be called. + +Signed-off-by: Ray Zhang +Message-Id: <20220922100523.2362205-1-zhanglei002@gmail.com> +Signed-off-by: Paolo Bonzini + + +Signed-off-by: cmss_dx +--- + target/i386/kvm/kvm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 20e418463d..5b15e0430b 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -151,7 +151,7 @@ bool kvm_has_adjust_clock_stable(void) + { + int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK); + +- return (ret == KVM_CLOCK_TSC_STABLE); ++ return (ret & KVM_CLOCK_TSC_STABLE); + } + + bool kvm_has_adjust_clock(void) +-- +2.27.0 + diff --git a/target-i386-kvm-initialize-feature-MSRs-very-early.patch b/target-i386-kvm-initialize-feature-MSRs-very-early.patch deleted file mode 100644 index 90b6f6fa4ba76fb4dde12567fcf3aee236236bde..0000000000000000000000000000000000000000 --- a/target-i386-kvm-initialize-feature-MSRs-very-early.patch +++ /dev/null @@ -1,178 +0,0 @@ -From c222711e37196e4be1776a084a1acb3c5a1f7283 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 17 Feb 2020 16:23:11 +0000 -Subject: [PATCH] target/i386: kvm: initialize feature MSRs very early -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20200217162316.2464-2-pbonzini@redhat.com> -Patchwork-id: 93899 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 1/6] target/i386: kvm: initialize feature MSRs very early -Bugzilla: 1791648 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Maxim Levitsky -RH-Acked-by: Dr. David Alan Gilbert - -Some read-only MSRs affect the behavior of ioctls such as -KVM_SET_NESTED_STATE. We can initialize them once and for all -right after the CPU is realized, since they will never be modified -by the guest. - -Reported-by: Qingua Cheng -Cc: qemu-stable@nongnu.org -Signed-off-by: Paolo Bonzini -Message-Id: <1579544504-3616-2-git-send-email-pbonzini@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 420ae1fc51c99abfd03b1c590f55617edd2a2bed) -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/kvm.c | 81 +++++++++++++++++++++++++----------------- - target/i386/kvm_i386.h | 1 + - 2 files changed, 49 insertions(+), 33 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 7328746d92..60060087fd 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -63,6 +63,8 @@ - * 255 kvm_msr_entry structs */ - #define MSR_BUF_SIZE 4096 - -+static void kvm_init_msrs(X86CPU *cpu); -+ - const KVMCapabilityInfo kvm_arch_required_capabilities[] = { - KVM_CAP_INFO(SET_TSS_ADDR), - KVM_CAP_INFO(EXT_CPUID), -@@ -1777,6 +1779,8 @@ int kvm_arch_init_vcpu(CPUState *cs) - has_msr_tsc_aux = false; - } - -+ kvm_init_msrs(cpu); -+ - r = hyperv_init_vcpu(cpu); - if (r) { - goto fail; -@@ -2592,11 +2596,53 @@ static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f) - VMCS12_MAX_FIELD_INDEX << 1); - } - -+static int kvm_buf_set_msrs(X86CPU *cpu) -+{ -+ int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ if (ret < cpu->kvm_msr_buf->nmsrs) { -+ struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ error_report("error: failed to set MSR 0x%" PRIx32 " to 0x%" PRIx64, -+ (uint32_t)e->index, (uint64_t)e->data); -+ } -+ -+ assert(ret == cpu->kvm_msr_buf->nmsrs); -+ return 0; -+} -+ -+static void kvm_init_msrs(X86CPU *cpu) -+{ -+ CPUX86State *env = &cpu->env; -+ -+ kvm_msr_buf_reset(cpu); -+ if (has_msr_arch_capabs) { -+ kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES, -+ env->features[FEAT_ARCH_CAPABILITIES]); -+ } -+ -+ if (has_msr_core_capabs) { -+ kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY, -+ env->features[FEAT_CORE_CAPABILITY]); -+ } -+ -+ /* -+ * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but -+ * all kernels with MSR features should have them. -+ */ -+ if (kvm_feature_msrs && cpu_has_vmx(env)) { -+ kvm_msr_entry_add_vmx(cpu, env->features); -+ } -+ -+ assert(kvm_buf_set_msrs(cpu) == 0); -+} -+ - static int kvm_put_msrs(X86CPU *cpu, int level) - { - CPUX86State *env = &cpu->env; - int i; -- int ret; - - kvm_msr_buf_reset(cpu); - -@@ -2648,17 +2694,6 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - } - #endif - -- /* If host supports feature MSR, write down. */ -- if (has_msr_arch_capabs) { -- kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES, -- env->features[FEAT_ARCH_CAPABILITIES]); -- } -- -- if (has_msr_core_capabs) { -- kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY, -- env->features[FEAT_CORE_CAPABILITY]); -- } -- - /* - * The following MSRs have side effects on the guest or are too heavy - * for normal writeback. Limit them to reset or full state updates. -@@ -2831,14 +2866,6 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - - /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see - * kvm_put_msr_feature_control. */ -- -- /* -- * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but -- * all kernels with MSR features should have them. -- */ -- if (kvm_feature_msrs && cpu_has_vmx(env)) { -- kvm_msr_entry_add_vmx(cpu, env->features); -- } - } - - if (env->mcg_cap) { -@@ -2854,19 +2881,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - } - } - -- ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); -- if (ret < 0) { -- return ret; -- } -- -- if (ret < cpu->kvm_msr_buf->nmsrs) { -- struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -- error_report("error: failed to set MSR 0x%" PRIx32 " to 0x%" PRIx64, -- (uint32_t)e->index, (uint64_t)e->data); -- } -- -- assert(ret == cpu->kvm_msr_buf->nmsrs); -- return 0; -+ return kvm_buf_set_msrs(cpu); - } - - -diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h -index 06fe06bdb3..d98c6f69d0 100644 ---- a/target/i386/kvm_i386.h -+++ b/target/i386/kvm_i386.h -@@ -66,4 +66,5 @@ bool kvm_enable_x2apic(void); - bool kvm_has_x2apic_api(void); - - bool kvm_hv_vpindex_settable(void); -+ - #endif --- -2.27.0 - diff --git a/target-i386-kvm-initialize-microcode-revision-from-K.patch b/target-i386-kvm-initialize-microcode-revision-from-K.patch deleted file mode 100644 index 5c15a47a5c025cc76e9f0fb2d9ade102a6cee294..0000000000000000000000000000000000000000 --- a/target-i386-kvm-initialize-microcode-revision-from-K.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 8664cd20e4cdb8594076a26dacef592a4b4816b2 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 20 Jan 2020 19:21:44 +0100 -Subject: [PATCH] target/i386: kvm: initialize microcode revision from KVM - -KVM can return the host microcode revision as a feature MSR. -Use it as the default value for -cpu host. - -Signed-off-by: Paolo Bonzini -Message-Id: <1579544504-3616-4-git-send-email-pbonzini@redhat.com> -Signed-off-by: Paolo Bonzini ---- - target/i386/cpu.c | 4 ++++ - target/i386/kvm.c | 5 +++++ - 2 files changed, 9 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index ec8bc9957e..1962f00c77 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6330,6 +6330,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - &cpu->mwait.ecx, &cpu->mwait.edx); - env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; - } -+ if (kvm_enabled() && cpu->ucode_rev == 0) { -+ cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state, -+ MSR_IA32_UCODE_REV); -+ } - } - - if (cpu->ucode_rev == 0) { -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 60060087fd..7437f86130 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -2628,6 +2628,11 @@ static void kvm_init_msrs(X86CPU *cpu) - env->features[FEAT_CORE_CAPABILITY]); - } - -+ if (kvm_arch_get_supported_msr_feature(kvm_state, -+ MSR_IA32_UCODE_REV)) { -+ kvm_msr_entry_add(cpu, MSR_IA32_UCODE_REV, cpu->ucode_rev); -+ } -+ - /* - * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but - * all kernels with MSR features should have them. --- -2.27.0 - diff --git a/target-i386-set-the-CPUID-level-to-0x14-on-old-machi.patch b/target-i386-set-the-CPUID-level-to-0x14-on-old-machi.patch deleted file mode 100644 index 462768e0318844720a338f553914e6bfbcdb0c8c..0000000000000000000000000000000000000000 --- a/target-i386-set-the-CPUID-level-to-0x14-on-old-machi.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 3b172cd5a6e62be725c778b8397310462fe0a890 Mon Sep 17 00:00:00 2001 -From: "plai@redhat.com" -Date: Thu, 7 May 2020 22:09:23 +0100 -Subject: [PATCH] target/i386: set the CPUID level to 0x14 on old machine-type - -RH-Author: plai@redhat.com -Message-id: <20200507220923.13723-1-plai@redhat.com> -Patchwork-id: 96347 -O-Subject: [RHEL8.2.1 AV qemu-kvm PATCH RESEND] target/i386: set the CPUID level to 0x14 on old machine-type -Bugzilla: 1513681 -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Igor Mammedov -RH-Acked-by: Danilo de Paula - -From: Luwei Kang - -BZ https://bugzilla.redhat.com/show_bug.cgi?id=1513681 -Brew: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=28146304 -Branch: rhel-av-8.2.1 - -Tested on intel-icelake-y-01.ml3.eng.bos.redhat.com. - -The CPUID level need to be set to 0x14 manually on old -machine-type if Intel PT is enabled in guest. E.g. the -CPUID[0].EAX(level)=7 and CPUID[7].EBX[25](intel-pt)=1 when the -Qemu with "-machine pc-i440fx-3.1 -cpu qemu64,+intel-pt" parameter. - -Some Intel PT capabilities are exposed by leaf 0x14 and the -missing capabilities will cause some MSRs access failed. -This patch add a warning message to inform the user to extend -the CPUID level. - -Suggested-by: Eduardo Habkost -Signed-off-by: Luwei Kang -Message-Id: <1584031686-16444-1-git-send-email-luwei.kang@intel.com> -Signed-off-by: Eduardo Habkost -(cherry picked from commit ddc2fc9e4e42ebce48b088963dc7fbd1c08d5f33) -Signed-off-by: Paul Lai -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/cpu.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 6147cd419a..35a33db39a 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6206,9 +6206,14 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE); - - /* Intel Processor Trace requires CPUID[0x14] */ -- if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) && -- kvm_enabled() && cpu->intel_pt_auto_level) { -- x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14); -+ if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT)) { -+ if (cpu->intel_pt_auto_level) { -+ x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14); -+ } else if (cpu->env.cpuid_min_level < 0x14) { -+ mark_unavailable_features(cpu, FEAT_7_0_EBX, -+ CPUID_7_0_EBX_INTEL_PT, -+ "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,level=0x14\""); -+ } - } - - /* CPU topology with multi-dies support requires CPUID[0x1F] */ --- -2.27.0 - diff --git a/target-i386-work-around-KVM_GET_MSRS-bug-for-seconda.patch b/target-i386-work-around-KVM_GET_MSRS-bug-for-seconda.patch deleted file mode 100644 index b4156952cf7fca7359fb38c8db086837b8ba3651..0000000000000000000000000000000000000000 --- a/target-i386-work-around-KVM_GET_MSRS-bug-for-seconda.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 70e4d278b89e04d7f9397ea25163feb6a7dbaa2d Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Tue, 2 Jul 2019 14:58:48 +0200 -Subject: [PATCH] target/i386: work around KVM_GET_MSRS bug for secondary - execution controls - -Some secondary controls are automatically enabled/disabled based on the CPUID -values that are set for the guest. However, they are still available at a -global level and therefore should be present when KVM_GET_MSRS is sent to -/dev/kvm. - -Unfortunately KVM forgot to include those, so fix that. - -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index fafb9fb26d..b97f40df6b 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -474,6 +474,23 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) - value = msr_data.entries[0].data; - switch (index) { - case MSR_IA32_VMX_PROCBASED_CTLS2: -+ /* KVM forgot to add these bits for some time, do this ourselves. */ -+ if (kvm_arch_get_supported_cpuid(s, 0xD, 1, R_ECX) & CPUID_XSAVE_XSAVES) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_XSAVES << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX) & CPUID_EXT_RDRAND) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDRAND_EXITING << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_INVPCID) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_ENABLE_INVPCID << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_RDSEED) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDSEED_EXITING << 32; -+ } -+ if (kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) { -+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDTSCP << 32; -+ } -+ /* fall through */ - case MSR_IA32_VMX_TRUE_PINBASED_CTLS: - case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: - case MSR_IA32_VMX_TRUE_ENTRY_CTLS: --- -2.27.0 - diff --git a/target-imx-reload-cmp-timer-outside-of-the-reload-pt.patch b/target-imx-reload-cmp-timer-outside-of-the-reload-pt.patch new file mode 100644 index 0000000000000000000000000000000000000000..273989a70d9344f63702f70b1a4cbd40dc56a2fb --- /dev/null +++ b/target-imx-reload-cmp-timer-outside-of-the-reload-pt.patch @@ -0,0 +1,43 @@ +From bdd1741cf18959e70cdfc6f46bb41d9209e86315 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 24 Nov 2022 17:18:00 +0800 +Subject: [PATCH 18/29] target/imx: reload cmp timer outside of the reload + ptimer transaction + +When running seL4 tests (https://docs.sel4.systems/projects/sel4test) +on the sabrelight platform, the timer tests fail. The arm/imx6 EPIT +timer interrupt does not fire properly, instead of a e.g. second in +can take up to a minute to finally see the interrupt. +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1263 + +Signed-off-by: Axel Heider +Signed-off-by: jianchunfu +--- + hw/timer/imx_epit.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c +index ebd58254d1..a78b625d15 100644 +--- a/hw/timer/imx_epit.c ++++ b/hw/timer/imx_epit.c +@@ -275,10 +275,15 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, + /* If IOVW bit is set then set the timer value */ + ptimer_set_count(s->timer_reload, s->lr); + } +- ++ /* ++ * Commit the change to s->timer_reload, so it can propagate. Otherwise ++ * the timer interrupt may not fire properly. The commit must happen ++ * before calling imx_epit_reload_compare_timer(), which reads ++ * s->timer_reload internally again. ++ */ ++ ptimer_transaction_commit(s->timer_reload); + imx_epit_reload_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); +- ptimer_transaction_commit(s->timer_reload); + break; + + case 3: /* CMP */ +-- +2.27.0 + diff --git a/target-ppc-Fix-the-order-of-kvm_enable-judgment-abou.patch b/target-ppc-Fix-the-order-of-kvm_enable-judgment-abou.patch new file mode 100644 index 0000000000000000000000000000000000000000..9485b039f10828edaa14d2d3f1a4683d4c70f25f --- /dev/null +++ b/target-ppc-Fix-the-order-of-kvm_enable-judgment-abou.patch @@ -0,0 +1,57 @@ +From ba1e022f06300e6dafc7e89a4f3fe756dc9691dd Mon Sep 17 00:00:00 2001 +From: JianChunfu +Date: Wed, 20 Sep 2023 18:58:00 +0800 +Subject: [PATCH] target/ppc: Fix the order of kvm_enable judgment about + kvmppc_set_interrupt() + +It's unnecessary for non-KVM accelerators(TCG, for example), +to call this function, so change the order of kvm_enable() judgment. +The static inline function that returns -1 directly does not work +in TCG's situation. + +Signed-off-by: JianChunfu +--- + hw/ppc/ppc.c | 8 ++++++-- + target/ppc/kvm.c | 2 +- + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c +index e8127599c9..cf90ab7805 100644 +--- a/hw/ppc/ppc.c ++++ b/hw/ppc/ppc.c +@@ -66,7 +66,9 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) + } + + if (old_pending != env->pending_interrupts) { +- kvmppc_set_interrupt(cpu, n_IRQ, level); ++ if (kvm_enabled()) { ++ kvmppc_set_interrupt(cpu, irq, level); ++ } + } + + +@@ -1461,5 +1463,7 @@ void ppc_irq_reset(PowerPCCPU *cpu) + CPUPPCState *env = &cpu->env; + + env->irq_input_state = 0; +- kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); ++ if (kvm_enabled()) { ++ kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); ++ } + } +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index d73563045b..397b1e902b 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -1323,7 +1323,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) + return 0; + } + +- if (!kvm_enabled() || !cap_interrupt_unset) { ++ if (!cap_interrupt_unset) { + return 0; + } + +-- +2.41.0.windows.1 + diff --git a/target-ppc-Fix-tlbie.patch b/target-ppc-Fix-tlbie.patch new file mode 100644 index 0000000000000000000000000000000000000000..63d3ebb86b56b9728a236cf16f1ea092c0e9ae5d --- /dev/null +++ b/target-ppc-Fix-tlbie.patch @@ -0,0 +1,47 @@ +From aba3dd63d054cd21054e295d5a9d493cb9d7a75f Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 26 Sep 2023 06:25:04 +0000 +Subject: [PATCH] target/ppc: Fix tlbie mainline inclusion commit + 4ddc104689b186c4e4ed30be59a54463501761cf category: bugfix + +--------------------------------------------------------------- + +Commit 74c4912f097bab98 changed check_tlb_flush() to use +tlb_flush_all_cpus_synced() instead of calling tlb_flush() on each +CPU. However, as side effect of this, a CPU executing a ptesync +after a tlbie will have its TLB flushed only after exiting its +current Translation Block (TB). + +This causes memory accesses to invalid pages to succeed, if they +happen to be on the same TB as the ptesync. + +To fix this, use tlb_flush_all_cpus() instead, that immediately +flushes the TLB of the CPU executing the ptesync instruction. + +Fixes: 74c4912f097bab98 ("target/ppc: Fix synchronization of mttcg with broadcast TLB flushes") +Signed-off-by: Leandro Lupori +Reviewed-by: Fabiano Rosas +Message-Id: <20220503163904.22575-1-leandro.lupori@eldorado.org.br> +Signed-off-by: Daniel Henrique Barboza + +Signed-off-by: tangbinzy +--- + target/ppc/helper_regs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c +index 99562edd57..e97d25e9ab 100644 +--- a/target/ppc/helper_regs.c ++++ b/target/ppc/helper_regs.c +@@ -288,7 +288,7 @@ void check_tlb_flush(CPUPPCState *env, bool global) + if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { + env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; +- tlb_flush_all_cpus_synced(cs); ++ tlb_flush_all_cpus(cs); + return; + } + +-- +2.41.0.windows.1 + diff --git a/target-ppc-add-error-report-when-fopen-fails-in-kvmp.patch b/target-ppc-add-error-report-when-fopen-fails-in-kvmp.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c0c8a19e865d1e99faf0131f33ab0896144983e --- /dev/null +++ b/target-ppc-add-error-report-when-fopen-fails-in-kvmp.patch @@ -0,0 +1,50 @@ +From 67a8e57c784ccbce4989c39dd44c70ae7f5aeda4 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 4 Aug 2022 15:37:47 +0800 +Subject: [PATCH 5/9] target/ppc: add error report when fopen fails in + kvmppc_read_int_dt() + +Use an Error pointer to report the error back to the caller. +While we're at it, return '0' instead of '-1' on error since the +function is supposed to return an uint64_t. + +Signed-off-by: jianchunfu +--- + target/ppc/kvm.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index dc93b99189..63382256c3 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -1895,7 +1895,7 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) + return 0; + } + +-static uint64_t kvmppc_read_int_dt(const char *filename) ++static uint64_t kvmppc_read_int_dt(const char *filename, Error **errp) + { + union { + uint32_t v32; +@@ -1906,7 +1906,8 @@ static uint64_t kvmppc_read_int_dt(const char *filename) + + f = fopen(filename, "rb"); + if (!f) { +- return -1; ++ error_setg_errno(errp, errno, "error opening %s", filename); ++ return 0; + } + + len = fread(&u, 1, sizeof(u), f); +@@ -1937,7 +1938,7 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname) + } + + tmp = g_strdup_printf("%s/%s", buf, propname); +- val = kvmppc_read_int_dt(tmp); ++ val = kvmppc_read_int_dt(tmp, NULL); + g_free(tmp); + + return val; +-- +2.27.0 + diff --git a/target-ppc-cpu-models-Remove-the-default-CPU-alias.patch b/target-ppc-cpu-models-Remove-the-default-CPU-alias.patch new file mode 100644 index 0000000000000000000000000000000000000000..048ca97c37788c5137a63877b726accc13f9b17b --- /dev/null +++ b/target-ppc-cpu-models-Remove-the-default-CPU-alias.patch @@ -0,0 +1,40 @@ +From 73ece819848b2ecc110ec676413d5a86ffc0f8fc Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:26:10 -0800 +Subject: [PATCH] target/ppc/cpu-models: Remove the "default" CPU alias +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 7886605961d0a9c40ada0c28dee5fa0b42a30836 + +QEMU emulates a *lot* of PowerPC-based machines - having a CPU +that is named "default" and cannot be used with most of those +machines sounds just wrong. Thus let's remove this old and confusing +alias now. + +Signed-off-by: Thomas Huth +Reviewed-by: Greg Kurz +Reviewed-by: Cédric Le Goater +Message-Id: <20220705151030.662140-1-thuth@redhat.com> +Signed-off-by: Daniel Henrique Barboza +Signed-off-by: Wanghe Xiao +--- + target/ppc/cpu-models.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c +index 4baa111713..02efc95723 100644 +--- a/target/ppc/cpu-models.c ++++ b/target/ppc/cpu-models.c +@@ -963,6 +963,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { + #endif + { "ppc32", "604" }, + { "ppc", "604" }, +- { "default", "604" }, ++ + { NULL, NULL } + }; +-- +2.27.0 + diff --git a/target-ppc-enhance-error-report-in-kvmppc_read_int_c.patch b/target-ppc-enhance-error-report-in-kvmppc_read_int_c.patch new file mode 100644 index 0000000000000000000000000000000000000000..c05844adc531e8046ab25a139b2ea87fef59e3d2 --- /dev/null +++ b/target-ppc-enhance-error-report-in-kvmppc_read_int_c.patch @@ -0,0 +1,81 @@ +From b167d664414e7d4a5a7a7058bc4c7699f6e66d48 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 4 Aug 2022 15:57:46 +0800 +Subject: [PATCH 6/9] target/ppc: enhance error report in + kvmppc_read_int_cpu_dt() + +First and foremost, the function can't return '-1' when an error occurs +because the return type is set to uint64_t. Let's fix that. +After that, the function can't simply return 0 whether an error happened +and call it a day. We must provide a way of letting callers know if the +zero return is legitimate or due to an error. +Add an Error pointer to kvmppc_read_int_cpu_dt() that will be filled +with an appropriate error, if one occurs. Callers are then free to pass +an Error pointer and handle it. + +Signed-off-by: jianchunfu +--- + target/ppc/kvm.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index 63382256c3..d64d7c5b4a 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -1925,20 +1925,22 @@ static uint64_t kvmppc_read_int_dt(const char *filename, Error **errp) + + /* + * Read a CPU node property from the host device tree that's a single +- * integer (32-bit or 64-bit). Returns 0 if anything goes wrong +- * (can't find or open the property, or doesn't understand the format) ++ * integer (32-bit or 64-bit). Returns 0 and set errp if anything goes ++ * wrong (can't find or open the property, or doesn't understand the ++ * format) + */ +-static uint64_t kvmppc_read_int_cpu_dt(const char *propname) ++static uint64_t kvmppc_read_int_cpu_dt(const char *propname, Error **errp) + { + char buf[PATH_MAX], *tmp; + uint64_t val; + + if (kvmppc_find_cpu_dt(buf, sizeof(buf))) { +- return -1; ++ error_setg(errp, "Failed to read CPU property %s", propname); ++ return 0; + } + + tmp = g_strdup_printf("%s/%s", buf, propname); +- val = kvmppc_read_int_dt(tmp, NULL); ++ val = kvmppc_read_int_dt(tmp, errp); + g_free(tmp); + + return val; +@@ -1946,12 +1948,12 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname) + + uint64_t kvmppc_get_clockfreq(void) + { +- return kvmppc_read_int_cpu_dt("clock-frequency"); ++ return kvmppc_read_int_cpu_dt("clock-frequency", NULL); + } + + static int kvmppc_get_dec_bits(void) + { +- int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits"); ++ int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits", NULL); + + if (nr_bits > 0) { + return nr_bits; +@@ -2336,8 +2338,8 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) + static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) + { + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); +- uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size"); +- uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size"); ++ uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size", NULL); ++ uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size", NULL); + + /* Now fix up the class with information we can query from the host */ + pcc->pvr = mfpvr(); +-- +2.27.0 + diff --git a/target-ppc-exit-1-on-failure-in-kvmppc_get_clockfreq.patch b/target-ppc-exit-1-on-failure-in-kvmppc_get_clockfreq.patch new file mode 100644 index 0000000000000000000000000000000000000000..140f2fd7f3ac3f77a78705e86a079896cc6f13ad --- /dev/null +++ b/target-ppc-exit-1-on-failure-in-kvmppc_get_clockfreq.patch @@ -0,0 +1,51 @@ +From 584a648e0de0b0bda49e87349f2db3b2f0f87c33 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 4 Aug 2022 16:47:26 +0800 +Subject: [PATCH 8/9] target/ppc: exit(1) on failure in kvmppc_get_clockfreq() + +When running under KVM accel it is expected to have 'clock-frequency' in +the DT. Not having this attribute is too risky for both the machine +emulation and userspace. +We have a way of telling whether this error scenario might happen or not +via kvmppc_read_int_cpu_dt() now being able to report errors. From now +on, when running KVM, we will assume that 'clock-frequency' will always +be present in the DT. + +Signed-off-by: jianchunfu +--- + target/ppc/kvm.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index 1a6c6b6fa0..d73563045b 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -1944,9 +1944,24 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname, Error **errp) + return kvmppc_read_int_dt(tmp, errp); + } + ++/* ++ * Read the clock-frequency from the DT. On error (e.g. ++ * 'clock-frequency' is not present in the DT) will ++ * report an error and exit(1). ++ */ + uint64_t kvmppc_get_clockfreq(void) + { +- return kvmppc_read_int_cpu_dt("clock-frequency", NULL); ++ Error *local_err = NULL; ++ int ret; ++ ++ ret = kvmppc_read_int_cpu_dt("clock-frequency", &local_err); ++ ++ if (local_err) { ++ error_report_err(local_err); ++ exit(1); ++ } ++ ++ return ret; + } + + static int kvmppc_get_dec_bits(void) +-- +2.27.0 + diff --git a/target-ppc-use-g_autofree-in-kvmppc_read_int_cpu_dt.patch b/target-ppc-use-g_autofree-in-kvmppc_read_int_cpu_dt.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ffb9733069ec41baa9155c92731b2ad43774253 --- /dev/null +++ b/target-ppc-use-g_autofree-in-kvmppc_read_int_cpu_dt.patch @@ -0,0 +1,43 @@ +From 02a15861235d29dcf89b61bf88fed2ec4ccee9dc Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Thu, 4 Aug 2022 16:41:35 +0800 +Subject: [PATCH 7/9] target/ppc: use g_autofree in kvmppc_read_int_cpu_dt() + +This spares us a g_free() call. Let's also not use 'val' and return the +value of kvmppc_read_int_dt() directly. + +Signed-off-by: jianchunfu +--- + target/ppc/kvm.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index d64d7c5b4a..1a6c6b6fa0 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -1931,8 +1931,8 @@ static uint64_t kvmppc_read_int_dt(const char *filename, Error **errp) + */ + static uint64_t kvmppc_read_int_cpu_dt(const char *propname, Error **errp) + { +- char buf[PATH_MAX], *tmp; +- uint64_t val; ++ g_autofree char *tmp = NULL; ++ char buf[PATH_MAX]; + + if (kvmppc_find_cpu_dt(buf, sizeof(buf))) { + error_setg(errp, "Failed to read CPU property %s", propname); +@@ -1940,10 +1940,8 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname, Error **errp) + } + + tmp = g_strdup_printf("%s/%s", buf, propname); +- val = kvmppc_read_int_dt(tmp, errp); +- g_free(tmp); + +- return val; ++ return kvmppc_read_int_dt(tmp, errp); + } + + uint64_t kvmppc_get_clockfreq(void) +-- +2.27.0 + diff --git a/target-riscv-pmp-fix-no-pmp-illegal-intrs.patch b/target-riscv-pmp-fix-no-pmp-illegal-intrs.patch new file mode 100644 index 0000000000000000000000000000000000000000..b10f7d0fef451d564ccd818b3a13ed092f86a5a9 --- /dev/null +++ b/target-riscv-pmp-fix-no-pmp-illegal-intrs.patch @@ -0,0 +1,43 @@ +From 5489264cd9583855d45fd0c21f18387b649f6e44 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 15:26:59 +0300 +Subject: [PATCH 15/29] target/riscv/pmp: fix no pmp illegal intrs + +mainline inclusion +commit 0fbb5d2d3c9ded9fbd3f6f993974cc5e88e28912 +category: bugfix + +----------------------------------------------- + +As per the privilege specification, any access from S/U mode should fail +if no pmp region is configured and pmp is present, othwerwise access +should succeed. + +Fixes: d102f19a208 (target/riscv/pmp: Raise exception if no PMP entry is configured) +Signed-off-by: Nikita Shubin +Reviewed-by: Alistair Francis +Message-id: 20211214092659.15709-1-nikita.shubin@maquefel.me +Signed-off-by: Alistair Francis + +Signed-off-by: tangbinzy +--- + target/riscv/op_helper.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c +index ee7c24efe7..58d992e98a 100644 +--- a/target/riscv/op_helper.c ++++ b/target/riscv/op_helper.c +@@ -146,7 +146,8 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) + uint64_t mstatus = env->mstatus; + target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); + +- if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) { ++ if (riscv_feature(env, RISCV_FEATURE_PMP) && ++ !pmp_get_num_rules(env) && (prev_priv != PRV_M)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } + +-- +2.27.0 + diff --git a/tcg-Reduce-tcg_assert_listed_vecop-scope.patch b/tcg-Reduce-tcg_assert_listed_vecop-scope.patch new file mode 100644 index 0000000000000000000000000000000000000000..15f46f796b48121394e93f17f2073af11bbccc15 --- /dev/null +++ b/tcg-Reduce-tcg_assert_listed_vecop-scope.patch @@ -0,0 +1,64 @@ +From 61af18384a150a2c7d1f54521692a93c0e4ebacc Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Sun, 2 Jul 2023 23:37:42 +0800 +Subject: [PATCH] tcg: Reduce tcg_assert_listed_vecop() scope + + tcg_assert_listed_vecop() is only used in tcg-op-vec.c. + + Signed-off-by: Philippe Mathieu-Daud + Message-Id: <20230629091107.74384-1-philmd@linaro.org> + Reviewed-by: Richard Henderson + Signed-off-by: Richard Henderson + + Signed-off-by: Zhongrui Tang +--- + include/tcg/tcg.h | 6 ------ + tcg/tcg-op-vec.c | 6 +++--- + 2 files changed, 3 insertions(+), 9 deletions(-) + +diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h +index 42f5b500ed..0ab8e4e735 100644 +--- a/include/tcg/tcg.h ++++ b/include/tcg/tcg.h +@@ -1240,12 +1240,6 @@ uint64_t dup_const(unsigned vece, uint64_t c); + : (target_long)dup_const(VECE, C)) + #endif + +-#ifdef CONFIG_DEBUG_TCG +-void tcg_assert_listed_vecop(TCGOpcode); +-#else +-static inline void tcg_assert_listed_vecop(TCGOpcode op) { } +-#endif +- + static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n) + { + #ifdef CONFIG_DEBUG_TCG +diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c +index faf30f9cdd..7c027099c4 100644 +--- a/tcg/tcg-op-vec.c ++++ b/tcg/tcg-op-vec.c +@@ -50,9 +50,9 @@ extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); + * tcg_ctx->vec_opt_opc is non-NULL, the tcg_gen_*_vec expanders + * will validate that their opcode is present in the list. + */ +-#ifdef CONFIG_DEBUG_TCG +-void tcg_assert_listed_vecop(TCGOpcode op) ++static void tcg_assert_listed_vecop(TCGOpcode op) + { ++#ifdef CONFIG_DEBUG_TCG + const TCGOpcode *p = tcg_ctx->vecop_list; + if (p) { + for (; *p; ++p) { +@@ -62,8 +62,8 @@ void tcg_assert_listed_vecop(TCGOpcode op) + } + g_assert_not_reached(); + } +-} + #endif ++} + + bool tcg_can_emit_vecop_list(const TCGOpcode *list, + TCGType type, unsigned vece) +-- +2.41.0.windows.1 + diff --git a/tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch b/tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch new file mode 100644 index 0000000000000000000000000000000000000000..190a5c3273ce557e8c98a0c174bdb33ec68bb21a --- /dev/null +++ b/tcg-loongarch64-Fix-tcg_out_mov-Aborted.patch @@ -0,0 +1,64 @@ +From ea14e0f1c97b6af8db9fa7b2d0df14ef03d9acb9 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 14:04:58 +0800 +Subject: [PATCH] tcg/loongarch64: Fix tcg_out_mov() Aborted +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 85d57a37be1461d599747ab86dc0acc46732dbce + +On LoongArch host, we got an Aborted from tcg_out_mov(). + +qemu-x86_64 configure with '--enable-debug'. + +> (gdb) b /home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc:312 +> Breakpoint 1 at 0x2576f0: file /home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc, line 312. +> (gdb) run hello +[...] +> Thread 1 "qemu-x86_64" hit Breakpoint 1, tcg_out_mov (s=0xaaaae91760 , type=TCG_TYPE_V128, ret=TCG_REG_V2, +> arg=TCG_REG_V0) at /home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc:312 +> 312 g_assert_not_reached(); +> (gdb) bt +> #0 tcg_out_mov (s=0xaaaae91760 , type=TCG_TYPE_V128, ret=TCG_REG_V2, arg=TCG_REG_V0) +> at /home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc:312 +> #1 0x000000aaaad0fee0 in tcg_reg_alloc_mov (s=0xaaaae91760 , op=0xaaaaf67c20) at ../tcg/tcg.c:4632 +> #2 0x000000aaaad142f4 in tcg_gen_code (s=0xaaaae91760 , tb=0xffe8030340 , +> pc_start=4346094) at ../tcg/tcg.c:6135 +[...] +> (gdb) c +> Continuing. +> ** +> ERROR:/home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc:312:tcg_out_mov: code should not be reached +> Bail out! ERROR:/home1/gaosong/code/qemu/tcg/loongarch64/tcg-target.c.inc:312:tcg_out_mov: code should not be reached +> +> Thread 1 "qemu-x86_64" received signal SIGABRT, Aborted. +> 0x000000fff7b1c390 in raise () from /lib64/libc.so.6 +> (gdb) q + +Fixes: 16288ded94 ("tcg/loongarch64: Lower basic tcg vec ops to LSX") +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Song Gao +Message-Id: <20231120065916.374045-1-gaosong@loongson.cn> +--- + tcg/loongarch64/tcg-target.c.inc | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc +index 0b28b30002..ee7d4d728d 100644 +--- a/tcg/loongarch64/tcg-target.c.inc ++++ b/tcg/loongarch64/tcg-target.c.inc +@@ -255,6 +255,9 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) + */ + tcg_out_opc_or(s, ret, arg, TCG_REG_ZERO); + break; ++ case TCG_TYPE_V128: ++ tcg_out_opc_vori_b(s, ret, arg, 0); ++ break; + default: + g_assert_not_reached(); + } +-- +2.27.0 + diff --git a/tcg-optimize-Fix-folding-of-vector-ops.patch b/tcg-optimize-Fix-folding-of-vector-ops.patch new file mode 100644 index 0000000000000000000000000000000000000000..9cfcc55b6dbf95420a1762938ba79d0138858d02 --- /dev/null +++ b/tcg-optimize-Fix-folding-of-vector-ops.patch @@ -0,0 +1,157 @@ +From 8eef73d0714c8bb5a4fc5a8b6ae007752d0061b2 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 15:35:25 -0800 +Subject: [PATCH 13/29] tcg/optimize: Fix folding of vector ops +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit c578ff18584666499c3141b2d770b9e36b5e9d7e +category: bugfix + +------------------------------------------------------------ + +Bitwise operations are easy to fold, because the operation is +identical regardless of element size. But add and sub need +extra element size info that is not currently propagated. + +Fixes: 2f9f08ba43d +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/799 +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + tcg/optimize.c | 49 ++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 38 insertions(+), 11 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 2397f2cf93..e573000951 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -308,13 +308,13 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) + CASE_OP_32_64(mul): + return x * y; + +- CASE_OP_32_64(and): ++ CASE_OP_32_64_VEC(and): + return x & y; + +- CASE_OP_32_64(or): ++ CASE_OP_32_64_VEC(or): + return x | y; + +- CASE_OP_32_64(xor): ++ CASE_OP_32_64_VEC(xor): + return x ^ y; + + case INDEX_op_shl_i32: +@@ -347,16 +347,16 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) + case INDEX_op_rotl_i64: + return rol64(x, y & 63); + +- CASE_OP_32_64(not): ++ CASE_OP_32_64_VEC(not): + return ~x; + + CASE_OP_32_64(neg): + return -x; + +- CASE_OP_32_64(andc): ++ CASE_OP_32_64_VEC(andc): + return x & ~y; + +- CASE_OP_32_64(orc): ++ CASE_OP_32_64_VEC(orc): + return x | ~y; + + CASE_OP_32_64(eqv): +@@ -751,6 +751,12 @@ static bool fold_const2(OptContext *ctx, TCGOp *op) + return false; + } + ++static bool fold_commutative(OptContext *ctx, TCGOp *op) ++{ ++ swap_commutative(op->args[0], &op->args[1], &op->args[2]); ++ return false; ++} ++ + static bool fold_const2_commutative(OptContext *ctx, TCGOp *op) + { + swap_commutative(op->args[0], &op->args[1], &op->args[2]); +@@ -905,6 +911,16 @@ static bool fold_add(OptContext *ctx, TCGOp *op) + return false; + } + ++/* We cannot as yet do_constant_folding with vectors. */ ++static bool fold_add_vec(OptContext *ctx, TCGOp *op) ++{ ++ if (fold_commutative(ctx, op) || ++ fold_xi_to_x(ctx, op, 0)) { ++ return true; ++ } ++ return false; ++} ++ + static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) + { + if (arg_is_const(op->args[2]) && arg_is_const(op->args[3]) && +@@ -1938,10 +1954,10 @@ static bool fold_sub_to_neg(OptContext *ctx, TCGOp *op) + return false; + } + +-static bool fold_sub(OptContext *ctx, TCGOp *op) ++/* We cannot as yet do_constant_folding with vectors. */ ++static bool fold_sub_vec(OptContext *ctx, TCGOp *op) + { +- if (fold_const2(ctx, op) || +- fold_xx_to_i(ctx, op, 0) || ++ if (fold_xx_to_i(ctx, op, 0) || + fold_xi_to_x(ctx, op, 0) || + fold_sub_to_neg(ctx, op)) { + return true; +@@ -1949,6 +1965,11 @@ static bool fold_sub(OptContext *ctx, TCGOp *op) + return false; + } + ++static bool fold_sub(OptContext *ctx, TCGOp *op) ++{ ++ return fold_const2(ctx, op) || fold_sub_vec(ctx, op); ++} ++ + static bool fold_sub2(OptContext *ctx, TCGOp *op) + { + return fold_addsub2(ctx, op, false); +@@ -2052,9 +2073,12 @@ void tcg_optimize(TCGContext *s) + * Sorted alphabetically by opcode as much as possible. + */ + switch (opc) { +- CASE_OP_32_64_VEC(add): ++ CASE_OP_32_64(add): + done = fold_add(&ctx, op); + break; ++ case INDEX_op_add_vec: ++ done = fold_add_vec(&ctx, op); ++ break; + CASE_OP_32_64(add2): + done = fold_add2(&ctx, op); + break; +@@ -2193,9 +2217,12 @@ void tcg_optimize(TCGContext *s) + CASE_OP_32_64(sextract): + done = fold_sextract(&ctx, op); + break; +- CASE_OP_32_64_VEC(sub): ++ CASE_OP_32_64(sub): + done = fold_sub(&ctx, op); + break; ++ case INDEX_op_sub_vec: ++ done = fold_sub_vec(&ctx, op); ++ break; + CASE_OP_32_64(sub2): + done = fold_sub2(&ctx, op); + break; +-- +2.27.0 + diff --git a/tcg-tci-fix-logic-error-when-registering-helpers-via.patch b/tcg-tci-fix-logic-error-when-registering-helpers-via.patch new file mode 100644 index 0000000000000000000000000000000000000000..6df462c8e0f13d4263f51a8886f66dd2c1a7845d --- /dev/null +++ b/tcg-tci-fix-logic-error-when-registering-helpers-via.patch @@ -0,0 +1,53 @@ +From 32533b4b6ea73b69f654ae2d337b3262da36830a Mon Sep 17 00:00:00 2001 +From: cmss_dx +Date: Wed, 23 Nov 2022 06:23:16 +0000 +Subject: [PATCH 07/29] tcg/tci: fix logic error when registering helpers via + FFI mainline inclusion from mainline-v7.2.0-rc1 commit + 9dd1d56e570e5119fef2b28fda811d6891e597a8 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +-------------------------------- + +When registering helpers via FFI for TCI, the inner loop that iterates +parameters of the helper reuses (and thus pollutes) the same variable +used by the outer loop that iterates all helpers, thus made some helpers +unregistered. + +Fix this logic error by using a dedicated temporary variable for the +inner loop. + +Fixes: 22f1557 ("tcg: Build ffi data structures for helpers") +Reviewed-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Icenowy Zheng +Message-Id: <20221028072145.1593205-1-uwu@icenowy.me> +[rth: Move declaration of j to the for loop itself] +Signed-off-by: Richard Henderson + +Signed-off-by: cmss_dx +--- + tcg/tcg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 934aa8510b..635555001b 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -632,9 +632,9 @@ static void tcg_context_init(unsigned max_cpus) + + if (nargs != 0) { + ca->cif.arg_types = ca->args; +- for (i = 0; i < nargs; ++i) { +- int typecode = extract32(typemask, (i + 1) * 3, 3); +- ca->args[i] = typecode_to_ffi[typecode]; ++ for (int j = 0; j < nargs; ++j) { ++ int typecode = extract32(typemask, (j + 1) * 3, 3); ++ ca->args[j] = typecode_to_ffi[typecode]; + } + } + +-- +2.27.0 + diff --git a/tcp_emu-Fix-oob-access.patch b/tcp_emu-Fix-oob-access.patch deleted file mode 100644 index 807dfef08e28fe33a65fede676bbb076f5d9e393..0000000000000000000000000000000000000000 --- a/tcp_emu-Fix-oob-access.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 585634894f511bc1821cef54494bf2d9abc109c9 Mon Sep 17 00:00:00 2001 -From: Samuel Thibault -Date: Tue, 14 Apr 2020 18:04:33 +0800 -Subject: [PATCH] tcp_emu: Fix oob access - -The main loop only checks for one available byte, while we sometimes -need two bytes. ---- - slirp/src/tcp_subr.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index d6dd133a..9c94c03a 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -886,6 +886,9 @@ int tcp_emu(struct socket *so, struct mbuf *m) - break; - - case 5: -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ -+ - /* - * The difference between versions 1.0 and - * 2.0 is here. For future versions of -@@ -901,6 +904,9 @@ int tcp_emu(struct socket *so, struct mbuf *m) - /* This is the field containing the port - * number that RA-player is listening to. - */ -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ -+ - lport = (((uint8_t *)bptr)[0] << 8) + ((uint8_t *)bptr)[1]; - if (lport < 6970) - lport += 256; /* don't know why */ --- -2.23.0 diff --git a/tcp_emu-fix-unsafe-snprintf-usages.patch b/tcp_emu-fix-unsafe-snprintf-usages.patch deleted file mode 100644 index 2f6850a60c2fb942ecc7ef15030686d3dd94aa9c..0000000000000000000000000000000000000000 --- a/tcp_emu-fix-unsafe-snprintf-usages.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 220a52fda279038d46c25d39a372154ff9b024d2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureauls?= -Date: Tue, 14 Apr 2020 19:06:35 +0800 -Subject: [PATCH] tcp_emu: fix unsafe snprintf() usages -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Various calls to snprintf() assume that snprintf() returns "only" the -number of bytes written (excluding terminating NUL). - -https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04 - -"Upon successful completion, the snprintf() function shall return the -number of bytes that would be written to s had n been sufficiently -large excluding the terminating null byte." - -Before patch ce131029, if there isn't enough room in "m_data" for the -"DCC ..." message, we overflow "m_data". - -After the patch, if there isn't enough room for the same, we don't -overflow "m_data", but we set "m_len" out-of-bounds. The next time an -access is bounded by "m_len", we'll have a buffer overflow then. - -Use slirp_fmt*() to fix potential OOB memory access. -Reported-by: default avatarLaszlo Ersek -Signed-off-by: default avatarMarc-André Lureau -Reviewed-by: Samuel Thibault's avatarSamuel Thibault -Message-Id: <20200127092414.169796-7-marcandre.lureau@redhat.com> ---- - slirp/src/tcp_subr.c | 15 +++++++-------- - 1 file changed, 7 insertions(+), 8 deletions(-) - -diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index 019b637a..6c1b17bd 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -655,8 +655,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - NTOHS(n1); - NTOHS(n2); - m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1); -- m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); -- assert(m->m_len < M_ROOM(m)); -+ m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); - } else { - *eol = '\r'; - } -@@ -696,7 +695,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, - n5, n6, x == 7 ? buff : ""); - return 1; -@@ -732,7 +731,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, M_FREEROOM(m), -+ slirp_fmt(bptr, M_FREEROOM(m), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); - -@@ -759,7 +758,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, - htons(lport), SS_FACCEPTONCE)) != NULL) - m->m_len = -- snprintf(m->m_data, M_ROOM(m), -+ slirp_fmt0(m->m_data, M_ROOM(m), - "%d", ntohs(so->so_fport)) + 1; - return 1; - -@@ -779,7 +778,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); -@@ -791,7 +790,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, M_FREEROOM(m), -+ slirp_fmt(bptr, M_FREEROOM(m), - "DCC SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); -@@ -803,7 +802,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += -- snprintf(bptr, M_FREEROOM(m), -+ slirp_fmt(bptr, M_FREEROOM(m), - "DCC MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); --- -2.23.0 diff --git a/test-Fix-test-crypto-secret-when-compiling-without-k.patch b/test-Fix-test-crypto-secret-when-compiling-without-k.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fc233b254b6e5e98f252408212e84e4aef679fa --- /dev/null +++ b/test-Fix-test-crypto-secret-when-compiling-without-k.patch @@ -0,0 +1,72 @@ +From edf3134ef2f98c7fd79f54a467631f091e52a980 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Fri, 14 Apr 2023 13:42:52 +0200 +Subject: [PATCH] test: Fix test-crypto-secret when compiling without keyring + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Linux keyring support is protected by CONFIG_KEYUTILS. +We also need CONFIG_SECRET_KEYRING. + +Signed-off-by: Juan Quintela +Message-Id: <20230414114252.1136-1-quintela@redhat.com> +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Thomas Huth +--- + tests/unit/test-crypto-secret.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tests/unit/test-crypto-secret.c b/tests/unit/test-crypto-secret.c +index 34a4aecc12..147b4af828 100644 +--- a/tests/unit/test-crypto-secret.c ++++ b/tests/unit/test-crypto-secret.c +@@ -24,7 +24,7 @@ + #include "crypto/secret.h" + #include "qapi/error.h" + #include "qemu/module.h" +-#ifdef CONFIG_KEYUTILS ++#if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING) + #include "crypto/secret_keyring.h" + #include + #endif +@@ -128,7 +128,7 @@ static void test_secret_indirect_emptyfile(void) + g_free(fname); + } + +-#ifdef CONFIG_KEYUTILS ++#if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING) + + #define DESCRIPTION "qemu_test_secret" + #define PAYLOAD "Test Payload" +@@ -268,7 +268,7 @@ static void test_secret_keyring_bad_key_access_right(void) + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); + } + +-#endif /* CONFIG_KEYUTILS */ ++#endif /* CONFIG_KEYUTILS && CONFIG_SECRET_KEYRING */ + + static void test_secret_noconv_base64_good(void) + { +@@ -571,7 +571,7 @@ int main(int argc, char **argv) + g_test_add_func("/crypto/secret/indirect/emptyfile", + test_secret_indirect_emptyfile); + +-#ifdef CONFIG_KEYUTILS ++#if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING) + g_test_add_func("/crypto/secret/keyring/good", + test_secret_keyring_good); + g_test_add_func("/crypto/secret/keyring/revoked_key", +@@ -582,7 +582,7 @@ int main(int argc, char **argv) + test_secret_keyring_bad_serial_key); + g_test_add_func("/crypto/secret/keyring/bad_key_access_right", + test_secret_keyring_bad_key_access_right); +-#endif /* CONFIG_KEYUTILS */ ++#endif /* CONFIG_KEYUTILS && CONFIG_SECRET_KEYRING */ + + g_test_add_func("/crypto/secret/noconv/base64/good", + test_secret_noconv_base64_good); +-- +2.41.0.windows.1 + diff --git a/test-numa-Adjust-aarch64-numa-test.patch b/test-numa-Adjust-aarch64-numa-test.patch index 24145937724385b1ff8dd0bd280e5e62341ad659..cb3331439de9a93efc720dd38dd5dac9e67caae1 100644 --- a/test-numa-Adjust-aarch64-numa-test.patch +++ b/test-numa-Adjust-aarch64-numa-test.patch @@ -1,4 +1,4 @@ -From 3ef97cc418d1061fc0ec70098270ce2d76005cc1 Mon Sep 17 00:00:00 2001 +From 1a347bf3f8e7e31cdaed265af22853d66c202090 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 23 Apr 2020 20:54:18 +0800 Subject: [PATCH] test/numa: Adjust aarch64 numa test @@ -8,20 +8,20 @@ changes the meaning of "thread-id", so we must modify test case. Signed-off-by: Keqian Zhu --- - tests/numa-test.c | 16 ++++++++-------- + tests/qtest/numa-test.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) -diff --git a/tests/numa-test.c b/tests/numa-test.c -index 8de8581231..71cdd7b4f7 100644 ---- a/tests/numa-test.c -+++ b/tests/numa-test.c -@@ -231,17 +231,17 @@ static void aarch64_numa_cpu(const void *data) - QObject *e; +diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c +index 90bf68a5b3..08f28012c8 100644 +--- a/tests/qtest/numa-test.c ++++ b/tests/qtest/numa-test.c +@@ -223,17 +223,17 @@ static void aarch64_numa_cpu(const void *data) QTestState *qts; - -- cli = make_cli(data, "-smp 2 " -+ cli = make_cli(data, "-smp 2,cores=2 " - "-numa node,nodeid=0 -numa node,nodeid=1 " + g_autofree char *cli = NULL; + +- cli = make_cli(data, "-machine smp.cpus=2 " ++ cli = make_cli(data, "-machine smp.cpus=2,smp.cores=2 " + "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 " - "-numa cpu,node-id=1,thread-id=0 " - "-numa cpu,node-id=0,thread-id=1"); + "-numa cpu,node-id=1,core-id=0 " @@ -29,23 +29,23 @@ index 8de8581231..71cdd7b4f7 100644 qts = qtest_init(cli); cpus = get_cpus(qts, &resp); g_assert(cpus); - + while ((e = qlist_pop(cpus))) { QDict *cpu, *props; - int64_t thread, node; + int64_t core, node; - + cpu = qobject_to(QDict, e); g_assert(qdict_haskey(cpu, "props")); -@@ -249,12 +249,12 @@ static void aarch64_numa_cpu(const void *data) - +@@ -241,12 +241,12 @@ static void aarch64_numa_cpu(const void *data) + g_assert(qdict_haskey(props, "node-id")); node = qdict_get_int(props, "node-id"); - g_assert(qdict_haskey(props, "thread-id")); - thread = qdict_get_int(props, "thread-id"); + g_assert(qdict_haskey(props, "core-id")); + core = qdict_get_int(props, "core-id"); - + - if (thread == 0) { + if (core == 0) { g_assert_cmpint(node, ==, 1); @@ -54,5 +54,6 @@ index 8de8581231..71cdd7b4f7 100644 g_assert_cmpint(node, ==, 0); } else { g_assert(false); --- -2.19.1 +-- +2.27.0 + diff --git a/test-tpm-pass-optional-machine-options-to-swtpm-test.patch b/test-tpm-pass-optional-machine-options-to-swtpm-test.patch deleted file mode 100644 index fe7fd4ac907813d676cdf0c2a713e31279c29685..0000000000000000000000000000000000000000 --- a/test-tpm-pass-optional-machine-options-to-swtpm-test.patch +++ /dev/null @@ -1,187 +0,0 @@ -From c06a3ceacc1793bc1cfe5c2a6ed510c9aea8253d Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Thu, 13 Aug 2020 20:28:25 +0800 -Subject: [PATCH 17/19] test: tpm: pass optional machine options to swtpm test - functions - -We plan to use swtpm test functions on ARM for testing the -sysbus TPM-TIS device. However on ARM there is no default machine -type. So we need to explictly pass some machine options on startup. -Let's allow this by adding a new parameter to both swtpm test -functions and update all call sites. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Message-id: 20200305165149.618-9-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - tests/tpm-crb-swtpm-test.c | 5 +++-- - tests/tpm-tests.c | 10 ++++++---- - tests/tpm-tests.h | 5 +++-- - tests/tpm-tis-swtpm-test.c | 5 +++-- - tests/tpm-util.c | 8 ++++++-- - tests/tpm-util.h | 3 ++- - 6 files changed, 23 insertions(+), 13 deletions(-) - -diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c -index 2c4fb8ae..5228cb7a 100644 ---- a/tests/tpm-crb-swtpm-test.c -+++ b/tests/tpm-crb-swtpm-test.c -@@ -29,7 +29,8 @@ static void tpm_crb_swtpm_test(const void *data) - { - const TestState *ts = data; - -- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb"); -+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, -+ "tpm-crb", NULL); - } - - static void tpm_crb_swtpm_migration_test(const void *data) -@@ -37,7 +38,7 @@ static void tpm_crb_swtpm_migration_test(const void *data) - const TestState *ts = data; - - tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, -- tpm_util_crb_transfer, "tpm-crb"); -+ tpm_util_crb_transfer, "tpm-crb", NULL); - } - - int main(int argc, char **argv) -diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c -index e640777a..d823bda8 100644 ---- a/tests/tpm-tests.c -+++ b/tests/tpm-tests.c -@@ -30,7 +30,7 @@ tpm_test_swtpm_skip(void) - } - - void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, -- const char *ifmodel) -+ const char *ifmodel, const char *machine_options) - { - char *args = NULL; - QTestState *s; -@@ -47,10 +47,11 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, - g_assert_true(succ); - - args = g_strdup_printf( -+ "%s " - "-chardev socket,id=chr,path=%s " - "-tpmdev emulator,id=dev,chardev=chr " - "-device %s,tpmdev=dev", -- addr->u.q_unix.path, ifmodel); -+ machine_options ? : "", addr->u.q_unix.path, ifmodel); - - s = qtest_start(args); - g_free(args); -@@ -78,7 +79,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, - void tpm_test_swtpm_migration_test(const char *src_tpm_path, - const char *dst_tpm_path, - const char *uri, tx_func *tx, -- const char *ifmodel) -+ const char *ifmodel, -+ const char *machine_options) - { - gboolean succ; - GPid src_tpm_pid, dst_tpm_pid; -@@ -100,7 +102,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path, - - tpm_util_migration_start_qemu(&src_qemu, &dst_qemu, - src_tpm_addr, dst_tpm_addr, uri, -- ifmodel); -+ ifmodel, machine_options); - - tpm_util_startup(src_qemu, tx); - tpm_util_pcrextend(src_qemu, tx); -diff --git a/tests/tpm-tests.h b/tests/tpm-tests.h -index b97688fe..a5df35ab 100644 ---- a/tests/tpm-tests.h -+++ b/tests/tpm-tests.h -@@ -16,11 +16,12 @@ - #include "tpm-util.h" - - void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, -- const char *ifmodel); -+ const char *ifmodel, const char *machine_options); - - void tpm_test_swtpm_migration_test(const char *src_tpm_path, - const char *dst_tpm_path, - const char *uri, tx_func *tx, -- const char *ifmodel); -+ const char *ifmodel, -+ const char *machine_options); - - #endif /* TESTS_TPM_TESTS_H */ -diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c -index 9f58a3a9..9470f157 100644 ---- a/tests/tpm-tis-swtpm-test.c -+++ b/tests/tpm-tis-swtpm-test.c -@@ -29,7 +29,8 @@ static void tpm_tis_swtpm_test(const void *data) - { - const TestState *ts = data; - -- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis"); -+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, -+ "tpm-tis", NULL); - } - - static void tpm_tis_swtpm_migration_test(const void *data) -@@ -37,7 +38,7 @@ static void tpm_tis_swtpm_migration_test(const void *data) - const TestState *ts = data; - - tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, -- tpm_util_tis_transfer, "tpm-tis"); -+ tpm_util_tis_transfer, "tpm-tis", NULL); - } - - int main(int argc, char **argv) -diff --git a/tests/tpm-util.c b/tests/tpm-util.c -index e08b1376..7ecdae2f 100644 ---- a/tests/tpm-util.c -+++ b/tests/tpm-util.c -@@ -258,23 +258,27 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, - SocketAddress *src_tpm_addr, - SocketAddress *dst_tpm_addr, - const char *miguri, -- const char *ifmodel) -+ const char *ifmodel, -+ const char *machine_options) - { - char *src_qemu_args, *dst_qemu_args; - - src_qemu_args = g_strdup_printf( -+ "%s " - "-chardev socket,id=chr,path=%s " - "-tpmdev emulator,id=dev,chardev=chr " - "-device %s,tpmdev=dev ", -- src_tpm_addr->u.q_unix.path, ifmodel); -+ machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel); - - *src_qemu = qtest_init(src_qemu_args); - - dst_qemu_args = g_strdup_printf( -+ "%s " - "-chardev socket,id=chr,path=%s " - "-tpmdev emulator,id=dev,chardev=chr " - "-device %s,tpmdev=dev " - "-incoming %s", -+ machine_options ? : "", - dst_tpm_addr->u.q_unix.path, - ifmodel, miguri); - -diff --git a/tests/tpm-util.h b/tests/tpm-util.h -index 5755698a..15e39249 100644 ---- a/tests/tpm-util.h -+++ b/tests/tpm-util.h -@@ -44,7 +44,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, - SocketAddress *src_tpm_addr, - SocketAddress *dst_tpm_addr, - const char *miguri, -- const char *ifmodel); -+ const char *ifmodel, -+ const char *machine_options); - - void tpm_util_wait_for_migration_complete(QTestState *who); - --- -2.23.0 - diff --git a/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch deleted file mode 100644 index fe33c8f4bd99eba304dc696d70a5126c559cd052..0000000000000000000000000000000000000000 --- a/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 2d28c0edddeaee5e4aa6e8c6b109776cddc1c4e4 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Thu, 13 Aug 2020 21:37:23 +0800 -Subject: [PATCH 19/19] test: tpm-tis: Add Sysbus TPM-TIS device test - -The tests themselves are the same as the ISA device ones. -Only the main() changes as the tpm-tis-device device gets -instantiated. Also the base address of the device is not -0xFED40000 anymore but matches the base address of the -ARM virt platform bus. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Message-id: 20200305165149.618-11-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - tests/Makefile.include | 5 ++ - tests/tpm-tis-device-swtpm-test.c | 76 +++++++++++++++++++++++++++ - tests/tpm-tis-device-test.c | 87 +++++++++++++++++++++++++++++++ - 3 files changed, 168 insertions(+) - create mode 100644 tests/tpm-tis-device-swtpm-test.c - create mode 100644 tests/tpm-tis-device-test.c - -diff --git a/tests/Makefile.include b/tests/Makefile.include -index 950b32a2..d6de4e10 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -263,6 +263,8 @@ check-qtest-arm-y += tests/boot-serial-test$(EXESUF) - check-qtest-arm-y += tests/hexloader-test$(EXESUF) - check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF) - -+check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-test -+check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-swtpm-test - check-qtest-aarch64-y = tests/numa-test$(EXESUF) - check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) - check-qtest-aarch64-y += tests/migration-test$(EXESUF) -@@ -667,7 +669,10 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ - tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) - tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ - tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) -+tests/tpm-tis-device-swtpm-test$(EXESUF): tests/tpm-tis-device-swtpm-test.o tests/tpm-emu.o \ -+ tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) - tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) -+tests/tpm-tis-device-test$(EXESUF): tests/tpm-tis-device-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) - tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ - tests/io-channel-helpers.o $(test-io-obj-y) - tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ -diff --git a/tests/tpm-tis-device-swtpm-test.c b/tests/tpm-tis-device-swtpm-test.c -new file mode 100644 -index 00000000..7b200351 ---- /dev/null -+++ b/tests/tpm-tis-device-swtpm-test.c -@@ -0,0 +1,76 @@ -+/* -+ * QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm -+ * migration -+ * -+ * Copyright (c) 2018 IBM Corporation -+ * with parts borrowed from migration-test.c that is: -+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates -+ * -+ * Authors: -+ * Stefan Berger -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include "libqtest.h" -+#include "qemu/module.h" -+#include "tpm-tests.h" -+#include "hw/acpi/tpm.h" -+ -+uint64_t tpm_tis_base_addr = 0xc000000; -+#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg" -+ -+typedef struct TestState { -+ char *src_tpm_path; -+ char *dst_tpm_path; -+ char *uri; -+} TestState; -+ -+static void tpm_tis_swtpm_test(const void *data) -+{ -+ const TestState *ts = data; -+ -+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, -+ "tpm-tis-device", MACHINE_OPTIONS); -+} -+ -+static void tpm_tis_swtpm_migration_test(const void *data) -+{ -+ const TestState *ts = data; -+ -+ tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, -+ tpm_util_tis_transfer, "tpm-tis-device", -+ MACHINE_OPTIONS); -+} -+ -+int main(int argc, char **argv) -+{ -+ int ret; -+ TestState ts = { 0 }; -+ -+ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", -+ NULL); -+ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", -+ NULL); -+ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path); -+ -+ module_call_init(MODULE_INIT_QOM); -+ g_test_init(&argc, &argv, NULL); -+ -+ qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test); -+ qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts, -+ tpm_tis_swtpm_migration_test); -+ ret = g_test_run(); -+ -+ g_rmdir(ts.dst_tpm_path); -+ g_free(ts.dst_tpm_path); -+ g_rmdir(ts.src_tpm_path); -+ g_free(ts.src_tpm_path); -+ g_free(ts.uri); -+ -+ return ret; -+} -diff --git a/tests/tpm-tis-device-test.c b/tests/tpm-tis-device-test.c -new file mode 100644 -index 00000000..63ed3644 ---- /dev/null -+++ b/tests/tpm-tis-device-test.c -@@ -0,0 +1,87 @@ -+/* -+ * QTest testcase for SYSBUS TPM TIS -+ * -+ * Copyright (c) 2018 Red Hat, Inc. -+ * Copyright (c) 2018 IBM Corporation -+ * -+ * Authors: -+ * Marc-André Lureau -+ * Stefan Berger -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include "io/channel-socket.h" -+#include "libqtest-single.h" -+#include "qemu/module.h" -+#include "tpm-emu.h" -+#include "tpm-util.h" -+#include "tpm-tis-util.h" -+ -+/* -+ * As the Sysbus tpm-tis-device is instantiated on the ARM virt -+ * platform bus and it is the only sysbus device dynamically -+ * instantiated, it gets plugged at its base address -+ */ -+uint64_t tpm_tis_base_addr = 0xc000000; -+ -+int main(int argc, char **argv) -+{ -+ char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL); -+ GThread *thread; -+ TestState test; -+ char *args; -+ int ret; -+ -+ module_call_init(MODULE_INIT_QOM); -+ g_test_init(&argc, &argv, NULL); -+ -+ test.addr = g_new0(SocketAddress, 1); -+ test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; -+ test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); -+ g_mutex_init(&test.data_mutex); -+ g_cond_init(&test.data_cond); -+ test.data_cond_signal = false; -+ -+ thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); -+ tpm_emu_test_wait_cond(&test); -+ -+ args = g_strdup_printf( -+ "-machine virt,gic-version=max -accel tcg " -+ "-chardev socket,id=chr,path=%s " -+ "-tpmdev emulator,id=dev,chardev=chr " -+ "-device tpm-tis-device,tpmdev=dev", -+ test.addr->u.q_unix.path); -+ qtest_start(args); -+ -+ qtest_add_data_func("/tpm-tis/test_check_localities", &test, -+ tpm_tis_test_check_localities); -+ -+ qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, -+ tpm_tis_test_check_access_reg); -+ -+ qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, -+ tpm_tis_test_check_access_reg_seize); -+ -+ qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, -+ tpm_tis_test_check_access_reg_release); -+ -+ qtest_add_data_func("/tpm-tis/test_check_transmit", &test, -+ tpm_tis_test_check_transmit); -+ -+ ret = g_test_run(); -+ -+ qtest_end(); -+ -+ g_thread_join(thread); -+ g_unlink(test.addr->u.q_unix.path); -+ qapi_free_SocketAddress(test.addr); -+ g_rmdir(tmp_path); -+ g_free(tmp_path); -+ g_free(args); -+ return ret; -+} --- -2.23.0 - diff --git a/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch b/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch deleted file mode 100644 index 4c7be00a5f1d015d5da4fcf4791e6a175f0ff9c7..0000000000000000000000000000000000000000 --- a/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch +++ /dev/null @@ -1,1044 +0,0 @@ -From c8ed2a1fbe306ecbfb5c7d4156ae81c029829d95 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Thu, 13 Aug 2020 20:56:54 +0800 -Subject: [PATCH 18/19] test: tpm-tis: Get prepared to share tests between ISA - and sysbus devices - -ISA and sysbus TPM-TIS devices will share their tests. Only -the main() will change (instantiation option is different). -Also the base address of the TPM-TIS device is going to be -different. on x86 it is located at 0xFED40000 while on ARM -it can be located at any location, discovered through the -device tree description. - -So we put shared test functions in a new object module. -Each test needs to set tpm_tis_base_addr global variable. - -Also take benefit of this move to fix "block comments using -a leading */ on a separate line" checkpatch warnings. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Message-id: 20200305165149.618-10-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - tests/Makefile.include | 2 +- - tests/tpm-crb-swtpm-test.c | 4 + - tests/tpm-crb-test.c | 3 + - tests/tpm-tis-swtpm-test.c | 3 + - tests/tpm-tis-test.c | 414 +--------------------------------- - tests/tpm-tis-util.c | 451 +++++++++++++++++++++++++++++++++++++ - tests/tpm-tis-util.h | 23 ++ - tests/tpm-util.c | 3 - - tests/tpm-util.h | 5 + - 9 files changed, 493 insertions(+), 415 deletions(-) - create mode 100644 tests/tpm-tis-util.c - create mode 100644 tests/tpm-tis-util.h - -diff --git a/tests/Makefile.include b/tests/Makefile.include -index c151de64..950b32a2 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -667,7 +667,7 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ - tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) - tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ - tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) --tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y) -+tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) - tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ - tests/io-channel-helpers.o $(test-io-obj-y) - tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ -diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c -index 5228cb7a..55fdb565 100644 ---- a/tests/tpm-crb-swtpm-test.c -+++ b/tests/tpm-crb-swtpm-test.c -@@ -18,6 +18,10 @@ - #include "libqtest.h" - #include "qemu/module.h" - #include "tpm-tests.h" -+#include "hw/acpi/tpm.h" -+ -+/* Not used but needed for linking */ -+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; - - typedef struct TestState { - char *src_tpm_path; -diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c -index a139caa5..32695810 100644 ---- a/tests/tpm-crb-test.c -+++ b/tests/tpm-crb-test.c -@@ -19,6 +19,9 @@ - #include "qemu/module.h" - #include "tpm-emu.h" - -+/* Not used but needed for linking */ -+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; -+ - #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" - - static void tpm_crb_test(const void *data) -diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c -index 9470f157..90131cb3 100644 ---- a/tests/tpm-tis-swtpm-test.c -+++ b/tests/tpm-tis-swtpm-test.c -@@ -18,6 +18,9 @@ - #include "libqtest.h" - #include "qemu/module.h" - #include "tpm-tests.h" -+#include "hw/acpi/tpm.h" -+ -+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; - - typedef struct TestState { - char *src_tpm_path; -diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c -index 92a7e95a..8042de13 100644 ---- a/tests/tpm-tis-test.c -+++ b/tests/tpm-tis-test.c -@@ -1,5 +1,5 @@ - /* -- * QTest testcase for TPM TIS -+ * QTest testcase for ISA TPM TIS - * - * Copyright (c) 2018 Red Hat, Inc. - * Copyright (c) 2018 IBM Corporation -@@ -20,417 +20,9 @@ - #include "libqtest.h" - #include "qemu/module.h" - #include "tpm-emu.h" -+#include "tpm-tis-util.h" - --#define TIS_REG(LOCTY, REG) \ -- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) -- --#define DEBUG_TIS_TEST 0 -- --#define DPRINTF(fmt, ...) do { \ -- if (DEBUG_TIS_TEST) { \ -- printf(fmt, ## __VA_ARGS__); \ -- } \ --} while (0) -- --#define DPRINTF_ACCESS \ -- DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ -- __func__, __LINE__, locty, l, access, pending_request_flag) -- --#define DPRINTF_STS \ -- DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) -- --static const uint8_t TPM_CMD[12] = -- "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; -- --static void tpm_tis_test_check_localities(const void *data) --{ -- uint8_t locty; -- uint8_t access; -- uint32_t ifaceid; -- uint32_t capability; -- uint32_t didvid; -- uint32_t rid; -- -- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { -- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); -- g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); -- -- ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); -- g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); -- -- didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); -- g_assert_cmpint(didvid, !=, 0); -- g_assert_cmpint(didvid, !=, 0xffffffff); -- -- rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); -- g_assert_cmpint(rid, !=, 0); -- g_assert_cmpint(rid, !=, 0xffffffff); -- } --} -- --static void tpm_tis_test_check_access_reg(const void *data) --{ -- uint8_t locty; -- uint8_t access; -- -- /* do not test locality 4 (hw only) */ -- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* request use of locality */ -- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* release access */ -- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- } --} -- --/* -- * Test case for seizing access by a higher number locality -- */ --static void tpm_tis_test_check_access_reg_seize(const void *data) --{ -- int locty, l; -- uint8_t access; -- uint8_t pending_request_flag; -- -- /* do not test locality 4 (hw only) */ -- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { -- pending_request_flag = 0; -- -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* request use of locality */ -- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* lower localities cannot seize access */ -- for (l = 0; l < locty; l++) { -- /* lower locality is not active */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* try to request use from 'l' */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- -- /* requesting use from 'l' was not possible; -- we must see REQUEST_USE and possibly PENDING_REQUEST */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_REQUEST_USE | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* locality 'locty' must be unchanged; -- we must see PENDING_REQUEST */ -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_PENDING_REQUEST | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* try to seize from 'l' */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); -- /* seize from 'l' was not possible */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_REQUEST_USE | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* locality 'locty' must be unchanged */ -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_PENDING_REQUEST | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* on the next loop we will have a PENDING_REQUEST flag -- set for locality 'l' */ -- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; -- } -- -- /* higher localities can 'seize' access but not 'request use'; -- note: this will activate first l+1, then l+2 etc. */ -- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -- /* try to 'request use' from 'l' */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- -- /* requesting use from 'l' was not possible; we should see -- REQUEST_USE and may see PENDING_REQUEST */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_REQUEST_USE | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* locality 'l-1' must be unchanged; we should always -- see PENDING_REQUEST from 'l' requesting access */ -- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_PENDING_REQUEST | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* try to seize from 'l' */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); -- -- /* seize from 'l' was possible */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* l - 1 should show that it has BEEN_SEIZED */ -- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_BEEN_SEIZED | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* clear the BEEN_SEIZED flag and make sure it's gone */ -- writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_BEEN_SEIZED); -- -- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- } -- -- /* PENDING_REQUEST will not be set if locty = 0 since all localities -- were active; in case of locty = 1, locality 0 will be active -- but no PENDING_REQUEST anywhere */ -- if (locty <= 1) { -- pending_request_flag = 0; -- } -- -- /* release access from l - 1; this activates locty - 1 */ -- l--; -- -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- -- DPRINTF("%s: %d: relinquishing control on l = %d\n", -- __func__, __LINE__, l); -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- for (l = locty - 1; l >= 0; l--) { -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* release this locality */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- -- if (l == 1) { -- pending_request_flag = 0; -- } -- } -- -- /* no locality may be active now */ -- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- } -- } --} -- --/* -- * Test case for getting access when higher number locality relinquishes access -- */ --static void tpm_tis_test_check_access_reg_release(const void *data) --{ -- int locty, l; -- uint8_t access; -- uint8_t pending_request_flag; -- -- /* do not test locality 4 (hw only) */ -- for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { -- pending_request_flag = 0; -- -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* request use of locality */ -- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- /* request use of all other localities */ -- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -- if (l == locty) { -- continue; -- } -- /* request use of locality 'l' -- we MUST see REQUEST USE and -- may see PENDING_REQUEST */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_REQUEST_USE | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; -- } -- /* release locality 'locty' */ -- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- /* highest locality should now be active; release it and make sure the -- next higest locality is active afterwards */ -- for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { -- if (l == locty) { -- continue; -- } -- /* 'l' should be active now */ -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- /* 'l' relinquishes access */ -- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -- TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -- DPRINTF_ACCESS; -- if (l == 1 || (locty <= 1 && l == 2)) { -- pending_request_flag = 0; -- } -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- pending_request_flag | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- } -- } --} -- --/* -- * Test case for transmitting packets -- */ --static void tpm_tis_test_check_transmit(const void *data) --{ -- const TestState *s = data; -- uint8_t access; -- uint32_t sts; -- uint16_t bcount; -- size_t i; -- -- /* request use of locality 0 */ -- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); -- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -- TPM_TIS_ACCESS_ACTIVE_LOCALITY | -- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -- -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- DPRINTF_STS; -- -- g_assert_cmpint(sts & 0xff, ==, 0); -- g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, -- TPM_TIS_STS_TPM_FAMILY2_0); -- -- bcount = (sts >> 8) & 0xffff; -- g_assert_cmpint(bcount, >=, 128); -- -- writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- DPRINTF_STS; -- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); -- -- /* transmit command */ -- for (i = 0; i < sizeof(TPM_CMD); i++) { -- writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- DPRINTF_STS; -- if (i < sizeof(TPM_CMD) - 1) { -- g_assert_cmpint(sts & 0xff, ==, -- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); -- } else { -- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); -- } -- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); -- } -- /* start processing */ -- writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); -- -- uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; -- do { -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { -- break; -- } -- } while (g_get_monotonic_time() < end_time); -- -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- DPRINTF_STS; -- g_assert_cmpint(sts & 0xff, == , -- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); -- bcount = (sts >> 8) & 0xffff; -- -- /* read response */ -- uint8_t tpm_msg[sizeof(struct tpm_hdr)]; -- g_assert_cmpint(sizeof(tpm_msg), ==, bcount); -- -- for (i = 0; i < sizeof(tpm_msg); i++) { -- tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); -- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -- DPRINTF_STS; -- if (sts & TPM_TIS_STS_DATA_AVAILABLE) { -- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); -- } -- } -- g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); -- -- /* relinquish use of locality 0 */ -- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); -- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); --} -+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; - - int main(int argc, char **argv) - { -diff --git a/tests/tpm-tis-util.c b/tests/tpm-tis-util.c -new file mode 100644 -index 00000000..9aff503f ---- /dev/null -+++ b/tests/tpm-tis-util.c -@@ -0,0 +1,451 @@ -+/* -+ * QTest testcase for TPM TIS: common test functions used for both -+ * the ISA and SYSBUS devices -+ * -+ * Copyright (c) 2018 Red Hat, Inc. -+ * Copyright (c) 2018 IBM Corporation -+ * -+ * Authors: -+ * Marc-André Lureau -+ * Stefan Berger -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include "hw/acpi/tpm.h" -+#include "io/channel-socket.h" -+#include "libqtest.h" -+#include "qemu/module.h" -+#include "tpm-emu.h" -+#include "tpm-util.h" -+#include "tpm-tis-util.h" -+ -+#define DEBUG_TIS_TEST 0 -+ -+#define DPRINTF(fmt, ...) do { \ -+ if (DEBUG_TIS_TEST) { \ -+ printf(fmt, ## __VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define DPRINTF_ACCESS \ -+ DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ -+ __func__, __LINE__, locty, l, access, pending_request_flag) -+ -+#define DPRINTF_STS \ -+ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) -+ -+static const uint8_t TPM_CMD[12] = -+ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; -+ -+void tpm_tis_test_check_localities(const void *data) -+{ -+ uint8_t locty; -+ uint8_t access; -+ uint32_t ifaceid; -+ uint32_t capability; -+ uint32_t didvid; -+ uint32_t rid; -+ -+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { -+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); -+ g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); -+ -+ ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); -+ g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); -+ -+ didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); -+ g_assert_cmpint(didvid, !=, 0); -+ g_assert_cmpint(didvid, !=, 0xffffffff); -+ -+ rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); -+ g_assert_cmpint(rid, !=, 0); -+ g_assert_cmpint(rid, !=, 0xffffffff); -+ } -+} -+ -+void tpm_tis_test_check_access_reg(const void *data) -+{ -+ uint8_t locty; -+ uint8_t access; -+ -+ /* do not test locality 4 (hw only) */ -+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* request use of locality */ -+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* release access */ -+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ } -+} -+ -+/* -+ * Test case for seizing access by a higher number locality -+ */ -+void tpm_tis_test_check_access_reg_seize(const void *data) -+{ -+ int locty, l; -+ uint8_t access; -+ uint8_t pending_request_flag; -+ -+ /* do not test locality 4 (hw only) */ -+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { -+ pending_request_flag = 0; -+ -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* request use of locality */ -+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* lower localities cannot seize access */ -+ for (l = 0; l < locty; l++) { -+ /* lower locality is not active */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* try to request use from 'l' */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ -+ /* -+ * requesting use from 'l' was not possible; -+ * we must see REQUEST_USE and possibly PENDING_REQUEST -+ */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_REQUEST_USE | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* -+ * locality 'locty' must be unchanged; -+ * we must see PENDING_REQUEST -+ */ -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_PENDING_REQUEST | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* try to seize from 'l' */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); -+ /* seize from 'l' was not possible */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_REQUEST_USE | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* locality 'locty' must be unchanged */ -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_PENDING_REQUEST | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* -+ * on the next loop we will have a PENDING_REQUEST flag -+ * set for locality 'l' -+ */ -+ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; -+ } -+ -+ /* -+ * higher localities can 'seize' access but not 'request use'; -+ * note: this will activate first l+1, then l+2 etc. -+ */ -+ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -+ /* try to 'request use' from 'l' */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ -+ /* -+ * requesting use from 'l' was not possible; we should see -+ * REQUEST_USE and may see PENDING_REQUEST -+ */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_REQUEST_USE | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* -+ * locality 'l-1' must be unchanged; we should always -+ * see PENDING_REQUEST from 'l' requesting access -+ */ -+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_PENDING_REQUEST | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* try to seize from 'l' */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); -+ -+ /* seize from 'l' was possible */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* l - 1 should show that it has BEEN_SEIZED */ -+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_BEEN_SEIZED | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* clear the BEEN_SEIZED flag and make sure it's gone */ -+ writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_BEEN_SEIZED); -+ -+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ } -+ -+ /* -+ * PENDING_REQUEST will not be set if locty = 0 since all localities -+ * were active; in case of locty = 1, locality 0 will be active -+ * but no PENDING_REQUEST anywhere -+ */ -+ if (locty <= 1) { -+ pending_request_flag = 0; -+ } -+ -+ /* release access from l - 1; this activates locty - 1 */ -+ l--; -+ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ -+ DPRINTF("%s: %d: relinquishing control on l = %d\n", -+ __func__, __LINE__, l); -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ for (l = locty - 1; l >= 0; l--) { -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* release this locality */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ -+ if (l == 1) { -+ pending_request_flag = 0; -+ } -+ } -+ -+ /* no locality may be active now */ -+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ } -+ } -+} -+ -+/* -+ * Test case for getting access when higher number locality relinquishes access -+ */ -+void tpm_tis_test_check_access_reg_release(const void *data) -+{ -+ int locty, l; -+ uint8_t access; -+ uint8_t pending_request_flag; -+ -+ /* do not test locality 4 (hw only) */ -+ for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { -+ pending_request_flag = 0; -+ -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* request use of locality */ -+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ /* request use of all other localities */ -+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { -+ if (l == locty) { -+ continue; -+ } -+ /* -+ * request use of locality 'l' -- we MUST see REQUEST USE and -+ * may see PENDING_REQUEST -+ */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_REQUEST_USE | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; -+ } -+ /* release locality 'locty' */ -+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ /* -+ * highest locality should now be active; release it and make sure the -+ * next higest locality is active afterwards -+ */ -+ for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { -+ if (l == locty) { -+ continue; -+ } -+ /* 'l' should be active now */ -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ /* 'l' relinquishes access */ -+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); -+ DPRINTF_ACCESS; -+ if (l == 1 || (locty <= 1 && l == 2)) { -+ pending_request_flag = 0; -+ } -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ pending_request_flag | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ } -+ } -+} -+ -+/* -+ * Test case for transmitting packets -+ */ -+void tpm_tis_test_check_transmit(const void *data) -+{ -+ const TestState *s = data; -+ uint8_t access; -+ uint32_t sts; -+ uint16_t bcount; -+ size_t i; -+ -+ /* request use of locality 0 */ -+ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); -+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); -+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY | -+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); -+ -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ DPRINTF_STS; -+ -+ g_assert_cmpint(sts & 0xff, ==, 0); -+ g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, -+ TPM_TIS_STS_TPM_FAMILY2_0); -+ -+ bcount = (sts >> 8) & 0xffff; -+ g_assert_cmpint(bcount, >=, 128); -+ -+ writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ DPRINTF_STS; -+ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); -+ -+ /* transmit command */ -+ for (i = 0; i < sizeof(TPM_CMD); i++) { -+ writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ DPRINTF_STS; -+ if (i < sizeof(TPM_CMD) - 1) { -+ g_assert_cmpint(sts & 0xff, ==, -+ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); -+ } else { -+ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); -+ } -+ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); -+ } -+ /* start processing */ -+ writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); -+ -+ uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; -+ do { -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { -+ break; -+ } -+ } while (g_get_monotonic_time() < end_time); -+ -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ DPRINTF_STS; -+ g_assert_cmpint(sts & 0xff, == , -+ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); -+ bcount = (sts >> 8) & 0xffff; -+ -+ /* read response */ -+ uint8_t tpm_msg[sizeof(struct tpm_hdr)]; -+ g_assert_cmpint(sizeof(tpm_msg), ==, bcount); -+ -+ for (i = 0; i < sizeof(tpm_msg); i++) { -+ tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); -+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); -+ DPRINTF_STS; -+ if (sts & TPM_TIS_STS_DATA_AVAILABLE) { -+ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); -+ } -+ } -+ g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); -+ -+ /* relinquish use of locality 0 */ -+ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); -+} -diff --git a/tests/tpm-tis-util.h b/tests/tpm-tis-util.h -new file mode 100644 -index 00000000..d10efe86 ---- /dev/null -+++ b/tests/tpm-tis-util.h -@@ -0,0 +1,23 @@ -+/* -+ * QTest TPM TIS: Common test functions used for both the -+ * ISA and SYSBUS devices -+ * -+ * Copyright (c) 2018 IBM Corporation -+ * -+ * Authors: -+ * Stefan Berger -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef TESTS_TPM_TIS_UTIL_H -+#define TESTS_TPM_TIS_UTIL_H -+ -+void tpm_tis_test_check_localities(const void *data); -+void tpm_tis_test_check_access_reg(const void *data); -+void tpm_tis_test_check_access_reg_seize(const void *data); -+void tpm_tis_test_check_access_reg_release(const void *data); -+void tpm_tis_test_check_transmit(const void *data); -+ -+#endif /* TESTS_TPM_TIS_UTIL_H */ -diff --git a/tests/tpm-util.c b/tests/tpm-util.c -index 7ecdae2f..34efae8f 100644 ---- a/tests/tpm-util.c -+++ b/tests/tpm-util.c -@@ -19,9 +19,6 @@ - #include "tpm-util.h" - #include "qapi/qmp/qdict.h" - --#define TIS_REG(LOCTY, REG) \ -- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) -- - void tpm_util_crb_transfer(QTestState *s, - const unsigned char *req, size_t req_size, - unsigned char *rsp, size_t rsp_size) -diff --git a/tests/tpm-util.h b/tests/tpm-util.h -index 15e39249..3b97d690 100644 ---- a/tests/tpm-util.h -+++ b/tests/tpm-util.h -@@ -15,6 +15,11 @@ - - #include "io/channel-socket.h" - -+extern uint64_t tpm_tis_base_addr; -+ -+#define TIS_REG(LOCTY, REG) \ -+ (tpm_tis_base_addr + ((LOCTY) << 12) + REG) -+ - typedef void (tx_func)(QTestState *s, - const unsigned char *req, size_t req_size, - unsigned char *rsp, size_t rsp_size); --- -2.23.0 - diff --git a/test-vmstate-fix-bad-GTree-usage-use-after-free.patch b/test-vmstate-fix-bad-GTree-usage-use-after-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..be6af283e43e28edec335125be05a013f8ed771c --- /dev/null +++ b/test-vmstate-fix-bad-GTree-usage-use-after-free.patch @@ -0,0 +1,64 @@ +From 974fcc3a97148b1af3bebfaa6a72645837233489 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Tue, 28 Feb 2023 10:29:44 +0100 +Subject: [PATCH] test-vmstate: fix bad GTree usage, use-after-free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to g_tree_foreach() documentation: +"The tree may not be modified while iterating over it (you can't +add/remove items)." + +compare_trees()/diff_tree() fail to respect this rule. +Historically GLib2 used a slice allocator for the GTree APIs +which did not immediately release the memory back to the system +allocator. As a result QEMU's use-after-free bug was not visible. +With GLib > 2.75.3 however, GLib2 has switched to using malloc +and now a SIGSEGV can be observed while running test-vmstate. + +Get rid of the node removal within the tree traversal. Also +check the trees have the same number of nodes before the actual +diff. + +Fixes: 9a85e4b8f6 ("migration: Support gtree migration") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1518 +Signed-off-by: Marc-André Lureau +Signed-off-by: Eric Auger +Reported-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +Reviewed-by: Richard W.M. Jones +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + tests/unit/test-vmstate.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c +index 4688c03ea7..ac47f0a44b 100644 +--- a/tests/unit/test-vmstate.c ++++ b/tests/unit/test-vmstate.c +@@ -1076,7 +1076,6 @@ static gboolean diff_tree(gpointer key, gpointer value, gpointer data) + struct match_node_data d = {tp->tree2, key, value}; + + g_tree_foreach(tp->tree2, tp->match_node, &d); +- g_tree_remove(tp->tree1, key); + return false; + } + +@@ -1085,9 +1084,9 @@ static void compare_trees(GTree *tree1, GTree *tree2, + { + struct tree_cmp_data tp = {tree1, tree2, function}; + ++ assert(g_tree_nnodes(tree1) == g_tree_nnodes(tree2)); + g_tree_foreach(tree1, diff_tree, &tp); +- assert(g_tree_nnodes(tree1) == 0); +- assert(g_tree_nnodes(tree2) == 0); ++ g_tree_destroy(g_tree_ref(tree1)); + } + + static void diff_domain(TestGTreeDomain *d1, TestGTreeDomain *d2) +-- +2.41.0.windows.1 + diff --git a/tests-Add-bios-tests-to-arm-virt.patch b/tests-Add-bios-tests-to-arm-virt.patch deleted file mode 100644 index 025afb506017f9bc1c6fdb26df35c9534a8f3672..0000000000000000000000000000000000000000 --- a/tests-Add-bios-tests-to-arm-virt.patch +++ /dev/null @@ -1,86 +0,0 @@ -From abbcc35ccb22d81d69a28dc66b5f5d94e673a25e Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:33 +0100 -Subject: [PATCH] tests: Add bios tests to arm/virt - -This adds numamem and memhp tests for arm/virt platform. - -Signed-off-by: Shameer Kolothum -Reviewed-by: Igor Mammedov -Message-Id: <20190918130633.4872-12-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - tests/bios-tables-test.c | 49 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 49 insertions(+) - -diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c -index 53a91a8067..5e177b7155 100644 ---- a/tests/bios-tables-test.c -+++ b/tests/bios-tables-test.c -@@ -874,6 +874,53 @@ static void test_acpi_piix4_tcg_dimm_pxm(void) - test_acpi_tcg_dimm_pxm(MACHINE_PC); - } - -+static void test_acpi_virt_tcg_memhp(void) -+{ -+ test_data data = { -+ .machine = "virt", -+ .accel = "tcg", -+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", -+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", -+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", -+ .ram_start = 0x40000000ULL, -+ .scan_len = 256ULL * 1024 * 1024, -+ }; -+ -+ data.variant = ".memhp"; -+ test_acpi_one(" -cpu cortex-a57" -+ " -m 256M,slots=3,maxmem=1G" -+ " -object memory-backend-ram,id=ram0,size=128M" -+ " -object memory-backend-ram,id=ram1,size=128M" -+ " -numa node,memdev=ram0 -numa node,memdev=ram1" -+ " -numa dist,src=0,dst=1,val=21", -+ &data); -+ -+ free_test_data(&data); -+ -+} -+ -+static void test_acpi_virt_tcg_numamem(void) -+{ -+ test_data data = { -+ .machine = "virt", -+ .accel = "tcg", -+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", -+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", -+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", -+ .ram_start = 0x40000000ULL, -+ .scan_len = 128ULL * 1024 * 1024, -+ }; -+ -+ data.variant = ".numamem"; -+ test_acpi_one(" -cpu cortex-a57" -+ " -object memory-backend-ram,id=ram0,size=128M" -+ " -numa node,memdev=ram0", -+ &data); -+ -+ free_test_data(&data); -+ -+} -+ - static void test_acpi_virt_tcg(void) - { - test_data data = { -@@ -920,6 +967,8 @@ int main(int argc, char *argv[]) - qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); - } else if (strcmp(arch, "aarch64") == 0) { - qtest_add_func("acpi/virt", test_acpi_virt_tcg); -+ qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem); -+ qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp); - } - ret = g_test_run(); - boot_sector_cleanup(disk); --- -2.19.1 diff --git a/tests-Add-dirty-page-rate-limit-test.patch b/tests-Add-dirty-page-rate-limit-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..12ae236505ebbc901c088879ca65c906412d91d9 --- /dev/null +++ b/tests-Add-dirty-page-rate-limit-test.patch @@ -0,0 +1,362 @@ +From 8a0f4dcf94b280d5b7db7f604c42d088c928ac0d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 26 Jun 2022 01:38:37 +0800 +Subject: [PATCH] tests: Add dirty page rate limit test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add dirty page rate limit test if kernel support dirty ring, + +The following qmp commands are covered by this test case: +"calc-dirty-rate", "query-dirty-rate", "set-vcpu-dirty-limit", +"cancel-vcpu-dirty-limit" and "query-vcpu-dirty-limit". + +Signed-off-by: Hyman Huang(黄勇) +Acked-by: Peter Xu +Message-Id: +Signed-off-by: Dr. David Alan Gilbert +--- + tests/qtest/migration-helpers.c | 22 +++ + tests/qtest/migration-helpers.h | 2 + + tests/qtest/migration-test.c | 256 ++++++++++++++++++++++++++++++++ + 3 files changed, 280 insertions(+) + +diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c +index 4ee26014b7..1e594f9cb1 100644 +--- a/tests/qtest/migration-helpers.c ++++ b/tests/qtest/migration-helpers.c +@@ -75,6 +75,28 @@ QDict *wait_command(QTestState *who, const char *command, ...) + return ret; + } + ++/* ++ * Execute the qmp command only ++ */ ++QDict *qmp_command(QTestState *who, const char *command, ...) ++{ ++ va_list ap; ++ QDict *resp, *ret; ++ ++ va_start(ap, command); ++ resp = qtest_vqmp(who, command, ap); ++ va_end(ap); ++ ++ g_assert(!qdict_haskey(resp, "error")); ++ g_assert(qdict_haskey(resp, "return")); ++ ++ ret = qdict_get_qdict(resp, "return"); ++ qobject_ref(ret); ++ qobject_unref(resp); ++ ++ return ret; ++} ++ + /* + * Send QMP command "migrate". + * Arguments are built from @fmt... (formatted like +diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h +index d63bba9630..9bc809fb75 100644 +--- a/tests/qtest/migration-helpers.h ++++ b/tests/qtest/migration-helpers.h +@@ -22,6 +22,8 @@ QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...); + GCC_FMT_ATTR(2, 3) + QDict *wait_command(QTestState *who, const char *command, ...); + ++QDict *qmp_command(QTestState *who, const char *command, ...); ++ + GCC_FMT_ATTR(3, 4) + void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); + +diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c +index 7b42f6fd90..8fad247f6c 100644 +--- a/tests/qtest/migration-test.c ++++ b/tests/qtest/migration-test.c +@@ -23,6 +23,7 @@ + #include "qapi/qapi-visit-sockets.h" + #include "qapi/qobject-input-visitor.h" + #include "qapi/qobject-output-visitor.h" ++#include "qapi/qmp/qlist.h" + + #include "migration-helpers.h" + #include "tests/migration/migration-test.h" +@@ -42,6 +43,12 @@ static bool uffd_feature_thread_id; + /* A downtime where the test really should converge */ + #define CONVERGE_DOWNTIME 1000 + ++/* ++ * Dirtylimit stop working if dirty page rate error ++ * value less than DIRTYLIMIT_TOLERANCE_RANGE ++ */ ++#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ ++ + #if defined(__linux__) + #include + #include +@@ -1394,6 +1401,253 @@ static void test_multifd_tcp_cancel(void) + test_migrate_end(from, to2, true); + } + ++static void calc_dirty_rate(QTestState *who, uint64_t calc_time) ++{ ++ qobject_unref(qmp_command(who, ++ "{ 'execute': 'calc-dirty-rate'," ++ "'arguments': { " ++ "'calc-time': %ld," ++ "'mode': 'dirty-ring' }}", ++ calc_time)); ++} ++ ++static QDict *query_dirty_rate(QTestState *who) ++{ ++ return qmp_command(who, "{ 'execute': 'query-dirty-rate' }"); ++} ++ ++static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) ++{ ++ qobject_unref(qmp_command(who, ++ "{ 'execute': 'set-vcpu-dirty-limit'," ++ "'arguments': { " ++ "'dirty-rate': %ld } }", ++ dirtyrate)); ++} ++ ++static void cancel_vcpu_dirty_limit(QTestState *who) ++{ ++ qobject_unref(qmp_command(who, ++ "{ 'execute': 'cancel-vcpu-dirty-limit' }")); ++} ++ ++static QDict *query_vcpu_dirty_limit(QTestState *who) ++{ ++ QDict *rsp; ++ ++ rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }"); ++ g_assert(!qdict_haskey(rsp, "error")); ++ g_assert(qdict_haskey(rsp, "return")); ++ ++ return rsp; ++} ++ ++static bool calc_dirtyrate_ready(QTestState *who) ++{ ++ QDict *rsp_return; ++ gchar *status; ++ ++ rsp_return = query_dirty_rate(who); ++ g_assert(rsp_return); ++ ++ status = g_strdup(qdict_get_str(rsp_return, "status")); ++ g_assert(status); ++ ++ return g_strcmp0(status, "measuring"); ++} ++ ++static void wait_for_calc_dirtyrate_complete(QTestState *who, ++ int64_t time_s) ++{ ++ int max_try_count = 10000; ++ usleep(time_s * 1000000); ++ ++ while (!calc_dirtyrate_ready(who) && max_try_count--) { ++ usleep(1000); ++ } ++ ++ /* ++ * Set the timeout with 10 s(max_try_count * 1000us), ++ * if dirtyrate measurement not complete, fail test. ++ */ ++ g_assert_cmpint(max_try_count, !=, 0); ++} ++ ++static int64_t get_dirty_rate(QTestState *who) ++{ ++ QDict *rsp_return; ++ gchar *status; ++ QList *rates; ++ const QListEntry *entry; ++ QDict *rate; ++ int64_t dirtyrate; ++ ++ rsp_return = query_dirty_rate(who); ++ g_assert(rsp_return); ++ ++ status = g_strdup(qdict_get_str(rsp_return, "status")); ++ g_assert(status); ++ g_assert_cmpstr(status, ==, "measured"); ++ ++ rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate"); ++ g_assert(rates && !qlist_empty(rates)); ++ ++ entry = qlist_first(rates); ++ g_assert(entry); ++ ++ rate = qobject_to(QDict, qlist_entry_obj(entry)); ++ g_assert(rate); ++ ++ dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1); ++ ++ qobject_unref(rsp_return); ++ return dirtyrate; ++} ++ ++static int64_t get_limit_rate(QTestState *who) ++{ ++ QDict *rsp_return; ++ QList *rates; ++ const QListEntry *entry; ++ QDict *rate; ++ int64_t dirtyrate; ++ ++ rsp_return = query_vcpu_dirty_limit(who); ++ g_assert(rsp_return); ++ ++ rates = qdict_get_qlist(rsp_return, "return"); ++ g_assert(rates && !qlist_empty(rates)); ++ ++ entry = qlist_first(rates); ++ g_assert(entry); ++ ++ rate = qobject_to(QDict, qlist_entry_obj(entry)); ++ g_assert(rate); ++ ++ dirtyrate = qdict_get_try_int(rate, "limit-rate", -1); ++ ++ qobject_unref(rsp_return); ++ return dirtyrate; ++} ++ ++static QTestState *dirtylimit_start_vm(void) ++{ ++ QTestState *vm = NULL; ++ g_autofree gchar *cmd = NULL; ++ const char *arch = qtest_get_arch(); ++ g_autofree char *bootpath = NULL; ++ ++ assert((strcmp(arch, "x86_64") == 0)); ++ bootpath = g_strdup_printf("%s/bootsect", tmpfs); ++ assert(sizeof(x86_bootsect) == 512); ++ init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); ++ ++ cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " ++ "-name dirtylimit-test,debug-threads=on " ++ "-m 150M -smp 1 " ++ "-serial file:%s/vm_serial " ++ "-drive file=%s,format=raw ", ++ tmpfs, bootpath); ++ ++ vm = qtest_init(cmd); ++ return vm; ++} ++ ++static void dirtylimit_stop_vm(QTestState *vm) ++{ ++ qtest_quit(vm); ++ cleanup("bootsect"); ++ cleanup("vm_serial"); ++} ++ ++static void test_vcpu_dirty_limit(void) ++{ ++ QTestState *vm; ++ int64_t origin_rate; ++ int64_t quota_rate; ++ int64_t rate ; ++ int max_try_count = 20; ++ int hit = 0; ++ ++ /* Start vm for vcpu dirtylimit test */ ++ vm = dirtylimit_start_vm(); ++ ++ /* Wait for the first serial output from the vm*/ ++ wait_for_serial("vm_serial"); ++ ++ /* Do dirtyrate measurement with calc time equals 1s */ ++ calc_dirty_rate(vm, 1); ++ ++ /* Sleep calc time and wait for calc dirtyrate complete */ ++ wait_for_calc_dirtyrate_complete(vm, 1); ++ ++ /* Query original dirty page rate */ ++ origin_rate = get_dirty_rate(vm); ++ ++ /* VM booted from bootsect should dirty memory steadily */ ++ assert(origin_rate != 0); ++ ++ /* Setup quota dirty page rate at half of origin */ ++ quota_rate = origin_rate / 2; ++ ++ /* Set dirtylimit */ ++ dirtylimit_set_all(vm, quota_rate); ++ ++ /* ++ * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit ++ * works literally ++ */ ++ g_assert_cmpint(quota_rate, ==, get_limit_rate(vm)); ++ ++ /* Sleep a bit to check if it take effect */ ++ usleep(2000000); ++ ++ /* ++ * Check if dirtylimit take effect realistically, set the ++ * timeout with 20 s(max_try_count * 1s), if dirtylimit ++ * doesn't take effect, fail test. ++ */ ++ while (--max_try_count) { ++ calc_dirty_rate(vm, 1); ++ wait_for_calc_dirtyrate_complete(vm, 1); ++ rate = get_dirty_rate(vm); ++ ++ /* ++ * Assume hitting if current rate is less ++ * than quota rate (within accepting error) ++ */ ++ if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { ++ hit = 1; ++ break; ++ } ++ } ++ ++ g_assert_cmpint(hit, ==, 1); ++ ++ hit = 0; ++ max_try_count = 20; ++ ++ /* Check if dirtylimit cancellation take effect */ ++ cancel_vcpu_dirty_limit(vm); ++ while (--max_try_count) { ++ calc_dirty_rate(vm, 1); ++ wait_for_calc_dirtyrate_complete(vm, 1); ++ rate = get_dirty_rate(vm); ++ ++ /* ++ * Assume dirtylimit be canceled if current rate is ++ * greater than quota rate (within accepting error) ++ */ ++ if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { ++ hit = 1; ++ break; ++ } ++ } ++ ++ g_assert_cmpint(hit, ==, 1); ++ dirtylimit_stop_vm(vm); ++} ++ + static bool kvm_dirty_ring_supported(void) + { + #if defined(__linux__) && defined(HOST_X86_64) +@@ -1483,6 +1737,8 @@ int main(int argc, char **argv) + if (kvm_dirty_ring_supported()) { + qtest_add_func("/migration/dirty_ring", + test_precopy_unix_dirty_ring); ++ qtest_add_func("/migration/vcpu_dirty_limit", ++ test_vcpu_dirty_limit); + } + + ret = g_test_run(); +-- +2.27.0 + diff --git a/tests-Disable-filemonitor-testcase.patch b/tests-Disable-filemonitor-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d7323635b2164ad0616805fd4eb511f6c3e986e --- /dev/null +++ b/tests-Disable-filemonitor-testcase.patch @@ -0,0 +1,31 @@ +From 4f09a1c2aa855aab666d729defce4c7f0466cb77 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Thu, 10 Feb 2022 17:16:55 +0800 +Subject: [PATCH] tests: Disable filemonitor testcase + +Since filemonitor testcase requires that host kernel being a LTS version, +we cannot guarantee that on OBS system. Lets disable it by default. + +Signed-off-by: Ying Fang +Signed-off-by: Jinhao Gao +--- + tests/unit/meson.build | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/tests/unit/meson.build b/tests/unit/meson.build +index acac3622ed..c21d817874 100644 +--- a/tests/unit/meson.build ++++ b/tests/unit/meson.build +@@ -129,9 +129,6 @@ if have_system + 'test-vmstate': [migration, io], + 'test-yank': ['socket-helpers.c', qom, io, chardev] + } +- if 'CONFIG_INOTIFY1' in config_host +- tests += {'test-util-filemonitor': []} +- endif + + # Some tests: test-char, test-qdev-global-props, and test-qga, + # are not runnable under TSan due to a known issue. +-- +2.27.0 + diff --git a/tests-Disalbe-filemonitor-testcase.patch b/tests-Disalbe-filemonitor-testcase.patch deleted file mode 100644 index b389299e35dd49154f6e660ee3d66237b15ec58b..0000000000000000000000000000000000000000 --- a/tests-Disalbe-filemonitor-testcase.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 4f1eaa63065594276c11958e963377a09668d44b Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Thu, 6 Aug 2020 10:05:00 +0800 -Subject: [PATCH] tests: Disalbe filemonitor testcase - -Since filemonitor testcase requires that host kernel being a LTS version, -we cannot guarantee that on OBS system. Let's disable it by default. - -Signed-of-by: Ying Fang - -diff --git a/tests/Makefile.include b/tests/Makefile.include -index d8cf00c1..f3273ad3 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -117,7 +117,6 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) - check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) - endif - check-unit-y += tests/test-timed-average$(EXESUF) --check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) - check-unit-y += tests/test-util-sockets$(EXESUF) - check-unit-$(CONFIG_BLOCK) += tests/test-authz-simple$(EXESUF) - check-unit-$(CONFIG_BLOCK) += tests/test-authz-list$(EXESUF) -@@ -654,8 +653,6 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ - tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ - tests/crypto-tls-psk-helpers.o \ - $(test-crypto-obj-y) --tests/test-util-filemonitor$(EXESUF): tests/test-util-filemonitor.o \ -- $(test-util-obj-y) - tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ - tests/socket-helpers.o $(test-util-obj-y) - tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o $(test-authz-obj-y) --- -2.23.0 - diff --git a/tests-Fix-printf-format-string-in-acpi-utils.c.patch b/tests-Fix-printf-format-string-in-acpi-utils.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..063584b36f2c158d596eaba750ac11870cec6ca1 --- /dev/null +++ b/tests-Fix-printf-format-string-in-acpi-utils.c.patch @@ -0,0 +1,30 @@ +From 847becf4850bc244b140644cb577e17e5ba5e732 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Thu, 26 Oct 2023 19:52:59 -0700 +Subject: [PATCH] tests: Fix printf format string in acpi-utils.c + +Inside of acpi_fetch_table() arguments are +printed via fprintf but '%d' is used to print @flags (of type +uint). Use '%u' instead. + +Signed-off-by: zhujun2 +--- + tests/qtest/acpi-utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qtest/acpi-utils.c b/tests/qtest/acpi-utils.c +index 766c48e3a6..c6f5169b80 100644 +--- a/tests/qtest/acpi-utils.c ++++ b/tests/qtest/acpi-utils.c +@@ -103,7 +103,7 @@ void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len, + char *fname = NULL; + GError *error = NULL; + +- fprintf(stderr, "Invalid '%.4s'(%d)\n", *aml, *aml_len); ++ fprintf(stderr, "Invalid '%.4s'(%u)\n", *aml, *aml_len); + fd = g_file_open_tmp("malformed-XXXXXX.dat", &fname, &error); + g_assert_no_error(error); + fprintf(stderr, "Dumping invalid table into '%s'\n", fname); +-- +2.41.0.windows.1 + diff --git a/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch b/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch deleted file mode 100644 index e739883feb04d14f33a97a2a0b6690ac6c5ccc24..0000000000000000000000000000000000000000 --- a/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 27e2533e43f0ab2b8a60f1902f58f8752581ea9f Mon Sep 17 00:00:00 2001 -From: Shameer Kolothum -Date: Wed, 18 Sep 2019 14:06:32 +0100 -Subject: [PATCH] tests: Update ACPI tables list for upcoming arm/virt tests - -This is in preparation to add numamem and memhp tests to -arm/virt platform. The bios-tables-test-allowed-diff.h -is updated with a list of expected ACPI tables that needs to be -present in tests/data/acpi/virt folder. - -Signed-off-by: Shameer Kolothum -Message-Id: <20190918130633.4872-11-shameerali.kolothum.thodi@huawei.com> -Acked-by: Peter Maydell -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Igor Mammedov ---- - tests/bios-tables-test-allowed-diff.h | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h -index 32a401ae35..3776dd2f3d 100644 ---- a/tests/bios-tables-test-allowed-diff.h -+++ b/tests/bios-tables-test-allowed-diff.h -@@ -1,4 +1,17 @@ - /* List of comma-separated changed AML files to ignore */ - "tests/data/acpi/virt/DSDT", -+"tests/data/acpi/virt/APIC.memhp", -+"tests/data/acpi/virt/APIC.numamem", - "tests/data/acpi/virt/DSDT.memhp", - "tests/data/acpi/virt/DSDT.numamem", -+"tests/data/acpi/virt/FACP.memhp", -+"tests/data/acpi/virt/FACP.numamem", -+"tests/data/acpi/virt/GTDT.memhp", -+"tests/data/acpi/virt/GTDT.numamem", -+"tests/data/acpi/virt/MCFG.memhp", -+"tests/data/acpi/virt/MCFG.numamem", -+"tests/data/acpi/virt/SLIT.memhp", -+"tests/data/acpi/virt/SPCR.memhp", -+"tests/data/acpi/virt/SPCR.numamem", -+"tests/data/acpi/virt/SRAT.memhp", -+"tests/data/acpi/virt/SRAT.numamem", --- -2.19.1 diff --git a/tests-acpi-SLIC-update-expected-blobs.patch b/tests-acpi-SLIC-update-expected-blobs.patch new file mode 100644 index 0000000000000000000000000000000000000000..ba1f9bc7e69efe83c08f335cfc7ebfca03db89af --- /dev/null +++ b/tests-acpi-SLIC-update-expected-blobs.patch @@ -0,0 +1,26 @@ +From 86392e80092e62197f51507513ee09100f9c1653 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 27 Dec 2021 14:31:20 -0500 +Subject: [PATCH 4/6] tests: acpi: SLIC: update expected blobs + +Signed-off-by: Igor Mammedov +Message-Id: <20211227193120.1084176-5-imammedo@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + tests/data/acpi/q35/FACP.slic | Bin 244 -> 244 bytes + tests/data/acpi/q35/SLIC.slic | Bin 0 -> 36 bytes + tests/qtest/bios-tables-test-allowed-diff.h | 2 -- + 3 files changed, 2 deletions(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index 49dbf8fa3e..dfb8523c8b 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,3 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/q35/FACP.slic", +-"tests/data/acpi/q35/SLIC.slic", +-- +2.27.0 + diff --git a/tests-acpi-add-SLIC-table-test.patch b/tests-acpi-add-SLIC-table-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..f0b1a6ec851f6e437043036daba8668f705301b8 --- /dev/null +++ b/tests-acpi-add-SLIC-table-test.patch @@ -0,0 +1,55 @@ +From b9c96b0a111e5333857682a5dc9770cbebcbabea Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 27 Dec 2021 14:31:19 -0500 +Subject: [PATCH 3/6] tests: acpi: add SLIC table test + +When user uses '-acpitable' to add SLIC table, some ACPI +tables (FADT) will change its 'Oem ID'/'Oem Table ID' fields to +match that of SLIC. Test makes sure thati QEMU handles +those fields correctly when SLIC table is added with +'-acpitable' option. + +Signed-off-by: Igor Mammedov +Message-Id: <20211227193120.1084176-4-imammedo@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + tests/qtest/bios-tables-test.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c +index 258874167e..184937e6ca 100644 +--- a/tests/qtest/bios-tables-test.c ++++ b/tests/qtest/bios-tables-test.c +@@ -1465,6 +1465,20 @@ static void test_acpi_virt_tcg(void) + free_test_data(&data); + } + ++static void test_acpi_q35_slic(void) ++{ ++ test_data data = { ++ .machine = MACHINE_Q35, ++ .variant = ".slic", ++ }; ++ ++ test_acpi_one("-acpitable sig=SLIC,oem_id='CRASH ',oem_table_id='ME'," ++ "oem_rev=00002210,asl_compiler_id='qemu'," ++ "asl_compiler_rev=00000000,data=/dev/null", ++ &data); ++ free_test_data(&data); ++} ++ + static void test_oem_fields(test_data *data) + { + int i; +@@ -1639,6 +1653,7 @@ int main(int argc, char *argv[]) + qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic); + qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); + } ++ qtest_add_func("acpi/q35/slic", test_acpi_q35_slic); + } else if (strcmp(arch, "aarch64") == 0) { + if (has_tcg) { + qtest_add_func("acpi/virt", test_acpi_virt_tcg); +-- +2.27.0 + diff --git a/tests-acpi-add-empty-files.patch b/tests-acpi-add-empty-files.patch deleted file mode 100644 index 46e51c0de0e0ba84b6edf01fb62e3005acd37697..0000000000000000000000000000000000000000 --- a/tests-acpi-add-empty-files.patch +++ /dev/null @@ -1,88 +0,0 @@ -From c943416df54931cea8b19183fd7c4f2dbd86ec72 Mon Sep 17 00:00:00 2001 -From: "Michael S. Tsirkin" -Date: Sun, 29 Sep 2019 10:54:12 -0400 -Subject: [PATCH] tests/acpi: add empty files - -Needed to make tests pass. Will replace with actual files. - -Signed-off-by: Michael S. Tsirkin ---- - tests/data/acpi/virt/APIC.memhp | 0 - tests/data/acpi/virt/APIC.numamem | 0 - tests/data/acpi/virt/DSDT.memhp | 0 - tests/data/acpi/virt/DSDT.numamem | 0 - tests/data/acpi/virt/FACP.memhp | 0 - tests/data/acpi/virt/FACP.numamem | 0 - tests/data/acpi/virt/GTDT.memhp | 0 - tests/data/acpi/virt/GTDT.numamem | 0 - tests/data/acpi/virt/MCFG.memhp | 0 - tests/data/acpi/virt/MCFG.numamem | 0 - tests/data/acpi/virt/SLIT.memhp | 0 - tests/data/acpi/virt/SPCR.memhp | 0 - tests/data/acpi/virt/SPCR.numamem | 0 - tests/data/acpi/virt/SRAT.memhp | 0 - tests/data/acpi/virt/SRAT.numamem | 0 - 15 files changed, 0 insertions(+), 0 deletions(-) - create mode 100644 tests/data/acpi/virt/APIC.memhp - create mode 100644 tests/data/acpi/virt/APIC.numamem - create mode 100644 tests/data/acpi/virt/DSDT.memhp - create mode 100644 tests/data/acpi/virt/DSDT.numamem - create mode 100644 tests/data/acpi/virt/FACP.memhp - create mode 100644 tests/data/acpi/virt/FACP.numamem - create mode 100644 tests/data/acpi/virt/GTDT.memhp - create mode 100644 tests/data/acpi/virt/GTDT.numamem - create mode 100644 tests/data/acpi/virt/MCFG.memhp - create mode 100644 tests/data/acpi/virt/MCFG.numamem - create mode 100644 tests/data/acpi/virt/SLIT.memhp - create mode 100644 tests/data/acpi/virt/SPCR.memhp - create mode 100644 tests/data/acpi/virt/SPCR.numamem - create mode 100644 tests/data/acpi/virt/SRAT.memhp - create mode 100644 tests/data/acpi/virt/SRAT.numamem - -diff --git a/tests/data/acpi/virt/APIC.memhp b/tests/data/acpi/virt/APIC.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/APIC.numamem b/tests/data/acpi/virt/APIC.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/DSDT.numamem b/tests/data/acpi/virt/DSDT.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/FACP.memhp b/tests/data/acpi/virt/FACP.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/FACP.numamem b/tests/data/acpi/virt/FACP.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/GTDT.memhp b/tests/data/acpi/virt/GTDT.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/GTDT.numamem b/tests/data/acpi/virt/GTDT.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/MCFG.memhp b/tests/data/acpi/virt/MCFG.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/MCFG.numamem b/tests/data/acpi/virt/MCFG.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/SLIT.memhp b/tests/data/acpi/virt/SLIT.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/SPCR.memhp b/tests/data/acpi/virt/SPCR.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/SPCR.numamem b/tests/data/acpi/virt/SPCR.numamem -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/SRAT.memhp b/tests/data/acpi/virt/SRAT.memhp -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/tests/data/acpi/virt/SRAT.numamem b/tests/data/acpi/virt/SRAT.numamem -new file mode 100644 -index 0000000000..e69de29bb2 --- -2.19.1 diff --git a/tests-acpi-bios-table-test-Update-expected-virt-DSDT.patch b/tests-acpi-bios-table-test-Update-expected-virt-DSDT.patch new file mode 100644 index 0000000000000000000000000000000000000000..22b88989e27f8a8ca7d34726a68b48ba63cb2ca5 --- /dev/null +++ b/tests-acpi-bios-table-test-Update-expected-virt-DSDT.patch @@ -0,0 +1,26 @@ +From d3d158cbf6b236022794e867ac395f75fb4f6436 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 11 Feb 2022 16:07:31 +0800 +Subject: [PATCH] tests/acpi/bios-table-test: Update expected virt/DSDT file + +Update DSDT binary and empty bios-tables-test-allowd-diff.h + +Signed-off-by: Keqian Zhu +--- + tests/data/acpi/virt/DSDT | Bin 5669 -> 5669 bytes + tests/data/acpi/virt/DSDT.memhp | Bin 7030 -> 7030 bytes + tests/data/acpi/virt/DSDT.numamem | Bin 5669 -> 5669 bytes + tests/data/acpi/virt/DSDT.pxb | Bin 8152 -> 8152 bytes + tests/qtest/bios-tables-test-allowed-diff.h | 1 - + 5 files changed, 1 deletion(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index 7b4adbc822..dfb8523c8b 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,2 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/virt/DSDT", +-- +2.27.0 + diff --git a/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch b/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f1de286e32e21794adfb2f054ea79278def18f4 --- /dev/null +++ b/tests-acpi-bios-table-test-Update-expected-virt-PPTT.patch @@ -0,0 +1,110 @@ +From 6f89f06e686a61acf681038ac06732facc6e7b93 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:32 +0800 +Subject: [PATCH 20/24] tests/acpi/bios-table-test: Update expected virt/PPTT + file + +Run ./tests/data/acpi/rebuild-expected-aml.sh from build directory +to update PPTT binary. Also empty bios-tables-test-allowed-diff.h. + +The disassembled differences between actual and expected PPTT: + + /* + * Intel ACPI Component Architecture + * AML/ASL+ Disassembler version 20200528 (64-bit version) + * Copyright (c) 2000 - 2020 Intel Corporation + * +- * Disassembly of tests/data/acpi/virt/PPTT, Tue Jan 4 12:51:11 2022 ++ * Disassembly of /tmp/aml-2ZGOF1, Tue Jan 4 12:51:11 2022 + * + * ACPI Data Table [PPTT] + * + * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue + */ + + [000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table] +-[004h 0004 4] Table Length : 0000004C ++[004h 0004 4] Table Length : 00000060 + [008h 0008 1] Revision : 02 +-[009h 0009 1] Checksum : A8 ++[009h 0009 1] Checksum : 48 + [00Ah 0010 6] Oem ID : "BOCHS " + [010h 0016 8] Oem Table ID : "BXPC " + [018h 0024 4] Oem Revision : 00000001 + [01Ch 0028 4] Asl Compiler ID : "BXPC" + [020h 0032 4] Asl Compiler Revision : 00000001 + + [024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node] + [025h 0037 1] Length : 14 + [026h 0038 2] Reserved : 0000 + [028h 0040 4] Flags (decoded below) : 00000001 + Physical package : 1 + ACPI Processor ID valid : 0 + Processor is a thread : 0 + Node is a leaf : 0 + Identical Implementation : 0 + [02Ch 0044 4] Parent : 00000000 + [030h 0048 4] ACPI Processor ID : 00000000 + [034h 0052 4] Private Resource Number : 00000000 + + [038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node] + [039h 0057 1] Length : 14 + [03Ah 0058 2] Reserved : 0000 +-[03Ch 0060 4] Flags (decoded below) : 0000000A ++[03Ch 0060 4] Flags (decoded below) : 00000000 + Physical package : 0 +- ACPI Processor ID valid : 1 ++ ACPI Processor ID valid : 0 + Processor is a thread : 0 +- Node is a leaf : 1 ++ Node is a leaf : 0 + Identical Implementation : 0 + [040h 0064 4] Parent : 00000024 + [044h 0068 4] ACPI Processor ID : 00000000 + [048h 0072 4] Private Resource Number : 00000000 + +-Raw Table Data: Length 76 (0x4C) ++[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node] ++[04Dh 0077 1] Length : 14 ++[04Eh 0078 2] Reserved : 0000 ++[050h 0080 4] Flags (decoded below) : 0000000A ++ Physical package : 0 ++ ACPI Processor ID valid : 1 ++ Processor is a thread : 0 ++ Node is a leaf : 1 ++ Identical Implementation : 0 ++[054h 0084 4] Parent : 00000038 ++[058h 0088 4] ACPI Processor ID : 00000000 ++[05Ch 0092 4] Private Resource Number : 00000000 ++ ++Raw Table Data: Length 96 (0x60) + +- 0000: 50 50 54 54 4C 00 00 00 02 A8 42 4F 43 48 53 20 // PPTTL.....BOCHS ++ 0000: 50 50 54 54 60 00 00 00 02 48 42 4F 43 48 53 20 // PPTT`....HBOCHS + 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC + 0020: 01 00 00 00 00 14 00 00 01 00 00 00 00 00 00 00 // ................ +- 0030: 00 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................ +- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 // $........... ++ 0030: 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 // ................ ++ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $............... ++ 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8........... + +Signed-off-by: Yanan Wang +Reviewed-by: Ani Sinha +Message-id: 20220107083232.16256-7-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + tests/data/acpi/virt/PPTT | Bin 76 -> 96 bytes + tests/qtest/bios-tables-test-allowed-diff.h | 1 - + 2 files changed, 1 deletion(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index cb143a55a6..dfb8523c8b 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,2 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/virt/PPTT", +-- +2.27.0 + diff --git a/tests-acpi-bios-tables-test-Allow-changes-to-virt-DS.patch b/tests-acpi-bios-tables-test-Allow-changes-to-virt-DS.patch new file mode 100644 index 0000000000000000000000000000000000000000..585df22e40a21c84d9df3e883197c42ec3868ced --- /dev/null +++ b/tests-acpi-bios-tables-test-Allow-changes-to-virt-DS.patch @@ -0,0 +1,22 @@ +From d215714b9ab38f6c9e0aacf2120b44888936a1ed Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 11 Feb 2022 15:48:16 +0800 +Subject: [PATCH] tests/acpi/bios-tables-test: Allow changes to virt/DSDT file + +Let virt/DSDT as the expected file allowed to be changed. + +Signed-off-by: Keqian Zhu +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523c8b..7b4adbc822 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/virt/DSDT", +-- +2.27.0 + diff --git a/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch b/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4801e55cd027f94f9e929f5dc86dcc5780620c6 --- /dev/null +++ b/tests-acpi-bios-tables-test-Allow-changes-to-virt-PP.patch @@ -0,0 +1,27 @@ +From 225034a72c803b8e3819cec22bc6fb8bfc9e7366 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Fri, 7 Jan 2022 16:32:30 +0800 +Subject: [PATCH 18/24] tests/acpi/bios-tables-test: Allow changes to virt/PPTT + file + +List test/data/acpi/virt/PPTT as the expected files allowed to +be changed in tests/qtest/bios-tables-test-allowed-diff.h + +Signed-off-by: Yanan Wang +Acked-by: Ani Sinha +Message-id: 20220107083232.16256-5-wangyanan55@huawei.com +Signed-off-by: Peter Maydell +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523c8b..cb143a55a6 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/virt/PPTT", +-- +2.27.0 + diff --git a/tests-acpi-whitelist-expected-blobs-before-changing-.patch b/tests-acpi-whitelist-expected-blobs-before-changing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..075361b2af5d521616d46941d9df90827fbee30d --- /dev/null +++ b/tests-acpi-whitelist-expected-blobs-before-changing-.patch @@ -0,0 +1,29 @@ +From 83229a5034161d021ac21f7c7f921d4398d388c6 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 27 Dec 2021 14:31:18 -0500 +Subject: [PATCH 2/6] tests: acpi: whitelist expected blobs before changing + them + +Signed-off-by: Igor Mammedov +Message-Id: <20211227193120.1084176-3-imammedo@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + tests/data/acpi/q35/FACP.slic | Bin 0 -> 244 bytes + tests/data/acpi/q35/SLIC.slic | 0 + tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ + 3 files changed, 2 insertions(+) + create mode 100644 tests/data/acpi/q35/FACP.slic + create mode 100644 tests/data/acpi/q35/SLIC.slic + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523c8b..49dbf8fa3e 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,3 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/q35/FACP.slic", ++"tests/data/acpi/q35/SLIC.slic", +-- +2.27.0 + diff --git a/tests-add-riscv-virt-machine-mapping-to-testenv.patch b/tests-add-riscv-virt-machine-mapping-to-testenv.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc008b5bc9e86e7a8c4956668a8fc56e9399e489 --- /dev/null +++ b/tests-add-riscv-virt-machine-mapping-to-testenv.patch @@ -0,0 +1,39 @@ +From f0dbc3b6101e39ce3bc5d38f34723d1c672a12e9 Mon Sep 17 00:00:00 2001 +From: laokz +Date: Mon, 13 Mar 2023 06:20:48 +0000 +Subject: [PATCH] tests: add (riscv virt) machine mapping to testenv from + v7.0.0 commit 3213bbaf5797cc405e57f122e72c1fb55d0b08ab Author: laokz + Date: Tue Mar 8 12:33:39 2022 +0800 + + tests: add (riscv virt) machine mapping to testenv + + Some qemu-iotests(040 etc) use PCI disk to do test. Without the + mapping, RISC-V flavor use spike as default machine which has no + PCI bus, causing test failure. + + Resolves: https://gitlab.com/qemu-project/qemu/-/issues/894 + + Signed-off-by: Kai Zhang + Message-Id: + Reviewed-by: Alistair Francis + Signed-off-by: Hanna Reitz +--- + tests/qemu-iotests/testenv.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py +index c33454fa68..26ae6945cc 100644 +--- a/tests/qemu-iotests/testenv.py ++++ b/tests/qemu-iotests/testenv.py +@@ -238,6 +238,8 @@ def __init__(self, imgfmt: str, imgproto: str, aiomode: str, + ('aarch64', 'virt'), + ('avr', 'mega2560'), + ('m68k', 'virt'), ++ ('riscv32', 'virt'), ++ ('riscv64', 'virt'), + ('rx', 'gdbsim-r5f562n8'), + ('tricore', 'tricore_testboard') + ) +-- +2.27.0 + diff --git a/tests-allow-empty-expected-files.patch b/tests-allow-empty-expected-files.patch deleted file mode 100644 index 615fb2121d3ffd93d926fe4f3e9623ffce16eb88..0000000000000000000000000000000000000000 --- a/tests-allow-empty-expected-files.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 2ab0636e0c8fcb8b5b1b222f0d5ae7f4dfc663c5 Mon Sep 17 00:00:00 2001 -From: "Michael S. Tsirkin" -Date: Sat, 5 Oct 2019 17:09:17 -0400 -Subject: [PATCH] tests: allow empty expected files - -An empty expected file is a handy way to seed the files -without creating merge conflicts. - -Signed-off-by: Michael S. Tsirkin ---- - tests/bios-tables-test.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c -index a356ac3489..53a91a8067 100644 ---- a/tests/bios-tables-test.c -+++ b/tests/bios-tables-test.c -@@ -334,7 +334,10 @@ try_again: - g_assert(ret); - g_assert_no_error(error); - g_assert(exp_sdt.aml); -- g_assert(exp_sdt.aml_len); -+ if (!exp_sdt.aml_len) { -+ fprintf(stderr, "Warning! zero length expected file '%s'\n", -+ aml_file); -+ } - - g_array_append_val(exp_tables, exp_sdt); - } --- -2.19.1 diff --git a/tests-allow-filtering-crypto-cipher-benchmark-tests.patch b/tests-allow-filtering-crypto-cipher-benchmark-tests.patch deleted file mode 100644 index 51f6b70461b0ade8ff80b2f8ac0302546593228f..0000000000000000000000000000000000000000 --- a/tests-allow-filtering-crypto-cipher-benchmark-tests.patch +++ /dev/null @@ -1,56 +0,0 @@ -From c2a6b4b3204aef2efc39f1b59bc110b54ca24587 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= -Date: Tue, 15 Oct 2019 11:19:29 +0100 -Subject: [PATCH] tests: allow filtering crypto cipher benchmark tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add support for specifying a cipher mode and chunk size as argv to -filter which combinations are benchmarked. For example to only -benchmark XTS mode with 512 byte chunks: - - ./tests/benchmark-crypto-cipher xts 512 - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefano Garzarella -Signed-off-by: Daniel P. Berrangé ---- - tests/benchmark-crypto-cipher.c | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/tests/benchmark-crypto-cipher.c b/tests/benchmark-crypto-cipher.c -index cb6b7200a5..53032334ec 100644 ---- a/tests/benchmark-crypto-cipher.c -+++ b/tests/benchmark-crypto-cipher.c -@@ -163,15 +163,26 @@ static void test_cipher_speed_xts_aes_256(const void *opaque) - - int main(int argc, char **argv) - { -+ char *alg = NULL; -+ char *size = NULL; - g_test_init(&argc, &argv, NULL); - g_assert(qcrypto_init(NULL) == 0); - - #define ADD_TEST(mode, cipher, keysize, chunk) \ -- g_test_add_data_func( \ -+ if ((!alg || g_str_equal(alg, #mode)) && \ -+ (!size || g_str_equal(size, #chunk))) \ -+ g_test_add_data_func( \ - "/crypto/cipher/" #mode "-" #cipher "-" #keysize "/chunk-" #chunk, \ - (void *)chunk, \ - test_cipher_speed_ ## mode ## _ ## cipher ## _ ## keysize) - -+ if (argc >= 2) { -+ alg = argv[1]; -+ } -+ if (argc >= 3) { -+ size = argv[2]; -+ } -+ - #define ADD_TESTS(chunk) \ - do { \ - ADD_TEST(ecb, aes, 128, chunk); \ --- -2.27.0 - diff --git a/tests-avocado-fix-waiting-for-vm-shutdown-in-replay_.patch b/tests-avocado-fix-waiting-for-vm-shutdown-in-replay_.patch new file mode 100644 index 0000000000000000000000000000000000000000..5c237216ba44a6e79a7672cd84a0419f06c4dbf7 --- /dev/null +++ b/tests-avocado-fix-waiting-for-vm-shutdown-in-replay_.patch @@ -0,0 +1,35 @@ +From 0242c2c743987efc6955fc4405b540140b1b678d Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 11:57:38 +0000 +Subject: [PATCH] tests/avocado: fix waiting for vm shutdown in replay_linux + +This patch fixes the race condition in waiting for shutdown +of the replay linux test. + +cheery-pick from b821109583a035a17fa5b89c0ebd8917d09cc82d + +Signed-off-by: jipengfei_yewu +Signed-off-by: Pavel Dovgalyuk +Suggested-by: John Snow +Message-ID: <20230811070608.3383343-4-pavel.dovgalyuk@ispras.ru> +Signed-off-by: Thomas Huth +--- + tests/avocado/replay_linux.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py +index 15953f9e49..897d5bad19 100644 +--- a/tests/avocado/replay_linux.py ++++ b/tests/avocado/replay_linux.py +@@ -82,7 +82,7 @@ def launch_and_wait(self, record, args, shift): + % os.path.getsize(replay_path)) + else: + vm.event_wait('SHUTDOWN', self.timeout) +- vm.shutdown(True) ++ vm.wait() + logger.info('successfully fihished the replay') + elapsed = time.time() - start_time + logger.info('elapsed time %.2f sec' % elapsed) +-- +2.27.0 + diff --git a/tests-avocado-mark-ReplayKernelNormal.test_mips64el_.patch b/tests-avocado-mark-ReplayKernelNormal.test_mips64el_.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc8f81aed54fcb488ae3a9a1cef9edfb1aebad3a --- /dev/null +++ b/tests-avocado-mark-ReplayKernelNormal.test_mips64el_.patch @@ -0,0 +1,48 @@ +From b4d96f201027d930ef84c8751909f3770e3d21f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Fri, 1 Dec 2023 20:10:27 +0000 +Subject: [PATCH] tests/avocado: mark ReplayKernelNormal.test_mips64el_malta as + flaky +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I missed this when going through the recent failure logs. I can run +the test 30 times without failure locally but it seems to hang pretty +reliably on GitLab's CI infra-structure. + +Cc: Philippe Mathieu-Daudé +Signed-off-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20231201201027.2689404-1-alex.bennee@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé + +Signed-off-by: Zhongrui Tang +--- + tests/avocado/replay_kernel.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py +index c68a953730..16421b3407 100644 +--- a/tests/avocado/replay_kernel.py ++++ b/tests/avocado/replay_kernel.py +@@ -113,6 +113,8 @@ def test_mips_malta(self): + + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) + ++ # See https://gitlab.com/qemu-project/qemu/-/issues/2013 ++ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') + def test_mips64el_malta(self): + """ + This test requires the ar tool to extract "data.tar.gz" from +@@ -128,6 +130,7 @@ def test_mips64el_malta(self): + + :avocado: tags=arch:mips64el + :avocado: tags=machine:malta ++ :avocado: tags=flaky + """ + deb_url = ('http://snapshot.debian.org/archive/debian/' + '20130217T032700Z/pool/main/l/linux-2.6/' +-- +2.27.0 + diff --git a/tests-avocado-raspi2_initrd-Wait-for-guest-shutdown-.patch b/tests-avocado-raspi2_initrd-Wait-for-guest-shutdown-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8bec1abebecfc66c45f617957f90d9efae00731 --- /dev/null +++ b/tests-avocado-raspi2_initrd-Wait-for-guest-shutdown-.patch @@ -0,0 +1,50 @@ +From b30894533ec65a304c304016eaa461c23ca8d70c Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Wed, 30 Nov 2022 14:21:17 +0800 +Subject: [PATCH 02/17] tests/avocado: raspi2_initrd: Wait for guest shutdown + message before stopping + +The avocado test + tests/avocado/boot_linux_console.py:BootLinuxConsole.test_arm_raspi2_initrd +finishes wiith + exec_command(self, 'halt') + # Wait for VM to shut down gracefully + self.vm.wait() +In theory this should be fine. In practice it runs into two bugs: + * when the test calls self.vm.wait() Avocado closes the socket + connection to the guest serial console immediately, so the + avocado logs don't have the last part of the guest output: + https://gitlab.com/qemu-project/qemu/-/issues/1265 + * when the socket is closed, a bug in the QEMU socket chardev + means that it loses any data that the guest UART has not + yet consumed. This means that the guest doesn't always read + the full 'halt' command string, so the test intermittently + fails with a timeout: + https://gitlab.com/qemu-project/qemu/-/issues/1264 +Work around both of these by waiting for the guest to print the +string that means it has completed the shutdown process. This fixes +a very long standing intermittent failure in this test. +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/636 + +Signed-off-by: Peter Maydell +Signed-off-by: jianchunfu +--- + tests/avocado/boot_linux_console.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py +index 9c618d4809..58864ec163 100644 +--- a/tests/avocado/boot_linux_console.py ++++ b/tests/avocado/boot_linux_console.py +@@ -512,7 +512,7 @@ def test_arm_raspi2_initrd(self): + 'BCM2835') + exec_command_and_wait_for_pattern(self, 'cat /proc/iomem', + '/soc/cprman@7e101000') +- exec_command(self, 'halt') ++ exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted') + # Wait for VM to shut down gracefully + self.vm.wait() + +-- +2.27.0 + diff --git a/tests-avocado-use-new-rootfs-for-orangepi-test.patch b/tests-avocado-use-new-rootfs-for-orangepi-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffd66757a43aa298d1f7b9a2b84e1a5cf692e621 --- /dev/null +++ b/tests-avocado-use-new-rootfs-for-orangepi-test.patch @@ -0,0 +1,39 @@ +From 5d2db876aa6f869dabe6f6132244c5ce2383af03 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 1 Dec 2022 17:00:40 +0800 +Subject: [PATCH 07/17] tests/avocado: use new rootfs for orangepi test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The old URL wasn't stable. I suspect the current URL will only be +stable for a few months so maybe we need another strategy for hosting +rootfs snapshots? + +Signed-off-by: Alex Bennée +Message-Id: <20221118113309.1057790-1-alex.bennee@linaro.org> +Signed-off-by: Thomas Huth + +Signed-off-by: tangzhongrui +--- + tests/avocado/boot_linux_console.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py +index 9c618d4809..733481c53c 100644 +--- a/tests/avocado/boot_linux_console.py ++++ b/tests/avocado/boot_linux_console.py +@@ -813,8 +813,8 @@ def test_arm_orangepi_sd(self): + dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb' + dtb_path = self.extract_from_deb(deb_path, dtb_path) + rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/' +- 'kci-2019.02/armel/base/rootfs.ext2.xz') +- rootfs_hash = '692510cb625efda31640d1de0a8d60e26040f061' ++ 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz') ++ rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a' + rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash) + rootfs_path = os.path.join(self.workdir, 'rootfs.cpio') + archive.lzma_uncompress(rootfs_path_xz, rootfs_path) +-- +2.27.0 + diff --git a/tests-benchmark-crypto-with-fixed-data-size-not-time.patch b/tests-benchmark-crypto-with-fixed-data-size-not-time.patch deleted file mode 100644 index 8841294a8a43877948bd2c74228794aafdaf0114..0000000000000000000000000000000000000000 --- a/tests-benchmark-crypto-with-fixed-data-size-not-time.patch +++ /dev/null @@ -1,150 +0,0 @@ -From c151519a7f5c08dde9a32534bc485588a5793967 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= -Date: Thu, 17 Oct 2019 14:22:19 +0100 -Subject: [PATCH] tests: benchmark crypto with fixed data size, not time period -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently the crypto benchmarks are processing data in varying chunk -sizes, over a fixed time period. This turns out to be a terrible idea -because with small chunk sizes the overhead of checking the elapsed -time on each loop iteration masks the true performance. - -Benchmarking over a fixed data size avoids the loop running any system -calls which can interfere with the performance measurements. - -Before this change - -Enc chunk 512 bytes 2283.47 MB/sec Dec chunk 512 bytes 2236.23 MB/sec OK -Enc chunk 4096 bytes 2744.97 MB/sec Dec chunk 4096 bytes 2614.71 MB/sec OK -Enc chunk 16384 bytes 2777.53 MB/sec Dec chunk 16384 bytes 2678.44 MB/sec OK -Enc chunk 65536 bytes 2809.34 MB/sec Dec chunk 65536 bytes 2699.47 MB/sec OK - -After this change - -Enc chunk 512 bytes 2058.22 MB/sec Dec chunk 512 bytes 2030.11 MB/sec OK -Enc chunk 4096 bytes 2699.27 MB/sec Dec chunk 4096 bytes 2573.78 MB/sec OK -Enc chunk 16384 bytes 2748.52 MB/sec Dec chunk 16384 bytes 2653.76 MB/sec OK -Enc chunk 65536 bytes 2814.08 MB/sec Dec chunk 65536 bytes 2712.74 MB/sec OK - -The actual crypto performance hasn't changed, which shows how -significant the mis-measurement has been for small data sizes. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefano Garzarella -Signed-off-by: Daniel P. Berrangé ---- - tests/benchmark-crypto-cipher.c | 26 ++++++++++++++------------ - tests/benchmark-crypto-hash.c | 17 +++++++++-------- - 2 files changed, 23 insertions(+), 20 deletions(-) - -diff --git a/tests/benchmark-crypto-cipher.c b/tests/benchmark-crypto-cipher.c -index 67fdf8c31d..cb6b7200a5 100644 ---- a/tests/benchmark-crypto-cipher.c -+++ b/tests/benchmark-crypto-cipher.c -@@ -21,11 +21,12 @@ static void test_cipher_speed(size_t chunk_size, - { - QCryptoCipher *cipher; - Error *err = NULL; -- double total = 0.0; - uint8_t *key = NULL, *iv = NULL; - uint8_t *plaintext = NULL, *ciphertext = NULL; - size_t nkey; - size_t niv; -+ const size_t total = 2 * GiB; -+ size_t remain; - - if (!qcrypto_cipher_supports(alg, mode)) { - return; -@@ -58,33 +59,34 @@ static void test_cipher_speed(size_t chunk_size, - &err) == 0); - - g_test_timer_start(); -- do { -+ remain = total; -+ while (remain) { - g_assert(qcrypto_cipher_encrypt(cipher, - plaintext, - ciphertext, - chunk_size, - &err) == 0); -- total += chunk_size; -- } while (g_test_timer_elapsed() < 1.0); -+ remain -= chunk_size; -+ } -+ g_test_timer_elapsed(); - -- total /= MiB; - g_print("Enc chunk %zu bytes ", chunk_size); -- g_print("%.2f MB/sec ", total / g_test_timer_last()); -+ g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last()); - -- total = 0.0; - g_test_timer_start(); -- do { -+ remain = total; -+ while (remain) { - g_assert(qcrypto_cipher_decrypt(cipher, - plaintext, - ciphertext, - chunk_size, - &err) == 0); -- total += chunk_size; -- } while (g_test_timer_elapsed() < 1.0); -+ remain -= chunk_size; -+ } -+ g_test_timer_elapsed(); - -- total /= MiB; - g_print("Dec chunk %zu bytes ", chunk_size); -- g_print("%.2f MB/sec ", total / g_test_timer_last()); -+ g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last()); - - qcrypto_cipher_free(cipher); - g_free(plaintext); -diff --git a/tests/benchmark-crypto-hash.c b/tests/benchmark-crypto-hash.c -index 9b6f7a9155..7f659f7323 100644 ---- a/tests/benchmark-crypto-hash.c -+++ b/tests/benchmark-crypto-hash.c -@@ -20,7 +20,8 @@ static void test_hash_speed(const void *opaque) - size_t chunk_size = (size_t)opaque; - uint8_t *in = NULL, *out = NULL; - size_t out_len = 0; -- double total = 0.0; -+ const size_t total = 2 * GiB; -+ size_t remain; - struct iovec iov; - int ret; - -@@ -31,20 +32,20 @@ static void test_hash_speed(const void *opaque) - iov.iov_len = chunk_size; - - g_test_timer_start(); -- do { -+ remain = total; -+ while (remain) { - ret = qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, - &iov, 1, &out, &out_len, - NULL); - g_assert(ret == 0); - -- total += chunk_size; -- } while (g_test_timer_elapsed() < 5.0); -+ remain -= chunk_size; -+ } -+ g_test_timer_elapsed(); - -- total /= MiB; - g_print("sha256: "); -- g_print("Testing chunk_size %zu bytes ", chunk_size); -- g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last()); -- g_print("%.2f MB/sec\n", total / g_test_timer_last()); -+ g_print("Hash %zu GB chunk size %zu bytes ", total / GiB, chunk_size); -+ g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last()); - - g_free(out); - g_free(in); --- -2.27.0 - diff --git a/tests-bios-tables-test-disable-this-testcase.patch b/tests-bios-tables-test-disable-this-testcase.patch deleted file mode 100644 index 993fee935546735c16bfe9a30ff856ac135f4d53..0000000000000000000000000000000000000000 --- a/tests-bios-tables-test-disable-this-testcase.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0814ef80cdf212c68b73fc1fbad4eeece3560ef9 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 15 Apr 2020 19:52:09 +0800 -Subject: [PATCH] tests/bios-tables-test: disable this testcase - -We will change ARM virt ACPI FACP and PPTT table in order to -support CPU topology information presentation. However our -change make this testcase fail since we changed the table -totally and we cannot apply patch with rpmbuild system. - -Signed-off-by: Ying Fang ---- - tests/Makefile.include | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tests/Makefile.include b/tests/Makefile.include -index fd7fdb86..d8cf00c1 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -164,7 +164,7 @@ check-qtest-i386-y += tests/ide-test$(EXESUF) - check-qtest-i386-y += tests/ahci-test$(EXESUF) - check-qtest-i386-y += tests/hd-geo-test$(EXESUF) - check-qtest-i386-y += tests/boot-order-test$(EXESUF) --check-qtest-i386-y += tests/bios-tables-test$(EXESUF) -+# check-qtest-i386-y += tests/bios-tables-test$(EXESUF) - check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF) - check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) - check-qtest-i386-y += tests/rtc-test$(EXESUF) -@@ -269,7 +269,7 @@ check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) - check-qtest-aarch64-y += tests/migration-test$(EXESUF) - # TODO: once aarch64 TCG is fixed on ARM 32 bit host, make test unconditional - ifneq ($(ARCH),arm) --check-qtest-aarch64-y += tests/bios-tables-test$(EXESUF) -+#check-qtest-aarch64-y += tests/bios-tables-test$(EXESUF) - endif - - check-qtest-microblazeel-y += $(check-qtest-microblaze-y) -@@ -783,7 +783,7 @@ tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o - tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o - tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) - tests/boot-serial-test$(EXESUF): tests/boot-serial-test.o $(libqos-obj-y) --tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ -+#tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ - tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) - tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) - tests/microbit-test$(EXESUF): tests/microbit-test.o --- -2.23.0 diff --git a/tests-document-how-to-update-acpi-tables.patch b/tests-document-how-to-update-acpi-tables.patch deleted file mode 100644 index c961069b6e77c2a193b34d606466f04c7b059611..0000000000000000000000000000000000000000 --- a/tests-document-how-to-update-acpi-tables.patch +++ /dev/null @@ -1,53 +0,0 @@ -From d9642ad522d34f0d803a87654a2c258baf1070dd Mon Sep 17 00:00:00 2001 -From: "Michael S. Tsirkin" -Date: Sat, 5 Oct 2019 17:25:55 -0400 -Subject: [PATCH] tests: document how to update acpi tables - -Looks like no one understands how to do it. -Document the process. - -Signed-off-by: Michael S. Tsirkin ---- - tests/bios-tables-test.c | 27 +++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c -index 5e177b7155..d47ee9be99 100644 ---- a/tests/bios-tables-test.c -+++ b/tests/bios-tables-test.c -@@ -10,6 +10,33 @@ - * See the COPYING file in the top-level directory. - */ - -+/* -+ * How to add or update the tests: -+ * Contributor: -+ * 1. add empty files for new tables, if any, under tests/data/acpi -+ * 2. list any changed files in tests/bios-tables-test-allowed-diff.h -+ * 3. commit the above *before* making changes that affect the tables -+ * Maintainer: -+ * After 1-3 above tests will pass but ignore differences with the expected files. -+ * You will also notice that tests/bios-tables-test-allowed-diff.h lists -+ * a bunch of files. This is your hint that you need to do the below: -+ * 4. Run -+ * make check V=1 -+ * this will produce a bunch of warnings about differences -+ * beween actual and expected ACPI tables. If you have IASL installed, -+ * they will also be disassembled so you can look at the disassembled -+ * output. If not - disassemble them yourself in any way you like. -+ * Look at the differences - make sure they make sense and match what the -+ * changes you are merging are supposed to do. -+ * -+ * 5. From build directory, run: -+ * $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh -+ * 6. Now commit any changes. -+ * 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h -+ * is empty - this will ensure following changes to ACPI tables will -+ * be noticed. -+ */ -+ - #include "qemu/osdep.h" - #include - #include "qemu-common.h" --- -2.19.1 diff --git a/tests-qtest-Add-fuzz-lsi53c895a-test.patch b/tests-qtest-Add-fuzz-lsi53c895a-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ab7705fa9527c03a594dfc03501fc481891b725 --- /dev/null +++ b/tests-qtest-Add-fuzz-lsi53c895a-test.patch @@ -0,0 +1,113 @@ +From 32e9fb62e900e94cb2e39e6bd9717983bb259d25 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Tue, 23 Nov 2021 12:17:32 +0100 +Subject: [PATCH 2/4] tests/qtest: Add fuzz-lsi53c895a-test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Without the previous commit, this test triggers: + + $ make check-qtest-x86_64 + [...] + Running test qtest-x86_64/fuzz-lsi53c895a-test + qemu-system-x86_64: hw/scsi/lsi53c895a.c:624: lsi_do_dma: Assertion `s->current' failed. + ERROR qtest-x86_64/fuzz-lsi53c895a-test - too few tests run (expected 1, got 0) + +Suggested-by: Alexander Bulekov +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laurent Vivier +Message-Id: <20211123111732.83137-3-philmd@redhat.com> +Signed-off-by: Paolo Bonzini +--- + MAINTAINERS | 1 + + tests/qtest/fuzz-lsi53c895a-test.c | 52 ++++++++++++++++++++++++++++++ + tests/qtest/meson.build | 1 + + 3 files changed, 54 insertions(+) + create mode 100644 tests/qtest/fuzz-lsi53c895a-test.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 7543eb4d59..fbd6d0b174 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1825,6 +1825,7 @@ F: hw/scsi/* + F: tests/qtest/virtio-scsi-test.c + F: tests/qtest/fuzz-virtio-scsi-test.c + F: tests/qtest/am53c974-test.c ++F: tests/qtest/fuzz-lsi53c895a-test.c + T: git https://github.com/bonzini/qemu.git scsi-next + + SSI +diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c +new file mode 100644 +index 0000000000..ba5d468970 +--- /dev/null ++++ b/tests/qtest/fuzz-lsi53c895a-test.c +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * QTest fuzzer-generated testcase for LSI53C895A device ++ * ++ * Copyright (c) Red Hat ++ */ ++ ++#include "qemu/osdep.h" ++#include "libqos/libqtest.h" ++ ++/* ++ * This used to trigger the assert in lsi_do_dma() ++ * https://bugs.launchpad.net/qemu/+bug/697510 ++ * https://bugs.launchpad.net/qemu/+bug/1905521 ++ * https://bugs.launchpad.net/qemu/+bug/1908515 ++ */ ++static void test_lsi_do_dma_empty_queue(void) ++{ ++ QTestState *s; ++ ++ s = qtest_init("-M q35 -nographic -monitor none -serial none " ++ "-drive if=none,id=drive0," ++ "file=null-co://,file.read-zeroes=on,format=raw " ++ "-device lsi53c895a,id=scsi0 " ++ "-device scsi-hd,drive=drive0," ++ "bus=scsi0.0,channel=0,scsi-id=0,lun=0"); ++ qtest_outl(s, 0xcf8, 0x80001814); ++ qtest_outl(s, 0xcfc, 0xe1068000); ++ qtest_outl(s, 0xcf8, 0x80001818); ++ qtest_outl(s, 0xcf8, 0x80001804); ++ qtest_outw(s, 0xcfc, 0x7); ++ qtest_outl(s, 0xcf8, 0x80002010); ++ ++ qtest_writeb(s, 0xe106802e, 0xff); /* Fill DSP bits 16-23 */ ++ qtest_writeb(s, 0xe106802f, 0xff); /* Fill DSP bits 24-31: trigger SCRIPT */ ++ ++ qtest_quit(s); ++} ++ ++int main(int argc, char **argv) ++{ ++ const char *arch = qtest_get_arch(); ++ ++ g_test_init(&argc, &argv, NULL); ++ ++ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { ++ qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", ++ test_lsi_do_dma_empty_queue); ++ } ++ ++ return g_test_run(); ++} +diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build +index c9d8458062..d2ce20d304 100644 +--- a/tests/qtest/meson.build ++++ b/tests/qtest/meson.build +@@ -19,6 +19,7 @@ slow_qtests = { + + qtests_generic = \ + (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ ++ (config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \ + (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ + (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ + (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ +-- +2.27.0 + diff --git a/tests-qtest-Fix-two-format-strings.patch b/tests-qtest-Fix-two-format-strings.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed739b906000a35e8c5efa91a34e6fa072b7f63d --- /dev/null +++ b/tests-qtest-Fix-two-format-strings.patch @@ -0,0 +1,44 @@ +From 00b21f96b39b892d9dff0fc7616e88e7238d54cc Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:14:16 -0800 +Subject: [PATCH] tests/qtest: Fix two format strings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit d46e6bba55f858b829251e2f4bd7b150cdb5b1d6 + +Signed-off-by: Stefan Weil +Message-Id: <20221105115525.623059-1-sw@weilnetz.de> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Huth +Signed-off-by: Wanghe Xiao +--- + tests/qtest/migration-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c +index 8fad247f6c..194c7cb661 100644 +--- a/tests/qtest/migration-test.c ++++ b/tests/qtest/migration-test.c +@@ -1406,7 +1406,7 @@ static void calc_dirty_rate(QTestState *who, uint64_t calc_time) + qobject_unref(qmp_command(who, + "{ 'execute': 'calc-dirty-rate'," + "'arguments': { " +- "'calc-time': %ld," ++ "'calc-time': %" PRIu64 "," + "'mode': 'dirty-ring' }}", + calc_time)); + } +@@ -1421,7 +1421,7 @@ static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) + qobject_unref(qmp_command(who, + "{ 'execute': 'set-vcpu-dirty-limit'," + "'arguments': { " +- "'dirty-rate': %ld } }", ++ "'dirty-rate': %" PRIu64 " } }", + dirtyrate)); + } + +-- +2.27.0 + diff --git a/tests-qtest-check-the-return-value.patch b/tests-qtest-check-the-return-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..ada8e4a34533defdd67bfda81721393fe039afe7 --- /dev/null +++ b/tests-qtest-check-the-return-value.patch @@ -0,0 +1,62 @@ +From 53e0242318e838013504688307af44e80ab36c70 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Tue, 21 Nov 2023 18:03:25 -0800 +Subject: [PATCH] tests/qtest: check the return value + +These variables "ret" are never referenced in the code, thus +add check logic for the "ret" + +Signed-off-by: zhujun2 +--- + tests/qtest/test-filter-mirror.c | 1 + + tests/qtest/test-filter-redirector.c | 2 ++ + tests/qtest/virtio-net-test.c | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/tests/qtest/test-filter-mirror.c b/tests/qtest/test-filter-mirror.c +index bc0dee64dd..40f736734a 100644 +--- a/tests/qtest/test-filter-mirror.c ++++ b/tests/qtest/test-filter-mirror.c +@@ -71,6 +71,7 @@ static void test_mirror(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock[0], recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); +diff --git a/tests/qtest/test-filter-redirector.c b/tests/qtest/test-filter-redirector.c +index 4269b2cdd9..f802c94f54 100644 +--- a/tests/qtest/test-filter-redirector.c ++++ b/tests/qtest/test-filter-redirector.c +@@ -133,6 +133,7 @@ static void test_redirector_tx(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock, recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); +@@ -201,6 +202,7 @@ static void test_redirector_rx(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(backend_sock[0], recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + close(send_sock); +diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c +index 8bf74e516c..aab4480fb0 100644 +--- a/tests/qtest/virtio-net-test.c ++++ b/tests/qtest/virtio-net-test.c +@@ -92,6 +92,7 @@ static void tx_test(QVirtioDevice *dev, + len = ntohl(len); + + ret = qemu_recv(socket, buffer, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(buffer, ==, "TEST"); + } + +-- +2.27.0 + diff --git a/tests-qtest-fdc-test-Add-a-regression-test-for-CVE-2.patch b/tests-qtest-fdc-test-Add-a-regression-test-for-CVE-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..d089fbbf6c9f7fc7f004463601b9ad9001fc502a --- /dev/null +++ b/tests-qtest-fdc-test-Add-a-regression-test-for-CVE-2.patch @@ -0,0 +1,110 @@ +From c3ed2f4828e29f5ac82efd6a32117e9b17180dd1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 18 Nov 2021 12:57:33 +0100 +Subject: [PATCH 6/6] tests/qtest/fdc-test: Add a regression test for + CVE-2021-3507 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the reproducer from https://gitlab.com/qemu-project/qemu/-/issues/339 + +Without the previous commit, when running 'make check-qtest-i386' +with QEMU configured with '--enable-sanitizers' we get: + + ==4028352==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000062a00 at pc 0x5626d03c491a bp 0x7ffdb4199410 sp 0x7ffdb4198bc0 + READ of size 786432 at 0x619000062a00 thread T0 + #0 0x5626d03c4919 in __asan_memcpy (qemu-system-i386+0x1e65919) + #1 0x5626d1c023cc in flatview_write_continue softmmu/physmem.c:2787:13 + #2 0x5626d1bf0c0f in flatview_write softmmu/physmem.c:2822:14 + #3 0x5626d1bf0798 in address_space_write softmmu/physmem.c:2914:18 + #4 0x5626d1bf0f37 in address_space_rw softmmu/physmem.c:2924:16 + #5 0x5626d1bf14c8 in cpu_physical_memory_rw softmmu/physmem.c:2933:5 + #6 0x5626d0bd5649 in cpu_physical_memory_write include/exec/cpu-common.h:82:5 + #7 0x5626d0bd0a07 in i8257_dma_write_memory hw/dma/i8257.c:452:9 + #8 0x5626d09f825d in fdctrl_transfer_handler hw/block/fdc.c:1616:13 + #9 0x5626d0a048b4 in fdctrl_start_transfer hw/block/fdc.c:1539:13 + #10 0x5626d09f4c3e in fdctrl_write_data hw/block/fdc.c:2266:13 + #11 0x5626d09f22f7 in fdctrl_write hw/block/fdc.c:829:9 + #12 0x5626d1c20bc5 in portio_write softmmu/ioport.c:207:17 + + 0x619000062a00 is located 0 bytes to the right of 512-byte region [0x619000062800,0x619000062a00) + allocated by thread T0 here: + #0 0x5626d03c66ec in posix_memalign (qemu-system-i386+0x1e676ec) + #1 0x5626d2b988d4 in qemu_try_memalign util/oslib-posix.c:210:11 + #2 0x5626d2b98b0c in qemu_memalign util/oslib-posix.c:226:27 + #3 0x5626d09fbaf0 in fdctrl_realize_common hw/block/fdc.c:2341:20 + #4 0x5626d0a150ed in isabus_fdc_realize hw/block/fdc-isa.c:113:5 + #5 0x5626d2367935 in device_set_realized hw/core/qdev.c:531:13 + + SUMMARY: AddressSanitizer: heap-buffer-overflow (qemu-system-i386+0x1e65919) in __asan_memcpy + Shadow bytes around the buggy address: + 0x0c32800044f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0c3280004510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0c3280004520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0c3280004530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + =>0x0c3280004540:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004550: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004560: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004570: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c3280004590: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd + Shadow byte legend (one shadow byte represents 8 application bytes): + Addressable: 00 + Heap left redzone: fa + Freed heap region: fd + ==4028352==ABORTING + +[ kwolf: Added snapshot=on to prevent write file lock failure ] + +Reported-by: Alexander Bulekov +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alexander Bulekov +Signed-off-by: Kevin Wolf +--- + tests/qtest/fdc-test.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c +index 8f6eee84a4..6f5850354f 100644 +--- a/tests/qtest/fdc-test.c ++++ b/tests/qtest/fdc-test.c +@@ -583,6 +583,26 @@ static void test_cve_2021_20196(void) + qtest_quit(s); + } + ++static void test_cve_2021_3507(void) ++{ ++ QTestState *s; ++ ++ s = qtest_initf("-nographic -m 32M -nodefaults " ++ "-drive file=%s,format=raw,if=floppy,snapshot=on", ++ test_image); ++ qtest_outl(s, 0x9, 0x0a0206); ++ qtest_outw(s, 0x3f4, 0x1600); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0200); ++ qtest_outw(s, 0x3f4, 0x0200); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_quit(s); ++} ++ + int main(int argc, char **argv) + { + int fd; +@@ -614,6 +634,7 @@ int main(int argc, char **argv) + qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); + qtest_add_func("/fdc/fuzz-registers", fuzz_registers); + qtest_add_func("/fdc/fuzz/cve_2021_20196", test_cve_2021_20196); ++ qtest_add_func("/fdc/fuzz/cve_2021_3507", test_cve_2021_3507); + + ret = g_test_run(); + +-- +2.27.0 + diff --git a/tests-qtest-intel-hda-test-Add-reproducer-for-issue-.patch b/tests-qtest-intel-hda-test-Add-reproducer-for-issue-.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ecfe2aa4ec98853e60b17d0dd3fd0bb46d5b99d --- /dev/null +++ b/tests-qtest-intel-hda-test-Add-reproducer-for-issue-.patch @@ -0,0 +1,135 @@ +From 16c1b4c9124da1b1e5fe123c9c9df683372f64a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Sat, 18 Dec 2021 17:09:12 +0100 +Subject: [PATCH 25/25] tests/qtest/intel-hda-test: Add reproducer for issue + #542 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Include the qtest reproducer provided by Alexander Bulekov +in https://gitlab.com/qemu-project/qemu/-/issues/542. +Without the previous commit, we get: + + $ make check-qtest-i386 + ... + Running test tests/qtest/intel-hda-test + AddressSanitizer:DEADLYSIGNAL + ================================================================= + ==1580408==ERROR: AddressSanitizer: stack-overflow on address 0x7ffc3d566fe0 + #0 0x63d297cf in address_space_translate_internal softmmu/physmem.c:356 + #1 0x63d27260 in flatview_do_translate softmmu/physmem.c:499:15 + #2 0x63d27af5 in flatview_translate softmmu/physmem.c:565:15 + #3 0x63d4ce84 in flatview_write softmmu/physmem.c:2850:10 + #4 0x63d4cb18 in address_space_write softmmu/physmem.c:2950:18 + #5 0x63d4d387 in address_space_rw softmmu/physmem.c:2960:16 + #6 0x62ae12f2 in dma_memory_rw_relaxed include/sysemu/dma.h:89:12 + #7 0x62ae104a in dma_memory_rw include/sysemu/dma.h:132:12 + #8 0x62ae6157 in dma_memory_write include/sysemu/dma.h:173:12 + #9 0x62ae5ec0 in stl_le_dma include/sysemu/dma.h:275:1 + #10 0x62ae5ba2 in stl_le_pci_dma include/hw/pci/pci.h:871:1 + #11 0x62ad59a6 in intel_hda_response hw/audio/intel-hda.c:372:12 + #12 0x62ad2afb in hda_codec_response hw/audio/intel-hda.c:107:5 + #13 0x62aec4e1 in hda_audio_command hw/audio/hda-codec.c:655:5 + #14 0x62ae05d9 in intel_hda_send_command hw/audio/intel-hda.c:307:5 + #15 0x62adff54 in intel_hda_corb_run hw/audio/intel-hda.c:342:9 + #16 0x62adc13b in intel_hda_set_corb_wp hw/audio/intel-hda.c:548:5 + #17 0x62ae5942 in intel_hda_reg_write hw/audio/intel-hda.c:977:9 + #18 0x62ada10a in intel_hda_mmio_write hw/audio/intel-hda.c:1054:5 + #19 0x63d8f383 in memory_region_write_accessor softmmu/memory.c:492:5 + #20 0x63d8ecc1 in access_with_adjusted_size softmmu/memory.c:554:18 + #21 0x63d8d5d6 in memory_region_dispatch_write softmmu/memory.c:1504:16 + #22 0x63d5e85e in flatview_write_continue softmmu/physmem.c:2812:23 + #23 0x63d4d05b in flatview_write softmmu/physmem.c:2854:12 + #24 0x63d4cb18 in address_space_write softmmu/physmem.c:2950:18 + #25 0x63d4d387 in address_space_rw softmmu/physmem.c:2960:16 + #26 0x62ae12f2 in dma_memory_rw_relaxed include/sysemu/dma.h:89:12 + #27 0x62ae104a in dma_memory_rw include/sysemu/dma.h:132:12 + #28 0x62ae6157 in dma_memory_write include/sysemu/dma.h:173:12 + #29 0x62ae5ec0 in stl_le_dma include/sysemu/dma.h:275:1 + #30 0x62ae5ba2 in stl_le_pci_dma include/hw/pci/pci.h:871:1 + #31 0x62ad59a6 in intel_hda_response hw/audio/intel-hda.c:372:12 + #32 0x62ad2afb in hda_codec_response hw/audio/intel-hda.c:107:5 + #33 0x62aec4e1 in hda_audio_command hw/audio/hda-codec.c:655:5 + #34 0x62ae05d9 in intel_hda_send_command hw/audio/intel-hda.c:307:5 + #35 0x62adff54 in intel_hda_corb_run hw/audio/intel-hda.c:342:9 + #36 0x62adc13b in intel_hda_set_corb_wp hw/audio/intel-hda.c:548:5 + #37 0x62ae5942 in intel_hda_reg_write hw/audio/intel-hda.c:977:9 + #38 0x62ada10a in intel_hda_mmio_write hw/audio/intel-hda.c:1054:5 + #39 0x63d8f383 in memory_region_write_accessor softmmu/memory.c:492:5 + #40 0x63d8ecc1 in access_with_adjusted_size softmmu/memory.c:554:18 + #41 0x63d8d5d6 in memory_region_dispatch_write softmmu/memory.c:1504:16 + #42 0x63d5e85e in flatview_write_continue softmmu/physmem.c:2812:23 + #43 0x63d4d05b in flatview_write softmmu/physmem.c:2854:12 + #44 0x63d4cb18 in address_space_write softmmu/physmem.c:2950:18 + #45 0x63d4d387 in address_space_rw softmmu/physmem.c:2960:16 + #46 0x62ae12f2 in dma_memory_rw_relaxed include/sysemu/dma.h:89:12 + #47 0x62ae104a in dma_memory_rw include/sysemu/dma.h:132:12 + #48 0x62ae6157 in dma_memory_write include/sysemu/dma.h:173:12 + ... + SUMMARY: AddressSanitizer: stack-overflow softmmu/physmem.c:356 in address_space_translate_internal + ==1580408==ABORTING + Broken pipe + Aborted (core dumped) + +Signed-off-by: Philippe Mathieu-Daudé +Acked-by: Thomas Huth +Message-Id: <20211218160912.1591633-4-philmd@redhat.com> +Signed-off-by: Thomas Huth +--- + tests/qtest/intel-hda-test.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/tests/qtest/intel-hda-test.c b/tests/qtest/intel-hda-test.c +index fc25ccc33c..a58c98e4d1 100644 +--- a/tests/qtest/intel-hda-test.c ++++ b/tests/qtest/intel-hda-test.c +@@ -29,11 +29,45 @@ static void ich9_test(void) + qtest_end(); + } + ++/* ++ * https://gitlab.com/qemu-project/qemu/-/issues/542 ++ * Used to trigger: ++ * AddressSanitizer: stack-overflow ++ */ ++static void test_issue542_ich6(void) ++{ ++ QTestState *s; ++ ++ s = qtest_init("-nographic -nodefaults -M pc-q35-6.2 " ++ "-device intel-hda,id=" HDA_ID CODEC_DEVICES); ++ ++ qtest_outl(s, 0xcf8, 0x80000804); ++ qtest_outw(s, 0xcfc, 0x06); ++ qtest_bufwrite(s, 0xff0d060f, "\x03", 1); ++ qtest_bufwrite(s, 0x0, "\x12", 1); ++ qtest_bufwrite(s, 0x2, "\x2a", 1); ++ qtest_writeb(s, 0x0, 0x12); ++ qtest_writeb(s, 0x2, 0x2a); ++ qtest_outl(s, 0xcf8, 0x80000811); ++ qtest_outl(s, 0xcfc, 0x006a4400); ++ qtest_bufwrite(s, 0x6a44005a, "\x01", 1); ++ qtest_bufwrite(s, 0x6a44005c, "\x02", 1); ++ qtest_bufwrite(s, 0x6a442050, "\x00\x00\x44\x6a", 4); ++ qtest_bufwrite(s, 0x6a44204a, "\x01", 1); ++ qtest_bufwrite(s, 0x6a44204c, "\x02", 1); ++ qtest_bufwrite(s, 0x6a44005c, "\x02", 1); ++ qtest_bufwrite(s, 0x6a442050, "\x00\x00\x44\x6a", 4); ++ qtest_bufwrite(s, 0x6a44204a, "\x01", 1); ++ qtest_bufwrite(s, 0x6a44204c, "\x02", 1); ++ qtest_quit(s); ++} ++ + int main(int argc, char **argv) + { + g_test_init(&argc, &argv, NULL); + qtest_add_func("/intel-hda/ich6", ich6_test); + qtest_add_func("/intel-hda/ich9", ich9_test); ++ qtest_add_func("/intel-hda/fuzz/issue542", test_issue542_ich6); + + return g_test_run(); + } +-- +2.27.0 + diff --git a/tests-qtest-libqos-e1000e-Refer-common-PCI-ID-defini.patch b/tests-qtest-libqos-e1000e-Refer-common-PCI-ID-defini.patch new file mode 100644 index 0000000000000000000000000000000000000000..d6dff2b8a5afd350cde232d918016532593b03bc --- /dev/null +++ b/tests-qtest-libqos-e1000e-Refer-common-PCI-ID-defini.patch @@ -0,0 +1,49 @@ +From f2ee9b7314f8abea5634c4d92991e6b668577499 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Mon, 5 Dec 2022 14:47:00 +0800 +Subject: [PATCH 12/17] tests/qtest/libqos/e1000e: Refer common PCI ID + definitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is yet another minor cleanup to ease understanding and +future refactoring of the tests. + +Signed-off-by: Akihiko Odaki +Message-Id: <20221103015017.19947-1-akihiko.odaki@daynix.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Huth + +Signed-off-by: tangzhongrui +--- + tests/qtest/libqos/e1000e.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c +index a451f6168f..d351136975 100644 +--- a/tests/qtest/libqos/e1000e.c ++++ b/tests/qtest/libqos/e1000e.c +@@ -26,6 +26,8 @@ + #include "malloc.h" + #include "qgraph.h" + #include "e1000e.h" ++#include "hw/net/e1000_regs.h" ++#include "hw/pci/pci_ids.h" + + #define E1000E_IMS (0x00d0) + +@@ -248,8 +250,8 @@ static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc, + static void e1000e_register_nodes(void) + { + QPCIAddress addr = { +- .vendor_id = 0x8086, +- .device_id = 0x10D3, ++ .vendor_id = PCI_VENDOR_ID_INTEL, ++ .device_id = E1000_DEV_ID_82574L, + }; + + /* FIXME: every test using this node needs to setup a -netdev socket,id=hs0 +-- +2.27.0 + diff --git a/tests-qtest-migration-test.c-spelling-fix-bandwith.patch b/tests-qtest-migration-test.c-spelling-fix-bandwith.patch new file mode 100644 index 0000000000000000000000000000000000000000..93b57eb5e4c4f498d2f37084f65ec600ac685aa3 --- /dev/null +++ b/tests-qtest-migration-test.c-spelling-fix-bandwith.patch @@ -0,0 +1,26 @@ +From a13b274df192b01a2b8f3f5ca5497a330705caa3 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Fri, 24 Nov 2023 00:46:51 -0800 +Subject: [PATCH] tests/qtest/migration-test.c: spelling fix: bandwith + +Signed-off-by: zhujun2 +--- + tests/qtest/migration-test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c +index 8fad247f6c..3813b15ea9 100644 +--- a/tests/qtest/migration-test.c ++++ b/tests/qtest/migration-test.c +@@ -1157,7 +1157,7 @@ static void test_migrate_auto_converge(void) + + /* + * We want the test to be stable and as fast as possible. +- * E.g., with 1Gb/s bandwith migration may pass without throttling, ++ * E.g., with 1Gb/s bandwidth migration may pass without throttling, + * so we need to decrease a bandwidth. + */ + const int64_t init_pct = 5, inc_pct = 50, max_pct = 95; +-- +2.27.0 + diff --git a/tests-qtest-pflash-Clean-up-local-variable-shadowing.patch b/tests-qtest-pflash-Clean-up-local-variable-shadowing.patch new file mode 100644 index 0000000000000000000000000000000000000000..e33ee823b42036af2d8563e9fd81745e4594c80b --- /dev/null +++ b/tests-qtest-pflash-Clean-up-local-variable-shadowing.patch @@ -0,0 +1,45 @@ +From 42e516ba6969b8f61d7e5e45a4f48f257fecf8e1 Mon Sep 17 00:00:00 2001 +From: dinglimin_yewu +Date: Sat, 16 Sep 2023 17:56:31 +0800 +Subject: [PATCH] tests/qtest/pflash: Clean up local variable shadowing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 82fdcd3e140c8d4c63f177ece554f90f2bccdf68 + +Fix: + + tests/qtest/pflash-cfi02-test.c: In function ‘test_geometry’: + tests/qtest/pflash-cfi02-test.c:409:22: warning: declaration of ‘byte_addr’ shadows a previous local [-Wshadow=compatible-local] + 409 | uint64_t byte_addr = (uint64_t)i * c->sector_len[region]; + | ^~~~~~~~~ + tests/qtest/pflash-cfi02-test.c:342:14: note: shadowed declaration is here + 342 | uint64_t byte_addr = 0; + | ^~~~~~~~~ + +Signed-off-by: Philippe Mathieu-Daudé +Message-ID: <20230904162824.85385-4-philmd@linaro.org> +Reviewed-by: Peter Maydell +Signed-off-by: Thomas Huth +Signed-off-by: dinglimin_yewu +--- + tests/qtest/pflash-cfi02-test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qtest/pflash-cfi02-test.c b/tests/qtest/pflash-cfi02-test.c +index 6168edc821..bd1f946fc0 100644 +--- a/tests/qtest/pflash-cfi02-test.c ++++ b/tests/qtest/pflash-cfi02-test.c +@@ -406,7 +406,7 @@ static void test_geometry(const void *opaque) + + for (int region = 0; region < nb_erase_regions; ++region) { + for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) { +- uint64_t byte_addr = (uint64_t)i * c->sector_len[region]; ++ byte_addr = (uint64_t)i * c->sector_len[region]; + g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); + } + } +-- +2.41.0.windows.1 + diff --git a/tests-tcg-Fix-target-specific-Makefile-variables-pat.patch b/tests-tcg-Fix-target-specific-Makefile-variables-pat.patch new file mode 100644 index 0000000000000000000000000000000000000000..39091adf308a3a03339957a9595b93e7d4484c27 --- /dev/null +++ b/tests-tcg-Fix-target-specific-Makefile-variables-pat.patch @@ -0,0 +1,40 @@ +From 83f5dc3719af39ab442cb7fe40a4dd752a82e53a Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Mar 2023 02:22:44 +0000 +Subject: [PATCH] tests/tcg: Fix target-specific Makefile variables path for + user-mode mainline inclusion commit 533b0a1a41df3d9edeb44d6dc957f04d20ca143f + category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +Commit 812b31d3f91 refactor missed to update this path. + +Fixes: 812b31d3f91 ("configs: rename default-configs to configs and reorganise") +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211226001541.3807919-1-f4bug@amsat.org> +Signed-off-by: Paolo Bonzini + +Signed-off-by: tangbinzy +--- + tests/tcg/Makefile.target | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target +index 63cf1b2573..2d6ec70156 100644 +--- a/tests/tcg/Makefile.target ++++ b/tests/tcg/Makefile.target +@@ -33,7 +33,7 @@ all: + -include ../../../config-host.mak + -include ../config-$(TARGET).mak + ifeq ($(CONFIG_USER_ONLY),y) +--include $(SRC_PATH)/default-configs/targets/$(TARGET).mak ++-include $(SRC_PATH)/configs/targets/$(TARGET)/default.mak + endif + + # for including , in command strings +-- +2.27.0 + diff --git a/tests-tcg-fix-unused-variable-in-linux-test.patch b/tests-tcg-fix-unused-variable-in-linux-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..98796967d983d70ca356f1deba2d15a75a34cbd8 --- /dev/null +++ b/tests-tcg-fix-unused-variable-in-linux-test.patch @@ -0,0 +1,48 @@ +From 050aa274447899ecb000aa8d62d95b6c6192fc56 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 28 Jun 2023 10:08:22 +0800 +Subject: [PATCH] tests/tcg: fix unused variable in linux-test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 2bc6c79417b89c3306b724577e775f03fe61fb2e + +The latest hexagon compiler picks up that we never consume wcount. +Given the name of the #define that rcount checks against is WCOUNT_MAX +I figured the check just got missed. + +Signed-off-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20221221090411.1995037-5-alex.bennee@linaro.org> +Signed-off-by: qihao_yewu +--- + tests/tcg/multiarch/linux/linux-test.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/tests/tcg/multiarch/linux/linux-test.c b/tests/tcg/multiarch/linux/linux-test.c +index 019d8175ca..78c68540ef 100644 +--- a/tests/tcg/multiarch/linux/linux-test.c ++++ b/tests/tcg/multiarch/linux/linux-test.c +@@ -354,13 +354,17 @@ static void test_pipe(void) + if (FD_ISSET(fds[0], &rfds)) { + chk_error(read(fds[0], &ch, 1)); + rcount++; +- if (rcount >= WCOUNT_MAX) ++ if (rcount >= WCOUNT_MAX) { + break; ++ } + } + if (FD_ISSET(fds[1], &wfds)) { + ch = 'a'; + chk_error(write(fds[1], &ch, 1)); + wcount++; ++ if (wcount >= WCOUNT_MAX) { ++ break; ++ } + } + } + } +-- +2.41.0.windows.1 + diff --git a/tests-unit-fix-a-Wformat-truncation-warning.patch b/tests-unit-fix-a-Wformat-truncation-warning.patch new file mode 100644 index 0000000000000000000000000000000000000000..40fb8d09daa1fcbfd1e12fd5013aac15a3f994c1 --- /dev/null +++ b/tests-unit-fix-a-Wformat-truncation-warning.patch @@ -0,0 +1,53 @@ +From 133b578fabea9f4cc5936da233c04463bf94b6db Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Thu, 7 Dec 2023 09:20:00 +0800 +Subject: [PATCH] tests/unit: fix a -Wformat-truncation warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 6a54ac2a9737057dc19aa584d823a3011717423b + +../tests/test-qobject-input-visitor.c: In function ‘test_visitor_in_list’: +../tests/test-qobject-input-visitor.c:454:49: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 6 [-Wformat-truncation=] + 454 | snprintf(string, sizeof(string), "string%d", i); + | ^~ +../tests/test-qobject-input-visitor.c:454:42: note: directive argument in the range [0, 2147483606] + 454 | snprintf(string, sizeof(string), "string%d", i); + | ^~~~~~~~~~ +../tests/test-qobject-input-visitor.c:454:9: note: ‘snprintf’ output between 8 and 17 bytes into a destination of size 12 + 454 | snprintf(string, sizeof(string), "string%d", i); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rather than trying to be clever, since this is called 3 times during +tests, let's simply use g_strdup_printf(). + +Signed-off-by: Marc-André Lureau +Reviewed-by: Markus Armbruster +Message-id: 20220810121513.1356081-1-marcandre.lureau@redhat.com +Reviewed-by: Peter Maydell +[PMM: fixed commit message typos] +Signed-off-by: Peter Maydell +Signed-off-by: boringandboring +--- + tests/unit/test-qobject-input-visitor.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c +index 6f59a7f432..0f28d46a4a 100644 +--- a/tests/unit/test-qobject-input-visitor.c ++++ b/tests/unit/test-qobject-input-visitor.c +@@ -448,9 +448,8 @@ static void test_visitor_in_list(TestInputVisitorData *data, + g_assert(head != NULL); + + for (i = 0, item = head; item; item = item->next, i++) { +- char string[12]; ++ g_autofree char *string = g_strdup_printf("string%d", i); + +- snprintf(string, sizeof(string), "string%d", i); + g_assert_cmpstr(item->value->string, ==, string); + g_assert_cmpint(item->value->integer, ==, 42 + i); + } +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch b/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ea0e6cd48e1d0df115b00da2711627375e7b5fd --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-generic-invalid-ma.patch @@ -0,0 +1,87 @@ +From 9a98659dcb37c81e69f54d8f6cbe5116ceba5a36 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 15:44:07 +0100 +Subject: [PATCH 05/24] tests/unit/test-smp-parse: Add 'smp-generic-invalid' + machine type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid modifying the MachineClass internals by adding the +'smp-generic-invalid' machine, which inherits from TYPE_MACHINE. + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Message-Id: <20211216132015.815493-5-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index f66cf7bb59..47e11089e2 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,6 +487,17 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + ++static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ /* Force invalid min CPUs and max CPUs */ ++ mc->min_cpus = 2; ++ mc->max_cpus = 511; ++ ++ mc->smp_props.dies_supported = false; ++} ++ + static void machine_with_dies_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); +@@ -530,10 +541,6 @@ static void test_generic_invalid(const void *opaque) + SMPTestData *data = &(SMPTestData){}; + int i; + +- /* Force invalid min CPUs and max CPUs */ +- mc->min_cpus = 2; +- mc->max_cpus = 511; +- + for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { + *data = data_generic_invalid[i]; + unsupported_params_init(mc, data); +@@ -541,10 +548,6 @@ static void test_generic_invalid(const void *opaque) + smp_parse_test(ms, data, false); + } + +- /* Reset the supported min CPUs and max CPUs */ +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + object_unref(obj); + } + +@@ -606,6 +609,10 @@ static const TypeInfo smp_machine_types[] = { + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-generic-invalid"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_generic_invalid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-with-dies"), + .parent = TYPE_MACHINE, +@@ -625,7 +632,7 @@ int main(int argc, char *argv[]) + TYPE_MACHINE, + test_generic_valid); + g_test_add_data_func("/test-smp-parse/generic/invalid", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-generic-invalid"), + test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", + MACHINE_TYPE_NAME("smp-with-dies"), +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch b/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch new file mode 100644 index 0000000000000000000000000000000000000000..a8b17e751a578f914102e7911b820888227dbe54 --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-generic-valid-mach.patch @@ -0,0 +1,75 @@ +From c33c7dd51eebf5ae7b7ece1e829b0a5ffdcebfe1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 15:49:59 +0100 +Subject: [PATCH 06/24] tests/unit/test-smp-parse: Add 'smp-generic-valid' + machine type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Keep the common TYPE_MACHINE class initialization in +machine_base_class_init(), make it abstract, and move +the non-common code to a new class: "smp-generic-valid". + +Reviewed-by: Richard Henderson +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Yanan Wang +Message-Id: <20211216132015.815493-6-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 47e11089e2..b20bf2c235 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -478,13 +478,19 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + ++ mc->smp_props.prefer_sockets = true; ++ ++ mc->name = g_strdup(SMP_MACHINE_NAME); ++} ++ ++static void machine_generic_valid_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; + +- mc->smp_props.prefer_sockets = true; + mc->smp_props.dies_supported = false; +- +- mc->name = g_strdup(SMP_MACHINE_NAME); + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -606,9 +612,14 @@ static const TypeInfo smp_machine_types[] = { + { + .name = TYPE_MACHINE, + .parent = TYPE_OBJECT, ++ .abstract = true, + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-generic-valid"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_generic_valid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-generic-invalid"), + .parent = TYPE_MACHINE, +@@ -629,7 +640,7 @@ int main(int argc, char *argv[]) + g_test_init(&argc, &argv, NULL); + + g_test_add_data_func("/test-smp-parse/generic/valid", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-generic-valid"), + test_generic_valid); + g_test_add_data_func("/test-smp-parse/generic/invalid", + MACHINE_TYPE_NAME("smp-generic-invalid"), +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch b/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d779fc274a8d8140d71c76d165fd0ca5e0644da --- /dev/null +++ b/tests-unit-test-smp-parse-Add-smp-with-dies-machine-.patch @@ -0,0 +1,85 @@ +From 4981e75623db6ca681d13719ffcf61b0cfac3edc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:39:12 +0100 +Subject: [PATCH 04/24] tests/unit/test-smp-parse: Add 'smp-with-dies' machine + type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid modifying the MachineClass internals by adding the +'smp-with-dies' machine, which inherits from TYPE_MACHINE. + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-4-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 425ed6b6b9..f66cf7bb59 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,6 +487,16 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + ++static void machine_with_dies_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ mc->min_cpus = MIN_CPUS; ++ mc->max_cpus = MAX_CPUS; ++ ++ mc->smp_props.dies_supported = true; ++} ++ + static void test_generic_valid(const void *opaque) + { + const char *machine_type = opaque; +@@ -548,9 +558,6 @@ static void test_with_dies(const void *opaque) + unsigned int num_dies = 2; + int i; + +- /* Force the SMP compat properties */ +- mc->smp_props.dies_supported = true; +- + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data = data_generic_valid[i]; + unsupported_params_init(mc, data); +@@ -588,9 +595,6 @@ static void test_with_dies(const void *opaque) + smp_parse_test(ms, data, false); + } + +- /* Restore the SMP compat properties */ +- mc->smp_props.dies_supported = false; +- + object_unref(obj); + } + +@@ -602,6 +606,10 @@ static const TypeInfo smp_machine_types[] = { + .class_init = machine_base_class_init, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-with-dies"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_with_dies_class_init, + } + }; + +@@ -620,7 +628,7 @@ int main(int argc, char *argv[]) + TYPE_MACHINE, + test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", +- TYPE_MACHINE, ++ MACHINE_TYPE_NAME("smp-with-dies"), + test_with_dies); + + g_test_run(); +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch b/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9c9aefbb230a5b0fb05a8e7f9f03f2bf6592158 --- /dev/null +++ b/tests-unit-test-smp-parse-Add-testcases-for-CPU-clus.patch @@ -0,0 +1,254 @@ +From 5e8a39a560ea58308f66d47639c0d5d2e704997f Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:11 +0800 +Subject: [PATCH 12/24] tests/unit/test-smp-parse: Add testcases for CPU + clusters +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add testcases for parsing of the four-level CPU topology hierarchy, +ie sockets/clusters/cores/threads, which will be supported on ARM +virt machines. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-5-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 130 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 123 insertions(+), 7 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b6df8137fc..331719bbc4 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -61,6 +61,20 @@ + .has_maxcpus = hf, .maxcpus = f, \ + } + ++/* ++ * Currently a 4-level topology hierarchy is supported on ARM virt machines ++ * -sockets/clusters/cores/threads ++ */ ++#define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ ++ { \ ++ .has_cpus = ha, .cpus = a, \ ++ .has_sockets = hb, .sockets = b, \ ++ .has_clusters = hc, .clusters = c, \ ++ .has_cores = hd, .cores = d, \ ++ .has_threads = he, .threads = e, \ ++ .has_maxcpus = hf, .maxcpus = f, \ ++ } ++ + /** + * @config - the given SMP configuration + * @expect_prefer_sockets - the expected parsing result for the +@@ -290,6 +304,10 @@ static const struct SMPTestData data_generic_invalid[] = { + /* config: -smp 2,dies=2 */ + .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), + .expect_error = "dies not supported by this machine's CPU topology", ++ }, { ++ /* config: -smp 2,clusters=2 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), ++ .expect_error = "clusters not supported by this machine's CPU topology", + }, { + /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), +@@ -337,20 +355,40 @@ static const struct SMPTestData data_with_dies_invalid[] = { + }, + }; + ++static const struct SMPTestData data_with_clusters_invalid[] = { ++ { ++ /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), ++ .expect_error = "Invalid CPU topology: " ++ "product of the hierarchy must match maxcpus: " ++ "sockets (2) * clusters (2) * cores (4) * threads (2) " ++ "!= maxcpus (16)", ++ }, { ++ /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */ ++ .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), ++ .expect_error = "Invalid CPU topology: " ++ "maxcpus must be equal to or greater than smp: " ++ "sockets (2) * clusters (2) * cores (4) * threads (2) " ++ "== maxcpus (32) < smp_cpus (34)", ++ }, ++}; ++ + static char *smp_config_to_string(const SMPConfiguration *config) + { + return g_strdup_printf( + "(SMPConfiguration) {\n" +- " .has_cpus = %5s, cpus = %" PRId64 ",\n" +- " .has_sockets = %5s, sockets = %" PRId64 ",\n" +- " .has_dies = %5s, dies = %" PRId64 ",\n" +- " .has_cores = %5s, cores = %" PRId64 ",\n" +- " .has_threads = %5s, threads = %" PRId64 ",\n" +- " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" ++ " .has_cpus = %5s, cpus = %" PRId64 ",\n" ++ " .has_sockets = %5s, sockets = %" PRId64 ",\n" ++ " .has_dies = %5s, dies = %" PRId64 ",\n" ++ " .has_clusters = %5s, clusters = %" PRId64 ",\n" ++ " .has_cores = %5s, cores = %" PRId64 ",\n" ++ " .has_threads = %5s, threads = %" PRId64 ",\n" ++ " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" + "}", + config->has_cpus ? "true" : "false", config->cpus, + config->has_sockets ? "true" : "false", config->sockets, + config->has_dies ? "true" : "false", config->dies, ++ config->has_clusters ? "true" : "false", config->clusters, + config->has_cores ? "true" : "false", config->cores, + config->has_threads ? "true" : "false", config->threads, + config->has_maxcpus ? "true" : "false", config->maxcpus); +@@ -363,11 +401,12 @@ static char *cpu_topology_to_string(const CpuTopology *topo) + " .cpus = %u,\n" + " .sockets = %u,\n" + " .dies = %u,\n" ++ " .clusters = %u,\n" + " .cores = %u,\n" + " .threads = %u,\n" + " .max_cpus = %u,\n" + "}", +- topo->cpus, topo->sockets, topo->dies, ++ topo->cpus, topo->sockets, topo->dies, topo->clusters, + topo->cores, topo->threads, topo->max_cpus); + } + +@@ -391,6 +430,7 @@ static void check_parse(MachineState *ms, const SMPConfiguration *config, + (ms->smp.cpus == expect_topo->cpus) && + (ms->smp.sockets == expect_topo->sockets) && + (ms->smp.dies == expect_topo->dies) && ++ (ms->smp.clusters == expect_topo->clusters) && + (ms->smp.cores == expect_topo->cores) && + (ms->smp.threads == expect_topo->threads) && + (ms->smp.max_cpus == expect_topo->max_cpus)) { +@@ -472,6 +512,11 @@ static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) + data->expect_prefer_sockets.dies = 1; + data->expect_prefer_cores.dies = 1; + } ++ ++ if (!mc->smp_props.clusters_supported) { ++ data->expect_prefer_sockets.clusters = 1; ++ data->expect_prefer_cores.clusters = 1; ++ } + } + + static void machine_base_class_init(ObjectClass *oc, void *data) +@@ -491,6 +536,7 @@ static void machine_generic_valid_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = false; ++ mc->smp_props.clusters_supported = false; + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -502,6 +548,7 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) + mc->max_cpus = 511; + + mc->smp_props.dies_supported = false; ++ mc->smp_props.clusters_supported = false; + } + + static void machine_with_dies_class_init(ObjectClass *oc, void *data) +@@ -512,6 +559,18 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = true; ++ mc->smp_props.clusters_supported = false; ++} ++ ++static void machine_with_clusters_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ mc->min_cpus = MIN_CPUS; ++ mc->max_cpus = MAX_CPUS; ++ ++ mc->smp_props.clusters_supported = true; ++ mc->smp_props.dies_supported = false; + } + + static void test_generic_valid(const void *opaque) +@@ -607,6 +666,56 @@ static void test_with_dies(const void *opaque) + object_unref(obj); + } + ++static void test_with_clusters(const void *opaque) ++{ ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); ++ MachineState *ms = MACHINE(obj); ++ MachineClass *mc = MACHINE_GET_CLASS(obj); ++ SMPTestData data = {}; ++ unsigned int num_clusters = 2; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); ++ ++ /* when clusters parameter is omitted, it will be set as 1 */ ++ data.expect_prefer_sockets.clusters = 1; ++ data.expect_prefer_cores.clusters = 1; ++ ++ smp_parse_test(ms, &data, true); ++ ++ /* when clusters parameter is specified */ ++ data.config.has_clusters = true; ++ data.config.clusters = num_clusters; ++ if (data.config.has_cpus) { ++ data.config.cpus *= num_clusters; ++ } ++ if (data.config.has_maxcpus) { ++ data.config.maxcpus *= num_clusters; ++ } ++ ++ data.expect_prefer_sockets.clusters = num_clusters; ++ data.expect_prefer_sockets.cpus *= num_clusters; ++ data.expect_prefer_sockets.max_cpus *= num_clusters; ++ data.expect_prefer_cores.clusters = num_clusters; ++ data.expect_prefer_cores.cpus *= num_clusters; ++ data.expect_prefer_cores.max_cpus *= num_clusters; ++ ++ smp_parse_test(ms, &data, true); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) { ++ data = data_with_clusters_invalid[i]; ++ unsupported_params_init(mc, &data); ++ ++ smp_parse_test(ms, &data, false); ++ } ++ ++ object_unref(obj); ++} ++ + /* Type info of the tested machine */ + static const TypeInfo smp_machine_types[] = { + { +@@ -628,6 +737,10 @@ static const TypeInfo smp_machine_types[] = { + .name = MACHINE_TYPE_NAME("smp-with-dies"), + .parent = TYPE_MACHINE, + .class_init = machine_with_dies_class_init, ++ }, { ++ .name = MACHINE_TYPE_NAME("smp-with-clusters"), ++ .parent = TYPE_MACHINE, ++ .class_init = machine_with_clusters_class_init, + } + }; + +@@ -648,6 +761,9 @@ int main(int argc, char *argv[]) + g_test_add_data_func("/test-smp-parse/with_dies", + MACHINE_TYPE_NAME("smp-with-dies"), + test_with_dies); ++ g_test_add_data_func("/test-smp-parse/with_clusters", ++ MACHINE_TYPE_NAME("smp-with-clusters"), ++ test_with_clusters); + + g_test_run(); + +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch b/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch new file mode 100644 index 0000000000000000000000000000000000000000..85a56a425c7be042146bc96406b52e162a5544da --- /dev/null +++ b/tests-unit-test-smp-parse-Constify-some-pointer-stru.patch @@ -0,0 +1,82 @@ +From bcf4b802bd8971c0c5a255e606b15900cd47c6b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 10:23:06 +0100 +Subject: [PATCH 08/24] tests/unit/test-smp-parse: Constify some pointer/struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Declare structures const when we don't need to modify +them at runtime. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-8-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 395929b66c..0f98c9509e 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -83,7 +83,7 @@ typedef struct SMPTestData { + * then test the automatic calculation algorithm of the missing + * values in the parser. + */ +-static struct SMPTestData data_generic_valid[] = { ++static const struct SMPTestData data_generic_valid[] = { + { + /* config: no configuration provided + * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */ +@@ -285,7 +285,7 @@ static struct SMPTestData data_generic_valid[] = { + }, + }; + +-static struct SMPTestData data_generic_invalid[] = { ++static const struct SMPTestData data_generic_invalid[] = { + { + /* config: -smp 2,dies=2 */ + .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), +@@ -319,7 +319,7 @@ static struct SMPTestData data_generic_invalid[] = { + }, + }; + +-static struct SMPTestData data_with_dies_invalid[] = { ++static const struct SMPTestData data_with_dies_invalid[] = { + { + /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), +@@ -356,7 +356,7 @@ static char *smp_config_to_string(SMPConfiguration *config) + config->has_maxcpus ? "true" : "false", config->maxcpus); + } + +-static char *cpu_topology_to_string(CpuTopology *topo) ++static char *cpu_topology_to_string(const CpuTopology *topo) + { + return g_strdup_printf( + "(CpuTopology) {\n" +@@ -372,7 +372,7 @@ static char *cpu_topology_to_string(CpuTopology *topo) + } + + static void check_parse(MachineState *ms, SMPConfiguration *config, +- CpuTopology *expect_topo, const char *expect_err, ++ const CpuTopology *expect_topo, const char *expect_err, + bool is_valid) + { + g_autofree char *config_str = smp_config_to_string(config); +@@ -466,7 +466,7 @@ static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) + } + + /* The parsed results of the unsupported parameters should be 1 */ +-static void unsupported_params_init(MachineClass *mc, SMPTestData *data) ++static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) + { + if (!mc->smp_props.dies_supported) { + data->expect_prefer_sockets.dies = 1; +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch b/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e343576fdca6a1ef4713535849d6d9375c71cd9 --- /dev/null +++ b/tests-unit-test-smp-parse-Keep-default-MIN-MAX-CPUs-.patch @@ -0,0 +1,76 @@ +From 214511b1799b94cfd514a222d087bb888ed808ba Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:13 +0800 +Subject: [PATCH 14/24] tests/unit/test-smp-parse: Keep default MIN/MAX CPUs in + machine_base_class_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Most machine types in test-smp-parse will be OK to have the default +MIN/MAX CPUs except "smp-generic-invalid", let's keep the default +values in machine_base_class_init which will be inherited. And if +we hope a different value for a specific machine, modify it in its +own initialization function. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-7-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 72d83d1bbc..fdc39a846c 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -523,15 +523,10 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->name = g_strdup(SMP_MACHINE_NAME); +-} +- +-static void machine_generic_valid_class_init(ObjectClass *oc, void *data) +-{ +- MachineClass *mc = MACHINE_CLASS(oc); +- + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; ++ ++ mc->name = g_strdup(SMP_MACHINE_NAME); + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -547,9 +542,6 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + mc->smp_props.dies_supported = true; + } + +@@ -557,9 +549,6 @@ static void machine_with_clusters_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->min_cpus = MIN_CPUS; +- mc->max_cpus = MAX_CPUS; +- + mc->smp_props.clusters_supported = true; + } + +@@ -718,7 +707,6 @@ static const TypeInfo smp_machine_types[] = { + }, { + .name = MACHINE_TYPE_NAME("smp-generic-valid"), + .parent = TYPE_MACHINE, +- .class_init = machine_generic_valid_class_init, + }, { + .name = MACHINE_TYPE_NAME("smp-generic-invalid"), + .parent = TYPE_MACHINE, +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch b/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch new file mode 100644 index 0000000000000000000000000000000000000000..59157169c32a498e5ae0455aaaf6dd1312c4b17f --- /dev/null +++ b/tests-unit-test-smp-parse-No-need-to-explicitly-zero.patch @@ -0,0 +1,75 @@ +From 77bca7d51e99f8ba4d11635ff9f51615739f4d55 Mon Sep 17 00:00:00 2001 +From: Yanan Wang +Date: Tue, 28 Dec 2021 17:22:12 +0800 +Subject: [PATCH 13/24] tests/unit/test-smp-parse: No need to explicitly zero + MachineClass members +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The default value of the MachineClass members is 0, which +means we don't have to explicitly zero them. Also the value +of "mc->smp_props.prefer_sockets" will be taken care of by +smp_parse_test(), we don't necessarily need the statement +in machine_base_class_init() either. + +Signed-off-by: Yanan Wang +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211228092221.21068-6-wangyanan55@huawei.com> +Signed-off-by: Philippe Mathieu-Daudé +--- + tests/unit/test-smp-parse.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 331719bbc4..72d83d1bbc 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -523,8 +523,6 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + +- mc->smp_props.prefer_sockets = true; +- + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +@@ -534,9 +532,6 @@ static void machine_generic_valid_class_init(ObjectClass *oc, void *data) + + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; +- +- mc->smp_props.dies_supported = false; +- mc->smp_props.clusters_supported = false; + } + + static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +@@ -546,9 +541,6 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) + /* Force invalid min CPUs and max CPUs */ + mc->min_cpus = 2; + mc->max_cpus = 511; +- +- mc->smp_props.dies_supported = false; +- mc->smp_props.clusters_supported = false; + } + + static void machine_with_dies_class_init(ObjectClass *oc, void *data) +@@ -559,7 +551,6 @@ static void machine_with_dies_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.dies_supported = true; +- mc->smp_props.clusters_supported = false; + } + + static void machine_with_clusters_class_init(ObjectClass *oc, void *data) +@@ -570,7 +561,6 @@ static void machine_with_clusters_class_init(ObjectClass *oc, void *data) + mc->max_cpus = MAX_CPUS; + + mc->smp_props.clusters_supported = true; +- mc->smp_props.dies_supported = false; + } + + static void test_generic_valid(const void *opaque) +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch b/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch new file mode 100644 index 0000000000000000000000000000000000000000..d30509c63c2344dd3d7f27352b874426505be9c6 --- /dev/null +++ b/tests-unit-test-smp-parse-Pass-machine-type-as-argum.patch @@ -0,0 +1,69 @@ +From d8b2aee4fd6ccd8eb621522b647c392c1dd7955c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:32:09 +0100 +Subject: [PATCH 02/24] tests/unit/test-smp-parse: Pass machine type as + argument to tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use g_test_add_data_func() instead of g_test_add_func() so we can +pass the machine type to the tests (we will soon have different +machine types). + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-2-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b02450e25a..37c6b4981d 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,9 +487,10 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +-static void test_generic(void) ++static void test_generic(const void *opaque) + { +- Object *obj = object_new(TYPE_MACHINE); ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; +@@ -525,9 +526,10 @@ static void test_generic(void) + object_unref(obj); + } + +-static void test_with_dies(void) ++static void test_with_dies(const void *opaque) + { +- Object *obj = object_new(TYPE_MACHINE); ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; +@@ -599,8 +601,12 @@ int main(int argc, char *argv[]) + + g_test_init(&argc, &argv, NULL); + +- g_test_add_func("/test-smp-parse/generic", test_generic); +- g_test_add_func("/test-smp-parse/with_dies", test_with_dies); ++ g_test_add_data_func("/test-smp-parse/generic", ++ TYPE_MACHINE, ++ test_generic); ++ g_test_add_data_func("/test-smp-parse/with_dies", ++ TYPE_MACHINE, ++ test_with_dies); + + g_test_run(); + +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch b/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch new file mode 100644 index 0000000000000000000000000000000000000000..68cc318f4b2054ce0adf70d4d66b2a4d09ce16e0 --- /dev/null +++ b/tests-unit-test-smp-parse-Simplify-pointer-to-compou.patch @@ -0,0 +1,143 @@ +From 964965721bbed1941bf77e5a748efc1274b7c289 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 11 Nov 2021 08:58:40 +0100 +Subject: [PATCH 07/24] tests/unit/test-smp-parse: Simplify pointer to compound + literal use +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can simply use a local variable (and pass its pointer) instead +of a pointer to a compound literal. + +Reviewed-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Tested-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-7-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 66 ++++++++++++++++++------------------- + 1 file changed, 33 insertions(+), 33 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index b20bf2c235..395929b66c 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -520,19 +520,19 @@ static void test_generic_valid(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){{ }}; ++ SMPTestData data = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { +- *data = data_generic_valid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + + /* Unsupported parameters can be provided with their values as 1 */ +- data->config.has_dies = true; +- data->config.dies = 1; +- smp_parse_test(ms, data, true); ++ data.config.has_dies = true; ++ data.config.dies = 1; ++ smp_parse_test(ms, &data, true); + } + + object_unref(obj); +@@ -544,14 +544,14 @@ static void test_generic_invalid(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){}; ++ SMPTestData data = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { +- *data = data_generic_invalid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_invalid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, false); ++ smp_parse_test(ms, &data, false); + } + + object_unref(obj); +@@ -563,45 +563,45 @@ static void test_with_dies(const void *opaque) + Object *obj = object_new(machine_type); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); +- SMPTestData *data = &(SMPTestData){{ }}; ++ SMPTestData data = {}; + unsigned int num_dies = 2; + int i; + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { +- *data = data_generic_valid[i]; +- unsupported_params_init(mc, data); ++ data = data_generic_valid[i]; ++ unsupported_params_init(mc, &data); + + /* when dies parameter is omitted, it will be set as 1 */ +- data->expect_prefer_sockets.dies = 1; +- data->expect_prefer_cores.dies = 1; ++ data.expect_prefer_sockets.dies = 1; ++ data.expect_prefer_cores.dies = 1; + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + + /* when dies parameter is specified */ +- data->config.has_dies = true; +- data->config.dies = num_dies; +- if (data->config.has_cpus) { +- data->config.cpus *= num_dies; ++ data.config.has_dies = true; ++ data.config.dies = num_dies; ++ if (data.config.has_cpus) { ++ data.config.cpus *= num_dies; + } +- if (data->config.has_maxcpus) { +- data->config.maxcpus *= num_dies; ++ if (data.config.has_maxcpus) { ++ data.config.maxcpus *= num_dies; + } + +- data->expect_prefer_sockets.dies = num_dies; +- data->expect_prefer_sockets.cpus *= num_dies; +- data->expect_prefer_sockets.max_cpus *= num_dies; +- data->expect_prefer_cores.dies = num_dies; +- data->expect_prefer_cores.cpus *= num_dies; +- data->expect_prefer_cores.max_cpus *= num_dies; ++ data.expect_prefer_sockets.dies = num_dies; ++ data.expect_prefer_sockets.cpus *= num_dies; ++ data.expect_prefer_sockets.max_cpus *= num_dies; ++ data.expect_prefer_cores.dies = num_dies; ++ data.expect_prefer_cores.cpus *= num_dies; ++ data.expect_prefer_cores.max_cpus *= num_dies; + +- smp_parse_test(ms, data, true); ++ smp_parse_test(ms, &data, true); + } + + for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { +- *data = data_with_dies_invalid[i]; +- unsupported_params_init(mc, data); ++ data = data_with_dies_invalid[i]; ++ unsupported_params_init(mc, &data); + +- smp_parse_test(ms, data, false); ++ smp_parse_test(ms, &data, false); + } + + object_unref(obj); +-- +2.27.0 + diff --git a/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch b/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc13f6dfd02c8d576d0674a8ce577b5ed17c6588 --- /dev/null +++ b/tests-unit-test-smp-parse-Split-the-generic-test-in-.patch @@ -0,0 +1,71 @@ +From fad259cf9996dbc4001cb94ec3c846d649401027 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 15 Nov 2021 12:35:43 +0100 +Subject: [PATCH 03/24] tests/unit/test-smp-parse: Split the 'generic' test in + valid / invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Split the 'generic' test in two tests: 'valid' and 'invalid'. +This will allow us to remove the hack which modifies the +MachineClass internal state. + +Reviewed-by: Richard Henderson +Reviewed-by: Yanan Wang +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20211216132015.815493-3-philmd@redhat.com> +--- + tests/unit/test-smp-parse.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c +index 37c6b4981d..425ed6b6b9 100644 +--- a/tests/unit/test-smp-parse.c ++++ b/tests/unit/test-smp-parse.c +@@ -487,7 +487,7 @@ static void machine_base_class_init(ObjectClass *oc, void *data) + mc->name = g_strdup(SMP_MACHINE_NAME); + } + +-static void test_generic(const void *opaque) ++static void test_generic_valid(const void *opaque) + { + const char *machine_type = opaque; + Object *obj = object_new(machine_type); +@@ -508,6 +508,18 @@ static void test_generic(const void *opaque) + smp_parse_test(ms, data, true); + } + ++ object_unref(obj); ++} ++ ++static void test_generic_invalid(const void *opaque) ++{ ++ const char *machine_type = opaque; ++ Object *obj = object_new(machine_type); ++ MachineState *ms = MACHINE(obj); ++ MachineClass *mc = MACHINE_GET_CLASS(obj); ++ SMPTestData *data = &(SMPTestData){}; ++ int i; ++ + /* Force invalid min CPUs and max CPUs */ + mc->min_cpus = 2; + mc->max_cpus = 511; +@@ -601,9 +613,12 @@ int main(int argc, char *argv[]) + + g_test_init(&argc, &argv, NULL); + +- g_test_add_data_func("/test-smp-parse/generic", ++ g_test_add_data_func("/test-smp-parse/generic/valid", ++ TYPE_MACHINE, ++ test_generic_valid); ++ g_test_add_data_func("/test-smp-parse/generic/invalid", + TYPE_MACHINE, +- test_generic); ++ test_generic_invalid); + g_test_add_data_func("/test-smp-parse/with_dies", + TYPE_MACHINE, + test_with_dies); +-- +2.27.0 + diff --git a/tests-vhost-user-test-release-mutex-on-protocol-viol.patch b/tests-vhost-user-test-release-mutex-on-protocol-viol.patch new file mode 100644 index 0000000000000000000000000000000000000000..884be58c52bf4ede91fee6afdbd16b3f10bee9d7 --- /dev/null +++ b/tests-vhost-user-test-release-mutex-on-protocol-viol.patch @@ -0,0 +1,40 @@ +From b09ffbe7b85f891a8f5d425e5a98298a55c8400b Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Sun, 6 Aug 2023 23:48:47 -0700 +Subject: [PATCH] tests: vhost-user-test: release mutex on protocol violation + +cherry picked from commit 9260993e27cdbbd2e829d405cc63b1faefec6088 + +chr_read() is printing an error message and returning with s->data_mutex taken. +This can potentially cause a hang. Reported by Coverity. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Wanghe Xiao +--- + tests/qtest/vhost-user-test.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c +index 3d6337fb5c..d07babc06d 100644 +--- a/tests/qtest/vhost-user-test.c ++++ b/tests/qtest/vhost-user-test.c +@@ -328,7 +328,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + if (size != msg.size) { + g_test_message("Wrong message size received %d != %d", + size, msg.size); +- return; ++ goto out; + } + } + +@@ -429,6 +429,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + break; + } + ++out: + g_mutex_unlock(&s->data_mutex); + } + +-- +2.41.0.windows.1 + diff --git a/tests-vm-use-o-IdentitiesOnly-yes-for-ssh.patch b/tests-vm-use-o-IdentitiesOnly-yes-for-ssh.patch new file mode 100644 index 0000000000000000000000000000000000000000..f528b6a77f8923e68da6e47f333677cac09f924c --- /dev/null +++ b/tests-vm-use-o-IdentitiesOnly-yes-for-ssh.patch @@ -0,0 +1,35 @@ +From 09ebd704c71b855a1c5732d4e4816aa9aed3fe13 Mon Sep 17 00:00:00 2001 +From: jianchunfu +Date: Tue, 22 Nov 2022 16:47:27 +0800 +Subject: [PATCH 02/29] tests/vm: use -o IdentitiesOnly=yes for ssh + +When one has a lot of keys in ~/.ssh directory, the ssh command will +try all of them before the one specified on the command line, and this +may cause the remote ssh server to reject the connection due to too +many failed authentication attempts. +Fix by adding -o IdentitiesOnly=yes, which makes the ssh client +consider only the keys specified on the command line. + +Signed-off-by: Ilya Leoshkevich +Signed-off-by: jianchunfu +--- + tests/vm/basevm.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py +index 254e11c932..4003bc5fef 100644 +--- a/tests/vm/basevm.py ++++ b/tests/vm/basevm.py +@@ -228,7 +228,8 @@ def _ssh_do(self, user, cmd, check): + "-o", "UserKnownHostsFile=" + os.devnull, + "-o", + "ConnectTimeout={}".format(self._config["ssh_timeout"]), +- "-p", str(self.ssh_port), "-i", self._ssh_tmp_key_file] ++ "-p", str(self.ssh_port), "-i", self._ssh_tmp_key_file, ++ "-o", "IdentitiesOnly=yes"] + # If not in debug mode, set ssh to quiet mode to + # avoid printing the results of commands. + if not self.debug: +-- +2.27.0 + diff --git a/thread-pool-optimize-scheduling-of-completion-bottom.patch b/thread-pool-optimize-scheduling-of-completion-bottom.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd24a4ee963a6e36db6bfce81b671b57c11b01b1 --- /dev/null +++ b/thread-pool-optimize-scheduling-of-completion-bottom.patch @@ -0,0 +1,45 @@ +From c84bb01c0c56cadb70a95c874b32ed85b8177504 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 26 Sep 2023 06:41:50 +0000 +Subject: [PATCH] thread-pool: optimize scheduling of completion bottom half + mainline inclusion commit 3c7b72ddca9ce85a9d1e8a98fd0996b74597b5ae category: + bugfix + +--------------------------------------------------------------- + +The completion bottom half was scheduled within the pool->lock +critical section. That actually results in worse performance, +because the worker thread can run its own small critical section +and go to sleep before the bottom half starts running. + +Note that this simple change does not produce an improvement without +changing the thread pool QemuSemaphore to a condition variable. + +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Nicolas Saenz Julienne +Message-Id: <20220514065012.1149539-2-pbonzini@redhat.com> +Signed-off-by: Paolo Bonzini + +Signed-off-by: tangbinzy +--- + util/thread-pool.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/util/thread-pool.c b/util/thread-pool.c +index d763cea505..7e9e2c178b 100644 +--- a/util/thread-pool.c ++++ b/util/thread-pool.c +@@ -108,9 +108,8 @@ static void *worker_thread(void *opaque) + smp_wmb(); + req->state = THREAD_DONE; + +- qemu_mutex_lock(&pool->lock); +- + qemu_bh_schedule(pool->completion_bh); ++ qemu_mutex_lock(&pool->lock); + } + + pool->cur_threads--; +-- +2.41.0.windows.1 + diff --git a/tools-virtiofsd-Add-rseq-syscall-to-the-seccomp-allo.patch b/tools-virtiofsd-Add-rseq-syscall-to-the-seccomp-allo.patch new file mode 100644 index 0000000000000000000000000000000000000000..b59ef0fb1cc4fb68c6f5fd1d148e4d4cf3cd7d76 --- /dev/null +++ b/tools-virtiofsd-Add-rseq-syscall-to-the-seccomp-allo.patch @@ -0,0 +1,58 @@ +From 5ca1beec7030b5d9fea36eb4f037d4e0e6c260bd Mon Sep 17 00:00:00 2001 +From: Christian Ehrhardt +Date: Wed, 9 Feb 2022 12:14:56 +0100 +Subject: [PATCH] tools/virtiofsd: Add rseq syscall to the seccomp allowlist + +The virtiofsd currently crashes when used with glibc 2.35. +That is due to the rseq system call being added to every thread +creation [1][2]. + +[1]: https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/ +[2]: https://sourceware.org/pipermail/libc-alpha/2022-February/136040.html + +This happens not at daemon start, but when a guest connects + + /usr/lib/qemu/virtiofsd -f --socket-path=/tmp/testvfsd -o sandbox=chroot \ + -o source=/var/guests/j-virtiofs --socket-group=kvm + virtio_session_mount: Waiting for vhost-user socket connection... + # start ok, now guest will connect + virtio_session_mount: Received vhost-user socket connection + virtio_loop: Entry + fv_queue_set_started: qidx=0 started=1 + fv_queue_set_started: qidx=1 started=1 + Bad system call (core dumped) + +We have to put rseq on the seccomp allowlist to avoid that the daemon +is crashing in this case. + +Reported-by: Michael Hudson-Doyle +Signed-off-by: Christian Ehrhardt +Reviewed-by: Dr. David Alan Gilbert +Message-id: 20220209111456.3328420-1-christian.ehrhardt@canonical.com + +[Moved rseq to its alphabetically ordered position in the seccomp +allowlist. +--Stefan] +Signed-off-by: Stefan Hajnoczi +Signed-off-by: qinyu +--- + tools/virtiofsd/passthrough_seccomp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c +index a3ce9f898d..2bc0127b69 100644 +--- a/tools/virtiofsd/passthrough_seccomp.c ++++ b/tools/virtiofsd/passthrough_seccomp.c +@@ -91,6 +91,9 @@ static const int syscall_allowlist[] = { + SCMP_SYS(renameat2), + SCMP_SYS(removexattr), + SCMP_SYS(restart_syscall), ++#ifdef __NR_rseq ++ SCMP_SYS(rseq), /* required since glibc 2.35 */ ++#endif + SCMP_SYS(rt_sigaction), + SCMP_SYS(rt_sigprocmask), + SCMP_SYS(rt_sigreturn), +-- +2.27.0 + diff --git a/tpm-Add-the-SysBus-TPM-TIS-device.patch b/tpm-Add-the-SysBus-TPM-TIS-device.patch deleted file mode 100644 index e0a6254025932eb942b3a15d16b66d4808a33f42..0000000000000000000000000000000000000000 --- a/tpm-Add-the-SysBus-TPM-TIS-device.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 4fe655326eeae322b621dcc25c53af722d2e1afa Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Tue, 11 Aug 2020 11:23:34 +0800 -Subject: [PATCH 14/19] tpm: Add the SysBus TPM TIS device - -Introduce the tpm-tis-device which is a sysbus device -and is bound to be used on ARM. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-6-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - hw/tpm/Kconfig | 5 ++ - hw/tpm/Makefile.objs | 1 + - hw/tpm/tpm_tis_sysbus.c | 159 ++++++++++++++++++++++++++++++++++++++++ - include/sysemu/tpm.h | 1 + - 4 files changed, 166 insertions(+) - create mode 100644 hw/tpm/tpm_tis_sysbus.c - -diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig -index 686f8206..4794e7fe 100644 ---- a/hw/tpm/Kconfig -+++ b/hw/tpm/Kconfig -@@ -7,6 +7,11 @@ config TPM_TIS_ISA - depends on TPM && ISA_BUS - select TPM_TIS - -+config TPM_TIS_SYSBUS -+ bool -+ depends on TPM -+ select TPM_TIS -+ - config TPM_TIS - bool - depends on TPM -diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs -index 3ef2036c..f1ec4beb 100644 ---- a/hw/tpm/Makefile.objs -+++ b/hw/tpm/Makefile.objs -@@ -1,6 +1,7 @@ - common-obj-$(CONFIG_TPM) += tpm_util.o - obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o - common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o -+common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o - common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o - common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o - common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o -diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c -new file mode 100644 -index 00000000..18c02aed ---- /dev/null -+++ b/hw/tpm/tpm_tis_sysbus.c -@@ -0,0 +1,159 @@ -+/* -+ * tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device -+ * -+ * Copyright (C) 2006,2010-2013 IBM Corporation -+ * -+ * Authors: -+ * Stefan Berger -+ * David Safford -+ * -+ * Xen 4 support: Andrease Niederl -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ * Implementation of the TIS interface according to specs found at -+ * http://www.trustedcomputinggroup.org. This implementation currently -+ * supports version 1.3, 21 March 2013 -+ * In the developers menu choose the PC Client section then find the TIS -+ * specification. -+ * -+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform -+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/qdev-properties.h" -+#include "migration/vmstate.h" -+#include "tpm_util.h" -+#include "hw/sysbus.h" -+#include "tpm_tis.h" -+ -+typedef struct TPMStateSysBus { -+ /*< private >*/ -+ SysBusDevice parent_obj; -+ -+ /*< public >*/ -+ TPMState state; /* not a QOM object */ -+} TPMStateSysBus; -+ -+#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS) -+ -+static int tpm_tis_pre_save_sysbus(void *opaque) -+{ -+ TPMStateSysBus *sbdev = opaque; -+ -+ return tpm_tis_pre_save(&sbdev->state); -+} -+ -+static const VMStateDescription vmstate_tpm_tis_sysbus = { -+ .name = "tpm-tis", -+ .version_id = 0, -+ .pre_save = tpm_tis_pre_save_sysbus, -+ .fields = (VMStateField[]) { -+ VMSTATE_BUFFER(state.buffer, TPMStateSysBus), -+ VMSTATE_UINT16(state.rw_offset, TPMStateSysBus), -+ VMSTATE_UINT8(state.active_locty, TPMStateSysBus), -+ VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus), -+ VMSTATE_UINT8(state.next_locty, TPMStateSysBus), -+ -+ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES, -+ 0, vmstate_locty, TPMLocality), -+ -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret) -+{ -+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); -+ TPMState *s = &sbdev->state; -+ -+ tpm_tis_request_completed(s, ret); -+} -+ -+static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti) -+{ -+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); -+ TPMState *s = &sbdev->state; -+ -+ return tpm_tis_get_tpm_version(s); -+} -+ -+static void tpm_tis_sysbus_reset(DeviceState *dev) -+{ -+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); -+ TPMState *s = &sbdev->state; -+ -+ return tpm_tis_reset(s); -+} -+ -+static Property tpm_tis_sysbus_properties[] = { -+ DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), -+ DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), -+ DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static void tpm_tis_sysbus_initfn(Object *obj) -+{ -+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj); -+ TPMState *s = &sbdev->state; -+ -+ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, -+ s, "tpm-tis-mmio", -+ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); -+ -+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); -+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); -+} -+ -+static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) -+{ -+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); -+ TPMState *s = &sbdev->state; -+ -+ if (!tpm_find()) { -+ error_setg(errp, "at most one TPM device is permitted"); -+ return; -+ } -+ -+ if (!s->be_driver) { -+ error_setg(errp, "'tpmdev' property is required"); -+ return; -+ } -+} -+ -+static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ TPMIfClass *tc = TPM_IF_CLASS(klass); -+ -+ dc->props = tpm_tis_sysbus_properties; -+ dc->vmsd = &vmstate_tpm_tis_sysbus; -+ tc->model = TPM_MODEL_TPM_TIS; -+ dc->realize = tpm_tis_sysbus_realizefn; -+ dc->user_creatable = true; -+ dc->reset = tpm_tis_sysbus_reset; -+ tc->request_completed = tpm_tis_sysbus_request_completed; -+ tc->get_version = tpm_tis_sysbus_get_tpm_version; -+} -+ -+static const TypeInfo tpm_tis_sysbus_info = { -+ .name = TYPE_TPM_TIS_SYSBUS, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(TPMStateSysBus), -+ .instance_init = tpm_tis_sysbus_initfn, -+ .class_init = tpm_tis_sysbus_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_TPM_IF }, -+ { } -+ } -+}; -+ -+static void tpm_tis_sysbus_register(void) -+{ -+ type_register_static(&tpm_tis_sysbus_info); -+} -+ -+type_init(tpm_tis_sysbus_register) -diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h -index 1691b92c..f37851b1 100644 ---- a/include/sysemu/tpm.h -+++ b/include/sysemu/tpm.h -@@ -44,6 +44,7 @@ typedef struct TPMIfClass { - } TPMIfClass; - - #define TYPE_TPM_TIS_ISA "tpm-tis" -+#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device" - #define TYPE_TPM_CRB "tpm-crb" - #define TYPE_TPM_SPAPR "tpm-spapr" - --- -2.23.0 - diff --git a/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch deleted file mode 100644 index 93139b5e7f8284cecf6faa9930eaa8e802db13d9..0000000000000000000000000000000000000000 --- a/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch +++ /dev/null @@ -1,146 +0,0 @@ -From c6cf45f38cb6e28cf4db42296fedcd5f26ca610b Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Tue, 21 Jan 2020 10:29:30 -0500 -Subject: [PATCH 03/19] tpm: Move tpm_tis_show_buffer to tpm_util.c -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Stefan Berger -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: David Gibson -Message-Id: <20200121152935.649898-2-stefanb@linux.ibm.com> -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - hw/tpm/tpm_tis.c | 32 ++++---------------------------- - hw/tpm/tpm_util.c | 25 +++++++++++++++++++++++++ - hw/tpm/tpm_util.h | 3 +++ - hw/tpm/trace-events | 2 +- - 4 files changed, 33 insertions(+), 29 deletions(-) - -diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c -index d6b32128..96a9ac48 100644 ---- a/hw/tpm/tpm_tis.c -+++ b/hw/tpm/tpm_tis.c -@@ -104,30 +104,6 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) - return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); - } - --static void tpm_tis_show_buffer(const unsigned char *buffer, -- size_t buffer_size, const char *string) --{ -- size_t len, i; -- char *line_buffer, *p; -- -- len = MIN(tpm_cmd_get_size(buffer), buffer_size); -- -- /* -- * allocate enough room for 3 chars per buffer entry plus a -- * newline after every 16 chars and a final null terminator. -- */ -- line_buffer = g_malloc(len * 3 + (len / 16) + 1); -- -- for (i = 0, p = line_buffer; i < len; i++) { -- if (i && !(i % 16)) { -- p += sprintf(p, "\n"); -- } -- p += sprintf(p, "%.2X ", buffer[i]); -- } -- trace_tpm_tis_show_buffer(string, len, line_buffer); -- -- g_free(line_buffer); --} - - /* - * Set the given flags in the STS register by clearing the register but -@@ -153,8 +129,8 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) - */ - static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) - { -- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { -- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); -+ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); - } - - /* -@@ -322,8 +298,8 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret) - s->loc[locty].state = TPM_TIS_STATE_COMPLETION; - s->rw_offset = 0; - -- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { -- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); -+ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); - } - - if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { -diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c -index ee41757e..8643eb50 100644 ---- a/hw/tpm/tpm_util.c -+++ b/hw/tpm/tpm_util.c -@@ -350,3 +350,28 @@ void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) - tsb->buffer = NULL; - tsb->size = 0; - } -+ -+void tpm_util_show_buffer(const unsigned char *buffer, -+ size_t buffer_size, const char *string) -+{ -+ size_t len, i; -+ char *line_buffer, *p; -+ -+ len = MIN(tpm_cmd_get_size(buffer), buffer_size); -+ -+ /* -+ * allocate enough room for 3 chars per buffer entry plus a -+ * newline after every 16 chars and a final null terminator. -+ */ -+ line_buffer = g_malloc(len * 3 + (len / 16) + 1); -+ -+ for (i = 0, p = line_buffer; i < len; i++) { -+ if (i && !(i % 16)) { -+ p += sprintf(p, "\n"); -+ } -+ p += sprintf(p, "%.2X ", buffer[i]); -+ } -+ trace_tpm_util_show_buffer(string, len, line_buffer); -+ -+ g_free(line_buffer); -+} -diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h -index f397ac21..7889081f 100644 ---- a/hw/tpm/tpm_util.h -+++ b/hw/tpm/tpm_util.h -@@ -79,4 +79,7 @@ typedef struct TPMSizedBuffer { - - void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); - -+void tpm_util_show_buffer(const unsigned char *buffer, -+ size_t buffer_size, const char *string); -+ - #endif /* TPM_TPM_UTIL_H */ -diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events -index 0b94aa15..82c45ee5 100644 ---- a/hw/tpm/trace-events -+++ b/hw/tpm/trace-events -@@ -14,6 +14,7 @@ tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, - tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" - tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" - tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" -+tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" - - # tpm_emulator.c - tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" -@@ -36,7 +37,6 @@ tpm_emulator_pre_save(void) "" - tpm_emulator_inst_init(void) "" - - # tpm_tis.c --tpm_tis_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\nbuf: %s" - tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" - tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" - tpm_tis_abort(uint8_t locty) "New active locality is %d" --- -2.23.0 - diff --git a/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch deleted file mode 100644 index 97dcaa000b251bd8a4390a5c68e75011aef9401f..0000000000000000000000000000000000000000 --- a/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 1eca7dbacabbc8ccc737f320839e7800fef5dfa1 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Tue, 11 Aug 2020 12:42:31 +0800 -Subject: [PATCH 13/19] tpm: Separate TPM_TIS and TPM_TIS_ISA configs - 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 - -Let's separate the compilation of tpm_tis_common.c from -the compilation of tpm_tis_isa.c - -The common part will be also compiled along with the -tpm_tis_sysbus device. - -Signed-off-by: Eric Auger -Reviewed-by: Philippe Mathieu-Daudé -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-5-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - default-configs/i386-softmmu.mak | 2 +- - hw/i386/Kconfig | 2 +- - hw/tpm/Kconfig | 7 ++++++- - hw/tpm/Makefile.objs | 3 ++- - tests/Makefile.include | 4 ++-- - 5 files changed, 12 insertions(+), 6 deletions(-) - -diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak -index cd5ea391..bdeef670 100644 ---- a/default-configs/i386-softmmu.mak -+++ b/default-configs/i386-softmmu.mak -@@ -17,7 +17,7 @@ - #CONFIG_SGA=n - #CONFIG_TEST_DEVICES=n - #CONFIG_TPM_CRB=n --#CONFIG_TPM_TIS=n -+#CONFIG_TPM_TIS_ISA=n - #CONFIG_VTD=n - - # Boards: -diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index 63504380..60334504 100644 ---- a/hw/i386/Kconfig -+++ b/hw/i386/Kconfig -@@ -17,7 +17,7 @@ config PC - imply SGA - imply TEST_DEVICES - imply TPM_CRB -- imply TPM_TIS -+ imply TPM_TIS_ISA - imply VGA_PCI - imply VIRTIO_VGA - select FDC -diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig -index 9e67d990..686f8206 100644 ---- a/hw/tpm/Kconfig -+++ b/hw/tpm/Kconfig -@@ -2,9 +2,14 @@ config TPMDEV - bool - depends on TPM - --config TPM_TIS -+config TPM_TIS_ISA - bool - depends on TPM && ISA_BUS -+ select TPM_TIS -+ -+config TPM_TIS -+ bool -+ depends on TPM - select TPMDEV - - config TPM_CRB -diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs -index fcc4c2f2..3ef2036c 100644 ---- a/hw/tpm/Makefile.objs -+++ b/hw/tpm/Makefile.objs -@@ -1,6 +1,7 @@ - common-obj-$(CONFIG_TPM) += tpm_util.o - obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o --common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o -+common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o -+common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o - common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o - common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o - common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o -diff --git a/tests/Makefile.include b/tests/Makefile.include -index f3273ad3..c151de64 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -190,8 +190,8 @@ check-qtest-i386-y += tests/q35-test$(EXESUF) - check-qtest-i386-y += tests/vmgenid-test$(EXESUF) - check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) - check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) --check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) --check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-test$(EXESUF) -+check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-swtpm-test$(EXESUF) -+check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-test$(EXESUF) - check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) - check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) - check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) --- -2.23.0 - diff --git a/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch b/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch deleted file mode 100644 index 32f180c98d784b1478268a768b4caed6c8a3fa23..0000000000000000000000000000000000000000 --- a/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch +++ /dev/null @@ -1,1194 +0,0 @@ -From 425f6bc8392c71d2f29b572d19232785d0ab0b73 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Tue, 11 Aug 2020 02:55:35 +0000 -Subject: [PATCH 12/19] tpm: Separate tpm_tis common functions from isa code - -Move the device agnostic code into tpm_tis_common.c and -put the ISA device specific code into tpm_tis_isa.c - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-4-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - hw/tpm/Makefile.objs | 2 +- - hw/tpm/{tpm_tis.c => tpm_tis.c.orig} | 0 - hw/tpm/tpm_tis.h | 91 +++ - hw/tpm/tpm_tis_common.c | 869 +++++++++++++++++++++++++++ - hw/tpm/tpm_tis_isa.c | 170 ++++++ - 5 files changed, 1131 insertions(+), 1 deletion(-) - rename hw/tpm/{tpm_tis.c => tpm_tis.c.orig} (100%) - create mode 100644 hw/tpm/tpm_tis.h - create mode 100644 hw/tpm/tpm_tis_common.c - create mode 100644 hw/tpm/tpm_tis_isa.c - -diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs -index 85eb99ae..fcc4c2f2 100644 ---- a/hw/tpm/Makefile.objs -+++ b/hw/tpm/Makefile.objs -@@ -1,6 +1,6 @@ - common-obj-$(CONFIG_TPM) += tpm_util.o - obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o --common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o -+common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o - common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o - common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o - common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o -diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c.orig -similarity index 100% -rename from hw/tpm/tpm_tis.c -rename to hw/tpm/tpm_tis.c.orig -diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h -new file mode 100644 -index 00000000..55549893 ---- /dev/null -+++ b/hw/tpm/tpm_tis.h -@@ -0,0 +1,91 @@ -+/* -+ * tpm_tis.h - QEMU's TPM TIS common header -+ * -+ * Copyright (C) 2006,2010-2013 IBM Corporation -+ * -+ * Authors: -+ * Stefan Berger -+ * David Safford -+ * -+ * Xen 4 support: Andrease Niederl -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ * Implementation of the TIS interface according to specs found at -+ * http://www.trustedcomputinggroup.org. This implementation currently -+ * supports version 1.3, 21 March 2013 -+ * In the developers menu choose the PC Client section then find the TIS -+ * specification. -+ * -+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform -+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 -+ */ -+#ifndef TPM_TPM_TIS_H -+#define TPM_TPM_TIS_H -+ -+#include "qemu/osdep.h" -+#include "sysemu/tpm_backend.h" -+#include "tpm_ppi.h" -+ -+#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ -+#define TPM_TIS_LOCALITY_SHIFT 12 -+#define TPM_TIS_NO_LOCALITY 0xff -+ -+#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) -+ -+#define TPM_TIS_BUFFER_MAX 4096 -+ -+typedef enum { -+ TPM_TIS_STATE_IDLE = 0, -+ TPM_TIS_STATE_READY, -+ TPM_TIS_STATE_COMPLETION, -+ TPM_TIS_STATE_EXECUTION, -+ TPM_TIS_STATE_RECEPTION, -+} TPMTISState; -+ -+/* locality data -- all fields are persisted */ -+typedef struct TPMLocality { -+ TPMTISState state; -+ uint8_t access; -+ uint32_t sts; -+ uint32_t iface_id; -+ uint32_t inte; -+ uint32_t ints; -+} TPMLocality; -+ -+typedef struct TPMState { -+ MemoryRegion mmio; -+ -+ unsigned char buffer[TPM_TIS_BUFFER_MAX]; -+ uint16_t rw_offset; -+ -+ uint8_t active_locty; -+ uint8_t aborting_locty; -+ uint8_t next_locty; -+ -+ TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; -+ -+ qemu_irq irq; -+ uint32_t irq_num; -+ -+ TPMBackendCmd cmd; -+ -+ TPMBackend *be_driver; -+ TPMVersion be_tpm_version; -+ -+ size_t be_buffer_size; -+ -+ bool ppi_enabled; -+ TPMPPI ppi; -+} TPMState; -+ -+extern const VMStateDescription vmstate_locty; -+extern const MemoryRegionOps tpm_tis_memory_ops; -+ -+int tpm_tis_pre_save(TPMState *s); -+void tpm_tis_reset(TPMState *s); -+enum TPMVersion tpm_tis_get_tpm_version(TPMState *s); -+void tpm_tis_request_completed(TPMState *s, int ret); -+ -+#endif /* TPM_TPM_TIS_H */ -diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c -new file mode 100644 -index 00000000..9a51c71e ---- /dev/null -+++ b/hw/tpm/tpm_tis_common.c -@@ -0,0 +1,869 @@ -+/* -+ * tpm_tis_common.c - QEMU's TPM TIS interface emulator -+ * device agnostic functions -+ * -+ * Copyright (C) 2006,2010-2013 IBM Corporation -+ * -+ * Authors: -+ * Stefan Berger -+ * David Safford -+ * -+ * Xen 4 support: Andrease Niederl -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ * Implementation of the TIS interface according to specs found at -+ * http://www.trustedcomputinggroup.org. This implementation currently -+ * supports version 1.3, 21 March 2013 -+ * In the developers menu choose the PC Client section then find the TIS -+ * specification. -+ * -+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform -+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 -+ */ -+#include "qemu/osdep.h" -+#include "hw/isa/isa.h" -+#include "qapi/error.h" -+#include "qemu/module.h" -+ -+#include "hw/acpi/tpm.h" -+#include "hw/pci/pci_ids.h" -+#include "sysemu/tpm_backend.h" -+#include "tpm_int.h" -+#include "tpm_util.h" -+#include "tpm_ppi.h" -+#include "trace.h" -+ -+#include "tpm_tis.h" -+ -+#define DEBUG_TIS 0 -+ -+/* local prototypes */ -+ -+static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, -+ unsigned size); -+ -+/* utility functions */ -+ -+static uint8_t tpm_tis_locality_from_addr(hwaddr addr) -+{ -+ return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); -+} -+ -+ -+/* -+ * Set the given flags in the STS register by clearing the register but -+ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting -+ * the new flags. -+ * -+ * The SELFTEST_DONE flag is acquired from the backend that determines it by -+ * peeking into TPM commands. -+ * -+ * A VM suspend/resume will preserve the flag by storing it into the VM -+ * device state, but the backend will not remember it when QEMU is started -+ * again. Therefore, we cache the flag here. Once set, it will not be unset -+ * except by a reset. -+ */ -+static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) -+{ -+ l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; -+ l->sts |= flags; -+} -+ -+/* -+ * Send a request to the TPM. -+ */ -+static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) -+{ -+ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); -+ } -+ -+ /* -+ * rw_offset serves as length indicator for length of data; -+ * it's reset when the response comes back -+ */ -+ s->loc[locty].state = TPM_TIS_STATE_EXECUTION; -+ -+ s->cmd = (TPMBackendCmd) { -+ .locty = locty, -+ .in = s->buffer, -+ .in_len = s->rw_offset, -+ .out = s->buffer, -+ .out_len = s->be_buffer_size, -+ }; -+ -+ tpm_backend_deliver_request(s->be_driver, &s->cmd); -+} -+ -+/* raise an interrupt if allowed */ -+static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) -+{ -+ if (!TPM_TIS_IS_VALID_LOCTY(locty)) { -+ return; -+ } -+ -+ if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) && -+ (s->loc[locty].inte & irqmask)) { -+ trace_tpm_tis_raise_irq(irqmask); -+ qemu_irq_raise(s->irq); -+ s->loc[locty].ints |= irqmask; -+ } -+} -+ -+static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) -+{ -+ uint8_t l; -+ -+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { -+ if (l == locty) { -+ continue; -+ } -+ if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) -+{ -+ bool change = (s->active_locty != new_active_locty); -+ bool is_seize; -+ uint8_t mask; -+ -+ if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { -+ is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && -+ s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; -+ -+ if (is_seize) { -+ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ } else { -+ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| -+ TPM_TIS_ACCESS_REQUEST_USE); -+ } -+ /* reset flags on the old active locality */ -+ s->loc[s->active_locty].access &= mask; -+ -+ if (is_seize) { -+ s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; -+ } -+ } -+ -+ s->active_locty = new_active_locty; -+ -+ trace_tpm_tis_new_active_locality(s->active_locty); -+ -+ if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { -+ /* set flags on the new active locality */ -+ s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; -+ s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | -+ TPM_TIS_ACCESS_SEIZE); -+ } -+ -+ if (change) { -+ tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); -+ } -+} -+ -+/* abort -- this function switches the locality */ -+static void tpm_tis_abort(TPMState *s) -+{ -+ s->rw_offset = 0; -+ -+ trace_tpm_tis_abort(s->next_locty); -+ -+ /* -+ * Need to react differently depending on who's aborting now and -+ * which locality will become active afterwards. -+ */ -+ if (s->aborting_locty == s->next_locty) { -+ s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY; -+ tpm_tis_sts_set(&s->loc[s->aborting_locty], -+ TPM_TIS_STS_COMMAND_READY); -+ tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY); -+ } -+ -+ /* locality after abort is another one than the current one */ -+ tpm_tis_new_active_locality(s, s->next_locty); -+ -+ s->next_locty = TPM_TIS_NO_LOCALITY; -+ /* nobody's aborting a command anymore */ -+ s->aborting_locty = TPM_TIS_NO_LOCALITY; -+} -+ -+/* prepare aborting current command */ -+static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) -+{ -+ uint8_t busy_locty; -+ -+ assert(TPM_TIS_IS_VALID_LOCTY(newlocty)); -+ -+ s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */ -+ s->next_locty = newlocty; /* locality after successful abort */ -+ -+ /* -+ * only abort a command using an interrupt if currently executing -+ * a command AND if there's a valid connection to the vTPM. -+ */ -+ for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { -+ if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { -+ /* -+ * request the backend to cancel. Some backends may not -+ * support it -+ */ -+ tpm_backend_cancel_cmd(s->be_driver); -+ return; -+ } -+ } -+ -+ tpm_tis_abort(s); -+} -+ -+/* -+ * Callback from the TPM to indicate that the response was received. -+ */ -+void tpm_tis_request_completed(TPMState *s, int ret) -+{ -+ uint8_t locty = s->cmd.locty; -+ uint8_t l; -+ -+ assert(TPM_TIS_IS_VALID_LOCTY(locty)); -+ -+ if (s->cmd.selftest_done) { -+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { -+ s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE; -+ } -+ } -+ -+ /* FIXME: report error if ret != 0 */ -+ tpm_tis_sts_set(&s->loc[locty], -+ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); -+ s->loc[locty].state = TPM_TIS_STATE_COMPLETION; -+ s->rw_offset = 0; -+ -+ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); -+ } -+ -+ if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { -+ tpm_tis_abort(s); -+ } -+ -+ tpm_tis_raise_irq(s, locty, -+ TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); -+} -+ -+/* -+ * Read a byte of response data -+ */ -+static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) -+{ -+ uint32_t ret = TPM_TIS_NO_DATA_BYTE; -+ uint16_t len; -+ -+ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { -+ len = MIN(tpm_cmd_get_size(&s->buffer), -+ s->be_buffer_size); -+ -+ ret = s->buffer[s->rw_offset++]; -+ if (s->rw_offset >= len) { -+ /* got last byte */ -+ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); -+ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); -+ } -+ trace_tpm_tis_data_read(ret, s->rw_offset - 1); -+ } -+ -+ return ret; -+} -+ -+#ifdef DEBUG_TIS -+static void tpm_tis_dump_state(TPMState *s, hwaddr addr) -+{ -+ static const unsigned regs[] = { -+ TPM_TIS_REG_ACCESS, -+ TPM_TIS_REG_INT_ENABLE, -+ TPM_TIS_REG_INT_VECTOR, -+ TPM_TIS_REG_INT_STATUS, -+ TPM_TIS_REG_INTF_CAPABILITY, -+ TPM_TIS_REG_STS, -+ TPM_TIS_REG_DID_VID, -+ TPM_TIS_REG_RID, -+ 0xfff}; -+ int idx; -+ uint8_t locty = tpm_tis_locality_from_addr(addr); -+ hwaddr base = addr & ~0xfff; -+ -+ printf("tpm_tis: active locality : %d\n" -+ "tpm_tis: state of locality %d : %d\n" -+ "tpm_tis: register dump:\n", -+ s->active_locty, -+ locty, s->loc[locty].state); -+ -+ for (idx = 0; regs[idx] != 0xfff; idx++) { -+ printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], -+ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); -+ } -+ -+ printf("tpm_tis: r/w offset : %d\n" -+ "tpm_tis: result buffer : ", -+ s->rw_offset); -+ for (idx = 0; -+ idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); -+ idx++) { -+ printf("%c%02x%s", -+ s->rw_offset == idx ? '>' : ' ', -+ s->buffer[idx], -+ ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); -+ } -+ printf("\n"); -+} -+#endif -+ -+/* -+ * Read a register of the TIS interface -+ * See specs pages 33-63 for description of the registers -+ */ -+static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ TPMState *s = opaque; -+ uint16_t offset = addr & 0xffc; -+ uint8_t shift = (addr & 0x3) * 8; -+ uint32_t val = 0xffffffff; -+ uint8_t locty = tpm_tis_locality_from_addr(addr); -+ uint32_t avail; -+ uint8_t v; -+ -+ if (tpm_backend_had_startup_error(s->be_driver)) { -+ return 0; -+ } -+ -+ switch (offset) { -+ case TPM_TIS_REG_ACCESS: -+ /* never show the SEIZE flag even though we use it internally */ -+ val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; -+ /* the pending flag is always calculated */ -+ if (tpm_tis_check_request_use_except(s, locty)) { -+ val |= TPM_TIS_ACCESS_PENDING_REQUEST; -+ } -+ val |= !tpm_backend_get_tpm_established_flag(s->be_driver); -+ break; -+ case TPM_TIS_REG_INT_ENABLE: -+ val = s->loc[locty].inte; -+ break; -+ case TPM_TIS_REG_INT_VECTOR: -+ val = s->irq_num; -+ break; -+ case TPM_TIS_REG_INT_STATUS: -+ val = s->loc[locty].ints; -+ break; -+ case TPM_TIS_REG_INTF_CAPABILITY: -+ switch (s->be_tpm_version) { -+ case TPM_VERSION_UNSPEC: -+ val = 0; -+ break; -+ case TPM_VERSION_1_2: -+ val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; -+ break; -+ case TPM_VERSION_2_0: -+ val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; -+ break; -+ } -+ break; -+ case TPM_TIS_REG_STS: -+ if (s->active_locty == locty) { -+ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { -+ val = TPM_TIS_BURST_COUNT( -+ MIN(tpm_cmd_get_size(&s->buffer), -+ s->be_buffer_size) -+ - s->rw_offset) | s->loc[locty].sts; -+ } else { -+ avail = s->be_buffer_size - s->rw_offset; -+ /* -+ * byte-sized reads should not return 0x00 for 0x100 -+ * available bytes. -+ */ -+ if (size == 1 && avail > 0xff) { -+ avail = 0xff; -+ } -+ val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts; -+ } -+ } -+ break; -+ case TPM_TIS_REG_DATA_FIFO: -+ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: -+ if (s->active_locty == locty) { -+ if (size > 4 - (addr & 0x3)) { -+ /* prevent access beyond FIFO */ -+ size = 4 - (addr & 0x3); -+ } -+ val = 0; -+ shift = 0; -+ while (size > 0) { -+ switch (s->loc[locty].state) { -+ case TPM_TIS_STATE_COMPLETION: -+ v = tpm_tis_data_read(s, locty); -+ break; -+ default: -+ v = TPM_TIS_NO_DATA_BYTE; -+ break; -+ } -+ val |= (v << shift); -+ shift += 8; -+ size--; -+ } -+ shift = 0; /* no more adjustments */ -+ } -+ break; -+ case TPM_TIS_REG_INTERFACE_ID: -+ val = s->loc[locty].iface_id; -+ break; -+ case TPM_TIS_REG_DID_VID: -+ val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; -+ break; -+ case TPM_TIS_REG_RID: -+ val = TPM_TIS_TPM_RID; -+ break; -+#ifdef DEBUG_TIS -+ case TPM_TIS_REG_DEBUG: -+ tpm_tis_dump_state(s, addr); -+ break; -+#endif -+ } -+ -+ if (shift) { -+ val >>= shift; -+ } -+ -+ trace_tpm_tis_mmio_read(size, addr, val); -+ -+ return val; -+} -+ -+/* -+ * Write a value to a register of the TIS interface -+ * See specs pages 33-63 for description of the registers -+ */ -+static void tpm_tis_mmio_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ TPMState *s = opaque; -+ uint16_t off = addr & 0xffc; -+ uint8_t shift = (addr & 0x3) * 8; -+ uint8_t locty = tpm_tis_locality_from_addr(addr); -+ uint8_t active_locty, l; -+ int c, set_new_locty = 1; -+ uint16_t len; -+ uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0); -+ -+ trace_tpm_tis_mmio_write(size, addr, val); -+ -+ if (locty == 4) { -+ trace_tpm_tis_mmio_write_locty4(); -+ return; -+ } -+ -+ if (tpm_backend_had_startup_error(s->be_driver)) { -+ return; -+ } -+ -+ val &= mask; -+ -+ if (shift) { -+ val <<= shift; -+ mask <<= shift; -+ } -+ -+ mask ^= 0xffffffff; -+ -+ switch (off) { -+ case TPM_TIS_REG_ACCESS: -+ -+ if ((val & TPM_TIS_ACCESS_SEIZE)) { -+ val &= ~(TPM_TIS_ACCESS_REQUEST_USE | -+ TPM_TIS_ACCESS_ACTIVE_LOCALITY); -+ } -+ -+ active_locty = s->active_locty; -+ -+ if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { -+ /* give up locality if currently owned */ -+ if (s->active_locty == locty) { -+ trace_tpm_tis_mmio_write_release_locty(locty); -+ -+ uint8_t newlocty = TPM_TIS_NO_LOCALITY; -+ /* anybody wants the locality ? */ -+ for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { -+ if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { -+ trace_tpm_tis_mmio_write_locty_req_use(c); -+ newlocty = c; -+ break; -+ } -+ } -+ trace_tpm_tis_mmio_write_next_locty(newlocty); -+ -+ if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { -+ set_new_locty = 0; -+ tpm_tis_prep_abort(s, locty, newlocty); -+ } else { -+ active_locty = TPM_TIS_NO_LOCALITY; -+ } -+ } else { -+ /* not currently the owner; clear a pending request */ -+ s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; -+ } -+ } -+ -+ if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { -+ s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; -+ } -+ -+ if ((val & TPM_TIS_ACCESS_SEIZE)) { -+ /* -+ * allow seize if a locality is active and the requesting -+ * locality is higher than the one that's active -+ * OR -+ * allow seize for requesting locality if no locality is -+ * active -+ */ -+ while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && -+ locty > s->active_locty) || -+ !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { -+ bool higher_seize = FALSE; -+ -+ /* already a pending SEIZE ? */ -+ if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { -+ break; -+ } -+ -+ /* check for ongoing seize by a higher locality */ -+ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { -+ if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { -+ higher_seize = TRUE; -+ break; -+ } -+ } -+ -+ if (higher_seize) { -+ break; -+ } -+ -+ /* cancel any seize by a lower locality */ -+ for (l = 0; l < locty; l++) { -+ s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; -+ } -+ -+ s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; -+ -+ trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty); -+ trace_tpm_tis_mmio_write_init_abort(); -+ -+ set_new_locty = 0; -+ tpm_tis_prep_abort(s, s->active_locty, locty); -+ break; -+ } -+ } -+ -+ if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { -+ if (s->active_locty != locty) { -+ if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { -+ s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; -+ } else { -+ /* no locality active -> make this one active now */ -+ active_locty = locty; -+ } -+ } -+ } -+ -+ if (set_new_locty) { -+ tpm_tis_new_active_locality(s, active_locty); -+ } -+ -+ break; -+ case TPM_TIS_REG_INT_ENABLE: -+ if (s->active_locty != locty) { -+ break; -+ } -+ -+ s->loc[locty].inte &= mask; -+ s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED | -+ TPM_TIS_INT_POLARITY_MASK | -+ TPM_TIS_INTERRUPTS_SUPPORTED)); -+ break; -+ case TPM_TIS_REG_INT_VECTOR: -+ /* hard wired -- ignore */ -+ break; -+ case TPM_TIS_REG_INT_STATUS: -+ if (s->active_locty != locty) { -+ break; -+ } -+ -+ /* clearing of interrupt flags */ -+ if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && -+ (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { -+ s->loc[locty].ints &= ~val; -+ if (s->loc[locty].ints == 0) { -+ qemu_irq_lower(s->irq); -+ trace_tpm_tis_mmio_write_lowering_irq(); -+ } -+ } -+ s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); -+ break; -+ case TPM_TIS_REG_STS: -+ if (s->active_locty != locty) { -+ break; -+ } -+ -+ if (s->be_tpm_version == TPM_VERSION_2_0) { -+ /* some flags that are only supported for TPM 2 */ -+ if (val & TPM_TIS_STS_COMMAND_CANCEL) { -+ if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) { -+ /* -+ * request the backend to cancel. Some backends may not -+ * support it -+ */ -+ tpm_backend_cancel_cmd(s->be_driver); -+ } -+ } -+ -+ if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { -+ if (locty == 3 || locty == 4) { -+ tpm_backend_reset_tpm_established_flag(s->be_driver, locty); -+ } -+ } -+ } -+ -+ val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | -+ TPM_TIS_STS_RESPONSE_RETRY); -+ -+ if (val == TPM_TIS_STS_COMMAND_READY) { -+ switch (s->loc[locty].state) { -+ -+ case TPM_TIS_STATE_READY: -+ s->rw_offset = 0; -+ break; -+ -+ case TPM_TIS_STATE_IDLE: -+ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY); -+ s->loc[locty].state = TPM_TIS_STATE_READY; -+ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); -+ break; -+ -+ case TPM_TIS_STATE_EXECUTION: -+ case TPM_TIS_STATE_RECEPTION: -+ /* abort currently running command */ -+ trace_tpm_tis_mmio_write_init_abort(); -+ tpm_tis_prep_abort(s, locty, locty); -+ break; -+ -+ case TPM_TIS_STATE_COMPLETION: -+ s->rw_offset = 0; -+ /* shortcut to ready state with C/R set */ -+ s->loc[locty].state = TPM_TIS_STATE_READY; -+ if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { -+ tpm_tis_sts_set(&s->loc[locty], -+ TPM_TIS_STS_COMMAND_READY); -+ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); -+ } -+ s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); -+ break; -+ -+ } -+ } else if (val == TPM_TIS_STS_TPM_GO) { -+ switch (s->loc[locty].state) { -+ case TPM_TIS_STATE_RECEPTION: -+ if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { -+ tpm_tis_tpm_send(s, locty); -+ } -+ break; -+ default: -+ /* ignore */ -+ break; -+ } -+ } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { -+ switch (s->loc[locty].state) { -+ case TPM_TIS_STATE_COMPLETION: -+ s->rw_offset = 0; -+ tpm_tis_sts_set(&s->loc[locty], -+ TPM_TIS_STS_VALID| -+ TPM_TIS_STS_DATA_AVAILABLE); -+ break; -+ default: -+ /* ignore */ -+ break; -+ } -+ } -+ break; -+ case TPM_TIS_REG_DATA_FIFO: -+ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: -+ /* data fifo */ -+ if (s->active_locty != locty) { -+ break; -+ } -+ -+ if (s->loc[locty].state == TPM_TIS_STATE_IDLE || -+ s->loc[locty].state == TPM_TIS_STATE_EXECUTION || -+ s->loc[locty].state == TPM_TIS_STATE_COMPLETION) { -+ /* drop the byte */ -+ } else { -+ trace_tpm_tis_mmio_write_data2send(val, size); -+ if (s->loc[locty].state == TPM_TIS_STATE_READY) { -+ s->loc[locty].state = TPM_TIS_STATE_RECEPTION; -+ tpm_tis_sts_set(&s->loc[locty], -+ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); -+ } -+ -+ val >>= shift; -+ if (size > 4 - (addr & 0x3)) { -+ /* prevent access beyond FIFO */ -+ size = 4 - (addr & 0x3); -+ } -+ -+ while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { -+ if (s->rw_offset < s->be_buffer_size) { -+ s->buffer[s->rw_offset++] = -+ (uint8_t)val; -+ val >>= 8; -+ size--; -+ } else { -+ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); -+ } -+ } -+ -+ /* check for complete packet */ -+ if (s->rw_offset > 5 && -+ (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { -+ /* we have a packet length - see if we have all of it */ -+ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); -+ -+ len = tpm_cmd_get_size(&s->buffer); -+ if (len > s->rw_offset) { -+ tpm_tis_sts_set(&s->loc[locty], -+ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); -+ } else { -+ /* packet complete */ -+ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); -+ } -+ if (need_irq) { -+ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); -+ } -+ } -+ } -+ break; -+ case TPM_TIS_REG_INTERFACE_ID: -+ if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { -+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { -+ s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; -+ } -+ } -+ break; -+ } -+} -+ -+const MemoryRegionOps tpm_tis_memory_ops = { -+ .read = tpm_tis_mmio_read, -+ .write = tpm_tis_mmio_write, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+ .valid = { -+ .min_access_size = 1, -+ .max_access_size = 4, -+ }, -+}; -+ -+/* -+ * Get the TPMVersion of the backend device being used -+ */ -+enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) -+{ -+ if (tpm_backend_had_startup_error(s->be_driver)) { -+ return TPM_VERSION_UNSPEC; -+ } -+ -+ return tpm_backend_get_tpm_version(s->be_driver); -+} -+ -+/* -+ * This function is called when the machine starts, resets or due to -+ * S3 resume. -+ */ -+void tpm_tis_reset(TPMState *s) -+{ -+ int c; -+ -+ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); -+ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), -+ TPM_TIS_BUFFER_MAX); -+ -+ if (s->ppi_enabled) { -+ tpm_ppi_reset(&s->ppi); -+ } -+ tpm_backend_reset(s->be_driver); -+ -+ s->active_locty = TPM_TIS_NO_LOCALITY; -+ s->next_locty = TPM_TIS_NO_LOCALITY; -+ s->aborting_locty = TPM_TIS_NO_LOCALITY; -+ -+ for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { -+ s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; -+ switch (s->be_tpm_version) { -+ case TPM_VERSION_UNSPEC: -+ break; -+ case TPM_VERSION_1_2: -+ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; -+ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; -+ break; -+ case TPM_VERSION_2_0: -+ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; -+ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; -+ break; -+ } -+ s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; -+ s->loc[c].ints = 0; -+ s->loc[c].state = TPM_TIS_STATE_IDLE; -+ -+ s->rw_offset = 0; -+ } -+ -+ if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) { -+ exit(1); -+ } -+} -+ -+/* persistent state handling */ -+ -+int tpm_tis_pre_save(TPMState *s) -+{ -+ uint8_t locty = s->active_locty; -+ -+ trace_tpm_tis_pre_save(locty, s->rw_offset); -+ -+ if (DEBUG_TIS) { -+ tpm_tis_dump_state(s, 0); -+ } -+ -+ /* -+ * Synchronize with backend completion. -+ */ -+ tpm_backend_finish_sync(s->be_driver); -+ -+ return 0; -+} -+ -+const VMStateDescription vmstate_locty = { -+ .name = "tpm-tis/locty", -+ .version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(state, TPMLocality), -+ VMSTATE_UINT32(inte, TPMLocality), -+ VMSTATE_UINT32(ints, TPMLocality), -+ VMSTATE_UINT8(access, TPMLocality), -+ VMSTATE_UINT32(sts, TPMLocality), -+ VMSTATE_UINT32(iface_id, TPMLocality), -+ VMSTATE_END_OF_LIST(), -+ } -+}; -+ -diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c -new file mode 100644 -index 00000000..45e25c02 ---- /dev/null -+++ b/hw/tpm/tpm_tis_isa.c -@@ -0,0 +1,170 @@ -+/* -+ * tpm_tis_isa.c - QEMU's TPM TIS ISA Device -+ * -+ * Copyright (C) 2006,2010-2013 IBM Corporation -+ * -+ * Authors: -+ * Stefan Berger -+ * David Safford -+ * -+ * Xen 4 support: Andrease Niederl -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ * Implementation of the TIS interface according to specs found at -+ * http://www.trustedcomputinggroup.org. This implementation currently -+ * supports version 1.3, 21 March 2013 -+ * In the developers menu choose the PC Client section then find the TIS -+ * specification. -+ * -+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform -+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/isa/isa.h" -+#include "hw/qdev-properties.h" -+#include "migration/vmstate.h" -+#include "tpm_util.h" -+#include "tpm_tis.h" -+ -+typedef struct TPMStateISA { -+ /*< private >*/ -+ ISADevice parent_obj; -+ -+ /*< public >*/ -+ TPMState state; /* not a QOM object */ -+} TPMStateISA; -+ -+#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) -+ -+static int tpm_tis_pre_save_isa(void *opaque) -+{ -+ TPMStateISA *isadev = opaque; -+ -+ return tpm_tis_pre_save(&isadev->state); -+} -+ -+static const VMStateDescription vmstate_tpm_tis_isa = { -+ .name = "tpm-tis", -+ .version_id = 0, -+ .pre_save = tpm_tis_pre_save_isa, -+ .fields = (VMStateField[]) { -+ VMSTATE_BUFFER(state.buffer, TPMStateISA), -+ VMSTATE_UINT16(state.rw_offset, TPMStateISA), -+ VMSTATE_UINT8(state.active_locty, TPMStateISA), -+ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), -+ VMSTATE_UINT8(state.next_locty, TPMStateISA), -+ -+ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, -+ vmstate_locty, TPMLocality), -+ -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(ti); -+ TPMState *s = &isadev->state; -+ -+ tpm_tis_request_completed(s, ret); -+} -+ -+static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(ti); -+ TPMState *s = &isadev->state; -+ -+ return tpm_tis_get_tpm_version(s); -+} -+ -+static void tpm_tis_isa_reset(DeviceState *dev) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(dev); -+ TPMState *s = &isadev->state; -+ -+ return tpm_tis_reset(s); -+} -+ -+static Property tpm_tis_isa_properties[] = { -+ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), -+ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), -+ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static void tpm_tis_isa_initfn(Object *obj) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(obj); -+ TPMState *s = &isadev->state; -+ -+ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, -+ s, "tpm-tis-mmio", -+ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); -+} -+ -+static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(dev); -+ TPMState *s = &isadev->state; -+ -+ if (!tpm_find()) { -+ error_setg(errp, "at most one TPM device is permitted"); -+ return; -+ } -+ -+ if (!s->be_driver) { -+ error_setg(errp, "'tpmdev' property is required"); -+ return; -+ } -+ if (s->irq_num > 15) { -+ error_setg(errp, "IRQ %d is outside valid range of 0 to 15", -+ s->irq_num); -+ return; -+ } -+ -+ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); -+ -+ memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), -+ TPM_TIS_ADDR_BASE, &s->mmio); -+ -+ if (s->ppi_enabled) { -+ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), -+ TPM_PPI_ADDR_BASE, OBJECT(dev)); -+ } -+} -+ -+static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ TPMIfClass *tc = TPM_IF_CLASS(klass); -+ -+ dc->props = tpm_tis_isa_properties; -+ dc->vmsd = &vmstate_tpm_tis_isa; -+ tc->model = TPM_MODEL_TPM_TIS; -+ dc->realize = tpm_tis_isa_realizefn; -+ dc->reset = tpm_tis_isa_reset; -+ tc->request_completed = tpm_tis_isa_request_completed; -+ tc->get_version = tpm_tis_isa_get_tpm_version; -+} -+ -+static const TypeInfo tpm_tis_isa_info = { -+ .name = TYPE_TPM_TIS_ISA, -+ .parent = TYPE_ISA_DEVICE, -+ .instance_size = sizeof(TPMStateISA), -+ .instance_init = tpm_tis_isa_initfn, -+ .class_init = tpm_tis_isa_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_TPM_IF }, -+ { } -+ } -+}; -+ -+static void tpm_tis_isa_register(void) -+{ -+ type_register_static(&tpm_tis_isa_info); -+} -+ -+type_init(tpm_tis_isa_register) --- -2.23.0 - diff --git a/tpm-Use-TPMState-as-a-common-struct.patch b/tpm-Use-TPMState-as-a-common-struct.patch deleted file mode 100644 index 61a1dd037bb2356cb7307d53f82732af404ed4e2..0000000000000000000000000000000000000000 --- a/tpm-Use-TPMState-as-a-common-struct.patch +++ /dev/null @@ -1,314 +0,0 @@ -From c57e57c86f9d3c13b33746436bc1f09db88d4d42 Mon Sep 17 00:00:00 2001 -From: jiangfangjie -Date: Tue, 11 Aug 2020 02:52:12 +0000 -Subject: [PATCH 11/19] tpm: Use TPMState as a common struct - -As we plan to introduce a SysBus TPM TIS device, let's -make the TPMState a common struct usable by both the -ISADevice and the SysBusDevice. TPMStateISA embeds the -struct and inherits from the ISADevice. - -The prototype of functions bound to be used by both -the ISA and SysBus devices is changed to take TPMState -handle. - -A bunch of structs also are renamed to be specialized -for the ISA device. Besides those transformations, no -functional change is expected. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-3-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - hw/tpm/tpm_tis.c | 147 +++++++++++++++++++++++++++++------------------ - 1 file changed, 92 insertions(+), 55 deletions(-) - -diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c -index 49d44652..735a528f 100644 ---- a/hw/tpm/tpm_tis.c -+++ b/hw/tpm/tpm_tis.c -@@ -62,7 +62,6 @@ typedef struct TPMLocality { - } TPMLocality; - - typedef struct TPMState { -- ISADevice busdev; - MemoryRegion mmio; - - unsigned char buffer[TPM_TIS_BUFFER_MAX]; -@@ -88,7 +87,15 @@ typedef struct TPMState { - TPMPPI ppi; - } TPMState; - --#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) -+typedef struct TPMStateISA { -+ /*< private >*/ -+ ISADevice parent_obj; -+ -+ /*< public >*/ -+ TPMState state; /* not a QOM object */ -+} TPMStateISA; -+ -+#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) - - #define DEBUG_TIS 0 - -@@ -278,9 +285,8 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) - /* - * Callback from the TPM to indicate that the response was received. - */ --static void tpm_tis_request_completed(TPMIf *ti, int ret) -+static void tpm_tis_request_completed(TPMState *s, int ret) - { -- TPMState *s = TPM(ti); - uint8_t locty = s->cmd.locty; - uint8_t l; - -@@ -335,7 +341,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) - } - - #ifdef DEBUG_TIS --static void tpm_tis_dump_state(void *opaque, hwaddr addr) -+static void tpm_tis_dump_state(TPMState *s, hwaddr addr) - { - static const unsigned regs[] = { - TPM_TIS_REG_ACCESS, -@@ -350,7 +356,6 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) - int idx; - uint8_t locty = tpm_tis_locality_from_addr(addr); - hwaddr base = addr & ~0xfff; -- TPMState *s = opaque; - - printf("tpm_tis: active locality : %d\n" - "tpm_tis: state of locality %d : %d\n" -@@ -360,7 +365,7 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) - - for (idx = 0; regs[idx] != 0xfff; idx++) { - printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], -- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); -+ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); - } - - printf("tpm_tis: r/w offset : %d\n" -@@ -485,7 +490,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, - break; - #ifdef DEBUG_TIS - case TPM_TIS_REG_DEBUG: -- tpm_tis_dump_state(opaque, addr); -+ tpm_tis_dump_state(s, addr); - break; - #endif - } -@@ -832,10 +837,8 @@ static const MemoryRegionOps tpm_tis_memory_ops = { - /* - * Get the TPMVersion of the backend device being used - */ --static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) -+static enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) - { -- TPMState *s = TPM(ti); -- - if (tpm_backend_had_startup_error(s->be_driver)) { - return TPM_VERSION_UNSPEC; - } -@@ -847,9 +850,8 @@ static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) - * This function is called when the machine starts, resets or due to - * S3 resume. - */ --static void tpm_tis_reset(DeviceState *dev) -+static void tpm_tis_reset(TPMState *s) - { -- TPMState *s = TPM(dev); - int c; - - s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); -@@ -893,15 +895,14 @@ static void tpm_tis_reset(DeviceState *dev) - - /* persistent state handling */ - --static int tpm_tis_pre_save(void *opaque) -+static int tpm_tis_pre_save(TPMState *s) - { -- TPMState *s = opaque; - uint8_t locty = s->active_locty; - - trace_tpm_tis_pre_save(locty, s->rw_offset); - - if (DEBUG_TIS) { -- tpm_tis_dump_state(opaque, 0); -+ tpm_tis_dump_state(s, 0); - } - - /* -@@ -926,34 +927,78 @@ static const VMStateDescription vmstate_locty = { - } - }; - --static const VMStateDescription vmstate_tpm_tis = { -+/* ISA */ -+ -+static int tpm_tis_pre_save_isa(void *opaque) -+{ -+ TPMStateISA *isadev = opaque; -+ -+ return tpm_tis_pre_save(&isadev->state); -+} -+ -+static const VMStateDescription vmstate_tpm_tis_isa = { - .name = "tpm-tis", - .version_id = 0, -- .pre_save = tpm_tis_pre_save, -+ .pre_save = tpm_tis_pre_save_isa, - .fields = (VMStateField[]) { -- VMSTATE_BUFFER(buffer, TPMState), -- VMSTATE_UINT16(rw_offset, TPMState), -- VMSTATE_UINT8(active_locty, TPMState), -- VMSTATE_UINT8(aborting_locty, TPMState), -- VMSTATE_UINT8(next_locty, TPMState), -+ VMSTATE_BUFFER(state.buffer, TPMStateISA), -+ VMSTATE_UINT16(state.rw_offset, TPMStateISA), -+ VMSTATE_UINT8(state.active_locty, TPMStateISA), -+ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), -+ VMSTATE_UINT8(state.next_locty, TPMStateISA), - -- VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0, -+ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, - vmstate_locty, TPMLocality), - - VMSTATE_END_OF_LIST() - } - }; - --static Property tpm_tis_properties[] = { -- DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), -- DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), -- DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), -+static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(ti); -+ TPMState *s = &isadev->state; -+ -+ tpm_tis_request_completed(s, ret); -+} -+ -+static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(ti); -+ TPMState *s = &isadev->state; -+ -+ return tpm_tis_get_tpm_version(s); -+} -+ -+static void tpm_tis_isa_reset(DeviceState *dev) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(dev); -+ TPMState *s = &isadev->state; -+ -+ return tpm_tis_reset(s); -+} -+ -+static Property tpm_tis_isa_properties[] = { -+ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), -+ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), -+ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), - DEFINE_PROP_END_OF_LIST(), - }; - --static void tpm_tis_realizefn(DeviceState *dev, Error **errp) -+static void tpm_tis_isa_initfn(Object *obj) - { -- TPMState *s = TPM(dev); -+ TPMStateISA *isadev = TPM_TIS_ISA(obj); -+ TPMState *s = &isadev->state; -+ -+ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, -+ s, "tpm-tis-mmio", -+ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); -+} -+ -+static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) -+{ -+ TPMStateISA *isadev = TPM_TIS_ISA(dev); -+ TPMState *s = &isadev->state; - - if (!tpm_find()) { - error_setg(errp, "at most one TPM device is permitted"); -@@ -970,55 +1015,47 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) - return; - } - -- isa_init_irq(&s->busdev, &s->irq, s->irq_num); -+ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); - - memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), - TPM_TIS_ADDR_BASE, &s->mmio); - - if (s->ppi_enabled) { - tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), -- TPM_PPI_ADDR_BASE, OBJECT(s)); -+ TPM_PPI_ADDR_BASE, OBJECT(dev)); - } - } - --static void tpm_tis_initfn(Object *obj) --{ -- TPMState *s = TPM(obj); -- -- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops, -- s, "tpm-tis-mmio", -- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); --} -- --static void tpm_tis_class_init(ObjectClass *klass, void *data) -+static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) - { - DeviceClass *dc = DEVICE_CLASS(klass); - TPMIfClass *tc = TPM_IF_CLASS(klass); - -- dc->realize = tpm_tis_realizefn; -- dc->props = tpm_tis_properties; -- dc->reset = tpm_tis_reset; -- dc->vmsd = &vmstate_tpm_tis; -+ dc->props = tpm_tis_isa_properties; -+ dc->vmsd = &vmstate_tpm_tis_isa; - tc->model = TPM_MODEL_TPM_TIS; -- tc->get_version = tpm_tis_get_tpm_version; -- tc->request_completed = tpm_tis_request_completed; -+ dc->realize = tpm_tis_isa_realizefn; -+ dc->reset = tpm_tis_isa_reset; -+ tc->request_completed = tpm_tis_isa_request_completed; -+ tc->get_version = tpm_tis_isa_get_tpm_version; -+ - } - --static const TypeInfo tpm_tis_info = { -+static const TypeInfo tpm_tis_isa_info = { - .name = TYPE_TPM_TIS_ISA, - .parent = TYPE_ISA_DEVICE, -- .instance_size = sizeof(TPMState), -- .instance_init = tpm_tis_initfn, -- .class_init = tpm_tis_class_init, -+ .instance_size = sizeof(TPMStateISA), -+ .instance_init = tpm_tis_isa_initfn, -+ .class_init = tpm_tis_isa_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_TPM_IF }, - { } - } - }; - --static void tpm_tis_register(void) -+static void tpm_tis_isa_register(void) - { -- type_register_static(&tpm_tis_info); -+ type_register_static(&tpm_tis_isa_info); - } - --type_init(tpm_tis_register) -+type_init(tpm_tis_isa_register) --- -2.23.0 - diff --git a/tpm-ppi-page-align-PPI-RAM.patch b/tpm-ppi-page-align-PPI-RAM.patch deleted file mode 100644 index d7ba2c876605392e79d887b89a4a274cb51660d4..0000000000000000000000000000000000000000 --- a/tpm-ppi-page-align-PPI-RAM.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 26b54c545f253049faa633ff886132602ff47241 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Fri, 3 Jan 2020 11:39:59 +0400 -Subject: [PATCH 02/19] tpm-ppi: page-align PPI RAM -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -post-copy migration fails on destination with error such as: -2019-12-26T10:22:44.714644Z qemu-kvm: ram_block_discard_range: -Unaligned start address: 0x559d2afae9a0 - -Use qemu_memalign() to constrain the PPI RAM memory alignment. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Marc-André Lureau -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Stefan Berger -Signed-off-by: Stefan Berger -Message-id: 20200103074000.1006389-3-marcandre.lureau@redhat.com -Signed-off-by: jiangfangjie ---- - hw/tpm/tpm_ppi.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c -index cd8205f2..6509ffd4 100644 ---- a/hw/tpm/tpm_ppi.c -+++ b/hw/tpm/tpm_ppi.c -@@ -44,7 +44,8 @@ void tpm_ppi_reset(TPMPPI *tpmppi) - void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, - hwaddr addr, Object *obj) - { -- tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); -+ tpmppi->buf = qemu_memalign(qemu_real_host_page_size, -+ HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); - memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", - TPM_PPI_ADDR_SIZE, tpmppi->buf); - vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); --- -2.23.0 - diff --git a/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch deleted file mode 100644 index ea6e1d28a10cb6d29ba1c1c76245ef6749825ba2..0000000000000000000000000000000000000000 --- a/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 7974f8ffd75171be106a1ce2705878abbb6c4477 Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Thu, 5 Mar 2020 17:51:40 +0100 -Subject: [PATCH 10/19] tpm: rename TPM_TIS into TPM_TIS_ISA -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As we plan to introduce a sysbus TPM_TIS, let's rename -TPM_TIS into TPM_TIS_ISA. - -Signed-off-by: Eric Auger -Reviewed-by: Stefan Berger -Reviewed-by: Philippe Mathieu-Daudé -Tested-by: Ard Biesheuvel -Acked-by: Ard Biesheuvel -Message-id: 20200305165149.618-2-eric.auger@redhat.com -Signed-off-by: Stefan Berger -Signed-off-by: jiangfangjie ---- - hw/i386/acpi-build.c | 6 +++--- - hw/tpm/tpm_tis.c | 4 ++-- - include/sysemu/tpm.h | 6 +++--- - 3 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index c97731ec..093f7d93 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -2007,7 +2007,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - } - } - -- if (TPM_IS_TIS(tpm_find())) { -+ if (TPM_IS_TIS_ISA(tpm_find())) { - aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, - TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); - } -@@ -2178,7 +2178,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - -- if (TPM_IS_TIS(tpm)) { -+ if (TPM_IS_TIS_ISA(tpm)) { - if (misc->tpm_version == TPM_VERSION_2_0) { - dev = aml_device("TPM"); - aml_append(dev, aml_name_decl("_HID", -@@ -2285,7 +2285,7 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) - (char *)&tpm2_ptr->log_area_start_address - table_data->data; - - tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); -- if (TPM_IS_TIS(tpm_find())) { -+ if (TPM_IS_TIS_ISA(tpm_find())) { - tpm2_ptr->control_area_address = cpu_to_le64(0); - tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); - } else if (TPM_IS_CRB(tpm_find())) { -diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c -index 96a9ac48..49d44652 100644 ---- a/hw/tpm/tpm_tis.c -+++ b/hw/tpm/tpm_tis.c -@@ -88,7 +88,7 @@ typedef struct TPMState { - TPMPPI ppi; - } TPMState; - --#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) -+#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) - - #define DEBUG_TIS 0 - -@@ -1005,7 +1005,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) - } - - static const TypeInfo tpm_tis_info = { -- .name = TYPE_TPM_TIS, -+ .name = TYPE_TPM_TIS_ISA, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(TPMState), - .instance_init = tpm_tis_initfn, -diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h -index 15979a36..1691b92c 100644 ---- a/include/sysemu/tpm.h -+++ b/include/sysemu/tpm.h -@@ -43,12 +43,12 @@ typedef struct TPMIfClass { - enum TPMVersion (*get_version)(TPMIf *obj); - } TPMIfClass; - --#define TYPE_TPM_TIS "tpm-tis" -+#define TYPE_TPM_TIS_ISA "tpm-tis" - #define TYPE_TPM_CRB "tpm-crb" - #define TYPE_TPM_SPAPR "tpm-spapr" - --#define TPM_IS_TIS(chr) \ -- object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) -+#define TPM_IS_TIS_ISA(chr) \ -+ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) - #define TPM_IS_CRB(chr) \ - object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) - #define TPM_IS_SPAPR(chr) \ --- -2.23.0 - diff --git a/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch b/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch new file mode 100644 index 0000000000000000000000000000000000000000..c989e26e417cfc3e093737193cf1babca5a6f3d3 --- /dev/null +++ b/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch @@ -0,0 +1,43 @@ +From 1e32685272ff1932b9ca022db8717720fc901d0e Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:17:47 +0000 +Subject: [PATCH] tpm_crb: mark command buffer as dirty on request completion + mainline inclusion commit e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 category: + bugfix + +--------------------------------------------------------------- + +At the moment, there doesn't seems to be any way to know that QEMU +made modification to the command buffer. This is potentially an issue +on Xen while migrating a guest, as modification to the buffer after +the migration as started could be ignored and not transfered to the +destination. + +Mark the memory region of the command buffer as dirty once a request +is completed. + +Signed-off-by: Anthony PERARD +Reviewed-by: Stefan Berger +Signed-off-by: Stefan Berger +Message-id: 20220411144749.47185-1-anthony.perard@citrix.com + +Signed-off-by: tangbinzy +--- + hw/tpm/tpm_crb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c +index 58ebd1469c..c05972736a 100644 +--- a/hw/tpm/tpm_crb.c ++++ b/hw/tpm/tpm_crb.c +@@ -196,6 +196,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret) + ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, + tpmSts, 1); /* fatal error */ + } ++ memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE); + } + + static enum TPMVersion tpm_crb_get_version(TPMIf *ti) +-- +2.27.0 + diff --git a/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch deleted file mode 100644 index ffc0b62ed7ef655056cfd1280282b768f22ad501..0000000000000000000000000000000000000000 --- a/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch +++ /dev/null @@ -1,552 +0,0 @@ -From 14402a8ca57fb722eb324d141fafb41ef06f4c2b Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Tue, 21 Jan 2020 10:29:32 -0500 -Subject: [PATCH 06/19] tpm_spapr: Support TPM for ppc64 using CRQ based - interface - -Implement support for TPM on ppc64 by implementing the vTPM CRQ interface -as a frontend. It can use the tpm_emulator driver backend with the external -swtpm. - -The Linux vTPM driver for ppc64 works with this emulation. - -This TPM emulator also handles the TPM 2 case. - -Signed-off-by: Stefan Berger -Reviewed-by: David Gibson -Message-Id: <20200121152935.649898-4-stefanb@linux.ibm.com> -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - docs/specs/tpm.txt | 20 ++- - hw/tpm/Kconfig | 6 + - hw/tpm/Makefile.objs | 1 + - hw/tpm/tpm_spapr.c | 379 +++++++++++++++++++++++++++++++++++++++++++ - hw/tpm/trace-events | 12 ++ - include/sysemu/tpm.h | 3 + - qapi/tpm.json | 6 +- - 7 files changed, 423 insertions(+), 4 deletions(-) - create mode 100644 hw/tpm/tpm_spapr.c - -diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt -index 9c8cca04..9c3e67d8 100644 ---- a/docs/specs/tpm.txt -+++ b/docs/specs/tpm.txt -@@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 - - QEMU files related to TPM CRB interface: - - hw/tpm/tpm_crb.c - -+ -+pSeries (ppc64) machines offer a tpm-spapr device model. -+ -+QEMU files related to the SPAPR interface: -+ - hw/tpm/tpm_spapr.c -+ - = fw_cfg interface = - - The bios/firmware may read the "etc/tpm/config" fw_cfg entry for -@@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \ - --log level=20 - - Command line to start QEMU with the TPM emulator device communicating with --the swtpm: -+the swtpm (x86): - - qemu-system-x86_64 -display sdl -accel kvm \ - -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ -@@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \ - -tpmdev emulator,id=tpm0,chardev=chrtpm \ - -device tpm-tis,tpmdev=tpm0 test.img - -+In case a pSeries machine is emulated, use the following command line: -+ -+qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ -+ -m 1024 -bios slof.bin -boot menu=on \ -+ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ -+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ -+ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -+ -device tpm-spapr,tpmdev=tpm0 \ -+ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ -+ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ -+ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 -+ - - In case SeaBIOS is used as firmware, it should show the TPM menu item - after entering the menu with 'ESC'. -diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig -index 4c8ee87d..4d4ab085 100644 ---- a/hw/tpm/Kconfig -+++ b/hw/tpm/Kconfig -@@ -22,3 +22,9 @@ config TPM_EMULATOR - bool - default y - depends on TPMDEV -+ -+config TPM_SPAPR -+ bool -+ default n -+ depends on TPM && PSERIES -+ select TPMDEV -diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs -index de0b85d0..85eb99ae 100644 ---- a/hw/tpm/Makefile.objs -+++ b/hw/tpm/Makefile.objs -@@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o - common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o - common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o - common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o -+obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o -diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c -new file mode 100644 -index 00000000..1db9696a ---- /dev/null -+++ b/hw/tpm/tpm_spapr.c -@@ -0,0 +1,379 @@ -+/* -+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator -+ * -+ * PAPR Virtual TPM -+ * -+ * Copyright (c) 2015, 2017, 2019 IBM Corporation. -+ * -+ * Authors: -+ * Stefan Berger -+ * -+ * This code is licensed under the GPL version 2 or later. See the -+ * COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/error-report.h" -+#include "qapi/error.h" -+#include "hw/qdev-properties.h" -+#include "migration/vmstate.h" -+ -+#include "sysemu/tpm_backend.h" -+#include "tpm_int.h" -+#include "tpm_util.h" -+ -+#include "hw/ppc/spapr.h" -+#include "hw/ppc/spapr_vio.h" -+#include "trace.h" -+ -+#define DEBUG_SPAPR 0 -+ -+#define VIO_SPAPR_VTPM(obj) \ -+ OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR) -+ -+typedef struct TpmCrq { -+ uint8_t valid; /* 0x80: cmd; 0xc0: init crq */ -+ /* 0x81-0x83: CRQ message response */ -+ uint8_t msg; /* see below */ -+ uint16_t len; /* len of TPM request; len of TPM response */ -+ uint32_t data; /* rtce_dma_handle when sending TPM request */ -+ uint64_t reserved; -+} TpmCrq; -+ -+#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0 -+#define SPAPR_VTPM_VALID_COMMAND 0x80 -+#define SPAPR_VTPM_MSG_RESULT 0x80 -+ -+/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */ -+#define SPAPR_VTPM_INIT_CRQ_RESULT 0x1 -+#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2 -+ -+/* msg types for valid = SPAPR_VTPM_VALID_CMD */ -+#define SPAPR_VTPM_GET_VERSION 0x1 -+#define SPAPR_VTPM_TPM_COMMAND 0x2 -+#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 -+#define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4 -+ -+/* response error messages */ -+#define SPAPR_VTPM_VTPM_ERROR 0xff -+ -+/* error codes */ -+#define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3 -+#define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4 -+ -+#define TPM_SPAPR_BUFFER_MAX 4096 -+ -+typedef struct { -+ SpaprVioDevice vdev; -+ -+ TpmCrq crq; /* track single TPM command */ -+ -+ uint8_t state; -+#define SPAPR_VTPM_STATE_NONE 0 -+#define SPAPR_VTPM_STATE_EXECUTION 1 -+#define SPAPR_VTPM_STATE_COMPLETION 2 -+ -+ unsigned char *buffer; -+ -+ TPMBackendCmd cmd; -+ -+ TPMBackend *be_driver; -+ TPMVersion be_tpm_version; -+ -+ size_t be_buffer_size; -+} SpaprTpmState; -+ -+/* -+ * Send a request to the TPM. -+ */ -+static void tpm_spapr_tpm_send(SpaprTpmState *s) -+{ -+ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); -+ } -+ -+ s->state = SPAPR_VTPM_STATE_EXECUTION; -+ s->cmd = (TPMBackendCmd) { -+ .locty = 0, -+ .in = s->buffer, -+ .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size), -+ .out = s->buffer, -+ .out_len = s->be_buffer_size, -+ }; -+ -+ tpm_backend_deliver_request(s->be_driver, &s->cmd); -+} -+ -+static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr) -+{ -+ long rc; -+ -+ /* a max. of be_buffer_size bytes can be transported */ -+ rc = spapr_vio_dma_read(&s->vdev, dataptr, -+ s->buffer, s->be_buffer_size); -+ if (rc) { -+ error_report("tpm_spapr_got_payload: DMA read failure"); -+ } -+ /* let vTPM handle any malformed request */ -+ tpm_spapr_tpm_send(s); -+ -+ return rc; -+} -+ -+static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq) -+{ -+ return spapr_vio_send_crq(dev, (uint8_t *)crq); -+} -+ -+static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); -+ TpmCrq local_crq; -+ TpmCrq *crq = &s->crq; /* requests only */ -+ int rc; -+ uint8_t valid = crq_data[0]; -+ uint8_t msg = crq_data[1]; -+ -+ trace_tpm_spapr_do_crq(valid, msg); -+ -+ switch (valid) { -+ case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */ -+ -+ /* Respond to initialization request */ -+ switch (msg) { -+ case SPAPR_VTPM_INIT_CRQ_RESULT: -+ trace_tpm_spapr_do_crq_crq_result(); -+ memset(&local_crq, 0, sizeof(local_crq)); -+ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; -+ local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT; -+ spapr_tpm_send_crq(dev, &local_crq); -+ break; -+ -+ case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT: -+ trace_tpm_spapr_do_crq_crq_complete_result(); -+ memset(&local_crq, 0, sizeof(local_crq)); -+ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; -+ local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT; -+ spapr_tpm_send_crq(dev, &local_crq); -+ break; -+ } -+ -+ break; -+ case SPAPR_VTPM_VALID_COMMAND: /* Payloads */ -+ switch (msg) { -+ case SPAPR_VTPM_TPM_COMMAND: -+ trace_tpm_spapr_do_crq_tpm_command(); -+ if (s->state == SPAPR_VTPM_STATE_EXECUTION) { -+ return H_BUSY; -+ } -+ memcpy(crq, crq_data, sizeof(*crq)); -+ -+ rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data)); -+ -+ if (rc == H_SUCCESS) { -+ crq->valid = be16_to_cpu(0); -+ } else { -+ local_crq.valid = SPAPR_VTPM_MSG_RESULT; -+ local_crq.msg = SPAPR_VTPM_VTPM_ERROR; -+ local_crq.len = cpu_to_be16(0); -+ local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED); -+ spapr_tpm_send_crq(dev, &local_crq); -+ } -+ break; -+ -+ case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE: -+ trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size); -+ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; -+ local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE | -+ SPAPR_VTPM_MSG_RESULT; -+ local_crq.len = cpu_to_be16(s->be_buffer_size); -+ spapr_tpm_send_crq(dev, &local_crq); -+ break; -+ -+ case SPAPR_VTPM_GET_VERSION: -+ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; -+ local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT; -+ local_crq.len = cpu_to_be16(0); -+ switch (s->be_tpm_version) { -+ case TPM_VERSION_1_2: -+ local_crq.data = cpu_to_be32(1); -+ break; -+ case TPM_VERSION_2_0: -+ local_crq.data = cpu_to_be32(2); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+ trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data)); -+ spapr_tpm_send_crq(dev, &local_crq); -+ break; -+ -+ case SPAPR_VTPM_PREPARE_TO_SUSPEND: -+ trace_tpm_spapr_do_crq_prepare_to_suspend(); -+ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; -+ local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND | -+ SPAPR_VTPM_MSG_RESULT; -+ spapr_tpm_send_crq(dev, &local_crq); -+ break; -+ -+ default: -+ trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg); -+ } -+ break; -+ default: -+ trace_tpm_spapr_do_crq_unknown_crq(valid, msg); -+ }; -+ -+ return H_SUCCESS; -+} -+ -+static void tpm_spapr_request_completed(TPMIf *ti, int ret) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); -+ TpmCrq *crq = &s->crq; -+ uint32_t len; -+ int rc; -+ -+ s->state = SPAPR_VTPM_STATE_COMPLETION; -+ -+ /* a max. of be_buffer_size bytes can be transported */ -+ len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); -+ rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), -+ s->buffer, len); -+ -+ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { -+ tpm_util_show_buffer(s->buffer, len, "From TPM"); -+ } -+ -+ crq->valid = SPAPR_VTPM_MSG_RESULT; -+ if (rc == H_SUCCESS) { -+ crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT; -+ crq->len = cpu_to_be16(len); -+ } else { -+ error_report("%s: DMA write failure", __func__); -+ crq->msg = SPAPR_VTPM_VTPM_ERROR; -+ crq->len = cpu_to_be16(0); -+ crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED); -+ } -+ -+ rc = spapr_tpm_send_crq(&s->vdev, crq); -+ if (rc) { -+ error_report("%s: Error sending response", __func__); -+ } -+} -+ -+static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize) -+{ -+ return tpm_backend_startup_tpm(s->be_driver, buffersize); -+} -+ -+static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); -+ -+ switch (s->be_tpm_version) { -+ case TPM_VERSION_1_2: -+ return "IBM,vtpm"; -+ case TPM_VERSION_2_0: -+ return "IBM,vtpm20"; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tpm_spapr_reset(SpaprVioDevice *dev) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); -+ -+ s->state = SPAPR_VTPM_STATE_NONE; -+ -+ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); -+ -+ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), -+ TPM_SPAPR_BUFFER_MAX); -+ -+ tpm_backend_reset(s->be_driver); -+ tpm_spapr_do_startup_tpm(s, s->be_buffer_size); -+} -+ -+static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); -+ -+ if (tpm_backend_had_startup_error(s->be_driver)) { -+ return TPM_VERSION_UNSPEC; -+ } -+ -+ return tpm_backend_get_tpm_version(s->be_driver); -+} -+ -+static const VMStateDescription vmstate_spapr_vtpm = { -+ .name = "tpm-spapr", -+ .unmigratable = 1, -+}; -+ -+static Property tpm_spapr_properties[] = { -+ DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev), -+ DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp) -+{ -+ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); -+ -+ if (!tpm_find()) { -+ error_setg(errp, "at most one TPM device is permitted"); -+ return; -+ } -+ -+ dev->crq.SendFunc = tpm_spapr_do_crq; -+ -+ if (!s->be_driver) { -+ error_setg(errp, "'tpmdev' property is required"); -+ return; -+ } -+ s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX); -+} -+ -+static void tpm_spapr_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); -+ TPMIfClass *tc = TPM_IF_CLASS(klass); -+ -+ k->realize = tpm_spapr_realizefn; -+ k->reset = tpm_spapr_reset; -+ k->dt_name = "vtpm"; -+ k->dt_type = "IBM,vtpm"; -+ k->get_dt_compatible = tpm_spapr_get_dt_compatible; -+ k->signal_mask = 0x00000001; -+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ dc->props = tpm_spapr_properties; -+ k->rtce_window_size = 0x10000000; -+ dc->vmsd = &vmstate_spapr_vtpm; -+ -+ tc->model = TPM_MODEL_TPM_SPAPR; -+ tc->get_version = tpm_spapr_get_version; -+ tc->request_completed = tpm_spapr_request_completed; -+} -+ -+static const TypeInfo tpm_spapr_info = { -+ .name = TYPE_TPM_SPAPR, -+ .parent = TYPE_VIO_SPAPR_DEVICE, -+ .instance_size = sizeof(SpaprTpmState), -+ .class_init = tpm_spapr_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_TPM_IF }, -+ { } -+ } -+}; -+ -+static void tpm_spapr_register_types(void) -+{ -+ type_register_static(&tpm_spapr_info); -+} -+ -+type_init(tpm_spapr_register_types) -diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events -index 82c45ee5..edbe1bd7 100644 ---- a/hw/tpm/trace-events -+++ b/hw/tpm/trace-events -@@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" - - # tpm_ppi.c - tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" -+ -+# hw/tpm/tpm_spapr.c -+tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" -+tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" -+tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" -+tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT" -+tpm_spapr_do_crq_tpm_command(void) "got TPM command payload" -+tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu" -+tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" -+tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" -+tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" -+tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." -diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h -index 5b541a71..15979a36 100644 ---- a/include/sysemu/tpm.h -+++ b/include/sysemu/tpm.h -@@ -45,11 +45,14 @@ typedef struct TPMIfClass { - - #define TYPE_TPM_TIS "tpm-tis" - #define TYPE_TPM_CRB "tpm-crb" -+#define TYPE_TPM_SPAPR "tpm-spapr" - - #define TPM_IS_TIS(chr) \ - object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) - #define TPM_IS_CRB(chr) \ - object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) -+#define TPM_IS_SPAPR(chr) \ -+ object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR) - - /* returns NULL unless there is exactly one TPM device */ - static inline TPMIf *tpm_find(void) -diff --git a/qapi/tpm.json b/qapi/tpm.json -index b30323bb..63878aa0 100644 ---- a/qapi/tpm.json -+++ b/qapi/tpm.json -@@ -12,11 +12,11 @@ - # - # @tpm-tis: TPM TIS model - # @tpm-crb: TPM CRB model (since 2.12) -+# @tpm-spapr: TPM SPAPR model (since 5.0) - # - # Since: 1.5 - ## --{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] } -- -+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] } - ## - # @query-tpm-models: - # -@@ -29,7 +29,7 @@ - # Example: - # - # -> { "execute": "query-tpm-models" } --# <- { "return": [ "tpm-tis", "tpm-crb" ] } -+# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] } - # - ## - { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } --- -2.23.0 - diff --git a/tpm_spapr-Support-suspend-and-resume.patch b/tpm_spapr-Support-suspend-and-resume.patch deleted file mode 100644 index 55ed521a261fe5c058d9f6b95334c0884cdfd7ea..0000000000000000000000000000000000000000 --- a/tpm_spapr-Support-suspend-and-resume.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 2948d9712a7058bcdca6732101874beb1a6e00a9 Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Tue, 21 Jan 2020 10:29:33 -0500 -Subject: [PATCH 07/19] tpm_spapr: Support suspend and resume -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Extend the tpm_spapr frontend with VM suspend and resume support. - -Signed-off-by: Stefan Berger -Message-Id: <20200121152935.649898-5-stefanb@linux.ibm.com> -Reviewed-by: Marc-André Lureau -Signed-off-by: David Gibson -Signed-off-by: jiangfangjie ---- - hw/tpm/tpm_spapr.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- - hw/tpm/trace-events | 2 ++ - 2 files changed, 53 insertions(+), 1 deletion(-) - -diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c -index 1db9696a..8ba561f4 100644 ---- a/hw/tpm/tpm_spapr.c -+++ b/hw/tpm/tpm_spapr.c -@@ -76,6 +76,8 @@ typedef struct { - - unsigned char *buffer; - -+ uint32_t numbytes; /* number of bytes to deliver on resume */ -+ - TPMBackendCmd cmd; - - TPMBackend *be_driver; -@@ -240,6 +242,14 @@ static void tpm_spapr_request_completed(TPMIf *ti, int ret) - - /* a max. of be_buffer_size bytes can be transported */ - len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); -+ -+ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { -+ trace_tpm_spapr_caught_response(len); -+ /* defer delivery of response until .post_load */ -+ s->numbytes = len; -+ return; -+ } -+ - rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), - s->buffer, len); - -@@ -288,6 +298,7 @@ static void tpm_spapr_reset(SpaprVioDevice *dev) - SpaprTpmState *s = VIO_SPAPR_VTPM(dev); - - s->state = SPAPR_VTPM_STATE_NONE; -+ s->numbytes = 0; - - s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); - -@@ -309,9 +320,48 @@ static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) - return tpm_backend_get_tpm_version(s->be_driver); - } - -+/* persistent state handling */ -+ -+static int tpm_spapr_pre_save(void *opaque) -+{ -+ SpaprTpmState *s = opaque; -+ -+ tpm_backend_finish_sync(s->be_driver); -+ /* -+ * we cannot deliver the results to the VM since DMA would touch VM memory -+ */ -+ -+ return 0; -+} -+ -+static int tpm_spapr_post_load(void *opaque, int version_id) -+{ -+ SpaprTpmState *s = opaque; -+ -+ if (s->numbytes) { -+ trace_tpm_spapr_post_load(); -+ /* deliver the results to the VM via DMA */ -+ tpm_spapr_request_completed(TPM_IF(s), 0); -+ s->numbytes = 0; -+ } -+ -+ return 0; -+} -+ - static const VMStateDescription vmstate_spapr_vtpm = { - .name = "tpm-spapr", -- .unmigratable = 1, -+ .pre_save = tpm_spapr_pre_save, -+ .post_load = tpm_spapr_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_SPAPR_VIO(vdev, SpaprTpmState), -+ -+ VMSTATE_UINT8(state, SpaprTpmState), -+ VMSTATE_UINT32(numbytes, SpaprTpmState), -+ VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes), -+ /* remember DMA address */ -+ VMSTATE_UINT32(crq.data, SpaprTpmState), -+ VMSTATE_END_OF_LIST(), -+ } - }; - - static Property tpm_spapr_properties[] = { -diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events -index edbe1bd7..b97eea24 100644 ---- a/hw/tpm/trace-events -+++ b/hw/tpm/trace-events -@@ -67,3 +67,5 @@ tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" - tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" - tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" - tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." -+tpm_spapr_post_load(void) "Delivering TPM response after resume" -+tpm_spapr_caught_response(uint32_t v) "Caught response to deliver after resume: %u bytes" --- -2.23.0 - diff --git a/tracetool-avoid-invalid-escape-in-Python-string.patch b/tracetool-avoid-invalid-escape-in-Python-string.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffd30a2c5787f4ce7a948eafd63d42bf89cc8b92 --- /dev/null +++ b/tracetool-avoid-invalid-escape-in-Python-string.patch @@ -0,0 +1,38 @@ +From cb5e4e55c489462a2ff11143a5768b5c096bf1ad Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 15 Nov 2023 14:49:44 +0800 +Subject: [PATCH] tracetool: avoid invalid escape in Python string +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 4d96307c5b4fac40c6ca25f38318b4b65d315de0 + +This is an error in Python 3.12; fix it by using a raw string literal. + +Cc: +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Message-ID: <20231108105649.60453-1-marcandre.lureau@redhat.com> +Signed-off-by: qihao_yewu +--- + scripts/tracetool/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py +index 5bc94d95cf..630e85a5d6 100644 +--- a/scripts/tracetool/__init__.py ++++ b/scripts/tracetool/__init__.py +@@ -94,7 +94,7 @@ def out(*lines, **kwargs): + def validate_type(name): + bits = name.split(" ") + for bit in bits: +- bit = re.sub("\*", "", bit) ++ bit = re.sub(r"\*", "", bit) + if bit == "": + continue + if bit == "const": +-- +2.27.0 + diff --git a/trivial-typos-namesapce.patch b/trivial-typos-namesapce.patch new file mode 100644 index 0000000000000000000000000000000000000000..60564e4efeb1b2667058de6897035cb5aa3dfcc0 --- /dev/null +++ b/trivial-typos-namesapce.patch @@ -0,0 +1,89 @@ +From ec92a6e31bb5bf118a09bdc085e1e4f476b98f1e Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 02:48:55 -0800 +Subject: [PATCH] trivial typos: namesapce + +cherry picked from commit a0984714fb700683094a754a2320a2e150cf10a7 + +'namespace' is misspelled in a bunch of places. + +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Klaus Jensen +Message-Id: <20220614104045.85728-3-dgilbert@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: Wanghe Xiao +--- + hw/9pfs/9p-xattr-user.c | 8 ++++---- + hw/acpi/nvdimm.c | 2 +- + hw/nvme/ctrl.c | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/9pfs/9p-xattr-user.c b/hw/9pfs/9p-xattr-user.c +index f2ae9582e6..535677ed60 100644 +--- a/hw/9pfs/9p-xattr-user.c ++++ b/hw/9pfs/9p-xattr-user.c +@@ -27,7 +27,7 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path, + { + if (strncmp(name, "user.virtfs.", 12) == 0) { + /* +- * Don't allow fetch of user.virtfs namesapce ++ * Don't allow fetch of user.virtfs namespace + * in case of mapped security + */ + errno = ENOATTR; +@@ -49,7 +49,7 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path, + name_size -= 12; + } else { + /* +- * Don't allow fetch of user.virtfs namesapce ++ * Don't allow fetch of user.virtfs namespace + * in case of mapped security + */ + return 0; +@@ -74,7 +74,7 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name, + { + if (strncmp(name, "user.virtfs.", 12) == 0) { + /* +- * Don't allow fetch of user.virtfs namesapce ++ * Don't allow fetch of user.virtfs namespace + * in case of mapped security + */ + errno = EACCES; +@@ -88,7 +88,7 @@ static int mp_user_removexattr(FsContext *ctx, + { + if (strncmp(name, "user.virtfs.", 12) == 0) { + /* +- * Don't allow fetch of user.virtfs namesapce ++ * Don't allow fetch of user.virtfs namespace + * in case of mapped security + */ + errno = EACCES; +diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c +index 0d43da19ea..5f85b16327 100644 +--- a/hw/acpi/nvdimm.c ++++ b/hw/acpi/nvdimm.c +@@ -476,7 +476,7 @@ struct NvdimmFuncGetLabelDataOut { + /* the size of buffer filled by QEMU. */ + uint32_t len; + uint32_t func_ret_status; /* return status code. */ +- uint8_t out_buf[]; /* the data got via Get Namesapce Label function. */ ++ uint8_t out_buf[]; /* the data got via Get Namespace Label function. */ + } QEMU_PACKED; + typedef struct NvdimmFuncGetLabelDataOut NvdimmFuncGetLabelDataOut; + QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataOut) > NVDIMM_DSM_MEMORY_SIZE); +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index d64dd9c361..7c9f97bdb3 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -71,7 +71,7 @@ + * the SUBNQN field in the controller will report the NQN of the subsystem + * device. This also enables multi controller capability represented in + * Identify Controller data structure in CMIC (Controller Multi-path I/O and +- * Namesapce Sharing Capabilities). ++ * Namespace Sharing Capabilities). + * + * - `aerl` + * The Asynchronous Event Request Limit (AERL). Indicates the maximum number +-- +2.27.0 + diff --git a/tulip-Assign-default-MAC-address-if-not-specified.patch b/tulip-Assign-default-MAC-address-if-not-specified.patch new file mode 100644 index 0000000000000000000000000000000000000000..5bf830823626516e81edb9e6b9fd81c70993bf32 --- /dev/null +++ b/tulip-Assign-default-MAC-address-if-not-specified.patch @@ -0,0 +1,58 @@ +From 78b2167f1e2fadb4de930bf51c699247031c8880 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 4 Sep 2023 08:27:33 +0000 +Subject: [PATCH] tulip: Assign default MAC address if not specified mainline + inclusion commit 052c2579b89b0d87debe8b05594b5180f0fde87d category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +The MAC of the tulip card is stored in the EEPROM and at startup +tulip_fill_eeprom() is called to initialize the EEPROM with the MAC +address given on the command line, e.g.: + -device tulip,mac=00:11:22:33:44:55 + +In case the mac address was not given on the command line, +tulip_fill_eeprom() initializes the MAC in EEPROM with 00:00:00:00:00:00 +which breaks e.g. a HP-UX guest. + +Fix this problem by moving qemu_macaddr_default_if_unset() a few lines +up, so that a default mac address is assigned before tulip_fill_eeprom() +initializes the EEPROM. + +Signed-off-by: Helge Deller +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + hw/net/tulip.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index 5f8badefca..b9e42c322a 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -967,6 +967,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) + pci_conf = s->dev.config; + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ + ++ qemu_macaddr_default_if_unset(&s->c.macaddr); ++ + s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); + tulip_fill_eeprom(s); + +@@ -981,8 +983,6 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) + + s->irq = pci_allocate_irq(&s->dev); + +- qemu_macaddr_default_if_unset(&s->c.macaddr); +- + s->nic = qemu_new_nic(&net_tulip_info, &s->c, + object_get_typename(OBJECT(pci_dev)), + pci_dev->qdev.id, s); +-- +2.41.0.windows.1 + diff --git a/tz-ppc-add-dummy-read-write-methods.patch b/tz-ppc-add-dummy-read-write-methods.patch deleted file mode 100644 index ee8fa6b096bf8e359cb326c581d0a72733c8c1c4..0000000000000000000000000000000000000000 --- a/tz-ppc-add-dummy-read-write-methods.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 52d1c1a258aef2b8ace50bb202ee7338ed0060f0 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:27:07 +0800 -Subject: [PATCH] tz-ppc: add dummy read/write methods - -fix CVE-2020-15469 - -Add tz-ppc-dummy mmio read/write methods to avoid assert failure -during initialisation. - -Signed-off-by: Prasad J Pandit - -Signed-off-by: Jiajie Li ---- - hw/misc/tz-ppc.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c -index 2a14a26f29..5b7b883866 100644 ---- a/hw/misc/tz-ppc.c -+++ b/hw/misc/tz-ppc.c -@@ -193,7 +193,20 @@ static bool tz_ppc_dummy_accepts(void *opaque, hwaddr addr, - g_assert_not_reached(); - } - -+static uint64_t tz_ppc_dummy_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ g_assert_not_reached(); -+} -+ -+static void tz_ppc_dummy_write(void *opaque, hwaddr addr, -+ uint64_t data, unsigned size) -+{ -+ g_assert_not_reached(); -+} -+ - static const MemoryRegionOps tz_ppc_dummy_ops = { -+ .read = tz_ppc_dummy_read, -+ .write = tz_ppc_dummy_write, - .valid.accepts = tz_ppc_dummy_accepts, - }; - --- -2.27.0 - diff --git a/uas-add-missing-return.patch b/uas-add-missing-return.patch new file mode 100644 index 0000000000000000000000000000000000000000..716c54073b7548f7cb460e89da78f8fc502fa318 --- /dev/null +++ b/uas-add-missing-return.patch @@ -0,0 +1,35 @@ +From da75066823387c4f24b55e21ee6c856ffa537174 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 10 Dec 2021 09:06:59 +0100 +Subject: [PATCH 2/6] uas: add missing return +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Otherwise we run the error handling code even for successful requests. + +Fixes: 13b250b12ad3 ("uas: add stream number sanity checks.") +Reported-by: Guenter Roeck +Signed-off-by: Gerd Hoffmann +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20211210080659.2537084-1-kraxel@redhat.com> +Signed-off-by: wanbo +--- + hw/usb/dev-uas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c +index 599d6b52a0..c9f295e7e4 100644 +--- a/hw/usb/dev-uas.c ++++ b/hw/usb/dev-uas.c +@@ -908,6 +908,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + p->status = USB_RET_STALL; + break; + } ++ return; + + err_stream: + error_report("%s: invalid stream %d", __func__, p->stream); +-- +2.27.0 + diff --git a/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch b/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch deleted file mode 100644 index 30724cedb050b52be09a0b081ffe36cd7599d268..0000000000000000000000000000000000000000 --- a/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 6705b9344f8d6f134f612c2e35e87cdda5aa6284 Mon Sep 17 00:00:00 2001 -From: Hikaru Nishida -Date: Tue, 15 Oct 2019 10:07:34 +0900 -Subject: [PATCH] ui: Fix hanging up Cocoa display on macOS 10.15 (Catalina) - -macOS API documentation says that before applicationDidFinishLaunching -is called, any events will not be processed. However, some events are -fired before it is called in macOS Catalina. This causes deadlock of -iothread_lock in handleEvent while it will be released after the -app_started_sem is posted. -This patch avoids processing events before the app_started_sem is -posted to prevent this deadlock. - -Buglink: https://bugs.launchpad.net/qemu/+bug/1847906 -Signed-off-by: Hikaru Nishida -Message-id: 20191015010734.85229-1-hikarupsp@gmail.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit dff742ad27efa474ec04accdbf422c9acfd3e30e) -Signed-off-by: Michael Roth ---- - ui/cocoa.m | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/ui/cocoa.m b/ui/cocoa.m -index c2984028c5..3026ead621 100644 ---- a/ui/cocoa.m -+++ b/ui/cocoa.m -@@ -132,6 +132,7 @@ NSArray * supportedImageFileTypes; - - static QemuSemaphore display_init_sem; - static QemuSemaphore app_started_sem; -+static bool allow_events; - - // Utility functions to run specified code block with iothread lock held - typedef void (^CodeBlock)(void); -@@ -727,6 +728,16 @@ QemuCocoaView *cocoaView; - - - (bool) handleEvent:(NSEvent *)event - { -+ if(!allow_events) { -+ /* -+ * Just let OSX have all events that arrive before -+ * applicationDidFinishLaunching. -+ * This avoids a deadlock on the iothread lock, which cocoa_display_init() -+ * will not drop until after the app_started_sem is posted. (In theory -+ * there should not be any such events, but OSX Catalina now emits some.) -+ */ -+ return false; -+ } - return bool_with_iothread_lock(^{ - return [self handleEventLocked:event]; - }); -@@ -1154,6 +1165,7 @@ QemuCocoaView *cocoaView; - - (void)applicationDidFinishLaunching: (NSNotification *) note - { - COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); -+ allow_events = true; - /* Tell cocoa_display_init to proceed */ - qemu_sem_post(&app_started_sem); - } --- -2.23.0 diff --git a/ui-clipboard-mark-type-as-not-available-when-there-i.patch b/ui-clipboard-mark-type-as-not-available-when-there-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..e698dec1d4dc9d0ebed4f3b6d287d7a23af335e5 --- /dev/null +++ b/ui-clipboard-mark-type-as-not-available-when-there-i.patch @@ -0,0 +1,89 @@ +From 6c61db85b2410480a203febabd12130a81f6f975 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Wed, 24 Jan 2024 11:57:48 +0100 +Subject: [PATCH] ui/clipboard: mark type as not available when there is no + data (CVE-2023-6683) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With VNC, a client can send a non-extended VNC_MSG_CLIENT_CUT_TEXT +message with len=0. In qemu_clipboard_set_data(), the clipboard info +will be updated setting data to NULL (because g_memdup(data, size) +returns NULL when size is 0). If the client does not set the +VNC_ENCODING_CLIPBOARD_EXT feature when setting up the encodings, then +the 'request' callback for the clipboard peer is not initialized. +Later, because data is NULL, qemu_clipboard_request() can be reached +via vdagent_chr_write() and vdagent_clipboard_recv_request() and +there, the clipboard owner's 'request' callback will be attempted to +be called, but that is a NULL pointer. + +In particular, this can happen when using the KRDC (22.12.3) VNC +client. + +Another scenario leading to the same issue is with two clients (say +noVNC and KRDC): + +The noVNC client sets the extension VNC_FEATURE_CLIPBOARD_EXT and +initializes its cbpeer. + +The KRDC client does not, but triggers a vnc_client_cut_text() (note +it's not the _ext variant)). There, a new clipboard info with it as +the 'owner' is created and via qemu_clipboard_set_data() is called, +which in turn calls qemu_clipboard_update() with that info. + +In qemu_clipboard_update(), the notifier for the noVNC client will be +called, i.e. vnc_clipboard_notify() and also set vs->cbinfo for the +noVNC client. The 'owner' in that clipboard info is the clipboard peer +for the KRDC client, which did not initialize the 'request' function. +That sounds correct to me, it is the owner of that clipboard info. + +Then when noVNC sends a VNC_MSG_CLIENT_CUT_TEXT message (it did set +the VNC_FEATURE_CLIPBOARD_EXT feature correctly, so a check for it +passes), that clipboard info is passed to qemu_clipboard_request() and +the original segfault still happens. + +Fix the issue by handling updates with size 0 differently. In +particular, mark in the clipboard info that the type is not available. + +While at it, switch to g_memdup2(), because g_memdup() is deprecated. + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2023-6683 +Reported-by: Markus Frank +Suggested-by: Marc-André Lureau +Signed-off-by: Fiona Ebner +Reviewed-by: Marc-André Lureau +Tested-by: Markus Frank +Message-ID: <20240124105749.204610-1-f.ebner@proxmox.com> +Signed-off-by: liuxiangdong +--- + ui/clipboard.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/ui/clipboard.c b/ui/clipboard.c +index d7b008d62a..6721852cb6 100644 +--- a/ui/clipboard.c ++++ b/ui/clipboard.c +@@ -123,9 +123,15 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer, + } + + g_free(info->types[type].data); +- info->types[type].data = g_memdup(data, size); +- info->types[type].size = size; +- info->types[type].available = true; ++ if (size) { ++ info->types[type].data = g_memdup(data, size); ++ info->types[type].size = size; ++ info->types[type].available = true; ++ } else { ++ info->types[type].data = NULL; ++ info->types[type].size = 0; ++ info->types[type].available = false; ++ } + + if (update) { + qemu_clipboard_update(info); +-- +2.27.0 + diff --git a/ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch b/ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..a63df9c4cfb1f10a1fb19fc76c0220c7e8be406c --- /dev/null +++ b/ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch @@ -0,0 +1,84 @@ +From 7da437c2f5440a9230e482d58d86b579221b3207 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Thu, 7 Apr 2022 10:17:12 +0200 +Subject: [PATCH 2/2] ui/cursor: fix integer overflow in cursor_alloc + (CVE-2021-4206) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Prevent potential integer overflow by limiting 'width' and 'height' to +512x512. Also change 'datasize' type to size_t. Refer to security +advisory https://starlabs.sg/advisories/22-4206/ for more information. + +Fixes: CVE-2021-4206 +Signed-off-by: Mauro Matteo Cascella +Reviewed-by: Marc-André Lureau +Message-Id: <20220407081712.345609-1-mcascell@redhat.com> +Signed-off-by: Gerd Hoffmann +--- + hw/display/qxl-render.c | 7 +++++++ + hw/display/vmware_vga.c | 2 ++ + ui/cursor.c | 8 +++++++- + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index 237ed293ba..ca217004bf 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -247,6 +247,13 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor, + size_t size; + + c = cursor_alloc(cursor->header.width, cursor->header.height); ++ ++ if (!c) { ++ qxl_set_guest_bug(qxl, "%s: cursor %ux%u alloc error", __func__, ++ cursor->header.width, cursor->header.height); ++ goto fail; ++ } ++ + c->hot_x = cursor->header.hot_spot_x; + c->hot_y = cursor->header.hot_spot_y; + switch (cursor->header.type) { +diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c +index e2969a6c81..2b81d6122f 100644 +--- a/hw/display/vmware_vga.c ++++ b/hw/display/vmware_vga.c +@@ -509,6 +509,8 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, + int i, pixels; + + qc = cursor_alloc(c->width, c->height); ++ assert(qc != NULL); ++ + qc->hot_x = c->hot_x; + qc->hot_y = c->hot_y; + switch (c->bpp) { +diff --git a/ui/cursor.c b/ui/cursor.c +index 1d62ddd4d0..835f0802f9 100644 +--- a/ui/cursor.c ++++ b/ui/cursor.c +@@ -46,6 +46,8 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[]) + + /* parse pixel data */ + c = cursor_alloc(width, height); ++ assert(c != NULL); ++ + for (pixel = 0, y = 0; y < height; y++, line++) { + for (x = 0; x < height; x++, pixel++) { + idx = xpm[line][x]; +@@ -91,7 +93,11 @@ QEMUCursor *cursor_builtin_left_ptr(void) + QEMUCursor *cursor_alloc(int width, int height) + { + QEMUCursor *c; +- int datasize = width * height * sizeof(uint32_t); ++ size_t datasize = width * height * sizeof(uint32_t); ++ ++ if (width > 512 || height > 512) { ++ return NULL; ++ } + + c = g_malloc0(sizeof(QEMUCursor) + datasize); + c->width = width; +-- +2.27.0 + diff --git a/ui-fix-crash-on-serial-reset-during-init.patch b/ui-fix-crash-on-serial-reset-during-init.patch new file mode 100644 index 0000000000000000000000000000000000000000..30aeb0cead9c1d76bea9d3c0ba716558ebb6017c --- /dev/null +++ b/ui-fix-crash-on-serial-reset-during-init.patch @@ -0,0 +1,70 @@ +From 548991fba5792b9efebc60cd75cba656624319d4 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Tue, 4 Apr 2023 18:11:30 +0800 +Subject: [PATCH] ui: fix crash on serial reset, during init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For ex, when resetting the xlnx-zcu102 machine: + +(lldb) bt +* thread #1, queue = 'com.apple.main-thread', stop reason = +EXC_BAD_ACCESS (code=1, address=0x50) + * frame #0: 0x10020a740 gd_vc_send_chars(vc=0x000000000) at +gtk.c:1759:41 [opt] + frame #1: 0x100636264 qemu_chr_fe_accept_input(be=) at +char-fe.c:159:9 [opt] + frame #2: 0x1000608e0 cadence_uart_reset_hold [inlined] +uart_rx_reset(s=0x10810a960) at cadence_uart.c:158:5 [opt] + frame #3: 0x1000608d4 cadence_uart_reset_hold(obj=0x10810a960) at +cadence_uart.c:530:5 [opt] + frame #4: 0x100580ab4 resettable_phase_hold(obj=0x10810a960, +opaque=0x000000000, type=) at resettable.c:0 [opt] + frame #5: 0x10057d1b0 bus_reset_child_foreach(obj=, +cb=(resettable_phase_hold at resettable.c:162), opaque=0x000000000, +type=RESET_TYPE_COLD) at bus.c:97:13 [opt] + frame #6: 0x1005809f8 resettable_phase_hold [inlined] +resettable_child_foreach(rc=0x000060000332d2c0, obj=0x0000600002c1c180, +cb=, opaque=0x000000000, type=RESET_TYPE_COLD) at +resettable.c:96:9 [opt] + frame #7: 0x1005809d8 resettable_phase_hold(obj=0x0000600002c1c180, +opaque=0x000000000, type=RESET_TYPE_COLD) at resettable.c:173:5 [opt] + frame #8: 0x1005803a0 +resettable_assert_reset(obj=0x0000600002c1c180, type=) at +resettable.c:60:5 [opt] + frame #9: 0x10058027c resettable_reset(obj=0x0000600002c1c180, +type=RESET_TYPE_COLD) at resettable.c:45:5 [opt] + +While the chardev is created early, the VirtualConsole is associated +after, during qemu_init_displays(). + +cheery-pick from 49152ac47003ca21fc6f2a5c3e517f79649e1541 +Signed-off-by: jipengfei_yewu@cmss.chinamobile.com +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20230220072251.3385878-1-marcandre.lureau@redhat.com> +--- + ui/gtk.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/ui/gtk.c b/ui/gtk.c +index 428f02f2df..6d9cb42b3d 100644 +--- a/ui/gtk.c ++++ b/ui/gtk.c +@@ -1718,8 +1718,10 @@ static void gd_vc_chr_accept_input(Chardev *chr) + { + VCChardev *vcd = VC_CHARDEV(chr); + VirtualConsole *vc = vcd->console; +- +- gd_vc_send_chars(vc); ++ ++ if (vc) { ++ gd_vc_send_chars(vc); ++ } + } + + static void gd_vc_chr_set_echo(Chardev *chr, bool echo) +-- +2.27.0 + diff --git a/ui-fix-crash-when-there-are-no-active_console.patch b/ui-fix-crash-when-there-are-no-active_console.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ed65946770fc864a1ebd499ef6bafa1e8163b3b --- /dev/null +++ b/ui-fix-crash-when-there-are-no-active_console.patch @@ -0,0 +1,42 @@ +From 89fda5a4410099a317bd1fcef56b130d6d97a2b5 Mon Sep 17 00:00:00 2001 +From: dinglimin_yewu +Date: Sat, 16 Sep 2023 17:41:07 +0800 +Subject: [PATCH] ui: fix crash when there are no active_console +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 48a35e12faf90a896c5aa4755812201e00d60316 + +Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. +0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812 +812 return con->hw_ops->ui_info != NULL; +(gdb) bt + +Fixes: +https://issues.redhat.com/browse/RHEL-2600 + +Signed-off-by: Marc-André Lureau +Reviewed-by: Albert Esteve +Signed-off-by: dinglimin_yewu +--- + ui/console.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ui/console.c b/ui/console.c +index 29a3e3f0f5..d22c3def20 100644 +--- a/ui/console.c ++++ b/ui/console.c +@@ -1526,6 +1526,9 @@ bool dpy_ui_info_supported(QemuConsole *con) + con = active_console; + } + ++ if (con == NULL) { ++ return false; ++ } + return con->hw_ops->ui_info != NULL; + } + +-- +2.41.0.windows.1 + diff --git a/ui-gtk-prevent-ui-lock-up-when-dpy_gl_update-called-.patch b/ui-gtk-prevent-ui-lock-up-when-dpy_gl_update-called-.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b658ad6cb1e68c7cf5873523c600f778daf0fec --- /dev/null +++ b/ui-gtk-prevent-ui-lock-up-when-dpy_gl_update-called-.patch @@ -0,0 +1,71 @@ +From 37625d78afdadb5e88aa4616d613f64184db41bf Mon Sep 17 00:00:00 2001 +From: Wanghe Xiao +Date: Sat, 25 Nov 2023 01:42:26 -0800 +Subject: [PATCH] ui/gtk: prevent ui lock up when dpy_gl_update called again + before current draw event occurs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 64f1359bd08060ffe7a5689fdcbaeec6d8a59980 + +A warning, "qemu: warning: console: no gl-unblock within" followed by +guest scanout lockup can happen if dpy_gl_update is called in a row +and the second call is made before gd_draw_event scheduled by the first +call is taking place. This is because draw call returns without decrementing +gl_block ref count if the dmabuf was already submitted as shown below. + +(gd_gl_area_draw/gd_egl_draw) + + if (dmabuf) { + if (!dmabuf->draw_submitted) { + return; + } else { + dmabuf->draw_submitted = false; + } + } + +So it should not schedule any redundant draw event in case draw_submitted is +already set in gd_egl_fluch/gd_gl_area_scanout_flush. + +Cc: Gerd Hoffmann +Cc: Vivek Kasireddy +Signed-off-by: Dongwon Kim +Reviewed-by: Marc-André Lureau +Message-Id: <20221021192315.9110-1-dongwon.kim@intel.com> +Signed-off-by: Gerd Hoffmann +Signed-off-by: Wanghe Xiao +--- + ui/gtk-egl.c | 2 +- + ui/gtk-gl-area.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c +index 45cb67712d..0e1e5bfaaa 100644 +--- a/ui/gtk-egl.c ++++ b/ui/gtk-egl.c +@@ -340,7 +340,7 @@ void gd_egl_flush(DisplayChangeListener *dcl, + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + GtkWidget *area = vc->gfx.drawing_area; + +- if (vc->gfx.guest_fb.dmabuf) { ++ if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { + graphic_hw_gl_block(vc->gfx.dcl.con, true); + vc->gfx.guest_fb.dmabuf->draw_submitted = true; + gtk_widget_queue_draw_area(area, x, y, w, h); +diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c +index 01e4e74ee3..11e0cb4af2 100644 +--- a/ui/gtk-gl-area.c ++++ b/ui/gtk-gl-area.c +@@ -246,7 +246,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, + { + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + +- if (vc->gfx.guest_fb.dmabuf) { ++ if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { + graphic_hw_gl_block(vc->gfx.dcl.con, true); + vc->gfx.guest_fb.dmabuf->draw_submitted = true; + } +-- +2.27.0 + diff --git a/ui-qmp-cmds-Improve-two-error-messages.patch b/ui-qmp-cmds-Improve-two-error-messages.patch new file mode 100644 index 0000000000000000000000000000000000000000..9cab96b9627fe5f75717433db4032e2d29a3efae --- /dev/null +++ b/ui-qmp-cmds-Improve-two-error-messages.patch @@ -0,0 +1,68 @@ +From 0425d773b3fa0da62be489ae6c76d1805f28f388 Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Mon, 27 Nov 2023 15:47:21 +0800 +Subject: [PATCH] ui/qmp-cmds: Improve two error messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from 517b0220efd421acf885eed109571a61e95b192a + +set_password with "protocol": "vnc" supports only "connected": "keep". +Any other value is rejected with + + Invalid parameter 'connected' + +Improve this to + + parameter 'connected' must be 'keep' when 'protocol' is 'vnc' + +client_migrate_info requires "port" or "tls-port". When both are +missing, it fails with + + Parameter 'port/tls-port' is missing + +Improve this to + + parameter 'port' or 'tls-port' is required + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-5-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé + +Signed-off-by: boringandboring +--- + monitor/misc.c | 2 +- + monitor/qmp-cmds.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/monitor/misc.c b/monitor/misc.c +index a3a6e47844..25a23e2290 100644 +--- a/monitor/misc.c ++++ b/monitor/misc.c +@@ -397,7 +397,7 @@ void qmp_client_migrate_info(const char *protocol, const char *hostname, + } + + if (!has_port && !has_tls_port) { +- error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port"); ++ error_setg(errp, "parameter 'port' or 'tls-port' is required"); + return; + } + +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index d71beace6a..b44cca8234 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -199,7 +199,8 @@ void qmp_set_password(const char *protocol, const char *password, + } else if (strcmp(protocol, "vnc") == 0) { + if (fail_if_connected || disconnect_if_connected) { + /* vnc supports "connected=keep" only */ +- error_setg(errp, QERR_INVALID_PARAMETER, "connected"); ++ error_setg(errp, "parameter 'connected' must be 'keep'" ++ " when 'protocol' is 'vnc'"); + return; + } + /* Note that setting an empty password will not disable login through +-- +2.27.0 + diff --git a/ui-vnc-clipboard-fix-infinite-loop-in-inflate_buffer.patch b/ui-vnc-clipboard-fix-infinite-loop-in-inflate_buffer.patch new file mode 100644 index 0000000000000000000000000000000000000000..ceb609cf569c7cfb25e88cb626980bfddbf71cba --- /dev/null +++ b/ui-vnc-clipboard-fix-infinite-loop-in-inflate_buffer.patch @@ -0,0 +1,58 @@ +From 2858029a5dbdd3fab73b1884e296daa3f3f0b1a1 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Tue, 4 Jul 2023 10:41:22 +0200 +Subject: [PATCH] ui/vnc-clipboard: fix infinite loop in inflate_buffer + (CVE-2023-3255) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A wrong exit condition may lead to an infinite loop when inflating a +valid zlib buffer containing some extra bytes in the `inflate_buffer` +function. The bug only occurs post-authentication. Return the buffer +immediately if the end of the compressed data has been reached +(Z_STREAM_END). + +Fixes: CVE-2023-3255 +Fixes: 0bf41cab ("ui/vnc: clipboard support") +Reported-by: Kevin Denis +Signed-off-by: Mauro Matteo Cascella +Reviewed-by: Marc-André Lureau +Tested-by: Marc-André Lureau +Message-ID: <20230704084210.101822-1-mcascell@redhat.com> +--- + ui/vnc-clipboard.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c +index 67284b556c..c84599cfdb 100644 +--- a/ui/vnc-clipboard.c ++++ b/ui/vnc-clipboard.c +@@ -51,8 +51,11 @@ static uint8_t *inflate_buffer(uint8_t *in, uint32_t in_len, uint32_t *size) + ret = inflate(&stream, Z_FINISH); + switch (ret) { + case Z_OK: +- case Z_STREAM_END: + break; ++ case Z_STREAM_END: ++ *size = stream.total_out; ++ inflateEnd(&stream); ++ return out; + case Z_BUF_ERROR: + out_len <<= 1; + if (out_len > (1 << 20)) { +@@ -67,11 +70,6 @@ static uint8_t *inflate_buffer(uint8_t *in, uint32_t in_len, uint32_t *size) + } + } + +- *size = stream.total_out; +- inflateEnd(&stream); +- +- return out; +- + err_end: + inflateEnd(&stream); + err: +-- +2.41.0.windows.1 + diff --git a/ui-vnc-clipboard-fix-inflate_buffer.patch b/ui-vnc-clipboard-fix-inflate_buffer.patch new file mode 100644 index 0000000000000000000000000000000000000000..f12ff9b4c00246c040c460a53c2a4d9b70e44371 --- /dev/null +++ b/ui-vnc-clipboard-fix-inflate_buffer.patch @@ -0,0 +1,47 @@ +From 7f19287be9b468b7065073a31d35c01b2632858d Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 5 Dec 2023 14:10:50 +0800 +Subject: [PATCH] ui/vnc-clipboard: fix inflate_buffer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from ebfbf394671163c14e2b24d98f3927a3151d1aff + +Commit d921fea338 ("ui/vnc-clipboard: fix infinite loop in +inflate_buffer (CVE-2023-3255)") removed this hunk, but it is still +required, because it can happen that stream.avail_in becomes zero +before coming across a return value of Z_STREAM_END in the loop. + +This fixes the host->guest direction of the clipboard with noVNC and +TigerVNC as clients. + +Fixes: d921fea338 ("ui/vnc-clipboard: fix infinite loop in inflate_buffer (CVE-2023-3255)") +Reported-by: Friedrich Weber +Signed-off-by: Fiona Ebner +Acked-by: Marc-André Lureau +Message-Id: <20231122125826.228189-1-f.ebner@proxmox.com> +Signed-off-by: qihao_yewu +--- + ui/vnc-clipboard.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c +index c84599cfdb..2bb1b07c40 100644 +--- a/ui/vnc-clipboard.c ++++ b/ui/vnc-clipboard.c +@@ -70,6 +70,11 @@ static uint8_t *inflate_buffer(uint8_t *in, uint32_t in_len, uint32_t *size) + } + } + ++ *size = stream.total_out; ++ inflateEnd(&stream); ++ ++ return out; ++ + err_end: + inflateEnd(&stream); + err: +-- +2.27.0 + diff --git a/ui-vnc-clipboard-fix-integer-underflow-in-vnc_client.patch b/ui-vnc-clipboard-fix-integer-underflow-in-vnc_client.patch new file mode 100644 index 0000000000000000000000000000000000000000..0fdcda62f03bc1fc1fbf418fc009c9eae5b92161 --- /dev/null +++ b/ui-vnc-clipboard-fix-integer-underflow-in-vnc_client.patch @@ -0,0 +1,55 @@ +From d307040b18bfcb1393b910f1bae753d5c12a4dc7 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Sun, 25 Sep 2022 22:45:11 +0200 +Subject: [PATCH] ui/vnc-clipboard: fix integer underflow in + vnc_client_cut_text_ext + +Extended ClientCutText messages start with a 4-byte header. If len < 4, +an integer underflow occurs in vnc_client_cut_text_ext. The result is +used to decompress data in a while loop in inflate_buffer, leading to +CPU consumption and denial of service. Prevent this by checking dlen in +protocol_client_msg. + +Fixes: CVE-2022-3165 +Fixes: 0bf41cab93e5 ("ui/vnc: clipboard support") +Reported-by: TangPeng +Signed-off-by: Mauro Matteo Cascella +Message-Id: <20220925204511.1103214-1-mcascell@redhat.com> +Signed-off-by: Gerd Hoffmann +--- + ui/vnc.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 6a05d06147..acb3629cd8 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -2442,8 +2442,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) + if (len == 1) { + return 8; + } ++ uint32_t dlen = abs(read_s32(data, 4)); + if (len == 8) { +- uint32_t dlen = abs(read_s32(data, 4)); + if (dlen > (1 << 20)) { + error_report("vnc: client_cut_text msg payload has %u bytes" + " which exceeds our limit of 1MB.", dlen); +@@ -2456,8 +2456,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) + } + + if (read_s32(data, 4) < 0) { +- vnc_client_cut_text_ext(vs, abs(read_s32(data, 4)), +- read_u32(data, 8), data + 12); ++ if (dlen < 4) { ++ error_report("vnc: malformed payload (header less than 4 bytes)" ++ " in extended clipboard pseudo-encoding."); ++ vnc_client_error(vs); ++ break; ++ } ++ vnc_client_cut_text_ext(vs, dlen, read_u32(data, 8), data + 12); + break; + } + vnc_client_cut_text(vs, read_u32(data, 4), data + 8); +-- +2.27.0 + diff --git a/ui-vnc-fix-debug-output-for-invalid-audio-message.patch b/ui-vnc-fix-debug-output-for-invalid-audio-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..080d37fc3025d3d7765e403f89f90a21c050f3f6 --- /dev/null +++ b/ui-vnc-fix-debug-output-for-invalid-audio-message.patch @@ -0,0 +1,36 @@ +From 2677d371ed65941912149218fb5683f0b8db0760 Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 09:57:38 +0000 +Subject: [PATCH] ui/vnc: fix debug output for invalid audio message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The debug message was cut and pasted from the invalid audio format +case, but the audio message is at bytes 2-3. + +cheery-pick from 0cb9c5880e6b8dedc4e20026ce859dd1ea9aac84 + +Signed-off-by: jipengfei_yewu +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Paolo Bonzini +--- + ui/vnc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index f4322a9065..f8978b0e65 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -2567,7 +2567,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) + vs, vs->ioc, vs->as.fmt, vs->as.nchannels, vs->as.freq); + break; + default: +- VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4)); ++ VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 2)); + vnc_client_error(vs); + break; + } +-- +2.27.0 + diff --git a/ui-vnc.c-Fixed-a-deadlock-bug.patch b/ui-vnc.c-Fixed-a-deadlock-bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..a2f1fa4c0d75a6fbfcd825b1eff8432395598e1a --- /dev/null +++ b/ui-vnc.c-Fixed-a-deadlock-bug.patch @@ -0,0 +1,71 @@ +From c6e08e8f6e296ab2e8149c4362363a5fd31813f6 Mon Sep 17 00:00:00 2001 +From: Rao Lei +Date: Wed, 5 Jan 2022 10:08:08 +0800 +Subject: [PATCH] ui/vnc.c: Fixed a deadlock bug. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The GDB statck is as follows: +(gdb) bt +0 __lll_lock_wait (futex=futex@entry=0x56211df20360, private=0) at lowlevellock.c:52 +1 0x00007f263caf20a3 in __GI___pthread_mutex_lock (mutex=0x56211df20360) at ../nptl/pthread_mutex_lock.c:80 +2 0x000056211a757364 in qemu_mutex_lock_impl (mutex=0x56211df20360, file=0x56211a804857 "../ui/vnc-jobs.h", line=60) + at ../util/qemu-thread-posix.c:80 +3 0x000056211a0ef8c7 in vnc_lock_output (vs=0x56211df14200) at ../ui/vnc-jobs.h:60 +4 0x000056211a0efcb7 in vnc_clipboard_send (vs=0x56211df14200, count=1, dwords=0x7ffdf1701338) at ../ui/vnc-clipboard.c:138 +5 0x000056211a0f0129 in vnc_clipboard_notify (notifier=0x56211df244c8, data=0x56211dd1bbf0) at ../ui/vnc-clipboard.c:209 +6 0x000056211a75dde8 in notifier_list_notify (list=0x56211afa17d0 , data=0x56211dd1bbf0) at ../util/notify.c:39 +7 0x000056211a0bf0e6 in qemu_clipboard_update (info=0x56211dd1bbf0) at ../ui/clipboard.c:50 +8 0x000056211a0bf05d in qemu_clipboard_peer_release (peer=0x56211df244c0, selection=QEMU_CLIPBOARD_SELECTION_CLIPBOARD) + at ../ui/clipboard.c:41 +9 0x000056211a0bef9b in qemu_clipboard_peer_unregister (peer=0x56211df244c0) at ../ui/clipboard.c:19 +10 0x000056211a0d45f3 in vnc_disconnect_finish (vs=0x56211df14200) at ../ui/vnc.c:1358 +11 0x000056211a0d4c9d in vnc_client_read (vs=0x56211df14200) at ../ui/vnc.c:1611 +12 0x000056211a0d4df8 in vnc_client_io (ioc=0x56211ce70690, condition=G_IO_IN, opaque=0x56211df14200) at ../ui/vnc.c:1649 +13 0x000056211a5b976c in qio_channel_fd_source_dispatch + (source=0x56211ce50a00, callback=0x56211a0d4d71 , user_data=0x56211df14200) at ../io/channel-watch.c:84 +14 0x00007f263ccede8e in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 +15 0x000056211a77d4a1 in glib_pollfds_poll () at ../util/main-loop.c:232 +16 0x000056211a77d51f in os_host_main_loop_wait (timeout=958545) at ../util/main-loop.c:255 +17 0x000056211a77d630 in main_loop_wait (nonblocking=0) at ../util/main-loop.c:531 +18 0x000056211a45bc8e in qemu_main_loop () at ../softmmu/runstate.c:726 +19 0x000056211a0b45fa in main (argc=69, argv=0x7ffdf1701778, envp=0x7ffdf17019a8) at ../softmmu/main.c:50 + +From the call trace, we can see it is a deadlock bug. +vnc_disconnect_finish will acquire the output_mutex. +But, the output_mutex will be acquired again in vnc_clipboard_send. +Repeated locking will cause deadlock. So, I move +qemu_clipboard_peer_unregister() behind vnc_unlock_output(); + +Fixes: 0bf41cab93e ("ui/vnc: clipboard support") +Signed-off-by: Lei Rao +Reviewed-by: Marc-André Lureau +Message-Id: <20220105020808.597325-1-lei.rao@intel.com> +Signed-off-by: Gerd Hoffmann +--- + ui/vnc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index f8978b0e65..71e3627be2 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -1354,12 +1354,12 @@ void vnc_disconnect_finish(VncState *vs) + /* last client gone */ + vnc_update_server_surface(vs->vd); + } ++ vnc_unlock_output(vs); ++ + if (vs->cbpeer.update.notify) { + qemu_clipboard_peer_unregister(&vs->cbpeer); + } + +- vnc_unlock_output(vs); +- + qemu_mutex_destroy(&vs->output_mutex); + if (vs->bh != NULL) { + qemu_bh_delete(vs->bh); +-- +2.27.0 + diff --git a/update-linux-headers-Import-iommu.h.patch b/update-linux-headers-Import-iommu.h.patch index eea744e5063aeba90d9e16967f88b9d902de93f1..5653e6a4ddd6b5cdb7a68dbef54f010d0e3a1cda 100644 --- a/update-linux-headers-Import-iommu.h.patch +++ b/update-linux-headers-Import-iommu.h.patch @@ -1,4 +1,4 @@ -From 78c269f4ed09a3272d99a65d9c86977a01ef99c8 Mon Sep 17 00:00:00 2001 +From 694acf3c321908d26ce508842b7bd076664ffbc6 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 9 May 2019 10:23:42 -0400 Subject: [PATCH] update-linux-headers: Import iommu.h @@ -12,15 +12,15 @@ Signed-off-by: Kunkun Jiang 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh -index f76d77363b..dfdfdfddcf 100755 +index fea4d6eb65..acde610733 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh -@@ -141,7 +141,7 @@ done +@@ -144,7 +144,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" --for header in kvm.h vfio.h vfio_ccw.h vhost.h \ -+for header in kvm.h vfio.h vfio_ccw.h vhost.h iommu.h \ +-for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ ++for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h iommu.h \ psci.h psp-sev.h userfaultfd.h mman.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done diff --git a/usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch b/usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch deleted file mode 100644 index 836e01ce8c2eda354b60c5b32b0e8303ab652f7c..0000000000000000000000000000000000000000 --- a/usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 93be5f3334394aa9a1794007aed79e75cf4d348b Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 21 Jun 2021 10:19:58 +0800 -Subject: [PATCH] usb: limit combined packets to 1 MiB (CVE-2021-3527) - -Fix CVE-2021-3527 - -usb-host and usb-redirect try to batch bulk transfers by combining many -small usb packets into a single, large transfer request, to reduce the -overhead and improve performance. - -This patch adds a size limit of 1 MiB for those combined packets to -restrict the host resources the guest can bind that way. -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann -Message-Id: <20210503132915.2335822-6-kraxel@redhat.com> - -Signed-off-by: Jiajie Li ---- - hw/usb/combined-packet.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c -index 5d57e883dc..e56802f89a 100644 ---- a/hw/usb/combined-packet.c -+++ b/hw/usb/combined-packet.c -@@ -171,7 +171,9 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) - if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok || - next == NULL || - /* Work around for Linux usbfs bulk splitting + migration */ -- (totalsize == (16 * KiB - 36) && p->int_req)) { -+ (totalsize == (16 * KiB - 36) && p->int_req) || -+ /* Next package may grow combined package over 1MiB */ -+ totalsize > 1 * MiB - ep->max_packet_size) { - usb_device_handle_data(ep->dev, first); - assert(first->status == USB_RET_ASYNC); - if (first->combined) { --- -2.27.0 - diff --git a/usbredir-Prevent-recursion-in-usbredir_write.patch b/usbredir-Prevent-recursion-in-usbredir_write.patch deleted file mode 100644 index 29eb50f2d08b41c570fa90940ac01894c046e90e..0000000000000000000000000000000000000000 --- a/usbredir-Prevent-recursion-in-usbredir_write.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 30203c01fa1bb2a7b92575683f85695a2d420b38 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 18 Dec 2019 11:30:12 +0000 -Subject: [PATCH] usbredir: Prevent recursion in usbredir_write - -I've got a case where usbredir_write manages to call back into itself -via spice; this patch causes the recursion to fail (0 bytes) the write; -this seems to avoid the deadlock I was previously seeing. - -I can't say I fully understand the interaction of usbredir and spice; -but there are a few similar guards in spice and usbredir -to catch other cases especially onces also related to spice_server_char_device_wakeup - -This case seems to be triggered by repeated migration+repeated -reconnection of the viewer; but my debugging suggests the migration -finished before this hits. - -The backtrace of the hang looks like: - reds_handle_ticket - reds_handle_other_links - reds_channel_do_link - red_channel_connect - spicevmc_connect - usbredir_create_parser - usbredirparser_do_write - usbredir_write - qemu_chr_fe_write - qemu_chr_write - qemu_chr_write_buffer - spice_chr_write - spice_server_char_device_wakeup - red_char_device_wakeup - red_char_device_write_to_device - vmc_write - usbredirparser_do_write - usbredir_write - qemu_chr_fe_write - qemu_chr_write - qemu_chr_write_buffer - qemu_mutex_lock_impl - -and we fail as we lang through qemu_chr_write_buffer's lock -twice. - -Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1752320 - -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20191218113012.13331-1-dgilbert@redhat.com> -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 9764a57987..3cf82589ed 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -109,6 +109,7 @@ struct USBRedirDevice { - /* Properties */ - CharBackend cs; - bool enable_streams; -+ bool in_write; - uint8_t debug; - int32_t bootindex; - char *filter_str; -@@ -286,6 +287,13 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - return 0; - } - -+ /* Recursion check */ -+ if (dev->in_write) { -+ DPRINTF("usbredir_write recursion\n"); -+ return 0; -+ } -+ dev->in_write = true; -+ - r = qemu_chr_fe_write(&dev->cs, data, count); - if (r < count) { - if (!dev->watch) { -@@ -296,6 +304,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - r = 0; - } - } -+ dev->in_write = false; - return r; - } - --- -2.27.0 - diff --git a/usbredir-fix-buffer-overflow-on-vmload.patch b/usbredir-fix-buffer-overflow-on-vmload.patch deleted file mode 100644 index 4a43c35cad37bcece9822ddf61033c18dd7edfc4..0000000000000000000000000000000000000000 --- a/usbredir-fix-buffer-overflow-on-vmload.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 66fce891aecec3969d1ba979cf0a9a6df70afecd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 7 Aug 2019 12:40:48 +0400 -Subject: [PATCH] usbredir: fix buffer-overflow on vmload -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If interface_count is NO_INTERFACE_INFO, let's not access the arrays -out-of-bounds. - -==994==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x625000243930 at pc 0x5642068086a8 bp 0x7f0b6f9ffa50 sp 0x7f0b6f9ffa40 -READ of size 1 at 0x625000243930 thread T0 - #0 0x5642068086a7 in usbredir_check_bulk_receiving /home/elmarco/src/qemu/hw/usb/redirect.c:1503 - #1 0x56420681301c in usbredir_post_load /home/elmarco/src/qemu/hw/usb/redirect.c:2154 - #2 0x5642068a56c2 in vmstate_load_state /home/elmarco/src/qemu/migration/vmstate.c:168 - #3 0x56420688e2ac in vmstate_load /home/elmarco/src/qemu/migration/savevm.c:829 - #4 0x5642068980cb in qemu_loadvm_section_start_full /home/elmarco/src/qemu/migration/savevm.c:2211 - #5 0x564206899645 in qemu_loadvm_state_main /home/elmarco/src/qemu/migration/savevm.c:2395 - #6 0x5642068998cf in qemu_loadvm_state /home/elmarco/src/qemu/migration/savevm.c:2467 - #7 0x56420685f3e9 in process_incoming_migration_co /home/elmarco/src/qemu/migration/migration.c:449 - #8 0x564207106c47 in coroutine_trampoline /home/elmarco/src/qemu/util/coroutine-ucontext.c:115 - #9 0x7f0c0604e37f (/lib64/libc.so.6+0x4d37f) - -Signed-off-by: Marc-André Lureau -Reviewed-by: Liam Merwick -Reviewed-by: Li Qiang -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 20190807084048.4258-1-marcandre.lureau@redhat.com -Signed-off-by: Gerd Hoffmann -Signed-off-by: Zhenyu Ye ---- - hw/usb/redirect.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 998fc6e4..9764a579 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1495,6 +1495,11 @@ static void usbredir_check_bulk_receiving(USBRedirDevice *dev) - for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { - dev->endpoint[i].bulk_receiving_enabled = 0; - } -+ -+ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) { -+ return; -+ } -+ - for (i = 0; i < dev->interface_info.interface_count; i++) { - quirks = usb_get_quirks(dev->device_info.vendor_id, - dev->device_info.product_id, --- -2.22.0.windows.1 - diff --git a/util-Add-iova_tree_alloc_map.patch b/util-Add-iova_tree_alloc_map.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1ab3f7cee5b07d2705e10d2ef2483c59ce78e38 --- /dev/null +++ b/util-Add-iova_tree_alloc_map.patch @@ -0,0 +1,219 @@ +From 6dac473fb3f4f98ef67c63a38b00465299519132 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:48 +0100 +Subject: [PATCH] util: Add iova_tree_alloc_map +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This iova tree function allows it to look for a hole in allocated +regions and return a totally new translation for a given translated +address. + +It's usage is mainly to allow devices to access qemu address space, +remapping guest's one into a new iova space where qemu can add chunks of +addresses. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Peter Xu +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 18 ++++++ + util/iova-tree.c | 136 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 154 insertions(+) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index 8249edd764..d066400f09 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -29,6 +29,7 @@ + #define IOVA_OK (0) + #define IOVA_ERR_INVALID (-1) /* Invalid parameters */ + #define IOVA_ERR_OVERLAP (-2) /* IOVA range overlapped */ ++#define IOVA_ERR_NOMEM (-3) /* Cannot allocate */ + + typedef struct IOVATree IOVATree; + typedef struct DMAMap { +@@ -119,6 +120,23 @@ const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova); + */ + void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator); + ++/** ++ * iova_tree_alloc_map: ++ * ++ * @tree: the iova tree to allocate from ++ * @map: the new map (as translated addr & size) to allocate in the iova region ++ * @iova_begin: the minimum address of the allocation ++ * @iova_end: the maximum addressable direction of the allocation ++ * ++ * Allocates a new region of a given size, between iova_min and iova_max. ++ * ++ * Return: Same as iova_tree_insert, but cannot overlap and can return error if ++ * iova tree is out of free contiguous range. The caller gets the assigned iova ++ * in map->iova. ++ */ ++int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin, ++ hwaddr iova_end); ++ + /** + * iova_tree_destroy: + * +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 23ea35b7a4..139626b46f 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -16,6 +16,40 @@ struct IOVATree { + GTree *tree; + }; + ++/* Args to pass to iova_tree_alloc foreach function. */ ++struct IOVATreeAllocArgs { ++ /* Size of the desired allocation */ ++ size_t new_size; ++ ++ /* The minimum address allowed in the allocation */ ++ hwaddr iova_begin; ++ ++ /* Map at the left of the hole, can be NULL if "this" is first one */ ++ const DMAMap *prev; ++ ++ /* Map at the right of the hole, can be NULL if "prev" is the last one */ ++ const DMAMap *this; ++ ++ /* If found, we fill in the IOVA here */ ++ hwaddr iova_result; ++ ++ /* Whether have we found a valid IOVA */ ++ bool iova_found; ++}; ++ ++/** ++ * Iterate args to the next hole ++ * ++ * @args: The alloc arguments ++ * @next: The next mapping in the tree. Can be NULL to signal the last one ++ */ ++static void iova_tree_alloc_args_iterate(struct IOVATreeAllocArgs *args, ++ const DMAMap *next) ++{ ++ args->prev = args->this; ++ args->this = next; ++} ++ + static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data) + { + const DMAMap *m1 = a, *m2 = b; +@@ -107,6 +141,108 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map) + return IOVA_OK; + } + ++/** ++ * Try to find an unallocated IOVA range between prev and this elements. ++ * ++ * @args: Arguments to allocation ++ * ++ * Cases: ++ * ++ * (1) !prev, !this: No entries allocated, always succeed ++ * ++ * (2) !prev, this: We're iterating at the 1st element. ++ * ++ * (3) prev, !this: We're iterating at the last element. ++ * ++ * (4) prev, this: this is the most common case, we'll try to find a hole ++ * between "prev" and "this" mapping. ++ * ++ * Note that this function assumes the last valid iova is HWADDR_MAX, but it ++ * searches linearly so it's easy to discard the result if it's not the case. ++ */ ++static void iova_tree_alloc_map_in_hole(struct IOVATreeAllocArgs *args) ++{ ++ const DMAMap *prev = args->prev, *this = args->this; ++ uint64_t hole_start, hole_last; ++ ++ if (this && this->iova + this->size < args->iova_begin) { ++ return; ++ } ++ ++ hole_start = MAX(prev ? prev->iova + prev->size + 1 : 0, args->iova_begin); ++ hole_last = this ? this->iova : HWADDR_MAX; ++ ++ if (hole_last - hole_start > args->new_size) { ++ args->iova_result = hole_start; ++ args->iova_found = true; ++ } ++} ++ ++/** ++ * Foreach dma node in the tree, compare if there is a hole with its previous ++ * node (or minimum iova address allowed) and the node. ++ * ++ * @key: Node iterating ++ * @value: Node iterating ++ * @pargs: Struct to communicate with the outside world ++ * ++ * Return: false to keep iterating, true if needs break. ++ */ ++static gboolean iova_tree_alloc_traverse(gpointer key, gpointer value, ++ gpointer pargs) ++{ ++ struct IOVATreeAllocArgs *args = pargs; ++ DMAMap *node = value; ++ ++ assert(key == value); ++ ++ iova_tree_alloc_args_iterate(args, node); ++ iova_tree_alloc_map_in_hole(args); ++ return args->iova_found; ++} ++ ++int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin, ++ hwaddr iova_last) ++{ ++ struct IOVATreeAllocArgs args = { ++ .new_size = map->size, ++ .iova_begin = iova_begin, ++ }; ++ ++ if (unlikely(iova_last < iova_begin)) { ++ return IOVA_ERR_INVALID; ++ } ++ ++ /* ++ * Find a valid hole for the mapping ++ * ++ * Assuming low iova_begin, so no need to do a binary search to ++ * locate the first node. ++ * ++ * TODO: Replace all this with g_tree_node_first/next/last when available ++ * (from glib since 2.68). To do it with g_tree_foreach complicates the ++ * code a lot. ++ * ++ */ ++ g_tree_foreach(tree->tree, iova_tree_alloc_traverse, &args); ++ if (!args.iova_found) { ++ /* ++ * Either tree is empty or the last hole is still not checked. ++ * g_tree_foreach does not compare (last, iova_last] range, so we check ++ * it here. ++ */ ++ iova_tree_alloc_args_iterate(&args, NULL); ++ iova_tree_alloc_map_in_hole(&args); ++ } ++ ++ if (!args.iova_found || args.iova_result + map->size > iova_last) { ++ return IOVA_ERR_NOMEM; ++ } ++ ++ map->iova = args.iova_result; ++ return iova_tree_insert(tree, map); ++} ++ + void iova_tree_destroy(IOVATree *tree) + { + g_tree_destroy(tree->tree); +-- +2.27.0 + diff --git a/util-Return-void-on-iova_tree_remove.patch b/util-Return-void-on-iova_tree_remove.patch new file mode 100644 index 0000000000000000000000000000000000000000..a38c7c3d52038de0581bc5dc0187273a530ec903 --- /dev/null +++ b/util-Return-void-on-iova_tree_remove.patch @@ -0,0 +1,61 @@ +From b4c0eb3ad95c5c9a32cf87d30647d63ec9c193a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 27 Apr 2022 17:49:31 +0200 +Subject: [PATCH] util: Return void on iova_tree_remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It always returns IOVA_OK so nobody uses it. + +Acked-by: Jason Wang +Reviewed-by: Peter Xu +Signed-off-by: Eugenio Pérez +Message-Id: <20220427154931.3166388-1-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 4 +--- + util/iova-tree.c | 4 +--- + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index c938fb0793..16bbfdf5f8 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -72,10 +72,8 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); + * provided. The range does not need to be exactly what has inserted, + * all the mappings that are included in the provided range will be + * removed from the tree. Here map->translated_addr is meaningless. +- * +- * Return: 0 if succeeded, or <0 if error. + */ +-int iova_tree_remove(IOVATree *tree, const DMAMap *map); ++void iova_tree_remove(IOVATree *tree, const DMAMap *map); + + /** + * iova_tree_find: +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 6dff29c1f6..fee530a579 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -164,15 +164,13 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) + g_tree_foreach(tree->tree, iova_tree_traverse, iterator); + } + +-int iova_tree_remove(IOVATree *tree, const DMAMap *map) ++void iova_tree_remove(IOVATree *tree, const DMAMap *map) + { + const DMAMap *overlap; + + while ((overlap = iova_tree_find(tree, map))) { + g_tree_remove(tree->tree, overlap); + } +- +- return IOVA_OK; + } + + /** +-- +2.27.0 + diff --git a/util-accept-iova_tree_remove_parameter-by-value.patch b/util-accept-iova_tree_remove_parameter-by-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ee105934c28c783b552eddec56e2490a9c38da8 --- /dev/null +++ b/util-accept-iova_tree_remove_parameter-by-value.patch @@ -0,0 +1,173 @@ +From 4ac2c0c847ffee0fb6aa92a9735be9448c62c107 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:04 +0200 +Subject: [PATCH] util: accept iova_tree_remove_parameter by value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's convenient to call iova_tree_remove from a map returned from +iova_tree_find or iova_tree_find_iova. With the current code this is not +possible, since we will free it, and then we will try to search for it +again. + +Fix it making accepting the map by value, forcing a copy of the +argument. Not applying a fixes tag, since there is no use like that at +the moment. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/i386/intel_iommu.c | 6 +++--- + hw/virtio/vhost-iova-tree.c | 2 +- + hw/virtio/vhost-iova-tree.h | 2 +- + hw/virtio/vhost-vdpa.c | 6 +++--- + include/qemu/iova-tree.h | 2 +- + net/vhost-vdpa.c | 4 ++-- + util/iova-tree.c | 4 ++-- + 7 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 5b865ac08c..2d5ad84149 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1157,7 +1157,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) + return ret; + } + /* Drop any existing mapping */ +- iova_tree_remove(as->iova_tree, &target); ++ iova_tree_remove(as->iova_tree, target); + /* Recover the correct type */ + event->type = IOMMU_NOTIFIER_MAP; + entry->perm = cache_perm; +@@ -1170,7 +1170,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) + trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); + return 0; + } +- iova_tree_remove(as->iova_tree, &target); ++ iova_tree_remove(as->iova_tree, target); + } + + trace_vtd_page_walk_one(info->domain_id, entry->iova, +@@ -3516,7 +3516,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + + map.iova = n->start; + map.size = size; +- iova_tree_remove(as->iova_tree, &map); ++ iova_tree_remove(as->iova_tree, map); + } + + static void vtd_address_space_unmap_all(IntelIOMMUState *s) +diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c +index 55fed1fefb..1339a4de8b 100644 +--- a/hw/virtio/vhost-iova-tree.c ++++ b/hw/virtio/vhost-iova-tree.c +@@ -104,7 +104,7 @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) + * @iova_tree: The vhost iova tree + * @map: The map to remove + */ +-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map) ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map) + { + iova_tree_remove(iova_tree->iova_taddr_map, map); + } +diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h +index 6a4f24e0f9..4adfd79ff0 100644 +--- a/hw/virtio/vhost-iova-tree.h ++++ b/hw/virtio/vhost-iova-tree.h +@@ -22,6 +22,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete); + const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree, + const DMAMap *map); + int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map); +-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map); ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map); + + #endif +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 02dab41c42..0f640f670b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -242,7 +242,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + + fail_map: + if (v->shadow_vqs_enabled) { +- vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ vhost_iova_tree_remove(v->iova_tree, mem_region); + } + + fail: +@@ -302,7 +302,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + return; + } + iova = result->iova; +- vhost_iova_tree_remove(v->iova_tree, result); ++ vhost_iova_tree_remove(v->iova_tree, *result); + } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); +@@ -946,7 +946,7 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, + needle->perm == IOMMU_RO); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Cannot map region to device"); +- vhost_iova_tree_remove(v->iova_tree, needle); ++ vhost_iova_tree_remove(v->iova_tree, *needle); + } + + return r == 0; +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index 16bbfdf5f8..8528e5c98f 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -73,7 +73,7 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); + * all the mappings that are included in the provided range will be + * removed from the tree. Here map->translated_addr is meaningless. + */ +-void iova_tree_remove(IOVATree *tree, const DMAMap *map); ++void iova_tree_remove(IOVATree *tree, DMAMap map); + + /** + * iova_tree_find: +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 0f75aa6080..8cfd086639 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -252,7 +252,7 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); + } + +- vhost_iova_tree_remove(tree, map); ++ vhost_iova_tree_remove(tree, *map); + } + + static size_t vhost_vdpa_net_cvq_cmd_len(void) +@@ -305,7 +305,7 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, + return true; + + dma_map_err: +- vhost_iova_tree_remove(v->iova_tree, &map); ++ vhost_iova_tree_remove(v->iova_tree, map); + return false; + } + +diff --git a/util/iova-tree.c b/util/iova-tree.c +index fee530a579..536789797e 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -164,11 +164,11 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) + g_tree_foreach(tree->tree, iova_tree_traverse, iterator); + } + +-void iova_tree_remove(IOVATree *tree, const DMAMap *map) ++void iova_tree_remove(IOVATree *tree, DMAMap map) + { + const DMAMap *overlap; + +- while ((overlap = iova_tree_find(tree, map))) { ++ while ((overlap = iova_tree_find(tree, &map))) { + g_tree_remove(tree->tree, overlap); + } + } +-- +2.27.0 + diff --git a/util-add-iova_tree_find_iova.patch b/util-add-iova_tree_find_iova.patch new file mode 100644 index 0000000000000000000000000000000000000000..fd935fe9927efbdb8a138985a9daa329035c599c --- /dev/null +++ b/util-add-iova_tree_find_iova.patch @@ -0,0 +1,116 @@ +From 087ef4f1cfef58eadcb157585b70cf716c567305 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:49 +0100 +Subject: [PATCH] util: add iova_tree_find_iova +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function does the reverse operation of iova_tree_find: To look for +a mapping that match a translated address so we can do the reverse. + +This have linear complexity instead of logarithmic, but it supports +overlapping HVA. Future developments could reduce it. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 20 +++++++++++++++++++- + util/iova-tree.c | 34 ++++++++++++++++++++++++++++++++++ + 2 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index d066400f09..c938fb0793 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -83,7 +83,7 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map); + * @tree: the iova tree to search from + * @map: the mapping to search + * +- * Search for a mapping in the iova tree that overlaps with the ++ * Search for a mapping in the iova tree that iova overlaps with the + * mapping range specified. Only the first found mapping will be + * returned. + * +@@ -95,6 +95,24 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map); + */ + const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map); + ++/** ++ * iova_tree_find_iova: ++ * ++ * @tree: the iova tree to search from ++ * @map: the mapping to search ++ * ++ * Search for a mapping in the iova tree that translated_addr overlaps with the ++ * mapping range specified. Only the first found mapping will be ++ * returned. ++ * ++ * Return: DMAMap pointer if found, or NULL if not found. Note that ++ * the returned DMAMap pointer is maintained internally. User should ++ * only read the content but never modify or free the content. Also, ++ * user is responsible to make sure the pointer is valid (say, no ++ * concurrent deletion in progress). ++ */ ++const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map); ++ + /** + * iova_tree_find_address: + * +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 139626b46f..6dff29c1f6 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -37,6 +37,11 @@ struct IOVATreeAllocArgs { + bool iova_found; + }; + ++typedef struct IOVATreeFindIOVAArgs { ++ const DMAMap *needle; ++ const DMAMap *result; ++} IOVATreeFindIOVAArgs; ++ + /** + * Iterate args to the next hole + * +@@ -81,6 +86,35 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map) + return g_tree_lookup(tree->tree, map); + } + ++static gboolean iova_tree_find_address_iterator(gpointer key, gpointer value, ++ gpointer data) ++{ ++ const DMAMap *map = key; ++ IOVATreeFindIOVAArgs *args = data; ++ const DMAMap *needle; ++ ++ g_assert(key == value); ++ ++ needle = args->needle; ++ if (map->translated_addr + map->size < needle->translated_addr || ++ needle->translated_addr + needle->size < map->translated_addr) { ++ return false; ++ } ++ ++ args->result = map; ++ return true; ++} ++ ++const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map) ++{ ++ IOVATreeFindIOVAArgs args = { ++ .needle = map, ++ }; ++ ++ g_tree_foreach(tree->tree, iova_tree_find_address_iterator, &args); ++ return args.result; ++} ++ + const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova) + { + const DMAMap map = { .iova = iova, .size = 0 }; +-- +2.27.0 + diff --git a/util-add-slirp_fmt-helpers.patch b/util-add-slirp_fmt-helpers.patch deleted file mode 100644 index b752f1293a0b88ef0ae01410a2fc63f9ff875df8..0000000000000000000000000000000000000000 --- a/util-add-slirp_fmt-helpers.patch +++ /dev/null @@ -1,124 +0,0 @@ -From f3475a4a22dd84be0d2d7daa11676ac861da64bc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureauls?= -Date: Tue, 14 Apr 2020 18:51:39 +0800 -Subject: [PATCH] util: add slirp_fmt() helpers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Various calls to snprintf() in libslirp assume that snprintf() returns -"only" the number of bytes written (excluding terminating NUL). - -https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04 - -"Upon successful completion, the snprintf() function shall return the -number of bytes that would be written to s had n been sufficiently -large excluding the terminating null byte." - -Introduce slirp_fmt() that handles several pathological cases the -way libslirp usually expect: - -- treat error as fatal (instead of silently returning -1) - -- fmt0() will always \0 end - -- return the number of bytes actually written (instead of what would -have been written, which would usually result in OOB later), including -the ending \0 for fmt0() - -- warn if truncation happened (instead of ignoring) - -Other less common cases can still be handled with strcpy/snprintf() etc. -Signed-off-by: default avatarMarc-André Lureau -Reviewed-by: Samuel Thibault's avatarSamuel Thibault -Message-Id: <20200127092414.169796-2-marcandre.lureau@redhat.com> ---- - slirp/src/util.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - slirp/src/util.h | 3 +++ - 2 files changed, 66 insertions(+) - -diff --git a/slirp/src/util.c b/slirp/src/util.c -index e5960871..dcae899e 100644 ---- a/slirp/src/util.c -+++ b/slirp/src/util.c -@@ -364,3 +364,66 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str) - } - *q = '\0'; - } -+ -+static int slirp_vsnprintf(char *str, size_t size, -+ const char *format, va_list args) -+{ -+ int rv = vsnprintf(str, size, format, args); -+ -+ if (rv < 0) { -+ g_error("vsnprintf() failed: %s", g_strerror(errno)); -+ } -+ -+ return rv; -+} -+ -+/* -+ * A snprintf()-like function that: -+ * - returns the number of bytes written (excluding optional \0-ending) -+ * - dies on error -+ * - warn on truncation -+ */ -+int slirp_fmt(char *str, size_t size, const char *format, ...) -+{ -+ va_list args; -+ int rv; -+ -+ va_start(args, format); -+ rv = slirp_vsnprintf(str, size, format, args); -+ va_end(args); -+ -+ if (rv > size) { -+ g_critical("vsnprintf() truncation"); -+ } -+ -+ return MIN(rv, size); -+} -+ -+/* -+ * A snprintf()-like function that: -+ * - always \0-end (unless size == 0) -+ * - returns the number of bytes actually written, including \0 ending -+ * - dies on error -+ * - warn on truncation -+ */ -+int slirp_fmt0(char *str, size_t size, const char *format, ...) -+{ -+ va_list args; -+ int rv; -+ -+ va_start(args, format); -+ rv = slirp_vsnprintf(str, size, format, args); -+ va_end(args); -+ -+ if (rv >= size) { -+ g_critical("vsnprintf() truncation"); -+ if (size > 0) -+ str[size - 1] = '\0'; -+ rv = size; -+ } else { -+ rv += 1; /* include \0 */ -+ } -+ -+ return rv; -+} -+ -diff --git a/slirp/src/util.h b/slirp/src/util.h -index 3c6223ce..0558dfc2 100644 ---- a/slirp/src/util.h -+++ b/slirp/src/util.h -@@ -177,4 +177,7 @@ static inline int slirp_socket_set_fast_reuse(int fd) - - void slirp_pstrcpy(char *buf, int buf_size, const char *str); - -+int slirp_fmt(char *str, size_t size, const char *format, ...); -+int slirp_fmt0(char *str, size_t size, const char *format, ...); -+ - #endif --- -2.23.0 diff --git a/util-async-hold-AioContext-ref-to-prevent-use-after-free.patch b/util-async-hold-AioContext-ref-to-prevent-use-after-free.patch deleted file mode 100644 index da4403c4ec7757c4860023b2a8e0018c3bf23b9d..0000000000000000000000000000000000000000 --- a/util-async-hold-AioContext-ref-to-prevent-use-after-free.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e965bc6c633921ab238b1f5ea64055975b24e2bb Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Tue, 23 Jul 2019 20:06:23 +0100 -Subject: [PATCH 4/5] util/async: hold AioContext ref to prevent use-after-free - -The tests/test-bdrv-drain /bdrv-drain/iothread/drain test case does the -following: - -1. The preadv coroutine calls aio_bh_schedule_oneshot() and then yields. -2. The one-shot BH executes in another AioContext. All it does is call - aio_co_wakeup(preadv_co). -3. The preadv coroutine is re-entered and returns. - -There is a race condition in aio_co_wake() where the preadv coroutine -returns and the test case destroys the preadv IOThread. aio_co_wake() -can still be running in the other AioContext and it performs an access -to the freed IOThread AioContext. - -Here is the race in aio_co_schedule(): - - QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, - co, co_scheduled_next); - <-- race: co may execute before we invoke qemu_bh_schedule()! - qemu_bh_schedule(ctx->co_schedule_bh); - -So if co causes ctx to be freed then we're in trouble. Fix this problem -by holding a reference to ctx. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Paolo Bonzini -Message-id: 20190723190623.21537-1-stefanha@redhat.com -Message-Id: <20190723190623.21537-1-stefanha@redhat.com> -Signed-off-by: Stefan Hajnoczi -(cherry-picked from commit f0f81002873c06fdef9bb2a272ddfd26af65b851) ---- - util/async.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/util/async.c b/util/async.c -index c10642a..afc17fb 100644 ---- a/util/async.c -+++ b/util/async.c -@@ -460,9 +460,17 @@ void aio_co_schedule(AioContext *ctx, Coroutine *co) - abort(); - } - -+ /* The coroutine might run and release the last ctx reference before we -+ * invoke qemu_bh_schedule(). Take a reference to keep ctx alive until -+ * we're done. -+ */ -+ aio_context_ref(ctx); -+ - QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, - co, co_scheduled_next); - qemu_bh_schedule(ctx->co_schedule_bh); -+ -+ aio_context_unref(ctx); - } - - void aio_co_wake(struct Coroutine *co) --- -1.8.3.1 - diff --git a/util-cacheinfo-fix-crash-when-compiling-with-uClibc.patch b/util-cacheinfo-fix-crash-when-compiling-with-uClibc.patch deleted file mode 100644 index 797d71e73d5115ead1f4bdf6ae3ed4aabebeb572..0000000000000000000000000000000000000000 --- a/util-cacheinfo-fix-crash-when-compiling-with-uClibc.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 00b5032eaddb7193f03f0a28b10286244d2e2a7b Mon Sep 17 00:00:00 2001 -From: Carlos Santos -Date: Thu, 17 Oct 2019 09:37:13 -0300 -Subject: [PATCH] util/cacheinfo: fix crash when compiling with uClibc - -uClibc defines _SC_LEVEL1_ICACHE_LINESIZE and _SC_LEVEL1_DCACHE_LINESIZE -but the corresponding sysconf calls returns -1, which is a valid result, -meaning that the limit is indeterminate. - -Handle this situation using the fallback values instead of crashing due -to an assertion failure. - -Signed-off-by: Carlos Santos -Message-Id: <20191017123713.30192-1-casantos@redhat.com> -Signed-off-by: Richard Henderson ---- - util/cacheinfo.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/util/cacheinfo.c b/util/cacheinfo.c -index ea6f3e99bf..d94dc6adc8 100644 ---- a/util/cacheinfo.c -+++ b/util/cacheinfo.c -@@ -93,10 +93,16 @@ static void sys_cache_info(int *isize, int *dsize) - static void sys_cache_info(int *isize, int *dsize) - { - # ifdef _SC_LEVEL1_ICACHE_LINESIZE -- *isize = sysconf(_SC_LEVEL1_ICACHE_LINESIZE); -+ int tmp_isize = (int) sysconf(_SC_LEVEL1_ICACHE_LINESIZE); -+ if (tmp_isize > 0) { -+ *isize = tmp_isize; -+ } - # endif - # ifdef _SC_LEVEL1_DCACHE_LINESIZE -- *dsize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); -+ int tmp_dsize = (int) sysconf(_SC_LEVEL1_DCACHE_LINESIZE); -+ if (tmp_dsize > 0) { -+ *dsize = tmp_dsize; -+ } - # endif - } - #endif /* sys_cache_info */ --- -2.27.0 - diff --git a/util-hbitmap-strict-hbitmap_reset.patch b/util-hbitmap-strict-hbitmap_reset.patch deleted file mode 100644 index b7f568f1bc6d21ae6923a552c2536414d5d33fdd..0000000000000000000000000000000000000000 --- a/util-hbitmap-strict-hbitmap_reset.patch +++ /dev/null @@ -1,77 +0,0 @@ -From fcd7cba6acb7344aca70f5f8ec16626e817b35a5 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 6 Aug 2019 18:26:11 +0300 -Subject: [PATCH] util/hbitmap: strict hbitmap_reset - -hbitmap_reset has an unobvious property: it rounds requested region up. -It may provoke bugs, like in recently fixed write-blocking mode of -mirror: user calls reset on unaligned region, not keeping in mind that -there are possible unrelated dirty bytes, covered by rounded-up region -and information of this unrelated "dirtiness" will be lost. - -Make hbitmap_reset strict: assert that arguments are aligned, allowing -only one exception when @start + @count == hb->orig_size. It's needed -to comfort users of hbitmap_next_dirty_area, which cares about -hb->orig_size. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Max Reitz -Message-Id: <20190806152611.280389-1-vsementsov@virtuozzo.com> -[Maintainer edit: Max's suggestions from on-list. --js] -[Maintainer edit: Eric's suggestion for aligned macro. --js] -Signed-off-by: John Snow -(cherry picked from commit 48557b138383aaf69c2617ca9a88bfb394fc50ec) -*prereq for fed33bd175f663cc8c13f8a490a4f35a19756cfe -Signed-off-by: Michael Roth ---- - include/qemu/hbitmap.h | 5 +++++ - tests/test-hbitmap.c | 2 +- - util/hbitmap.c | 4 ++++ - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h -index 4afbe6292e..1bf944ca3d 100644 ---- a/include/qemu/hbitmap.h -+++ b/include/qemu/hbitmap.h -@@ -132,6 +132,11 @@ void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count); - * @count: Number of bits to reset. - * - * Reset a consecutive range of bits in an HBitmap. -+ * @start and @count must be aligned to bitmap granularity. The only exception -+ * is resetting the tail of the bitmap: @count may be equal to hb->orig_size - -+ * @start, in this case @count may be not aligned. The sum of @start + @count is -+ * allowed to be greater than hb->orig_size, but only if @start < hb->orig_size -+ * and @start + @count = ALIGN_UP(hb->orig_size, granularity). - */ - void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count); - -diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c -index 592d8219db..2be56d1597 100644 ---- a/tests/test-hbitmap.c -+++ b/tests/test-hbitmap.c -@@ -423,7 +423,7 @@ static void test_hbitmap_granularity(TestHBitmapData *data, - hbitmap_test_check(data, 0); - hbitmap_test_set(data, 0, 3); - g_assert_cmpint(hbitmap_count(data->hb), ==, 4); -- hbitmap_test_reset(data, 0, 1); -+ hbitmap_test_reset(data, 0, 2); - g_assert_cmpint(hbitmap_count(data->hb), ==, 2); - } - -diff --git a/util/hbitmap.c b/util/hbitmap.c -index bcc0acdc6a..71c6ba2c52 100644 ---- a/util/hbitmap.c -+++ b/util/hbitmap.c -@@ -476,6 +476,10 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count) - /* Compute range in the last layer. */ - uint64_t first; - uint64_t last = start + count - 1; -+ uint64_t gran = 1ULL << hb->granularity; -+ -+ assert(QEMU_IS_ALIGNED(start, gran)); -+ assert(QEMU_IS_ALIGNED(count, gran) || (start + count == hb->orig_size)); - - trace_hbitmap_reset(hb, start, count, - start >> hb->granularity, last >> hb->granularity); --- -2.23.0 diff --git a/util-iov-improve-qemu_iovec_is_zero.patch b/util-iov-improve-qemu_iovec_is_zero.patch deleted file mode 100644 index 0cca67b8b1ed17eb873514c177eb6e371ae21f17..0000000000000000000000000000000000000000 --- a/util-iov-improve-qemu_iovec_is_zero.patch +++ /dev/null @@ -1,102 +0,0 @@ -From b3b76fc643912d2c86b13caff30a1151f2958702 Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 4 Jun 2019 19:15:04 +0300 -Subject: [PATCH] util/iov: improve qemu_iovec_is_zero - -We'll need to check a part of qiov soon, so implement it now. - -Optimization with align down to 4 * sizeof(long) is dropped due to: -1. It is strange: it aligns length of the buffer, but where is a - guarantee that buffer pointer is aligned itself? -2. buffer_is_zero() is a better place for optimizations and it has - them. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Acked-by: Stefan Hajnoczi -Message-id: 20190604161514.262241-3-vsementsov@virtuozzo.com -Message-Id: <20190604161514.262241-3-vsementsov@virtuozzo.com> -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit f76889e7b947d896db51be8a4d9c941c2f70365a) -*prereq for 292d06b9 -Signed-off-by: Michael Roth ---- - block/io.c | 2 +- - include/qemu/iov.h | 2 +- - util/iov.c | 31 +++++++++++++++++++------------ - 3 files changed, 21 insertions(+), 14 deletions(-) - -diff --git a/block/io.c b/block/io.c -index 06305c6ea6..dccf687acc 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -1715,7 +1715,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, - - if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF && - !(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_pwrite_zeroes && -- qemu_iovec_is_zero(qiov)) { -+ qemu_iovec_is_zero(qiov, 0, qiov->size)) { - flags |= BDRV_REQ_ZERO_WRITE; - if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) { - flags |= BDRV_REQ_MAY_UNMAP; -diff --git a/include/qemu/iov.h b/include/qemu/iov.h -index f3787a0cf7..29957c8a72 100644 ---- a/include/qemu/iov.h -+++ b/include/qemu/iov.h -@@ -212,7 +212,7 @@ void qemu_iovec_concat(QEMUIOVector *dst, - size_t qemu_iovec_concat_iov(QEMUIOVector *dst, - struct iovec *src_iov, unsigned int src_cnt, - size_t soffset, size_t sbytes); --bool qemu_iovec_is_zero(QEMUIOVector *qiov); -+bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t qiov_offeset, size_t bytes); - void qemu_iovec_destroy(QEMUIOVector *qiov); - void qemu_iovec_reset(QEMUIOVector *qiov); - size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset, -diff --git a/util/iov.c b/util/iov.c -index 366ff9cdd1..9ac0261853 100644 ---- a/util/iov.c -+++ b/util/iov.c -@@ -451,23 +451,30 @@ void qemu_iovec_init_extended( - } - - /* -- * Check if the contents of the iovecs are all zero -+ * Check if the contents of subrange of qiov data is all zeroes. - */ --bool qemu_iovec_is_zero(QEMUIOVector *qiov) -+bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t offset, size_t bytes) - { -- int i; -- for (i = 0; i < qiov->niov; i++) { -- size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long)); -- uint8_t *ptr = qiov->iov[i].iov_base; -- if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) { -+ struct iovec *iov; -+ size_t current_offset; -+ -+ assert(offset + bytes <= qiov->size); -+ -+ iov = iov_skip_offset(qiov->iov, offset, ¤t_offset); -+ -+ while (bytes) { -+ uint8_t *base = (uint8_t *)iov->iov_base + current_offset; -+ size_t len = MIN(iov->iov_len - current_offset, bytes); -+ -+ if (!buffer_is_zero(base, len)) { - return false; - } -- for (; offs < qiov->iov[i].iov_len; offs++) { -- if (ptr[offs]) { -- return false; -- } -- } -+ -+ current_offset = 0; -+ bytes -= len; -+ iov++; - } -+ - return true; - } - --- -2.23.0 diff --git a/util-iov-introduce-qemu_iovec_init_extended.patch b/util-iov-introduce-qemu_iovec_init_extended.patch deleted file mode 100644 index 0a488a63413b69816576ff8394f1e282c292e7d7..0000000000000000000000000000000000000000 --- a/util-iov-introduce-qemu_iovec_init_extended.patch +++ /dev/null @@ -1,177 +0,0 @@ -From cff024fe856ab36db3056ba4cb1d7cfa4c39795d Mon Sep 17 00:00:00 2001 -From: Vladimir Sementsov-Ogievskiy -Date: Tue, 4 Jun 2019 19:15:03 +0300 -Subject: [PATCH] util/iov: introduce qemu_iovec_init_extended - -Introduce new initialization API, to create requests with padding. Will -be used in the following patch. New API uses qemu_iovec_init_buf if -resulting io vector has only one element, to avoid extra allocations. -So, we need to update qemu_iovec_destroy to support destroying such -QIOVs. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Acked-by: Stefan Hajnoczi -Message-id: 20190604161514.262241-2-vsementsov@virtuozzo.com -Message-Id: <20190604161514.262241-2-vsementsov@virtuozzo.com> -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit d953169d4840f312d3b9a54952f4a7ccfcb3b311) -*prereq for 292d06b9 -Signed-off-by: Michael Roth ---- - include/qemu/iov.h | 7 +++ - util/iov.c | 112 +++++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 114 insertions(+), 5 deletions(-) - -diff --git a/include/qemu/iov.h b/include/qemu/iov.h -index 48b45987b7..f3787a0cf7 100644 ---- a/include/qemu/iov.h -+++ b/include/qemu/iov.h -@@ -199,6 +199,13 @@ static inline void *qemu_iovec_buf(QEMUIOVector *qiov) - - void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); - void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); -+void qemu_iovec_init_extended( -+ QEMUIOVector *qiov, -+ void *head_buf, size_t head_len, -+ QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, -+ void *tail_buf, size_t tail_len); -+void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, -+ size_t offset, size_t len); - void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); - void qemu_iovec_concat(QEMUIOVector *dst, - QEMUIOVector *src, size_t soffset, size_t sbytes); -diff --git a/util/iov.c b/util/iov.c -index 74e6ca8ed7..366ff9cdd1 100644 ---- a/util/iov.c -+++ b/util/iov.c -@@ -353,6 +353,103 @@ void qemu_iovec_concat(QEMUIOVector *dst, - qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes); - } - -+/* -+ * qiov_find_iov -+ * -+ * Return pointer to iovec structure, where byte at @offset in original vector -+ * @iov exactly is. -+ * Set @remaining_offset to be offset inside that iovec to the same byte. -+ */ -+static struct iovec *iov_skip_offset(struct iovec *iov, size_t offset, -+ size_t *remaining_offset) -+{ -+ while (offset > 0 && offset >= iov->iov_len) { -+ offset -= iov->iov_len; -+ iov++; -+ } -+ *remaining_offset = offset; -+ -+ return iov; -+} -+ -+/* -+ * qiov_slice -+ * -+ * Find subarray of iovec's, containing requested range. @head would -+ * be offset in first iov (returned by the function), @tail would be -+ * count of extra bytes in last iovec (returned iov + @niov - 1). -+ */ -+static struct iovec *qiov_slice(QEMUIOVector *qiov, -+ size_t offset, size_t len, -+ size_t *head, size_t *tail, int *niov) -+{ -+ struct iovec *iov, *end_iov; -+ -+ assert(offset + len <= qiov->size); -+ -+ iov = iov_skip_offset(qiov->iov, offset, head); -+ end_iov = iov_skip_offset(iov, *head + len, tail); -+ -+ if (*tail > 0) { -+ assert(*tail < end_iov->iov_len); -+ *tail = end_iov->iov_len - *tail; -+ end_iov++; -+ } -+ -+ *niov = end_iov - iov; -+ -+ return iov; -+} -+ -+/* -+ * Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov, -+ * and @tail_buf buffer into new qiov. -+ */ -+void qemu_iovec_init_extended( -+ QEMUIOVector *qiov, -+ void *head_buf, size_t head_len, -+ QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, -+ void *tail_buf, size_t tail_len) -+{ -+ size_t mid_head, mid_tail; -+ int total_niov, mid_niov = 0; -+ struct iovec *p, *mid_iov; -+ -+ if (mid_len) { -+ mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len, -+ &mid_head, &mid_tail, &mid_niov); -+ } -+ -+ total_niov = !!head_len + mid_niov + !!tail_len; -+ if (total_niov == 1) { -+ qemu_iovec_init_buf(qiov, NULL, 0); -+ p = &qiov->local_iov; -+ } else { -+ qiov->niov = qiov->nalloc = total_niov; -+ qiov->size = head_len + mid_len + tail_len; -+ p = qiov->iov = g_new(struct iovec, qiov->niov); -+ } -+ -+ if (head_len) { -+ p->iov_base = head_buf; -+ p->iov_len = head_len; -+ p++; -+ } -+ -+ if (mid_len) { -+ memcpy(p, mid_iov, mid_niov * sizeof(*p)); -+ p[0].iov_base = (uint8_t *)p[0].iov_base + mid_head; -+ p[0].iov_len -= mid_head; -+ p[mid_niov - 1].iov_len -= mid_tail; -+ p += mid_niov; -+ } -+ -+ if (tail_len) { -+ p->iov_base = tail_buf; -+ p->iov_len = tail_len; -+ } -+} -+ - /* - * Check if the contents of the iovecs are all zero - */ -@@ -374,14 +471,19 @@ bool qemu_iovec_is_zero(QEMUIOVector *qiov) - return true; - } - -+void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, -+ size_t offset, size_t len) -+{ -+ qemu_iovec_init_extended(qiov, NULL, 0, source, offset, len, NULL, 0); -+} -+ - void qemu_iovec_destroy(QEMUIOVector *qiov) - { -- assert(qiov->nalloc != -1); -+ if (qiov->nalloc != -1) { -+ g_free(qiov->iov); -+ } - -- qemu_iovec_reset(qiov); -- g_free(qiov->iov); -- qiov->nalloc = 0; -- qiov->iov = NULL; -+ memset(qiov, 0, sizeof(*qiov)); - } - - void qemu_iovec_reset(QEMUIOVector *qiov) --- -2.23.0 diff --git a/util-log-add-CONFIG_DISABLE_QEMU_LOG-macro.patch b/util-log-add-CONFIG_DISABLE_QEMU_LOG-macro.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6940d69d12b29d8f6740cb87dec83b5eaa1356a --- /dev/null +++ b/util-log-add-CONFIG_DISABLE_QEMU_LOG-macro.patch @@ -0,0 +1,41 @@ +From 05462305ec8b9ce5b414ede1e7e680b16d1a08ad Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Fri, 11 Feb 2022 18:20:59 +0800 +Subject: [PATCH] util/log: add CONFIG_DISABLE_QEMU_LOG macro + +Using CONFIG_DISABLE_QEMU_LOG macro to control +qemu_log function. + +Signed-off-by: Yan Wang +--- + util/log.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/util/log.c b/util/log.c +index 2ee1500bee..ed3029fe5c 100644 +--- a/util/log.c ++++ b/util/log.c +@@ -34,6 +34,12 @@ int qemu_loglevel; + static int log_append = 0; + static GArray *debug_regions; + ++#ifdef CONFIG_DISABLE_QEMU_LOG ++int qemu_log(const char *fmt, ...) ++{ ++ return 0; ++} ++#else + /* Return the number of characters emitted. */ + int qemu_log(const char *fmt, ...) + { +@@ -56,6 +62,7 @@ int qemu_log(const char *fmt, ...) + rcu_read_unlock(); + return ret; + } ++#endif + + static void __attribute__((__constructor__)) qemu_logfile_init(void) + { +-- +2.27.0 + diff --git a/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch b/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd93861b7c35afe0c1461f2b767acb3b6035ac3e --- /dev/null +++ b/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch @@ -0,0 +1,59 @@ +From d42fea8a40c4a5d8909103910d86da8e674d1fb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:52 +0100 +Subject: [PATCH] vdpa: Adapt vhost_vdpa_get_vring_base to SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed to achieve migration, so the destination can restore its +index. + +Setting base as last used idx, so destination will see as available all +the entries that the device did not use, including the in-flight +processing ones. + +This is ok for networking, but other kinds of devices might have +problems with these retransmissions. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8245345bcd..428137f654 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1143,8 +1143,25 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + ++ if (v->shadow_vqs_enabled) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, ++ ring->index); ++ ++ /* ++ * Setting base as last used idx, so destination will see as available ++ * all the entries that the device did not use, including the in-flight ++ * processing ones. ++ * ++ * TODO: This is ok for networking, but other kinds of devices might ++ * have problems with these retransmissions. ++ */ ++ ring->num = svq->last_used_idx; ++ return 0; ++ } ++ + ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring); + trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num); + return ret; +-- +2.27.0 + diff --git a/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch b/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f6c127279c478229ac54998e980f19e6270b81f --- /dev/null +++ b/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch @@ -0,0 +1,415 @@ +From 649e277b6ec0d2cd798f6d43776ea38b00450db9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:51 +0100 +Subject: [PATCH] vdpa: Add custom IOTLB translations to SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use translations added in VhostIOVATree in SVQ. + +Only introduce usage here, not allocation and deallocation. As with +previous patches, we use the dead code paths of shadow_vqs_enabled to +avoid commiting too many changes at once. These are impossible to take +at the moment. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 86 +++++++++++++++++--- + hw/virtio/vhost-shadow-virtqueue.h | 6 +- + hw/virtio/vhost-vdpa.c | 122 ++++++++++++++++++++++++----- + include/hw/virtio/vhost-vdpa.h | 3 + + 4 files changed, 187 insertions(+), 30 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 46e94f0861..c38b6b6ab5 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -69,7 +69,59 @@ static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) + return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); + } + +-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, ++/** ++ * Translate addresses between the qemu's virtual address and the SVQ IOVA ++ * ++ * @svq: Shadow VirtQueue ++ * @vaddr: Translated IOVA addresses ++ * @iovec: Source qemu's VA addresses ++ * @num: Length of iovec and minimum length of vaddr ++ */ ++static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, ++ hwaddr *addrs, const struct iovec *iovec, ++ size_t num) ++{ ++ if (num == 0) { ++ return true; ++ } ++ ++ for (size_t i = 0; i < num; ++i) { ++ DMAMap needle = { ++ .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base, ++ .size = iovec[i].iov_len, ++ }; ++ Int128 needle_last, map_last; ++ size_t off; ++ ++ const DMAMap *map = vhost_iova_tree_find_iova(svq->iova_tree, &needle); ++ /* ++ * Map cannot be NULL since iova map contains all guest space and ++ * qemu already has a physical address mapped ++ */ ++ if (unlikely(!map)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Invalid address 0x%"HWADDR_PRIx" given by guest", ++ needle.translated_addr); ++ return false; ++ } ++ ++ off = needle.translated_addr - map->translated_addr; ++ addrs[i] = map->iova + off; ++ ++ needle_last = int128_add(int128_make64(needle.translated_addr), ++ int128_make64(iovec[i].iov_len)); ++ map_last = int128_make64(map->translated_addr + map->size); ++ if (unlikely(int128_gt(needle_last, map_last))) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Guest buffer expands over iova range"); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + const struct iovec *iovec, size_t num, + bool more_descs, bool write) + { +@@ -88,7 +140,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, + } else { + descs[i].flags = flags; + } +- descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base); ++ descs[i].addr = cpu_to_le64(sg[n]); + descs[i].len = cpu_to_le32(iovec[n].iov_len); + + last = i; +@@ -103,6 +155,8 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + { + unsigned avail_idx; + vring_avail_t *avail = svq->vring.avail; ++ bool ok; ++ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num)); + + *head = svq->free_head; + +@@ -113,9 +167,20 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return false; + } + +- vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0, +- false); +- vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true); ++ ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, ++ elem->in_num > 0, false); ++ ++ ++ ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true); + + /* + * Put the entry in the available array (but don't update avail->idx until +@@ -394,9 +459,9 @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) + void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, + struct vhost_vring_addr *addr) + { +- addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc; +- addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail; +- addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used; ++ addr->desc_user_addr = (uint64_t)(uintptr_t)svq->vring.desc; ++ addr->avail_user_addr = (uint64_t)(uintptr_t)svq->vring.avail; ++ addr->used_user_addr = (uint64_t)(uintptr_t)svq->vring.used; + } + + size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq) +@@ -517,11 +582,13 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * Creates vhost shadow virtqueue, and instructs the vhost device to use the + * shadow methods and file descriptors. + * ++ * @iova_tree: Tree to perform descriptors translations ++ * + * Returns the new virtqueue or NULL. + * + * In case of error, reason is reported through error_report. + */ +-VhostShadowVirtqueue *vhost_svq_new(void) ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) + { + g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + int r; +@@ -542,6 +609,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); ++ svq->iova_tree = iova_tree; + return g_steal_pointer(&svq); + + err_init_hdev_call: +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 38b3b91ca7..e5e24c536d 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -13,6 +13,7 @@ + #include "qemu/event_notifier.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" ++#include "hw/virtio/vhost-iova-tree.h" + + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { +@@ -43,6 +44,9 @@ typedef struct VhostShadowVirtqueue { + /* Virtio device */ + VirtIODevice *vdev; + ++ /* IOVA mapping */ ++ VhostIOVATree *iova_tree; ++ + /* Map for use the guest's descriptors */ + VirtQueueElement **ring_id_maps; + +@@ -75,7 +79,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(void); ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree); + + void vhost_svq_free(gpointer vq); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index db34f26246..8245345bcd 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -211,6 +211,21 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + + llsize = int128_sub(llend, int128_make64(iova)); ++ if (v->shadow_vqs_enabled) { ++ DMAMap mem_region = { ++ .translated_addr = (hwaddr)(uintptr_t)vaddr, ++ .size = int128_get64(llsize) - 1, ++ .perm = IOMMU_ACCESS_FLAG(true, section->readonly), ++ }; ++ ++ int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); ++ if (unlikely(r != IOVA_OK)) { ++ error_report("Can't allocate a mapping (%d)", r); ++ goto fail; ++ } ++ ++ iova = mem_region.iova; ++ } + + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), +@@ -263,6 +278,20 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + ++ if (v->shadow_vqs_enabled) { ++ const DMAMap *result; ++ const void *vaddr = memory_region_get_ram_ptr(section->mr) + ++ section->offset_within_region + ++ (iova - section->offset_within_address_space); ++ DMAMap mem_region = { ++ .translated_addr = (hwaddr)(uintptr_t)vaddr, ++ .size = int128_get64(llsize) - 1, ++ }; ++ ++ result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); ++ iova = result->iova; ++ vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); + if (ret) { +@@ -372,7 +401,7 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); ++ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree); + + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); +@@ -809,33 +838,70 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova, +- hwaddr size) ++static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, ++ const DMAMap *needle) + { ++ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); ++ hwaddr size; + int r; + +- size = ROUND_UP(size, qemu_real_host_page_size); +- r = vhost_vdpa_dma_unmap(v, iova, size); ++ if (unlikely(!result)) { ++ error_report("Unable to find SVQ address to unmap"); ++ return false; ++ } ++ ++ size = ROUND_UP(result->size, qemu_real_host_page_size); ++ r = vhost_vdpa_dma_unmap(v, result->iova, size); + return r == 0; + } + + static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { ++ DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; +- size_t device_size = vhost_svq_device_area_size(svq); +- size_t driver_size = vhost_svq_driver_area_size(svq); + bool ok; + + vhost_svq_get_vring_addr(svq, &svq_addr); + +- ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size); ++ needle.translated_addr = svq_addr.desc_user_addr; ++ ok = vhost_vdpa_svq_unmap_ring(v, &needle); + if (unlikely(!ok)) { + return false; + } + +- return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size); ++ needle.translated_addr = svq_addr.used_user_addr; ++ return vhost_vdpa_svq_unmap_ring(v, &needle); ++} ++ ++/** ++ * Map the SVQ area in the device ++ * ++ * @v: Vhost-vdpa device ++ * @needle: The area to search iova ++ * @errorp: Error pointer ++ */ ++static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, ++ Error **errp) ++{ ++ int r; ++ ++ r = vhost_iova_tree_map_alloc(v->iova_tree, needle); ++ if (unlikely(r != IOVA_OK)) { ++ error_setg(errp, "Cannot allocate iova (%d)", r); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1, ++ (void *)(uintptr_t)needle->translated_addr, ++ needle->perm == IOMMU_RO); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot map region to device"); ++ vhost_iova_tree_remove(v->iova_tree, needle); ++ } ++ ++ return r == 0; + } + + /** +@@ -851,28 +917,44 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, + struct vhost_vring_addr *addr, + Error **errp) + { ++ DMAMap device_region, driver_region; ++ struct vhost_vring_addr svq_addr; + struct vhost_vdpa *v = dev->opaque; + size_t device_size = vhost_svq_device_area_size(svq); + size_t driver_size = vhost_svq_driver_area_size(svq); +- int r; ++ size_t avail_offset; ++ bool ok; + + ERRP_GUARD(); +- vhost_svq_get_vring_addr(svq, addr); ++ vhost_svq_get_vring_addr(svq, &svq_addr); + +- r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size, +- (void *)(uintptr_t)addr->desc_user_addr, true); +- if (unlikely(r != 0)) { +- error_setg_errno(errp, -r, "Cannot create vq driver region: "); ++ driver_region = (DMAMap) { ++ .translated_addr = svq_addr.desc_user_addr, ++ .size = driver_size - 1, ++ .perm = IOMMU_RO, ++ }; ++ ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp); ++ if (unlikely(!ok)) { ++ error_prepend(errp, "Cannot create vq driver region: "); + return false; + } ++ addr->desc_user_addr = driver_region.iova; ++ avail_offset = svq_addr.avail_user_addr - svq_addr.desc_user_addr; ++ addr->avail_user_addr = driver_region.iova + avail_offset; + +- r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size, +- (void *)(intptr_t)addr->used_user_addr, false); +- if (unlikely(r != 0)) { +- error_setg_errno(errp, -r, "Cannot create vq device region: "); ++ device_region = (DMAMap) { ++ .translated_addr = svq_addr.used_user_addr, ++ .size = device_size - 1, ++ .perm = IOMMU_RW, ++ }; ++ ok = vhost_vdpa_svq_map_ring(v, &device_region, errp); ++ if (unlikely(!ok)) { ++ error_prepend(errp, "Cannot create vq device region: "); ++ vhost_vdpa_svq_unmap_ring(v, &driver_region); + } ++ addr->used_user_addr = device_region.iova; + +- return r == 0; ++ return ok; + } + + static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 009a9f3b6b..ee8e939ad0 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -14,6 +14,7 @@ + + #include + ++#include "hw/virtio/vhost-iova-tree.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -30,6 +31,8 @@ typedef struct vhost_vdpa { + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; + bool shadow_vqs_enabled; ++ /* IOVA mapping used by the Shadow Virtqueue */ ++ VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; +-- +2.27.0 + diff --git a/vdpa-Add-device-migration-blocker.patch b/vdpa-Add-device-migration-blocker.patch new file mode 100644 index 0000000000000000000000000000000000000000..85644d9cda441e30e50eff50ea69f4b411a5e21d --- /dev/null +++ b/vdpa-Add-device-migration-blocker.patch @@ -0,0 +1,87 @@ +From 3f0eafe9e86bac9cf99176bf65a22d2dab154617 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:45 +0200 +Subject: [PATCH] vdpa: Add device migration blocker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since the vhost-vdpa device is exposing _F_LOG, adding a migration blocker if +it uses CVQ. + +However, qemu is able to migrate simple devices with no CVQ as long as +they use SVQ. To allow it, add a placeholder error to vhost_vdpa, and +only add to vhost_dev when used. vhost_dev machinery place the migration +blocker if needed. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 +++++++++++++++ + include/hw/virtio/vhost-vdpa.h | 1 + + 2 files changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 31b58aec59..5956ff4660 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -20,6 +20,7 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/vhost-vdpa.h" + #include "exec/address-spaces.h" ++#include "migration/blocker.h" + #include "qemu/main-loop.h" + #include "cpu.h" + #include "trace.h" +@@ -1024,6 +1025,13 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + return true; + } + ++ if (v->migration_blocker) { ++ int r = migrate_add_blocker(v->migration_blocker, &err); ++ if (unlikely(r < 0)) { ++ return false; ++ } ++ } ++ + for (i = 0; i < v->shadow_vqs->len; ++i) { + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +@@ -1066,6 +1074,10 @@ err: + vhost_svq_stop(svq); + } + ++ if (v->migration_blocker) { ++ migrate_del_blocker(v->migration_blocker); ++ } ++ + return false; + } + +@@ -1085,6 +1097,9 @@ static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) + } + } + ++ if (v->migration_blocker) { ++ migrate_del_blocker(v->migration_blocker); ++ } + return true; + } + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 1111d85643..d10a89303e 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -35,6 +35,7 @@ typedef struct vhost_vdpa { + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; ++ Error *migration_blocker; + GPtrArray *shadow_vqs; + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; +-- +2.27.0 + diff --git a/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch b/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..b305d760ec0a4c0c5a8fa76e89f6ab46a9919b8a --- /dev/null +++ b/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch @@ -0,0 +1,58 @@ +From d3aa8e2f948c0b3cd2cd723364fe968fd6befca9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 5 Apr 2022 08:36:28 +0200 +Subject: [PATCH] vdpa: Add missing tracing to batch mapping functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These functions were not traced properly. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Laurent Vivier +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Message-Id: <20220405063628.853745-1-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 2 ++ + hw/virtio/vhost-vdpa.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 650e521e35..37c1555330 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -25,6 +25,8 @@ vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%" + # vhost-vdpa.c + vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 + vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 ++vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 ++vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" + vhost_vdpa_listener_region_del(void *vdpa, uint64_t iova, uint64_t llend) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64 + vhost_vdpa_add_status(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8 +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index b66697da6e..022d70aefb 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -131,6 +131,7 @@ static void vhost_vdpa_listener_begin_batch(struct vhost_vdpa *v) + .iotlb.type = VHOST_IOTLB_BATCH_BEGIN, + }; + ++ trace_vhost_vdpa_listener_begin_batch(v, fd, msg.type, msg.iotlb.type); + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); +@@ -165,6 +166,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) + msg.type = v->msg_type; + msg.iotlb.type = VHOST_IOTLB_BATCH_END; + ++ trace_vhost_vdpa_listener_commit(v, fd, msg.type, msg.iotlb.type); + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); +-- +2.27.0 + diff --git a/vdpa-Add-vhost_vdpa_net_load_mq.patch b/vdpa-Add-vhost_vdpa_net_load_mq.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b06bfd4aac7a1d735ddf655abed58ec1b30c19d --- /dev/null +++ b/vdpa-Add-vhost_vdpa_net_load_mq.patch @@ -0,0 +1,65 @@ +From 6dc398327ebe7fcfe78b3df4fe9c1386bafef552 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:16 +0200 +Subject: [PATCH] vdpa: Add vhost_vdpa_net_load_mq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Same way as with the MAC, restore the expected number of queues at +device's start. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 15cd38b52e..b32fe5e68a 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -408,6 +408,28 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) + return 0; + } + ++static int vhost_vdpa_net_load_mq(VhostVDPAState *s, ++ const VirtIONet *n) ++{ ++ struct virtio_net_ctrl_mq mq; ++ uint64_t features = n->parent_obj.guest_features; ++ ssize_t dev_written; ++ ++ if (!(features & BIT_ULL(VIRTIO_NET_F_MQ))) { ++ return 0; ++ } ++ ++ mq.virtqueue_pairs = cpu_to_le16(n->curr_queue_pairs); ++ dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MQ, ++ VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &mq, ++ sizeof(mq)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *s->status != VIRTIO_NET_OK; ++} ++ + static int vhost_vdpa_net_load(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -426,6 +448,10 @@ static int vhost_vdpa_net_load(NetClientState *nc) + if (unlikely(r < 0)) { + return r; + } ++ r = vhost_vdpa_net_load_mq(s, n); ++ if (unlikely(r)) { ++ return r; ++ } + + return 0; + } +-- +2.27.0 + diff --git a/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch b/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad2ab280fd464dcfae6a2f2ea64fc8c5835426bd --- /dev/null +++ b/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch @@ -0,0 +1,78 @@ +From 8df992cbd90fb742e14ea1a90211cf535f20fbaa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:36 +0200 +Subject: [PATCH] vdpa: Add virtio-net mac address via CVQ at start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed so the destination vdpa device see the same state a the +guest set in the source. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b24e0919d0..561e43fa92 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -371,11 +371,51 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + return vhost_svq_poll(svq); + } + ++static int vhost_vdpa_net_load(NetClientState *nc) ++{ ++ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ const struct vhost_vdpa *v = &s->vhost_vdpa; ++ const VirtIONet *n; ++ uint64_t features; ++ ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ if (!v->shadow_vqs_enabled) { ++ return 0; ++ } ++ ++ n = VIRTIO_NET(v->dev->vdev); ++ features = n->parent_obj.guest_features; ++ if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { ++ const struct virtio_net_ctrl_hdr ctrl = { ++ .class = VIRTIO_NET_CTRL_MAC, ++ .cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET, ++ }; ++ char *cursor = s->cvq_cmd_out_buffer; ++ ssize_t dev_written; ++ ++ memcpy(cursor, &ctrl, sizeof(ctrl)); ++ cursor += sizeof(ctrl); ++ memcpy(cursor, n->mac, sizeof(n->mac)); ++ ++ dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac), ++ sizeof(virtio_net_ctrl_ack)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK; ++ } ++ ++ return 0; ++} ++ + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .receive = vhost_vdpa_receive, + .start = vhost_vdpa_net_cvq_start, ++ .load = vhost_vdpa_net_load, + .stop = vhost_vdpa_net_cvq_stop, + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, +-- +2.27.0 + diff --git a/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch b/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch new file mode 100644 index 0000000000000000000000000000000000000000..b97319d652678643789740cf2f42ac5baeaddd3a --- /dev/null +++ b/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch @@ -0,0 +1,208 @@ +From 3f278509424df64a731f69f4599460eda9a8d133 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:46 +0200 +Subject: [PATCH] vdpa: Add x-svq to NetdevVhostVDPAOptions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Finally offering the possibility to enable SVQ from the command line. + +Signed-off-by: Eugenio Pérez +Acked-by: Markus Armbruster +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- + qapi/net.json | 9 +++++- + 2 files changed, 77 insertions(+), 4 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 6a0fcab443..460f9674d7 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -74,6 +74,28 @@ const int vdpa_feature_bits[] = { + VHOST_INVALID_FEATURE_BIT + }; + ++/** Supported device specific feature bits with SVQ */ ++static const uint64_t vdpa_svq_device_features = ++ BIT_ULL(VIRTIO_NET_F_CSUM) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | ++ BIT_ULL(VIRTIO_NET_F_MTU) | ++ BIT_ULL(VIRTIO_NET_F_MAC) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | ++ BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | ++ BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | ++ BIT_ULL(VIRTIO_NET_F_HOST_ECN) | ++ BIT_ULL(VIRTIO_NET_F_HOST_UFO) | ++ BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | ++ BIT_ULL(VIRTIO_NET_F_STATUS) | ++ BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | ++ BIT_ULL(VIRTIO_F_ANY_LAYOUT) | ++ BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | ++ BIT_ULL(VIRTIO_NET_F_RSC_EXT) | ++ BIT_ULL(VIRTIO_NET_F_STANDBY); ++ + VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -132,6 +154,7 @@ err_init: + static void vhost_vdpa_cleanup(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ struct vhost_dev *dev = &s->vhost_net->dev; + + /* + * If a peer NIC is attached, do not cleanup anything. +@@ -144,6 +167,9 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + + qemu_vfree(s->cvq_cmd_out_buffer); + qemu_vfree(s->cvq_cmd_in_buffer); ++ if (dev->vq_index + dev->nvqs == dev->vq_index_end) { ++ g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); ++ } + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); +@@ -445,7 +471,9 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + int vdpa_device_fd, + int queue_pair_index, + int nvqs, +- bool is_datapath) ++ bool is_datapath, ++ bool svq, ++ VhostIOVATree *iova_tree) + { + NetClientState *nc = NULL; + VhostVDPAState *s; +@@ -463,6 +491,8 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ s->vhost_vdpa.shadow_vqs_enabled = svq; ++ s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, + vhost_vdpa_net_cvq_cmd_page_len()); +@@ -473,6 +503,8 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "Migration disabled: vhost-vdpa uses CVQ."); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +@@ -482,6 +514,14 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + ++static int vhost_vdpa_get_iova_range(int fd, ++ struct vhost_vdpa_iova_range *iova_range) ++{ ++ int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); ++ ++ return ret < 0 ? -errno : 0; ++} ++ + static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) + { + int ret = ioctl(fd, VHOST_GET_FEATURES, features); +@@ -532,6 +572,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + uint64_t features; + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; ++ g_autoptr(VhostIOVATree) iova_tree = NULL; + NetClientState *nc; + int queue_pairs, r, i, has_cvq = 0; + +@@ -559,22 +600,45 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + ++ if (opts->x_svq) { ++ struct vhost_vdpa_iova_range iova_range; ++ ++ uint64_t invalid_dev_features = ++ features & ~vdpa_svq_device_features & ++ /* Transport are all accepted at this point */ ++ ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, ++ VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); ++ ++ if (invalid_dev_features) { ++ error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, ++ invalid_dev_features); ++ goto err_svq; ++ } ++ ++ vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last); ++ } ++ + ncs = g_malloc0(sizeof(*ncs) * queue_pairs); + + for (i = 0; i < queue_pairs; i++) { + ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, +- vdpa_device_fd, i, 2, true); ++ vdpa_device_fd, i, 2, true, opts->x_svq, ++ iova_tree); + if (!ncs[i]) + goto err; + } + + if (has_cvq) { + nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, +- vdpa_device_fd, i, 1, false); ++ vdpa_device_fd, i, 1, false, ++ opts->x_svq, iova_tree); + if (!nc) + goto err; + } + ++ /* iova_tree ownership belongs to last NetClientState */ ++ g_steal_pointer(&iova_tree); + return 0; + + err: +@@ -583,6 +647,8 @@ err: + qemu_del_net_client(ncs[i]); + } + } ++ ++err_svq: + qemu_close(vdpa_device_fd); + + return -1; +diff --git a/qapi/net.json b/qapi/net.json +index 7fab2e7cd8..6a5460ce56 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -445,12 +445,19 @@ + # @queues: number of queues to be created for multiqueue vhost-vdpa + # (default: 1) + # ++# @x-svq: Start device with (experimental) shadow virtqueue. (Since 7.1) ++# (default: false) ++# ++# Features: ++# @unstable: Member @x-svq is experimental. ++# + # Since: 5.1 + ## + { 'struct': 'NetdevVhostVDPAOptions', + 'data': { + '*vhostdev': 'str', +- '*queues': 'int' } } ++ '*queues': 'int', ++ '*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } } + + ## + # @NetClientDriver: +-- +2.27.0 + diff --git a/vdpa-Allow-MQ-feature-in-SVQ.patch b/vdpa-Allow-MQ-feature-in-SVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ebfa15a51d2cfdb0337ab5dd9ac2d1675b201b1 --- /dev/null +++ b/vdpa-Allow-MQ-feature-in-SVQ.patch @@ -0,0 +1,32 @@ +From 275135fcfb7e7c22ec84a79297ffc9c96fb82639 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:19 +0200 +Subject: [PATCH] vdpa: Allow MQ feature in SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Finally enable SVQ with MQ feature. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 831709a270..479abf97a7 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -93,6 +93,7 @@ static const uint64_t vdpa_svq_device_features = + BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | + BIT_ULL(VIRTIO_NET_F_STATUS) | + BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | ++ BIT_ULL(VIRTIO_NET_F_MQ) | + BIT_ULL(VIRTIO_F_ANY_LAYOUT) | + BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | + BIT_ULL(VIRTIO_NET_F_RSC_EXT) | +-- +2.27.0 + diff --git a/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch b/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch new file mode 100644 index 0000000000000000000000000000000000000000..64e5871e3221bed882da165bad4e7e129477873d --- /dev/null +++ b/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch @@ -0,0 +1,46 @@ +From 853f14a29c9a31ca132647770f7d6886103b2b77 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:29 +0200 +Subject: [PATCH] vdpa: Avoid compiler to squash reads to used idx +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the next patch we will allow busypolling of this value. The compiler +have a running path where shadow_used_idx, last_used_idx, and vring used +idx are not modified within the same thread busypolling. + +This was not an issue before since we always cleared device event +notifier before checking it, and that could act as memory barrier. +However, the busypoll needs something similar to kernel READ_ONCE. + +Let's add it here, sepparated from the polling. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index da1e1ce3c7..acf50a9a0b 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -326,11 +326,12 @@ static void vhost_handle_guest_kick_notifier(EventNotifier *n) + + static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) + { ++ uint16_t *used_idx = &svq->vring.used->idx; + if (svq->last_used_idx != svq->shadow_used_idx) { + return true; + } + +- svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx); ++ svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx); + + return svq->last_used_idx != svq->shadow_used_idx; + } +-- +2.27.0 + diff --git a/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch b/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch new file mode 100644 index 0000000000000000000000000000000000000000..fdbcc5d8b586708665382397e3dc48e077a68125 --- /dev/null +++ b/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch @@ -0,0 +1,305 @@ +From 31bf37b3097c1ece48b915137167bbd4bd7340aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:43 +0200 +Subject: [PATCH] vdpa: Buffer CVQ support on shadow virtqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce the control virtqueue support for vDPA shadow virtqueue. This +is needed for advanced networking features like rx filtering. + +Virtio-net control VQ copies the descriptors to qemu's VA, so we avoid +TOCTOU with the guest's or device's memory every time there is a device +model change. Otherwise, the guest could change the memory content in +the time between qemu and the device read it. + +To demonstrate command handling, VIRTIO_NET_F_CTRL_MACADDR is +implemented. If the virtio-net driver changes MAC the virtio-net device +model will be updated with the new one, and a rx filtering change event +will be raised. + +More cvq commands could be added here straightforwardly but they have +not been tested. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 214 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 206 insertions(+), 8 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 53a14bc756..2d928feefb 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -32,6 +32,9 @@ typedef struct VhostVDPAState { + NetClientState nc; + struct vhost_vdpa vhost_vdpa; + VHostNetState *vhost_net; ++ ++ /* Control commands shadow buffers */ ++ void *cvq_cmd_out_buffer, *cvq_cmd_in_buffer; + bool started; + } VhostVDPAState; + +@@ -138,6 +141,9 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { + return; + } ++ ++ qemu_vfree(s->cvq_cmd_out_buffer); ++ qemu_vfree(s->cvq_cmd_in_buffer); + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); +@@ -197,24 +203,191 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) ++{ ++ VhostIOVATree *tree = v->iova_tree; ++ DMAMap needle = { ++ /* ++ * No need to specify size or to look for more translations since ++ * this contiguous chunk was allocated by us. ++ */ ++ .translated_addr = (hwaddr)(uintptr_t)addr, ++ }; ++ const DMAMap *map = vhost_iova_tree_find_iova(tree, &needle); ++ int r; ++ ++ if (unlikely(!map)) { ++ error_report("Cannot locate expected map"); ++ return; ++ } ++ ++ r = vhost_vdpa_dma_unmap(v, map->iova, map->size + 1); ++ if (unlikely(r != 0)) { ++ error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); ++ } ++ ++ vhost_iova_tree_remove(tree, map); ++} ++ ++static size_t vhost_vdpa_net_cvq_cmd_len(void) ++{ ++ /* ++ * MAC_TABLE_SET is the ctrl command that produces the longer out buffer. ++ * In buffer is always 1 byte, so it should fit here ++ */ ++ return sizeof(struct virtio_net_ctrl_hdr) + ++ 2 * sizeof(struct virtio_net_ctrl_mac) + ++ MAC_TABLE_ENTRIES * ETH_ALEN; ++} ++ ++static size_t vhost_vdpa_net_cvq_cmd_page_len(void) ++{ ++ return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size); ++} ++ ++/** Copy and map a guest buffer. */ ++static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, ++ const struct iovec *out_data, ++ size_t out_num, size_t data_len, void *buf, ++ size_t *written, bool write) ++{ ++ DMAMap map = {}; ++ int r; ++ ++ if (unlikely(!data_len)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n", ++ __func__, write ? "in" : "out"); ++ return false; ++ } ++ ++ *written = iov_to_buf(out_data, out_num, 0, buf, data_len); ++ map.translated_addr = (hwaddr)(uintptr_t)buf; ++ map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1; ++ map.perm = write ? IOMMU_RW : IOMMU_RO, ++ r = vhost_iova_tree_map_alloc(v->iova_tree, &map); ++ if (unlikely(r != IOVA_OK)) { ++ error_report("Cannot map injected element"); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, ++ !write); ++ if (unlikely(r < 0)) { ++ goto dma_map_err; ++ } ++ ++ return true; ++ ++dma_map_err: ++ vhost_iova_tree_remove(v->iova_tree, &map); ++ return false; ++} ++ + /** +- * Forward buffer for the moment. ++ * Copy the guest element into a dedicated buffer suitable to be sent to NIC ++ * ++ * @iov: [0] is the out buffer, [1] is the in one ++ */ ++static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, ++ VirtQueueElement *elem, ++ struct iovec *iov) ++{ ++ size_t in_copied; ++ bool ok; ++ ++ iov[0].iov_base = s->cvq_cmd_out_buffer; ++ ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num, ++ vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base, ++ &iov[0].iov_len, false); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ iov[1].iov_base = s->cvq_cmd_in_buffer; ++ ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0, ++ sizeof(virtio_net_ctrl_ack), iov[1].iov_base, ++ &in_copied, true); ++ if (unlikely(!ok)) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); ++ return false; ++ } ++ ++ iov[1].iov_len = sizeof(virtio_net_ctrl_ack); ++ return true; ++} ++ ++/** ++ * Do not forward commands not supported by SVQ. Otherwise, the device could ++ * accept it and qemu would not know how to update the device model. ++ */ ++static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, ++ size_t out_num) ++{ ++ struct virtio_net_ctrl_hdr ctrl; ++ size_t n; ++ ++ n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl)); ++ if (unlikely(n < sizeof(ctrl))) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: invalid legnth of out buffer %zu\n", __func__, n); ++ return false; ++ } ++ ++ switch (ctrl.class) { ++ case VIRTIO_NET_CTRL_MAC: ++ switch (ctrl.cmd) { ++ case VIRTIO_NET_CTRL_MAC_ADDR_SET: ++ return true; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mac cmd %u\n", ++ __func__, ctrl.cmd); ++ }; ++ break; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", ++ __func__, ctrl.class); ++ }; ++ ++ return false; ++} ++ ++/** ++ * Validate and copy control virtqueue commands. ++ * ++ * Following QEMU guidelines, we offer a copy of the buffers to the device to ++ * prevent TOCTOU bugs. + */ + static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + VirtQueueElement *elem, + void *opaque) + { +- unsigned int n = elem->out_num + elem->in_num; +- g_autofree struct iovec *dev_buffers = g_new(struct iovec, n); ++ VhostVDPAState *s = opaque; + size_t in_len, dev_written; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- int r; ++ /* out and in buffers sent to the device */ ++ struct iovec dev_buffers[2] = { ++ { .iov_base = s->cvq_cmd_out_buffer }, ++ { .iov_base = s->cvq_cmd_in_buffer }, ++ }; ++ /* in buffer used for device model */ ++ const struct iovec in = { ++ .iov_base = &status, ++ .iov_len = sizeof(status), ++ }; ++ int r = -EINVAL; ++ bool ok; ++ ++ ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers); ++ if (unlikely(!ok)) { ++ goto out; ++ } + +- memcpy(dev_buffers, elem->out_sg, elem->out_num); +- memcpy(dev_buffers + elem->out_num, elem->in_sg, elem->in_num); ++ ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1); ++ if (unlikely(!ok)) { ++ goto out; ++ } + +- r = vhost_svq_add(svq, &dev_buffers[0], elem->out_num, &dev_buffers[1], +- elem->in_num, elem); ++ r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem); + if (unlikely(r != 0)) { + if (unlikely(r == -ENOSPC)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +@@ -231,6 +404,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + dev_written = vhost_svq_poll(svq); + if (unlikely(dev_written < sizeof(status))) { + error_report("Insufficient written data (%zu)", dev_written); ++ goto out; ++ } ++ ++ memcpy(&status, dev_buffers[1].iov_base, sizeof(status)); ++ if (status != VIRTIO_NET_OK) { ++ goto out; ++ } ++ ++ status = VIRTIO_NET_ERR; ++ virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1); ++ if (status != VIRTIO_NET_OK) { ++ error_report("Bad CVQ processing in model"); + } + + out: +@@ -241,6 +426,12 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); ++ if (dev_buffers[0].iov_base) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base); ++ } ++ if (dev_buffers[1].iov_base) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base); ++ } + return r; + } + +@@ -273,6 +464,13 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; + if (!is_datapath) { ++ s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ s->cvq_cmd_in_buffer = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->cvq_cmd_in_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; + } +-- +2.27.0 + diff --git a/vdpa-Delete-CVQ-migration-blocker.patch b/vdpa-Delete-CVQ-migration-blocker.patch new file mode 100644 index 0000000000000000000000000000000000000000..568fb20d6e0088f5695037006f1ee88ba5eca8e3 --- /dev/null +++ b/vdpa-Delete-CVQ-migration-blocker.patch @@ -0,0 +1,89 @@ +From cdc1b97f133a2b79318cc10aa6d1a9b69abac78f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:37 +0200 +Subject: [PATCH] vdpa: Delete CVQ migration blocker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can restore the device state in the destination via CVQ now. Remove +the migration blocker. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 --------------- + include/hw/virtio/vhost-vdpa.h | 1 - + net/vhost-vdpa.c | 2 -- + 3 files changed, 18 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d7bdc0f37c..0f07c85b91 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1035,13 +1035,6 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + return true; + } + +- if (v->migration_blocker) { +- int r = migrate_add_blocker(v->migration_blocker, &err); +- if (unlikely(r < 0)) { +- return false; +- } +- } +- + for (i = 0; i < v->shadow_vqs->len; ++i) { + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +@@ -1084,10 +1077,6 @@ err: + vhost_svq_stop(svq); + } + +- if (v->migration_blocker) { +- migrate_del_blocker(v->migration_blocker); +- } +- + return false; + } + +@@ -1103,10 +1092,6 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + vhost_vdpa_svq_unmap_rings(dev, svq); + } +- +- if (v->migration_blocker) { +- migrate_del_blocker(v->migration_blocker); +- } + } + + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index d10a89303e..1111d85643 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -35,7 +35,6 @@ typedef struct vhost_vdpa { + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; +- Error *migration_blocker; + GPtrArray *shadow_vqs; + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 561e43fa92..b10a18aeb4 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -563,8 +563,6 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; +- error_setg(&s->vhost_vdpa.migration_blocker, +- "Migration disabled: vhost-vdpa uses CVQ."); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch b/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch new file mode 100644 index 0000000000000000000000000000000000000000..8a0b3658838ed87d72c63ec50928dc2a05304de1 --- /dev/null +++ b/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch @@ -0,0 +1,34 @@ +From e316083c41f99c424879622c6e79452a6878b32f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 20 Oct 2022 10:00:58 +0200 +Subject: [PATCH] vdpa: Delete duplicated vdpa_feature_bits entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This entry was duplicated on referenced commit. Removing it. + +Fixes: 402378407dbd ("vhost-vdpa: multiqueue support") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 479abf97a7..f4f6b8587f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -62,7 +62,6 @@ const int vdpa_feature_bits[] = { + VIRTIO_NET_F_CTRL_RX, + VIRTIO_NET_F_CTRL_RX_EXTRA, + VIRTIO_NET_F_CTRL_VLAN, +- VIRTIO_NET_F_GUEST_ANNOUNCE, + VIRTIO_NET_F_CTRL_MAC_ADDR, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_MQ, +-- +2.27.0 + diff --git a/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch b/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fade98571914a50d432284994bf526b538fcb87 --- /dev/null +++ b/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch @@ -0,0 +1,65 @@ +From 4054b1e42fde8f22703d5fc9bc84a9179ee8f9f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:40 +0200 +Subject: [PATCH] vdpa: Export vhost_vdpa_dma_map and unmap calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Shadow CVQ will copy buffers on qemu VA, so we avoid TOCTOU attacks from +the guest that could set a different state in qemu device model and vdpa +device. + +To do so, it needs to be able to map these new buffers to the device. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 7 +++---- + include/hw/virtio/vhost-vdpa.h | 4 ++++ + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index a8d42655f0..8e962f511d 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -73,8 +73,8 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, + return false; + } + +-static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly) ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, ++ void *vaddr, bool readonly) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; +@@ -99,8 +99,7 @@ static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, + return ret; + } + +-static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, +- hwaddr size) ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index a29dbb3f53..7214eb47dc 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -39,4 +39,8 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, ++ void *vaddr, bool readonly); ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size); ++ + #endif +-- +2.27.0 + diff --git a/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch b/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..610d418620c7af70a3948e2cea25844529b3c0b4 --- /dev/null +++ b/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch @@ -0,0 +1,120 @@ +From a531a56bddf997f559f67fe9d3dc6d4258c82eb1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:54 +0100 +Subject: [PATCH] vdpa: Expose VHOST_F_LOG_ALL on SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SVQ is able to log the dirty bits by itself, so let's use it to not +block migration. + +Also, ignore set and clear of VHOST_F_LOG_ALL on set_features if SVQ is +enabled. Even if the device supports it, the reports would be nonsense +because SVQ memory is in the qemu region. + +The log region is still allocated. Future changes might skip that, but +this series is already long enough. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 39 ++++++++++++++++++++++++++++++---- + include/hw/virtio/vhost-vdpa.h | 1 + + 2 files changed, 36 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 840141321a..3b5456cc0e 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -375,6 +375,16 @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) + return v->index != 0; + } + ++static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, ++ uint64_t *features) ++{ ++ int ret; ++ ++ ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); ++ trace_vhost_vdpa_get_features(dev, *features); ++ return ret; ++} ++ + static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + Error **errp) + { +@@ -387,7 +397,7 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + return 0; + } + +- r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features); ++ r = vhost_vdpa_get_dev_features(hdev, &dev_features); + if (r != 0) { + error_setg_errno(errp, -r, "Can't get vdpa device features"); + return r; +@@ -612,12 +622,29 @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + static int vhost_vdpa_set_features(struct vhost_dev *dev, + uint64_t features) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + + if (vhost_vdpa_one_time_request(dev)) { + return 0; + } + ++ if (v->shadow_vqs_enabled) { ++ if ((v->acked_features ^ features) == BIT_ULL(VHOST_F_LOG_ALL)) { ++ /* ++ * QEMU is just trying to enable or disable logging. SVQ handles ++ * this sepparately, so no need to forward this. ++ */ ++ v->acked_features = features; ++ return 0; ++ } ++ ++ v->acked_features = features; ++ ++ /* We must not ack _F_LOG if SVQ is enabled */ ++ features &= ~BIT_ULL(VHOST_F_LOG_ALL); ++ } ++ + trace_vhost_vdpa_set_features(dev, features); + ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); + if (ret) { +@@ -1202,10 +1229,14 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) + { +- int ret; ++ struct vhost_vdpa *v = dev->opaque; ++ int ret = vhost_vdpa_get_dev_features(dev, features); ++ ++ if (ret == 0 && v->shadow_vqs_enabled) { ++ /* Add SVQ logging capabilities */ ++ *features |= BIT_ULL(VHOST_F_LOG_ALL); ++ } + +- ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); +- trace_vhost_vdpa_get_features(dev, *features); + return ret; + } + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index ee8e939ad0..a29dbb3f53 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -30,6 +30,7 @@ typedef struct vhost_vdpa { + bool iotlb_batch_begin_sent; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; ++ uint64_t acked_features; + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; +-- +2.27.0 + diff --git a/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch b/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a2f33770e657c8e2683630ed59d7c5b4cc8eef8 --- /dev/null +++ b/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch @@ -0,0 +1,89 @@ +From 29048bdf8848d527b39a383c7f0c4f8c60870f71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:44 +0200 +Subject: [PATCH] vdpa: Extract get features part from + vhost_vdpa_get_max_queue_pairs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To know the device features is needed for CVQ SVQ, so SVQ knows if it +can handle all commands or not. Extract from +vhost_vdpa_get_max_queue_pairs so we can reuse it. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 2d928feefb..6a0fcab443 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -482,20 +482,24 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + +-static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp) ++static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) ++{ ++ int ret = ioctl(fd, VHOST_GET_FEATURES, features); ++ if (unlikely(ret < 0)) { ++ error_setg_errno(errp, errno, ++ "Fail to query features from vhost-vDPA device"); ++ } ++ return ret; ++} ++ ++static int vhost_vdpa_get_max_queue_pairs(int fd, uint64_t features, ++ int *has_cvq, Error **errp) + { + unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); + g_autofree struct vhost_vdpa_config *config = NULL; + __virtio16 *max_queue_pairs; +- uint64_t features; + int ret; + +- ret = ioctl(fd, VHOST_GET_FEATURES, &features); +- if (ret) { +- error_setg(errp, "Fail to query features from vhost-vDPA device"); +- return ret; +- } +- + if (features & (1 << VIRTIO_NET_F_CTRL_VQ)) { + *has_cvq = 1; + } else { +@@ -525,10 +529,11 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) + { + const NetdevVhostVDPAOptions *opts; ++ uint64_t features; + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; + NetClientState *nc; +- int queue_pairs, i, has_cvq = 0; ++ int queue_pairs, r, i, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +@@ -542,7 +547,12 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return -errno; + } + +- queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, ++ r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, + &has_cvq, errp); + if (queue_pairs < 0) { + qemu_close(vdpa_device_fd); +-- +2.27.0 + diff --git a/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch b/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch new file mode 100644 index 0000000000000000000000000000000000000000..a156e6c89539f5adcfc8593baaea0dd782b6e5f9 --- /dev/null +++ b/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch @@ -0,0 +1,41 @@ +From b37494d53478957b9e126e97f03d9501888a4d83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:44 +0200 +Subject: [PATCH] vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 6d0b222666 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") + +Acked-by: Jason Wang +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 022d70aefb..3b67c9fd12 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1174,11 +1174,11 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; ++ int vdpa_idx = ring->index - dev->vq_index; + int ret; + + if (v->shadow_vqs_enabled) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, +- ring->index); ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); + + /* + * Setting base as last used idx, so destination will see as available +-- +2.27.0 + diff --git a/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch b/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..6436bab1faf6f73d18d987e622bf2fd0be61aa2d --- /dev/null +++ b/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch @@ -0,0 +1,50 @@ +From 4077ce7f2d21dc67d18dc444165859b8496a185e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 2 Aug 2022 13:24:46 +0200 +Subject: [PATCH] vdpa: Fix file descriptor leak on get features error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +File descriptor vdpa_device_fd is not free in the case of returning +error from vhost_vdpa_get_features. Fixing it by making all errors go to +the same error path. + +Resolves: Coverity CID 1490785 +Fixes: 8170ab3f43 ("vdpa: Extract get features part from vhost_vdpa_get_max_queue_pairs") + +Signed-off-by: Eugenio Pérez +Reviewed-by: Laurent Vivier +Reviewed-by: Michael S. Tsirkin +Message-Id: <20220802112447.249436-2-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 460f9674d7..0f75aa6080 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -574,7 +574,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + g_autofree NetClientState **ncs = NULL; + g_autoptr(VhostIOVATree) iova_tree = NULL; + NetClientState *nc; +- int queue_pairs, r, i, has_cvq = 0; ++ int queue_pairs, r, i = 0, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +@@ -590,7 +590,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); + if (unlikely(r < 0)) { +- return r; ++ goto err; + } + + queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, +-- +2.27.0 + diff --git a/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch b/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch new file mode 100644 index 0000000000000000000000000000000000000000..69f14963ab928202a072bf909fb55add1c9de1e4 --- /dev/null +++ b/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch @@ -0,0 +1,37 @@ +From 2f19a3fd1fbaca215906199ab7da7cd961b68d65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:45 +0200 +Subject: [PATCH] vdpa: Fix index calculus at vhost_vdpa_svqs_start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the introduction of MQ the index of the vq needs to be calculated +with the device model vq_index. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20220512175747.142058-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3b67c9fd12..1360f2eaf7 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1020,7 +1020,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + struct vhost_vring_addr addr = { +- .index = i, ++ .index = dev->vq_index + i, + }; + int r; + bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); +-- +2.27.0 + diff --git a/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch b/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch new file mode 100644 index 0000000000000000000000000000000000000000..bba1ee0f2540ae492c4cef6d0e342196c9e1a34a --- /dev/null +++ b/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch @@ -0,0 +1,53 @@ +From de9a72905ad70e256a73608c92f50c3862b8eb8e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 22 Jul 2022 10:26:30 +0200 +Subject: [PATCH] vdpa: Fix memory listener deletions of iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +vhost_vdpa_listener_region_del is always deleting the first iova entry +of the tree, since it's using the needle iova instead of the result's +one. + +This was detected using a vga virtual device in the VM using vdpa SVQ. +It makes some extra memory adding and deleting, so the wrong one was +mapped / unmapped. This was undetected before since all the memory was +mappend and unmapped totally without that device, but other conditions +could trigger it too: + +* mem_region was with .iova = 0, .translated_addr = (correct GPA). +* iova_tree_find_iova returned right result, but does not update + mem_region. +* iova_tree_remove always removed region with .iova = 0. Right iova were + sent to the device. +* Next map will fill the first region with .iova = 0, causing a mapping + with the same iova and device complains, if the next action is a map. +* Next unmap will cause to try to unmap again iova = 0, causing the + device to complain that no region was mapped at iova = 0. + +Fixes: 34e3c94edaef ("vdpa: Add custom IOTLB translations to SVQ") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 6304f174c2..d0cf7a0745 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -292,7 +292,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); + iova = result->iova; +- vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ vhost_iova_tree_remove(v->iova_tree, result); + } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); +-- +2.27.0 + diff --git a/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch b/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch new file mode 100644 index 0000000000000000000000000000000000000000..925cb9efdfda400301f49446b1fb776aa3108219 --- /dev/null +++ b/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch @@ -0,0 +1,63 @@ +From c8d132a62f026e51c2fb1f87dbf40aad8080fa9a Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Sat, 8 Jul 2023 00:44:42 +0800 +Subject: [PATCH] vdpa: Fix possible use-after-free for VirtQueueElement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU uses vhost_handle_guest_kick() to forward guest's available +buffers to the vdpa device in SVQ avail ring. + +In vhost_handle_guest_kick(), a `g_autofree` `elem` is used to +iterate through the available VirtQueueElements. This `elem` is +then passed to `svq->ops->avail_handler`, specifically to the +vhost_vdpa_net_handle_ctrl_avail(). If this handler fails to +process the CVQ command, vhost_handle_guest_kick() regains +ownership of the `elem`, and either frees it or requeues it. + +Yet the problem is that, vhost_vdpa_net_handle_ctrl_avail() +mistakenly frees the `elem`, even if it fails to forward the +CVQ command to vdpa device. This can result in a use-after-free +for the `elem` in vhost_handle_guest_kick(). + +This patch solves this problem by refactoring +vhost_vdpa_net_handle_ctrl_avail() to only freeing the `elem` if +it owns it. + +Fixes: bd907ae4b0 ("vdpa: manual forward CVQ buffers") +Signed-off-by: Hawkins Jiawei +Message-Id: +Reviewed-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index fd5dc8c6aa..94f74b54ae 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -658,7 +658,16 @@ out: + error_report("Bad device CVQ written length"); + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); +- g_free(elem); ++ /* ++ * `elem` belongs to vhost_vdpa_net_handle_ctrl_avail() only when ++ * the function successfully forwards the CVQ command, indicated ++ * by a non-negative value of `dev_written`. Otherwise, it still ++ * belongs to SVQ. ++ * This function should only free the `elem` when it owns. ++ */ ++ if (dev_written >= 0) { ++ g_free(elem); ++ } + return dev_written < 0 ? dev_written : 0; + } + +-- +2.27.0 + diff --git a/vdpa-Make-SVQ-vring-unmapping-return-void.patch b/vdpa-Make-SVQ-vring-unmapping-return-void.patch new file mode 100644 index 0000000000000000000000000000000000000000..589898bd978c8ac58fea72bfcb8fed9830284841 --- /dev/null +++ b/vdpa-Make-SVQ-vring-unmapping-return-void.patch @@ -0,0 +1,124 @@ +From 39de24fc2b1cd16e8810b9e26cd23bb3896982a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:06 +0200 +Subject: [PATCH] vdpa: Make SVQ vring unmapping return void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Nothing actually reads the return value, but an error in cleaning some +entries could cause device stop to abort, making a restart impossible. +Better ignore explicitely the return value. + +Reported-by: Lei Yang +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 32 ++++++++++---------------------- + 1 file changed, 10 insertions(+), 22 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3be6988e9c..31c1b71498 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -886,7 +886,7 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, ++static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + const DMAMap *needle) + { + const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); +@@ -895,38 +895,33 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + + if (unlikely(!result)) { + error_report("Unable to find SVQ address to unmap"); +- return false; ++ return; + } + + size = ROUND_UP(result->size, qemu_real_host_page_size); + r = vhost_vdpa_dma_unmap(v, result->iova, size); + if (unlikely(r < 0)) { + error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); +- return false; ++ return; + } + + vhost_iova_tree_remove(v->iova_tree, *result); +- return r == 0; + } + +-static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, ++static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { + DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; +- bool ok; + + vhost_svq_get_vring_addr(svq, &svq_addr); + + needle.translated_addr = svq_addr.desc_user_addr; +- ok = vhost_vdpa_svq_unmap_ring(v, &needle); +- if (unlikely(!ok)) { +- return false; +- } ++ vhost_vdpa_svq_unmap_ring(v, &needle); + + needle.translated_addr = svq_addr.used_user_addr; +- return vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, &needle); + } + + /** +@@ -1097,26 +1092,22 @@ err: + return false; + } + +-static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) ++static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + + if (!v->shadow_vqs) { +- return true; ++ return; + } + + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +- bool ok = vhost_vdpa_svq_unmap_rings(dev, svq); +- if (unlikely(!ok)) { +- return false; +- } ++ vhost_vdpa_svq_unmap_rings(dev, svq); + } + + if (v->migration_blocker) { + migrate_del_blocker(v->migration_blocker); + } +- return true; + } + + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) +@@ -1133,10 +1124,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + vhost_vdpa_set_vring_ready(dev); + } else { +- ok = vhost_vdpa_svqs_stop(dev); +- if (unlikely(!ok)) { +- return -1; +- } ++ vhost_vdpa_svqs_stop(dev); + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + } + +-- +2.27.0 + diff --git a/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch b/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9efa4973e7362c210a970d06dbcb3dc6ac79a8f --- /dev/null +++ b/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch @@ -0,0 +1,103 @@ +From fdb55acf1833e6a35171b4e7e1c357f4b133e26f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:14 +0200 +Subject: [PATCH] vdpa: Make VhostVDPAState cvq_cmd_in_buffer control ack type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows to simplify the code. Rename to status while we're at it. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b10a18aeb4..2700ef656f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -34,7 +34,9 @@ typedef struct VhostVDPAState { + VHostNetState *vhost_net; + + /* Control commands shadow buffers */ +- void *cvq_cmd_out_buffer, *cvq_cmd_in_buffer; ++ void *cvq_cmd_out_buffer; ++ virtio_net_ctrl_ack *status; ++ + bool started; + } VhostVDPAState; + +@@ -166,7 +168,7 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + } + + qemu_vfree(s->cvq_cmd_out_buffer); +- qemu_vfree(s->cvq_cmd_in_buffer); ++ qemu_vfree(s->status); + if (dev->vq_index + dev->nvqs == dev->vq_index_end) { + g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); + } +@@ -318,7 +320,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) + return r; + } + +- r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer, ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->status, + vhost_vdpa_net_cvq_cmd_page_len(), true); + if (unlikely(r < 0)) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +@@ -335,7 +337,7 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + + if (s->vhost_vdpa.shadow_vqs_enabled) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer); ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status); + } + } + +@@ -348,7 +350,7 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + .iov_len = out_len, + }; + const struct iovec in = { +- .iov_base = s->cvq_cmd_in_buffer, ++ .iov_base = s->status, + .iov_len = sizeof(virtio_net_ctrl_ack), + }; + VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); +@@ -404,7 +406,7 @@ static int vhost_vdpa_net_load(NetClientState *nc) + return dev_written; + } + +- return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK; ++ return *s->status != VIRTIO_NET_OK; + } + + return 0; +@@ -499,8 +501,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); +- if (status != VIRTIO_NET_OK) { ++ if (*s->status != VIRTIO_NET_OK) { + return VIRTIO_NET_ERR; + } + +@@ -557,9 +558,9 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, + vhost_vdpa_net_cvq_cmd_page_len()); + memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); +- s->cvq_cmd_in_buffer = qemu_memalign(qemu_real_host_page_size, +- vhost_vdpa_net_cvq_cmd_page_len()); +- memset(s->cvq_cmd_in_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ s->status = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->status, 0, vhost_vdpa_net_cvq_cmd_page_len()); + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; +-- +2.27.0 + diff --git a/vdpa-Make-ncs-autofree.patch b/vdpa-Make-ncs-autofree.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2b8775f8fd136d35f5abca7f53fc76e7544c197 --- /dev/null +++ b/vdpa-Make-ncs-autofree.patch @@ -0,0 +1,54 @@ +From 1f1c2f74668cd1250cbd00b397dd59be92121314 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Feb 2022 20:34:15 +0100 +Subject: [PATCH] vdpa: Make ncs autofree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Simplifying memory management. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Stefano Garzarella +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220214193415.1606752-2-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 60b715aef1..9ba0f7bfca 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -271,7 +271,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + { + const NetdevVhostVDPAOptions *opts; + int vdpa_device_fd; +- NetClientState **ncs, *nc; ++ g_autofree NetClientState **ncs = NULL; ++ NetClientState *nc; + int queue_pairs, i, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); +@@ -309,7 +310,6 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + goto err; + } + +- g_free(ncs); + return 0; + + err: +@@ -317,7 +317,6 @@ err: + qemu_del_net_client(ncs[0]); + } + qemu_close(vdpa_device_fd); +- g_free(ncs); + + return -1; + } +-- +2.27.0 + diff --git a/vdpa-Move-command-buffers-map-to-start-of-net-device.patch b/vdpa-Move-command-buffers-map-to-start-of-net-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b943d29176ebc67fe93c7ba35b63cbdb87b432a --- /dev/null +++ b/vdpa-Move-command-buffers-map-to-start-of-net-device.patch @@ -0,0 +1,242 @@ +From 811a2e0b40724cc505141d4caf322030b83f86a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:33 +0200 +Subject: [PATCH] vdpa: Move command buffers map to start of net device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As this series will reuse them to restore the device state at the end of +a migration (or a device start), let's allocate only once at the device +start so we don't duplicate their map and unmap. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 123 ++++++++++++++++++++++------------------------- + 1 file changed, 58 insertions(+), 65 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 04cb08d418..882f5ee89c 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -271,29 +271,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void) + return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size); + } + +-/** Copy and map a guest buffer. */ +-static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, +- const struct iovec *out_data, +- size_t out_num, size_t data_len, void *buf, +- size_t *written, bool write) ++/** Map CVQ buffer. */ ++static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, ++ bool write) + { + DMAMap map = {}; + int r; + +- if (unlikely(!data_len)) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n", +- __func__, write ? "in" : "out"); +- return false; +- } +- +- *written = iov_to_buf(out_data, out_num, 0, buf, data_len); + map.translated_addr = (hwaddr)(uintptr_t)buf; +- map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1; ++ map.size = size - 1; + map.perm = write ? IOMMU_RW : IOMMU_RO, + r = vhost_iova_tree_map_alloc(v->iova_tree, &map); + if (unlikely(r != IOVA_OK)) { + error_report("Cannot map injected element"); +- return false; ++ return r; + } + + r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, +@@ -302,50 +293,58 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, + goto dma_map_err; + } + +- return true; ++ return 0; + + dma_map_err: + vhost_iova_tree_remove(v->iova_tree, map); +- return false; ++ return r; + } + +-/** +- * Copy the guest element into a dedicated buffer suitable to be sent to NIC +- * +- * @iov: [0] is the out buffer, [1] is the in one +- */ +-static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, +- VirtQueueElement *elem, +- struct iovec *iov) ++static int vhost_vdpa_net_cvq_start(NetClientState *nc) + { +- size_t in_copied; +- bool ok; ++ VhostVDPAState *s; ++ int r; + +- iov[0].iov_base = s->cvq_cmd_out_buffer; +- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num, +- vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base, +- &iov[0].iov_len, false); +- if (unlikely(!ok)) { +- return false; ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ s = DO_UPCAST(VhostVDPAState, nc, nc); ++ if (!s->vhost_vdpa.shadow_vqs_enabled) { ++ return 0; + } + +- iov[1].iov_base = s->cvq_cmd_in_buffer; +- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0, +- sizeof(virtio_net_ctrl_ack), iov[1].iov_base, +- &in_copied, true); +- if (unlikely(!ok)) { ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer, ++ vhost_vdpa_net_cvq_cmd_page_len(), false); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer, ++ vhost_vdpa_net_cvq_cmd_page_len(), true); ++ if (unlikely(r < 0)) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +- return false; + } + +- iov[1].iov_len = sizeof(virtio_net_ctrl_ack); +- return true; ++ return r; ++} ++ ++static void vhost_vdpa_net_cvq_stop(NetClientState *nc) ++{ ++ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ if (s->vhost_vdpa.shadow_vqs_enabled) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer); ++ } + } + + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .receive = vhost_vdpa_receive, ++ .start = vhost_vdpa_net_cvq_start, ++ .stop = vhost_vdpa_net_cvq_stop, + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .has_ufo = vhost_vdpa_has_ufo, +@@ -356,19 +355,17 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { + * Do not forward commands not supported by SVQ. Otherwise, the device could + * accept it and qemu would not know how to update the device model. + */ +-static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, +- size_t out_num) ++static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) + { + struct virtio_net_ctrl_hdr ctrl; +- size_t n; + +- n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl)); +- if (unlikely(n < sizeof(ctrl))) { ++ if (unlikely(len < sizeof(ctrl))) { + qemu_log_mask(LOG_GUEST_ERROR, +- "%s: invalid legnth of out buffer %zu\n", __func__, n); ++ "%s: invalid legnth of out buffer %zu\n", __func__, len); + return false; + } + ++ memcpy(&ctrl, out_buf, sizeof(ctrl)); + switch (ctrl.class) { + case VIRTIO_NET_CTRL_MAC: + switch (ctrl.cmd) { +@@ -400,10 +397,14 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + VhostVDPAState *s = opaque; + size_t in_len, dev_written; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- /* out and in buffers sent to the device */ +- struct iovec dev_buffers[2] = { +- { .iov_base = s->cvq_cmd_out_buffer }, +- { .iov_base = s->cvq_cmd_in_buffer }, ++ /* Out buffer sent to both the vdpa device and the device model */ ++ struct iovec out = { ++ .iov_base = s->cvq_cmd_out_buffer, ++ }; ++ /* In buffer sent to the device */ ++ const struct iovec dev_in = { ++ .iov_base = s->cvq_cmd_in_buffer, ++ .iov_len = sizeof(virtio_net_ctrl_ack), + }; + /* in buffer used for device model */ + const struct iovec in = { +@@ -413,17 +414,15 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + int r = -EINVAL; + bool ok; + +- ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers); +- if (unlikely(!ok)) { +- goto out; +- } +- +- ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1); ++ out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, ++ s->cvq_cmd_out_buffer, ++ vhost_vdpa_net_cvq_cmd_len()); ++ ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len); + if (unlikely(!ok)) { + goto out; + } + +- r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem); ++ r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem); + if (unlikely(r != 0)) { + if (unlikely(r == -ENOSPC)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +@@ -443,13 +442,13 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- memcpy(&status, dev_buffers[1].iov_base, sizeof(status)); ++ memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); + if (status != VIRTIO_NET_OK) { + goto out; + } + + status = VIRTIO_NET_ERR; +- virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1); ++ virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, &out, 1); + if (status != VIRTIO_NET_OK) { + error_report("Bad CVQ processing in model"); + } +@@ -462,12 +461,6 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); +- if (dev_buffers[0].iov_base) { +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base); +- } +- if (dev_buffers[1].iov_base) { +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base); +- } + return r; + } + +-- +2.27.0 + diff --git a/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch b/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch new file mode 100644 index 0000000000000000000000000000000000000000..6778cdedec69f3291832cc0f7722ef7ee9390428 --- /dev/null +++ b/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch @@ -0,0 +1,36 @@ +From b34bcf052293861e8b88a41dad194d0889c6692f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:53 +0100 +Subject: [PATCH] vdpa: Never set log_base addr if SVQ is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Setting the log address would make the device start reporting invalid +dirty memory because the SVQ vrings are located in qemu's memory. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 428137f654..840141321a 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1092,7 +1092,8 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ struct vhost_vdpa *v = dev->opaque; ++ if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { + return 0; + } + +-- +2.27.0 + diff --git a/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch b/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch new file mode 100644 index 0000000000000000000000000000000000000000..be0cb96a1e6e4d7a7d2ae03d2b1da83d91f276ec --- /dev/null +++ b/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch @@ -0,0 +1,40 @@ +From f52985fb819fbf8efb162a25096abb4c174b9f40 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:05 +0200 +Subject: [PATCH] vdpa: Remove SVQ vring from iova_tree at shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Although the device will be reset before usage, the right thing to do is +to clean it. + +Reported-by: Lei Yang +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 0f640f670b..3be6988e9c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -900,6 +900,12 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + + size = ROUND_UP(result->size, qemu_real_host_page_size); + r = vhost_vdpa_dma_unmap(v, result->iova, size); ++ if (unlikely(r < 0)) { ++ error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); ++ return false; ++ } ++ ++ vhost_iova_tree_remove(v->iova_tree, *result); + return r == 0; + } + +-- +2.27.0 + diff --git a/vdpa-Remove-shadow-CVQ-command-check.patch b/vdpa-Remove-shadow-CVQ-command-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..90ef701b966ae62965a11d759621b2cb0c0a7420 --- /dev/null +++ b/vdpa-Remove-shadow-CVQ-command-check.patch @@ -0,0 +1,94 @@ +From 6cb9e17dcc07d6fc1467a585fb015991191a92da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 20 Oct 2022 10:02:30 +0200 +Subject: [PATCH] vdpa: Remove shadow CVQ command check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The guest will see undefined behavior if it issue not negotiate +commands, bit it is expected somehow. + +Simplify code deleting this check. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 48 ------------------------------------------------ + 1 file changed, 48 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index f4f6b8587f..c8c433002d 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -469,48 +469,6 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + +-/** +- * Do not forward commands not supported by SVQ. Otherwise, the device could +- * accept it and qemu would not know how to update the device model. +- */ +-static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) +-{ +- struct virtio_net_ctrl_hdr ctrl; +- +- if (unlikely(len < sizeof(ctrl))) { +- qemu_log_mask(LOG_GUEST_ERROR, +- "%s: invalid legnth of out buffer %zu\n", __func__, len); +- return false; +- } +- +- memcpy(&ctrl, out_buf, sizeof(ctrl)); +- switch (ctrl.class) { +- case VIRTIO_NET_CTRL_MAC: +- switch (ctrl.cmd) { +- case VIRTIO_NET_CTRL_MAC_ADDR_SET: +- return true; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mac cmd %u\n", +- __func__, ctrl.cmd); +- }; +- break; +- case VIRTIO_NET_CTRL_MQ: +- switch (ctrl.cmd) { +- case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: +- return true; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n", +- __func__, ctrl.cmd); +- }; +- break; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", +- __func__, ctrl.class); +- }; +- +- return false; +-} +- + /** + * Validate and copy control virtqueue commands. + * +@@ -534,16 +492,10 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + .iov_len = sizeof(status), + }; + ssize_t dev_written = -EINVAL; +- bool ok; + + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); +- ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len); +- if (unlikely(!ok)) { +- goto out; +- } +- + dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); + if (unlikely(dev_written < 0)) { + goto out; +-- +2.27.0 + diff --git a/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..6471c52fbb90f0a5442e4831e1350a060d0858da --- /dev/null +++ b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch @@ -0,0 +1,63 @@ +From 8f2a04c1b5790f6e00160920c3bc88801b5afc16 Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 4 Jul 2023 11:34:34 +0800 +Subject: [PATCH] vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in + _load_mq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to VirtIO standard, "The class, command and +command-specific-data are set by the driver, +and the device sets the ack byte. +There is little it can do except issue a diagnostic +if ack is not VIRTIO_NET_OK." + +Therefore, QEMU should stop sending the queued SVQ commands and +cancel the device startup if the device's ack is not VIRTIO_NET_OK. + +Yet the problem is that, vhost_vdpa_net_load_mq() returns 1 based on +`*s->status != VIRTIO_NET_OK` when the device's ack is VIRTIO_NET_ERR. +As a result, net->nc->info->load() also returns 1, this makes +vhost_net_start_one() incorrectly assume the device state is +successfully loaded by vhost_vdpa_net_load() and return 0, instead of +goto `fail` label to cancel the device startup, as vhost_net_start_one() +only cancels the device startup when net->nc->info->load() returns a +negative value. + +This patch fixes this problem by returning -EIO when the device's +ack is not VIRTIO_NET_OK. + +Fixes: f64c7cda69 ("vdpa: Add vhost_vdpa_net_load_mq") +Signed-off-by: Hawkins Jiawei +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 9af9f6554e..8192045735 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -553,8 +553,11 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, + if (unlikely(dev_written < 0)) { + return dev_written; + } ++ if (*s->status != VIRTIO_NET_OK) { ++ return -EIO; ++ } + +- return *s->status != VIRTIO_NET_OK; ++ return 0; + } + + static int vhost_vdpa_net_load(NetClientState *nc) +-- +2.27.0 + diff --git a/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch new file mode 100644 index 0000000000000000000000000000000000000000..f457ca3a3a411bf462e12b49f7b521cea965c5e8 --- /dev/null +++ b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch @@ -0,0 +1,62 @@ +From 1c9d6dde6fabf6c1f6a4aeb388921a83279d3071 Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 4 Jul 2023 11:34:33 +0800 +Subject: [PATCH] vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in + _load_mac() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to VirtIO standard, "The class, command and +command-specific-data are set by the driver, +and the device sets the ack byte. +There is little it can do except issue a diagnostic +if ack is not VIRTIO_NET_OK." + +Therefore, QEMU should stop sending the queued SVQ commands and +cancel the device startup if the device's ack is not VIRTIO_NET_OK. + +Yet the problem is that, vhost_vdpa_net_load_mac() returns 1 based on +`*s->status != VIRTIO_NET_OK` when the device's ack is VIRTIO_NET_ERR. +As a result, net->nc->info->load() also returns 1, this makes +vhost_net_start_one() incorrectly assume the device state is +successfully loaded by vhost_vdpa_net_load() and return 0, instead of +goto `fail` label to cancel the device startup, as vhost_net_start_one() +only cancels the device startup when net->nc->info->load() returns a +negative value. + +This patch fixes this problem by returning -EIO when the device's +ack is not VIRTIO_NET_OK. + +Fixes: f73c0c43ac ("vdpa: extract vhost_vdpa_net_load_mac from vhost_vdpa_net_load") +Signed-off-by: Hawkins Jiawei +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index afca8740bc..9af9f6554e 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -527,8 +527,9 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) + if (unlikely(dev_written < 0)) { + return dev_written; + } +- +- return *s->status != VIRTIO_NET_OK; ++ if (*s->status != VIRTIO_NET_OK) { ++ return -EIO; ++ } + } + + return 0; +-- +2.27.0 + diff --git a/vdpa-Skip-the-maps-not-in-the-iova-tree.patch b/vdpa-Skip-the-maps-not-in-the-iova-tree.patch new file mode 100644 index 0000000000000000000000000000000000000000..17e13206247600b5c252e7284abe205c2c831029 --- /dev/null +++ b/vdpa-Skip-the-maps-not-in-the-iova-tree.patch @@ -0,0 +1,39 @@ +From a498bc3ae687778dad2f8161ff17532432df0c1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:02 +0200 +Subject: [PATCH] vdpa: Skip the maps not in the iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Next patch will skip the registering of dma maps that the vdpa device +rejects in the iova tree. We need to consider that here or we cause a +SIGSEGV accessing result. + +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d0cf7a0745..c551665f5d 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -291,6 +291,10 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + }; + + result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); ++ if (!result) { ++ /* The memory listener map wasn't mapped */ ++ return; ++ } + iova = result->iova; + vhost_iova_tree_remove(v->iova_tree, result); + } +-- +2.27.0 + diff --git a/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch b/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch new file mode 100644 index 0000000000000000000000000000000000000000..606084cd679eae428b7b3f8e53e96d4c678aa7dd --- /dev/null +++ b/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch @@ -0,0 +1,70 @@ +From 1c3e4f7326031d0b689821f655a4352bb746a405 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:08 +0200 +Subject: [PATCH] vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reduce code duplication. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 31c1b71498..d7bdc0f37c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -886,10 +886,12 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, +- const DMAMap *needle) ++static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr) + { +- const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); ++ const DMAMap needle = { ++ .translated_addr = addr, ++ }; ++ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, &needle); + hwaddr size; + int r; + +@@ -911,17 +913,14 @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { +- DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; + + vhost_svq_get_vring_addr(svq, &svq_addr); + +- needle.translated_addr = svq_addr.desc_user_addr; +- vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr); + +- needle.translated_addr = svq_addr.used_user_addr; +- vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr); + } + + /** +@@ -999,7 +998,7 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, + ok = vhost_vdpa_svq_map_ring(v, &device_region, errp); + if (unlikely(!ok)) { + error_prepend(errp, "Cannot create vq device region: "); +- vhost_vdpa_svq_unmap_ring(v, &driver_region); ++ vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr); + } + addr->used_user_addr = device_region.iova; + +-- +2.27.0 + diff --git a/vdpa-adapt-vhost_ops-callbacks-to-svq.patch b/vdpa-adapt-vhost_ops-callbacks-to-svq.patch new file mode 100644 index 0000000000000000000000000000000000000000..914e13a7d9873dfb686646c7355ba4d5fd74ce54 --- /dev/null +++ b/vdpa-adapt-vhost_ops-callbacks-to-svq.patch @@ -0,0 +1,104 @@ +From 1ae2ad1afcb032dc933104da5ad922173961caf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:46 +0100 +Subject: [PATCH] vdpa: adapt vhost_ops callbacks to svq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +First half of the buffers forwarding part, preparing vhost-vdpa +callbacks to SVQ to offer it. QEMU cannot enable it at this moment, so +this is effectively dead code at the moment, but it helps to reduce +patch size. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 48 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 7 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8ee63933a8..2f0e6a9bef 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -735,6 +735,13 @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, + return ret; + } + ++static int vhost_vdpa_set_dev_vring_base(struct vhost_dev *dev, ++ struct vhost_vring_state *ring) ++{ ++ trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); ++} ++ + static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +@@ -749,6 +756,18 @@ static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev, + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } + ++static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev, ++ struct vhost_vring_addr *addr) ++{ ++ trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags, ++ addr->desc_user_addr, addr->used_user_addr, ++ addr->avail_user_addr, ++ addr->log_guest_addr); ++ ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); ++ ++} ++ + /** + * Set the shadow virtqueue descriptors to the device + * +@@ -858,11 +877,17 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) + { +- trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags, +- addr->desc_user_addr, addr->used_user_addr, +- addr->avail_user_addr, +- addr->log_guest_addr); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ /* ++ * Device vring addr was set at device start. SVQ base is handled by ++ * VirtQueue code. ++ */ ++ return 0; ++ } ++ ++ return vhost_vdpa_set_vring_dev_addr(dev, addr); + } + + static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, +@@ -875,8 +900,17 @@ static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { +- trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ /* ++ * Device vring base was set at device start. SVQ base is handled by ++ * VirtQueue code. ++ */ ++ return 0; ++ } ++ ++ return vhost_vdpa_set_dev_vring_base(dev, ring); + } + + static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, +-- +2.27.0 + diff --git a/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch b/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch new file mode 100644 index 0000000000000000000000000000000000000000..0e6774f32e49419894ac807c6207003873990fd3 --- /dev/null +++ b/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch @@ -0,0 +1,227 @@ +From 657f5e7b200bec7b124ca5e2cf4d8e1b721cbfde Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:41 +0100 +Subject: [PATCH] vdpa: add asid parameter to vhost_vdpa_dma_map/unmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So the caller can choose which ASID is destined. + +No need to update the batch functions as they will always be called from +memory listener updates at the moment. Memory listener updates will +always update ASID 0, as it's the passthrough ASID. + +All vhost devices's ASID are 0 at this moment. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-10-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 4 +-- + hw/virtio/vhost-vdpa.c | 36 ++++++++++++++------ + include/hw/virtio/vhost-vdpa.h | 14 ++++++-- + include/standard-headers/linux/vhost_types.h | 2 +- + net/vhost-vdpa.c | 6 ++-- + 5 files changed, 42 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 35d4c00e59..edbbbeb621 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -29,8 +29,8 @@ vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + + # vhost-vdpa.c +-vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 +-vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 ++vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 ++vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 + vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 450b5effd2..f4a0878e34 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -74,22 +74,28 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, + return false; + } + +-int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly) ++/* ++ * The caller must set asid = 0 if the device does not support asid. ++ * This is not an ABI break since it is set to 0 by the initializer anyway. ++ */ ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size, void *vaddr, bool readonly) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; ++ msg.asid = asid; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.uaddr = (uint64_t)(uintptr_t)vaddr; + msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW; + msg.iotlb.type = VHOST_IOTLB_UPDATE; + +- trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.iotlb.iova, msg.iotlb.size, +- msg.iotlb.uaddr, msg.iotlb.perm, msg.iotlb.type); ++ trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.asid, msg.iotlb.iova, ++ msg.iotlb.size, msg.iotlb.uaddr, msg.iotlb.perm, ++ msg.iotlb.type); + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", +@@ -100,18 +106,24 @@ int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, + return ret; + } + +-int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size) ++/* ++ * The caller must set asid = 0 if the device does not support asid. ++ * This is not an ABI break since it is set to 0 by the initializer anyway. ++ */ ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; ++ msg.asid = asid; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.type = VHOST_IOTLB_INVALIDATE; + +- trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.iotlb.iova, ++ trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.asid, msg.iotlb.iova, + msg.iotlb.size, msg.iotlb.type); + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { +@@ -231,8 +243,8 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + } + + vhost_vdpa_iotlb_batch_begin_once(v); +- ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), +- vaddr, section->readonly); ++ ret = vhost_vdpa_dma_map(v, VHOST_VDPA_GUEST_PA_ASID, iova, ++ int128_get64(llsize), vaddr, section->readonly); + if (ret) { + error_report("vhost vdpa map fail!"); + goto fail_map; +@@ -305,7 +317,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + vhost_iova_tree_remove(v->iova_tree, *result); + } + vhost_vdpa_iotlb_batch_begin_once(v); +- ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); ++ ret = vhost_vdpa_dma_unmap(v, VHOST_VDPA_GUEST_PA_ASID, iova, ++ int128_get64(llsize)); + if (ret) { + error_report("vhost_vdpa dma unmap error!"); + } +@@ -872,7 +885,7 @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr) + } + + size = ROUND_UP(result->size, qemu_real_host_page_size); +- r = vhost_vdpa_dma_unmap(v, result->iova, size); ++ r = vhost_vdpa_dma_unmap(v, v->address_space_id, result->iova, size); + if (unlikely(r < 0)) { + error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); + return; +@@ -912,7 +925,8 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, + return false; + } + +- r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1, ++ r = vhost_vdpa_dma_map(v, v->address_space_id, needle->iova, ++ needle->size + 1, + (void *)(uintptr_t)needle->translated_addr, + needle->perm == IOMMU_RO); + if (unlikely(r != 0)) { +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 1111d85643..e57dfa1fd1 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -19,6 +19,12 @@ + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + ++/* ++ * ASID dedicated to map guest's addresses. If SVQ is disabled it maps GPA to ++ * qemu's IOVA. If SVQ is enabled it maps also the SVQ vring here ++ */ ++#define VHOST_VDPA_GUEST_PA_ASID 0 ++ + typedef struct VhostVDPAHostNotifier { + MemoryRegion mr; + void *addr; +@@ -29,6 +35,7 @@ typedef struct vhost_vdpa { + int index; + uint32_t msg_type; + bool iotlb_batch_begin_sent; ++ uint32_t address_space_id; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; + uint64_t acked_features; +@@ -42,8 +49,9 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + +-int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly); +-int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size); ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size, void *vaddr, bool readonly); ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size); + + #endif +diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h +index 0bd2684a2a..fa267e39d4 100644 +--- a/include/standard-headers/linux/vhost_types.h ++++ b/include/standard-headers/linux/vhost_types.h +@@ -87,7 +87,7 @@ struct vhost_msg { + + struct vhost_msg_v2 { + uint32_t type; +- uint32_t reserved; ++ uint32_t asid; + union { + struct vhost_iotlb_msg iotlb; + uint8_t padding[64]; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index e250d34462..cb1cc2523d 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -266,7 +266,7 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + return; + } + +- r = vhost_vdpa_dma_unmap(v, map->iova, map->size + 1); ++ r = vhost_vdpa_dma_unmap(v, v->address_space_id, map->iova, map->size + 1); + if (unlikely(r != 0)) { + error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); + } +@@ -306,8 +306,8 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, + return r; + } + +- r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, +- !write); ++ r = vhost_vdpa_dma_map(v, v->address_space_id, map.iova, ++ vhost_vdpa_net_cvq_cmd_page_len(), buf, !write); + if (unlikely(r < 0)) { + goto dma_map_err; + } +-- +2.27.0 + diff --git a/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch b/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch new file mode 100644 index 0000000000000000000000000000000000000000..f06ea91d973931a3b5bc516453816c51f0664c73 --- /dev/null +++ b/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch @@ -0,0 +1,53 @@ +From a5717856457e72575a32dfc8e28ec6ba6dcf6d59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:32 +0200 +Subject: [PATCH] vdpa: add net_vhost_vdpa_cvq_info NetClientInfo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Next patches will add a new info callback to restore NIC status through +CVQ. Since only the CVQ vhost device is needed, create it with a new +NetClientInfo. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 8cfd086639..04cb08d418 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -342,6 +342,16 @@ static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, + return true; + } + ++static NetClientInfo net_vhost_vdpa_cvq_info = { ++ .type = NET_CLIENT_DRIVER_VHOST_VDPA, ++ .size = sizeof(VhostVDPAState), ++ .receive = vhost_vdpa_receive, ++ .cleanup = vhost_vdpa_cleanup, ++ .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, ++ .has_ufo = vhost_vdpa_has_ufo, ++ .check_peer_type = vhost_vdpa_check_peer_type, ++}; ++ + /** + * Do not forward commands not supported by SVQ. Otherwise, the device could + * accept it and qemu would not know how to update the device model. +@@ -483,7 +493,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, + name); + } else { +- nc = qemu_new_net_control_client(&net_vhost_vdpa_info, peer, ++ nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer, + device, name); + } + snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); +-- +2.27.0 + diff --git a/vdpa-add-shadow_data-to-vhost_vdpa.patch b/vdpa-add-shadow_data-to-vhost_vdpa.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c457064f957298fb9263cd62cba4875d0019df4 --- /dev/null +++ b/vdpa-add-shadow_data-to-vhost_vdpa.patch @@ -0,0 +1,86 @@ +From e64b1a8253b9161e16b0a7f6c3beb77fb854660d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:43 +0100 +Subject: [PATCH] vdpa: add shadow_data to vhost_vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The memory listener that thells the device how to convert GPA to qemu's +va is registered against CVQ vhost_vdpa. memory listener translations +are always ASID 0, CVQ ones are ASID 1 if supported. + +Let's tell the listener if it needs to register them on iova tree or +not. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-12-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 6 +++--- + include/hw/virtio/vhost-vdpa.h | 2 ++ + net/vhost-vdpa.c | 1 + + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f4a0878e34..6d0d85b733 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -226,7 +226,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + + llsize = int128_sub(llend, int128_make64(iova)); +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + int r; + + mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr, +@@ -253,7 +253,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + return; + + fail_map: +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + vhost_iova_tree_remove(v->iova_tree, mem_region); + } + +@@ -298,7 +298,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + const DMAMap *result; + const void *vaddr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index e57dfa1fd1..45b969a311 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -40,6 +40,8 @@ typedef struct vhost_vdpa { + struct vhost_vdpa_iova_range iova_range; + uint64_t acked_features; + bool shadow_vqs_enabled; ++ /* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */ ++ bool shadow_data; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 7adba2c2b6..21fb89bb6b 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -580,6 +580,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->always_svq = svq; + s->vhost_vdpa.shadow_vqs_enabled = svq; + s->vhost_vdpa.iova_range = iova_range; ++ s->vhost_vdpa.shadow_data = svq; + s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, +-- +2.27.0 + diff --git a/vdpa-add-vdpa-dev-pci-support.patch b/vdpa-add-vdpa-dev-pci-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..90eaa55d68fbfa7a63581cd09c2925c68c7ded92 --- /dev/null +++ b/vdpa-add-vdpa-dev-pci-support.patch @@ -0,0 +1,141 @@ +From e422f956fa13298c25ac645d9d822d3ca92f8e31 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 12 Nov 2022 22:40:11 +0800 +Subject: [PATCH 4/7] vdpa: add vdpa-dev-pci support + +Supports vdpa-dev-pci, we can use the device as follow: + +-device vhost-vdpa-device-pci,vhostdev=/dev/vhost-vdpa-X + +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Signed-off-by: Longpeng +--- + hw/virtio/meson.build | 1 + + hw/virtio/vdpa-dev-pci.c | 102 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 103 insertions(+) + create mode 100644 hw/virtio/vdpa-dev-pci.c + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index 289e955478..8e8943e20b 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -50,6 +50,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-serial-pc + virtio_pci_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem-pci.c')) + virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu-pci.c')) + virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) ++virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c')) + + virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) + +diff --git a/hw/virtio/vdpa-dev-pci.c b/hw/virtio/vdpa-dev-pci.c +new file mode 100644 +index 0000000000..5446e6b393 +--- /dev/null ++++ b/hw/virtio/vdpa-dev-pci.c +@@ -0,0 +1,102 @@ ++/* ++ * Vhost Vdpa Device PCI Bindings ++ * ++ * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. ++ * ++ * Authors: ++ * Longpeng ++ * ++ * Largely based on the "vhost-user-blk-pci.c" and "vhost-user-blk.c" ++ * implemented by: ++ * Changpeng Liu ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++#include "qemu/osdep.h" ++#include ++#include ++#include "hw/virtio/virtio.h" ++#include "hw/virtio/vdpa-dev.h" ++#include "hw/pci/pci.h" ++#include "hw/qdev-properties.h" ++#include "qapi/error.h" ++#include "qemu/error-report.h" ++#include "qemu/module.h" ++#include "hw/virtio/virtio-pci.h" ++#include "qom/object.h" ++ ++ ++typedef struct VhostVdpaDevicePCI VhostVdpaDevicePCI; ++ ++#define TYPE_VHOST_VDPA_DEVICE_PCI "vhost-vdpa-device-pci-base" ++DECLARE_INSTANCE_CHECKER(VhostVdpaDevicePCI, VHOST_VDPA_DEVICE_PCI, ++ TYPE_VHOST_VDPA_DEVICE_PCI) ++ ++struct VhostVdpaDevicePCI { ++ VirtIOPCIProxy parent_obj; ++ VhostVdpaDevice vdev; ++}; ++ ++static void vhost_vdpa_device_pci_instance_init(Object *obj) ++{ ++ VhostVdpaDevicePCI *dev = VHOST_VDPA_DEVICE_PCI(obj); ++ ++ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), ++ TYPE_VHOST_VDPA_DEVICE); ++ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), ++ "bootindex"); ++} ++ ++static Property vhost_vdpa_device_pci_properties[] = { ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static int vhost_vdpa_device_pci_post_init(VhostVdpaDevice *v, Error **errp) ++{ ++ VhostVdpaDevicePCI *dev = container_of(v, VhostVdpaDevicePCI, vdev); ++ VirtIOPCIProxy *vpci_dev = &dev->parent_obj; ++ ++ vpci_dev->class_code = virtio_pci_get_class_id(v->vdev_id); ++ vpci_dev->trans_devid = virtio_pci_get_trans_devid(v->vdev_id); ++ /* one for config vector */ ++ vpci_dev->nvectors = v->num_queues + 1; ++ ++ return 0; ++} ++ ++static void ++vhost_vdpa_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) ++{ ++ VhostVdpaDevicePCI *dev = VHOST_VDPA_DEVICE_PCI(vpci_dev); ++ ++ dev->vdev.post_init = vhost_vdpa_device_pci_post_init; ++ qdev_realize(DEVICE(&dev->vdev), BUS(&vpci_dev->bus), errp); ++} ++ ++static void vhost_vdpa_device_pci_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); ++ ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ device_class_set_props(dc, vhost_vdpa_device_pci_properties); ++ k->realize = vhost_vdpa_device_pci_realize; ++} ++ ++static const VirtioPCIDeviceTypeInfo vhost_vdpa_device_pci_info = { ++ .base_name = TYPE_VHOST_VDPA_DEVICE_PCI, ++ .generic_name = "vhost-vdpa-device-pci", ++ .transitional_name = "vhost-vdpa-device-pci-transitional", ++ .non_transitional_name = "vhost-vdpa-device-pci-non-transitional", ++ .instance_size = sizeof(VhostVdpaDevicePCI), ++ .instance_init = vhost_vdpa_device_pci_instance_init, ++ .class_init = vhost_vdpa_device_pci_class_init, ++}; ++ ++static void vhost_vdpa_device_pci_register(void) ++{ ++ virtio_pci_types_register(&vhost_vdpa_device_pci_info); ++} ++ ++type_init(vhost_vdpa_device_pci_register); +-- +2.27.0 + diff --git a/vdpa-add-vdpa-dev-support.patch b/vdpa-add-vdpa-dev-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..b42b54b7db8df2a1d0275c5061d97ac2606dff1b --- /dev/null +++ b/vdpa-add-vdpa-dev-support.patch @@ -0,0 +1,481 @@ +From 813ab05c3e508a702457236abd40e8256312a499 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 12 Nov 2022 22:40:10 +0800 +Subject: [PATCH 3/7] vdpa: add vdpa-dev support + +Supports vdpa-dev, we can use the deivce directly: + +-M microvm -m 512m -smp 2 -kernel ... -initrd ... -device \ +vhost-vdpa-device,vhostdev=/dev/vhost-vdpa-x + +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Signed-off-by: Longpeng +--- + hw/virtio/Kconfig | 5 + + hw/virtio/meson.build | 1 + + hw/virtio/vdpa-dev.c | 376 +++++++++++++++++++++++++++++++++++ + include/hw/virtio/vdpa-dev.h | 43 ++++ + 4 files changed, 425 insertions(+) + create mode 100644 hw/virtio/vdpa-dev.c + create mode 100644 include/hw/virtio/vdpa-dev.h + +diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig +index c144d42f9b..724eb58a32 100644 +--- a/hw/virtio/Kconfig ++++ b/hw/virtio/Kconfig +@@ -68,3 +68,8 @@ config VHOST_USER_RNG + bool + default y + depends on VIRTIO && VHOST_USER ++ ++config VHOST_VDPA_DEV ++ bool ++ default y ++ depends on VIRTIO && VHOST_VDPA && LINUX +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index 521f7d64a8..289e955478 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -29,6 +29,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) + virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) + virtio_ss.add(when: ['CONFIG_VHOST_USER_RNG', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-rng-pci.c')) ++virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) + + virtio_pci_ss = ss.source_set() + virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +new file mode 100644 +index 0000000000..42ab74c255 +--- /dev/null ++++ b/hw/virtio/vdpa-dev.c +@@ -0,0 +1,376 @@ ++/* ++ * Vhost Vdpa Device ++ * ++ * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. ++ * ++ * Authors: ++ * Longpeng ++ * ++ * Largely based on the "vhost-user-blk-pci.c" and "vhost-user-blk.c" ++ * implemented by: ++ * Changpeng Liu ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++#include "qemu/osdep.h" ++#include ++#include ++#include "qapi/error.h" ++#include "qemu/error-report.h" ++#include "qemu/cutils.h" ++#include "hw/qdev-core.h" ++#include "hw/qdev-properties.h" ++#include "hw/qdev-properties-system.h" ++#include "hw/virtio/vhost.h" ++#include "hw/virtio/virtio.h" ++#include "hw/virtio/virtio-bus.h" ++#include "hw/virtio/virtio-access.h" ++#include "hw/virtio/vdpa-dev.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/runstate.h" ++ ++static void ++vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) ++{ ++ /* Nothing to do */ ++} ++ ++static uint32_t ++vhost_vdpa_device_get_u32(int fd, unsigned long int cmd, Error **errp) ++{ ++ uint32_t val = (uint32_t)-1; ++ ++ if (ioctl(fd, cmd, &val) < 0) { ++ error_setg(errp, "vhost-vdpa-device: cmd 0x%lx failed: %s", ++ cmd, strerror(errno)); ++ } ++ ++ return val; ++} ++ ++static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) ++{ ++ VirtIODevice *vdev = VIRTIO_DEVICE(dev); ++ VhostVdpaDevice *v = VHOST_VDPA_DEVICE(vdev); ++ uint16_t max_queue_size; ++ struct vhost_virtqueue *vqs; ++ int i, ret; ++ ++ if (!v->vhostdev) { ++ error_setg(errp, "vhost-vdpa-device: vhostdev are missing"); ++ return; ++ } ++ ++ v->vhostfd = qemu_open(v->vhostdev, O_RDWR, errp); ++ if (*errp) { ++ return; ++ } ++ v->vdpa.device_fd = v->vhostfd; ++ ++ v->vdev_id = vhost_vdpa_device_get_u32(v->vhostfd, ++ VHOST_VDPA_GET_DEVICE_ID, errp); ++ if (*errp) { ++ goto out; ++ } ++ ++ max_queue_size = vhost_vdpa_device_get_u32(v->vhostfd, ++ VHOST_VDPA_GET_VRING_NUM, errp); ++ if (*errp) { ++ goto out; ++ } ++ ++ if (v->queue_size > max_queue_size) { ++ error_setg(errp, "vhost-vdpa-device: invalid queue_size: %u (max:%u)", ++ v->queue_size, max_queue_size); ++ goto out; ++ } else if (!v->queue_size) { ++ v->queue_size = max_queue_size; ++ } ++ ++ v->num_queues = vhost_vdpa_device_get_u32(v->vhostfd, ++ VHOST_VDPA_GET_VQS_COUNT, errp); ++ if (*errp) { ++ goto out; ++ } ++ ++ if (!v->num_queues || v->num_queues > VIRTIO_QUEUE_MAX) { ++ error_setg(errp, "invalid number of virtqueues: %u (max:%u)", ++ v->num_queues, VIRTIO_QUEUE_MAX); ++ goto out; ++ } ++ ++ v->dev.nvqs = v->num_queues; ++ vqs = g_new0(struct vhost_virtqueue, v->dev.nvqs); ++ v->dev.vqs = vqs; ++ v->dev.vq_index = 0; ++ v->dev.vq_index_end = v->dev.nvqs; ++ v->dev.backend_features = 0; ++ v->started = false; ++ ++ ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL); ++ if (ret < 0) { ++ error_setg(errp, "vhost-vdpa-device: vhost initialization failed: %s", ++ strerror(-ret)); ++ goto free_vqs; ++ } ++ ++ v->config_size = vhost_vdpa_device_get_u32(v->vhostfd, ++ VHOST_VDPA_GET_CONFIG_SIZE, ++ errp); ++ if (*errp) { ++ goto vhost_cleanup; ++ } ++ ++ /* ++ * Invoke .post_init() to initialize the transport-specific fields ++ * before calling virtio_init(). ++ */ ++ if (v->post_init && v->post_init(v, errp) < 0) { ++ goto vhost_cleanup; ++ } ++ ++ v->config = g_malloc0(v->config_size); ++ ++ ret = vhost_dev_get_config(&v->dev, v->config, v->config_size, NULL); ++ if (ret < 0) { ++ error_setg(errp, "vhost-vdpa-device: get config failed"); ++ goto free_config; ++ } ++ ++ virtio_init(vdev, "vhost-vdpa", v->vdev_id, v->config_size); ++ ++ v->virtqs = g_new0(VirtQueue *, v->dev.nvqs); ++ for (i = 0; i < v->dev.nvqs; i++) { ++ v->virtqs[i] = virtio_add_queue(vdev, v->queue_size, ++ vhost_vdpa_device_dummy_handle_output); ++ } ++ ++ return; ++ ++free_config: ++ g_free(v->config); ++vhost_cleanup: ++ vhost_dev_cleanup(&v->dev); ++free_vqs: ++ g_free(vqs); ++out: ++ qemu_close(v->vhostfd); ++ v->vhostfd = -1; ++} ++ ++static void vhost_vdpa_device_unrealize(DeviceState *dev) ++{ ++ VirtIODevice *vdev = VIRTIO_DEVICE(dev); ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ int i; ++ ++ virtio_set_status(vdev, 0); ++ ++ for (i = 0; i < s->num_queues; i++) { ++ virtio_delete_queue(s->virtqs[i]); ++ } ++ g_free(s->virtqs); ++ virtio_cleanup(vdev); ++ ++ g_free(s->config); ++ g_free(s->dev.vqs); ++ vhost_dev_cleanup(&s->dev); ++ qemu_close(s->vhostfd); ++ s->vhostfd = -1; ++} ++ ++static void ++vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ ++ memcpy(config, s->config, s->config_size); ++} ++ ++static void ++vhost_vdpa_device_set_config(VirtIODevice *vdev, const uint8_t *config) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ int ret; ++ ++ ret = vhost_dev_set_config(&s->dev, s->config, 0, s->config_size, ++ VHOST_SET_CONFIG_TYPE_MASTER); ++ if (ret) { ++ error_report("set device config space failed"); ++ return; ++ } ++} ++ ++static uint64_t vhost_vdpa_device_get_features(VirtIODevice *vdev, ++ uint64_t features, ++ Error **errp) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ uint64_t backend_features = s->dev.features; ++ ++ if (!virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM)) { ++ virtio_clear_feature(&backend_features, VIRTIO_F_IOMMU_PLATFORM); ++ } ++ ++ return backend_features; ++} ++ ++static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); ++ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); ++ int i, ret; ++ ++ if (!k->set_guest_notifiers) { ++ error_setg(errp, "binding does not support guest notifiers"); ++ return -ENOSYS; ++ } ++ ++ ret = vhost_dev_enable_notifiers(&s->dev, vdev); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Error enabling host notifiers"); ++ return ret; ++ } ++ ++ ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Error binding guest notifier"); ++ goto err_host_notifiers; ++ } ++ ++ s->dev.acked_features = vdev->guest_features; ++ ++ ret = vhost_dev_start(&s->dev, vdev); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Error starting vhost"); ++ goto err_guest_notifiers; ++ } ++ s->started = true; ++ ++ /* ++ * guest_notifier_mask/pending not used yet, so just unmask ++ * everything here. virtio-pci will do the right thing by ++ * enabling/disabling irqfd. ++ */ ++ for (i = 0; i < s->dev.nvqs; i++) { ++ vhost_virtqueue_mask(&s->dev, vdev, i, false); ++ } ++ ++ return ret; ++ ++err_guest_notifiers: ++ k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); ++err_host_notifiers: ++ vhost_dev_disable_notifiers(&s->dev, vdev); ++ return ret; ++} ++ ++static void vhost_vdpa_device_stop(VirtIODevice *vdev) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); ++ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); ++ int ret; ++ ++ if (!s->started) { ++ return; ++ } ++ s->started = false; ++ ++ if (!k->set_guest_notifiers) { ++ return; ++ } ++ ++ vhost_dev_stop(&s->dev, vdev); ++ ++ ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); ++ if (ret < 0) { ++ error_report("vhost guest notifier cleanup failed: %d", ret); ++ return; ++ } ++ ++ vhost_dev_disable_notifiers(&s->dev, vdev); ++} ++ ++static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ bool should_start = virtio_device_started(vdev, status); ++ Error *local_err = NULL; ++ int ret; ++ ++ if (!vdev->vm_running) { ++ should_start = false; ++ } ++ ++ if (s->started == should_start) { ++ return; ++ } ++ ++ if (should_start) { ++ ret = vhost_vdpa_device_start(vdev, &local_err); ++ if (ret < 0) { ++ error_reportf_err(local_err, "vhost-vdpa-device: start failed: "); ++ } ++ } else { ++ vhost_vdpa_device_stop(vdev); ++ } ++} ++ ++static Property vhost_vdpa_device_properties[] = { ++ DEFINE_PROP_STRING("vhostdev", VhostVdpaDevice, vhostdev), ++ DEFINE_PROP_UINT16("queue-size", VhostVdpaDevice, queue_size, 0), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static const VMStateDescription vmstate_vhost_vdpa_device = { ++ .name = "vhost-vdpa-device", ++ .minimum_version_id = 1, ++ .version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_VIRTIO_DEVICE, ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ ++static void vhost_vdpa_device_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); ++ ++ device_class_set_props(dc, vhost_vdpa_device_properties); ++ dc->desc = "VDPA-based generic device assignment"; ++ dc->vmsd = &vmstate_vhost_vdpa_device; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ vdc->realize = vhost_vdpa_device_realize; ++ vdc->unrealize = vhost_vdpa_device_unrealize; ++ vdc->get_config = vhost_vdpa_device_get_config; ++ vdc->set_config = vhost_vdpa_device_set_config; ++ vdc->get_features = vhost_vdpa_device_get_features; ++ vdc->set_status = vhost_vdpa_device_set_status; ++} ++ ++static void vhost_vdpa_device_instance_init(Object *obj) ++{ ++ VhostVdpaDevice *s = VHOST_VDPA_DEVICE(obj); ++ ++ device_add_bootindex_property(obj, &s->bootindex, "bootindex", ++ NULL, DEVICE(obj)); ++} ++ ++static const TypeInfo vhost_vdpa_device_info = { ++ .name = TYPE_VHOST_VDPA_DEVICE, ++ .parent = TYPE_VIRTIO_DEVICE, ++ .instance_size = sizeof(VhostVdpaDevice), ++ .class_init = vhost_vdpa_device_class_init, ++ .instance_init = vhost_vdpa_device_instance_init, ++}; ++ ++static void register_vhost_vdpa_device_type(void) ++{ ++ type_register_static(&vhost_vdpa_device_info); ++} ++ ++type_init(register_vhost_vdpa_device_type); +diff --git a/include/hw/virtio/vdpa-dev.h b/include/hw/virtio/vdpa-dev.h +new file mode 100644 +index 0000000000..4dbf98195c +--- /dev/null ++++ b/include/hw/virtio/vdpa-dev.h +@@ -0,0 +1,43 @@ ++/* ++ * Vhost Vdpa Device ++ * ++ * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. ++ * ++ * Authors: ++ * Longpeng ++ * ++ * Largely based on the "vhost-user-blk.h" implemented by: ++ * Changpeng Liu ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++#ifndef _VHOST_VDPA_DEVICE_H ++#define _VHOST_VDPA_DEVICE_H ++ ++#include "hw/virtio/vhost.h" ++#include "hw/virtio/vhost-vdpa.h" ++#include "qom/object.h" ++ ++ ++#define TYPE_VHOST_VDPA_DEVICE "vhost-vdpa-device" ++OBJECT_DECLARE_SIMPLE_TYPE(VhostVdpaDevice, VHOST_VDPA_DEVICE) ++ ++struct VhostVdpaDevice { ++ VirtIODevice parent_obj; ++ char *vhostdev; ++ int vhostfd; ++ int32_t bootindex; ++ uint32_t vdev_id; ++ uint32_t num_queues; ++ struct vhost_dev dev; ++ struct vhost_vdpa vdpa; ++ VirtQueue **virtqs; ++ uint8_t *config; ++ int config_size; ++ uint16_t queue_size; ++ bool started; ++ int (*post_init)(VhostVdpaDevice *v, Error **errp); ++}; ++ ++#endif +-- +2.27.0 + diff --git a/vdpa-add-vhost_vdpa_net_valid_svq_features.patch b/vdpa-add-vhost_vdpa_net_valid_svq_features.patch new file mode 100644 index 0000000000000000000000000000000000000000..622c8901c9170db52a54d57d8702d5a8ed6e5b21 --- /dev/null +++ b/vdpa-add-vhost_vdpa_net_valid_svq_features.patch @@ -0,0 +1,68 @@ +From 9cd4a76f615cea230ffc33d5b3666f84216f694b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:37 +0100 +Subject: [PATCH] vdpa: add vhost_vdpa_net_valid_svq_features +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It will be reused at vdpa device start so let's extract in its own +function. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-6-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index eae2ed364f..217d2545c1 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -105,6 +105,22 @@ VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + return s->vhost_net; + } + ++static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) ++{ ++ uint64_t invalid_dev_features = ++ features & ~vdpa_svq_device_features & ++ /* Transport are all accepted at this point */ ++ ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, ++ VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); ++ ++ if (invalid_dev_features) { ++ error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, ++ invalid_dev_features); ++ } ++ ++ return !invalid_dev_features; ++} ++ + static int vhost_vdpa_net_check_device_id(struct vhost_net *net) + { + uint32_t device_id; +@@ -683,15 +699,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (opts->x_svq) { + struct vhost_vdpa_iova_range iova_range; + +- uint64_t invalid_dev_features = +- features & ~vdpa_svq_device_features & +- /* Transport are all accepted at this point */ +- ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, +- VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); +- +- if (invalid_dev_features) { +- error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, +- invalid_dev_features); ++ if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; + } + +-- +2.27.0 + diff --git a/vdpa-allocate-SVQ-array-unconditionally.patch b/vdpa-allocate-SVQ-array-unconditionally.patch new file mode 100644 index 0000000000000000000000000000000000000000..9e8cc601130872604eb9420172d0a1e9ec0f8660 --- /dev/null +++ b/vdpa-allocate-SVQ-array-unconditionally.patch @@ -0,0 +1,42 @@ +From fea179d880cd502f291cc6079b565bc059612d48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:40 +0100 +Subject: [PATCH] vdpa: allocate SVQ array unconditionally +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SVQ may run or not in a device depending on runtime conditions (for +example, if the device can move CVQ to its own group or not). + +Allocate the SVQ array unconditionally at startup, since its hard to +move this allocation elsewhere. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-9-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 59bfdbfc24..450b5effd2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -535,10 +535,6 @@ static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) + struct vhost_vdpa *v = dev->opaque; + size_t idx; + +- if (!v->shadow_vqs) { +- return; +- } +- + for (idx = 0; idx < v->shadow_vqs->len; ++idx) { + vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx)); + } +-- +2.27.0 + diff --git a/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch b/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch new file mode 100644 index 0000000000000000000000000000000000000000..32a59b8166f98a3176663addb05e80e51ee696bf --- /dev/null +++ b/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch @@ -0,0 +1,224 @@ +From e2e9aeaacdb28b6c2a1bfcfef09113dc9b26a420 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:44 +0100 +Subject: [PATCH] vdpa: always start CVQ in SVQ mode if possible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Isolate control virtqueue in its own group, allowing to intercept control +commands but letting dataplane run totally passthrough to the guest. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221215113144.322011-13-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 +- + include/standard-headers/linux/vhost_types.h | 5 + + linux-headers/linux/vhost.h | 14 +++ + net/vhost-vdpa.c | 110 ++++++++++++++++++- + 4 files changed, 130 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 6d0d85b733..8b44f5a7b8 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -641,7 +641,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + { + uint64_t features; + uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | +- 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH; ++ 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | ++ 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID; + int r; + + if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { +diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h +index fa267e39d4..17833e320e 100644 +--- a/include/standard-headers/linux/vhost_types.h ++++ b/include/standard-headers/linux/vhost_types.h +@@ -153,4 +153,9 @@ struct vhost_vdpa_iova_range { + /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ + #define VHOST_NET_F_VIRTIO_NET_HDR 27 + ++/* IOTLB can accept address space identifier through V2 type of IOTLB ++ * message ++ */ ++#define VHOST_BACKEND_F_IOTLB_ASID 0x3 ++ + #endif +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index 5d99e7c242..b6ded7f831 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -157,4 +157,18 @@ + /* Get the count of all virtqueues */ + #define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + ++/* Get the group for a virtqueue: read index, write group in num, ++ * The virtqueue index is stored in the index field of ++ * vhost_vring_state. The group for this specific virtqueue is ++ * returned via num field of vhost_vring_state. ++ */ ++#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ ++ struct vhost_vring_state) ++/* Set the ASID for a virtqueue group. The group index is stored in ++ * the index field of vhost_vring_state, the ASID associated with this ++ * group is stored at num field of vhost_vring_state. ++ */ ++#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ ++ struct vhost_vring_state) ++ + #endif +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 21fb89bb6b..24c4c2ef51 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -100,6 +100,8 @@ static const uint64_t vdpa_svq_device_features = + BIT_ULL(VIRTIO_NET_F_RSC_EXT) | + BIT_ULL(VIRTIO_NET_F_STANDBY); + ++#define VHOST_VDPA_NET_CVQ_ASID 1 ++ + VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -250,6 +252,40 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) ++{ ++ struct vhost_vring_state state = { ++ .index = vq_index, ++ }; ++ int r = ioctl(device_fd, VHOST_VDPA_GET_VRING_GROUP, &state); ++ ++ if (unlikely(r < 0)) { ++ error_report("Cannot get VQ %u group: %s", vq_index, ++ g_strerror(errno)); ++ return r; ++ } ++ ++ return state.num; ++} ++ ++static int vhost_vdpa_set_address_space_id(struct vhost_vdpa *v, ++ unsigned vq_group, ++ unsigned asid_num) ++{ ++ struct vhost_vring_state asid = { ++ .index = vq_group, ++ .num = asid_num, ++ }; ++ int r; ++ ++ r = ioctl(v->device_fd, VHOST_VDPA_SET_GROUP_ASID, &asid); ++ if (unlikely(r < 0)) { ++ error_report("Can't set vq group %u asid %u, errno=%d (%s)", ++ asid.index, asid.num, errno, g_strerror(errno)); ++ } ++ return r; ++} ++ + static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + { + VhostIOVATree *tree = v->iova_tree; +@@ -324,11 +360,75 @@ dma_map_err: + static int vhost_vdpa_net_cvq_start(NetClientState *nc) + { + VhostVDPAState *s; +- int r; ++ struct vhost_vdpa *v; ++ uint64_t backend_features; ++ int64_t cvq_group; ++ int cvq_index, r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + s = DO_UPCAST(VhostVDPAState, nc, nc); ++ v = &s->vhost_vdpa; ++ ++ v->shadow_data = s->always_svq; ++ v->shadow_vqs_enabled = s->always_svq; ++ s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID; ++ ++ if (s->always_svq) { ++ /* SVQ is already configured for all virtqueues */ ++ goto out; ++ } ++ ++ /* ++ * If we early return in these cases SVQ will not be enabled. The migration ++ * will be blocked as long as vhost-vdpa backends will not offer _F_LOG. ++ * ++ * Calling VHOST_GET_BACKEND_FEATURES as they are not available in v->dev ++ * yet. ++ */ ++ r = ioctl(v->device_fd, VHOST_GET_BACKEND_FEATURES, &backend_features); ++ if (unlikely(r < 0)) { ++ error_report("Cannot get vdpa backend_features: %s(%d)", ++ g_strerror(errno), errno); ++ return -1; ++ } ++ if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || ++ !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { ++ return 0; ++ } ++ ++ /* ++ * Check if all the virtqueues of the virtio device are in a different vq ++ * than the last vq. VQ group of last group passed in cvq_group. ++ */ ++ cvq_index = v->dev->vq_index_end - 1; ++ cvq_group = vhost_vdpa_get_vring_group(v->device_fd, cvq_index); ++ if (unlikely(cvq_group < 0)) { ++ return cvq_group; ++ } ++ for (int i = 0; i < cvq_index; ++i) { ++ int64_t group = vhost_vdpa_get_vring_group(v->device_fd, i); ++ ++ if (unlikely(group < 0)) { ++ return group; ++ } ++ ++ if (group == cvq_group) { ++ return 0; ++ } ++ } ++ ++ r = vhost_vdpa_set_address_space_id(v, cvq_group, VHOST_VDPA_NET_CVQ_ASID); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ v->iova_tree = vhost_iova_tree_new(v->iova_range.first, ++ v->iova_range.last); ++ v->shadow_vqs_enabled = true; ++ s->vhost_vdpa.address_space_id = VHOST_VDPA_NET_CVQ_ASID; ++ ++out: + if (!s->vhost_vdpa.shadow_vqs_enabled) { + return 0; + } +@@ -357,6 +457,14 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + if (s->vhost_vdpa.shadow_vqs_enabled) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status); ++ if (!s->always_svq) { ++ /* ++ * If only the CVQ is shadowed we can delete this safely. ++ * If all the VQs are shadows this will be needed by the time the ++ * device is started again to register SVQ vrings and similar. ++ */ ++ g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); ++ } + } + } + +-- +2.27.0 + diff --git a/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch b/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c805b2df967ac61e8a1994a3bce99ca34666688 --- /dev/null +++ b/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch @@ -0,0 +1,79 @@ +From aa9c65215f37fc54a280ce89a2cbfd6235e8ec9f Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Tue, 27 Dec 2022 15:20:15 +0800 +Subject: [PATCH] vdpa: commit all host notifier MRs in a single MR transaction +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows the vhost-vdpa device to batch the setup of all its MRs of +host notifiers. + +This significantly reduces the device starting time, e.g. the time spend +on setup the host notifier MRs reduce from 423ms to 32ms for a VM with +64 vCPUs and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device). + +Signed-off-by: Longpeng +Message-Id: <20221227072015.3134-4-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f93fac538c..2fd7af1c6b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -522,9 +522,18 @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) + { + int i; + ++ /* ++ * Pack all the changes to the memory regions in a single ++ * transaction to avoid a few updating of the address space ++ * topology. ++ */ ++ memory_region_transaction_begin(); ++ + for (i = dev->vq_index; i < dev->vq_index + n; i++) { + vhost_vdpa_host_notifier_uninit(dev, i); + } ++ ++ memory_region_transaction_commit(); + } + + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) +@@ -537,17 +546,21 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + return; + } + ++ /* ++ * Pack all the changes to the memory regions in a single ++ * transaction to avoid a few updating of the address space ++ * topology. ++ */ ++ memory_region_transaction_begin(); ++ + for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) { + if (vhost_vdpa_host_notifier_init(dev, i)) { +- goto err; ++ vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); ++ break; + } + } + +- return; +- +-err: +- vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); +- return; ++ memory_region_transaction_commit(); + } + + static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) +-- +2.27.0 + diff --git a/vdpa-correct-param-passed-in-when-unregister-save.patch b/vdpa-correct-param-passed-in-when-unregister-save.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b7ce2772e56b6a60dbe7847936397351efed879 --- /dev/null +++ b/vdpa-correct-param-passed-in-when-unregister-save.patch @@ -0,0 +1,30 @@ +From 9f0b9d2d71b9fa21789981d68335ee417e18b025 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 14 Dec 2023 11:22:54 +0800 +Subject: [PATCH] vdpa: correct param passed in when unregister save + +The idstr passed in the unregister_savevm function is inconsisten +with the idstr passed in when register_savevm_live registration. +Needs to be modified, otherwise migration will fail after hotunplug +all vdpa devices. + +Signed-off-by: jiangdongxu +--- + hw/virtio/vdpa-dev-mig.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index ee3e27f2bb..c71e71fd64 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -400,6 +400,6 @@ void vdpa_migration_register(VhostVdpaDevice *vdev) + void vdpa_migration_unregister(VhostVdpaDevice *vdev) + { + remove_migration_state_change_notifier(&vdev->migration_state); +- unregister_savevm(VMSTATE_IF(&vdev->parent_obj.parent_obj), "vdpa", DEVICE(vdev)); ++ unregister_savevm(NULL, "vdpa", DEVICE(vdev)); + qemu_del_vm_change_state_handler(vdev->vmstate); + } +-- +2.27.0 + diff --git a/vdpa-dev-get-iova-range-explicitly.patch b/vdpa-dev-get-iova-range-explicitly.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9f8e1a8b67616c0e51a96ad9f09728d518487dc --- /dev/null +++ b/vdpa-dev-get-iova-range-explicitly.patch @@ -0,0 +1,104 @@ +From f5d338d28758db5066f199c35d56e0953edcc5d9 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 24 Dec 2022 19:48:47 +0800 +Subject: [PATCH] vdpa-dev: get iova range explicitly + +In commit a585fad26b ("vdpa: request iova_range only once") we remove +GET_IOVA_RANGE form vhost_vdpa_init, the generic vdpa device will start +without iova_range populated, so the device won't work. Let's call +GET_IOVA_RANGE ioctl explicitly. + +Fixes: a585fad26b2e6ccc ("vdpa: request iova_range only once") +Signed-off-by: Longpeng +Message-Id: <20221224114848.3062-2-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev.c | 9 +++++++++ + hw/virtio/vhost-vdpa.c | 7 +++++++ + include/hw/virtio/vhost-vdpa.h | 2 ++ + net/vhost-vdpa.c | 8 -------- + 4 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 465b08c0e3..254a213117 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -53,6 +53,7 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VhostVdpaDevice *v = VHOST_VDPA_DEVICE(vdev); ++ struct vhost_vdpa_iova_range iova_range; + uint16_t max_queue_size; + struct vhost_virtqueue *vqs; + int i, ret; +@@ -108,6 +109,14 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + v->dev.backend_features = 0; + v->started = false; + ++ ret = vhost_vdpa_get_iova_range(v->vhostfd, &iova_range); ++ if (ret < 0) { ++ error_setg(errp, "vhost-vdpa-device: get iova range failed: %s", ++ strerror(-ret)); ++ goto free_vqs; ++ } ++ v->vdpa.iova_range = iova_range; ++ + ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL); + if (ret < 0) { + error_setg(errp, "vhost-vdpa-device: vhost initialization failed: %s", +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c9289e2c01..f93fac538c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -380,6 +380,13 @@ static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + return 0; + } + ++int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range) ++{ ++ int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); ++ ++ return ret < 0 ? -errno : 0; ++} ++ + /* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 45b969a311..7997f09a8d 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -51,6 +51,8 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + ++int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range); ++ + int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size, void *vaddr, bool readonly); + int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 3dcf341722..3c370f2dc5 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -717,14 +717,6 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + +-static int vhost_vdpa_get_iova_range(int fd, +- struct vhost_vdpa_iova_range *iova_range) +-{ +- int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); +- +- return ret < 0 ? -errno : 0; +-} +- + static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) + { + int ret = ioctl(fd, VHOST_GET_FEATURES, features); +-- +2.27.0 + diff --git a/vdpa-dev-mark-the-device-as-unmigratable.patch b/vdpa-dev-mark-the-device-as-unmigratable.patch new file mode 100644 index 0000000000000000000000000000000000000000..77a90515207c87acd67abc9e1861fb05a85e0bf5 --- /dev/null +++ b/vdpa-dev-mark-the-device-as-unmigratable.patch @@ -0,0 +1,30 @@ +From 90615553b0062b0c971cd1ce5b90aad4a9ea9b6a Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 12 Nov 2022 22:40:12 +0800 +Subject: [PATCH 5/7] vdpa-dev: mark the device as unmigratable + +The generic vDPA device doesn't support migration currently, so +mark it as unmigratable temporarily. + +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Signed-off-by: Longpeng +--- + hw/virtio/vdpa-dev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 42ab74c255..1840f0e450 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -327,6 +327,7 @@ static Property vhost_vdpa_device_properties[] = { + + static const VMStateDescription vmstate_vhost_vdpa_device = { + .name = "vhost-vdpa-device", ++ .unmigratable = 1, + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { +-- +2.27.0 + diff --git a/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch b/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch new file mode 100644 index 0000000000000000000000000000000000000000..4956a0fd552ff9d71ac31bf96faa0cef548182db --- /dev/null +++ b/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch @@ -0,0 +1,52 @@ +From 5bd89df7b5c1448f22f37a918569d0367458591b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 2 Jun 2023 16:38:52 +0200 +Subject: [PATCH] vdpa: do not block migration if device has cvq and x-svq=on +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was a mistake to forbid in all cases, as SVQ is already able to send +all the CVQ messages before start forwarding data vqs. It actually +caused a regression, making impossible to migrate device previously +migratable. + +Fixes: 36e4647247f2 ("vdpa: add vhost_vdpa_net_valid_svq_features") +Signed-off-by: Eugenio Pérez +Message-Id: <20230602143854.1879091-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index dc1b4c4be2..cdc54a7b54 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -723,13 +723,16 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.shadow_vq_ops_opaque = s; + + /* +- * TODO: We cannot migrate devices with CVQ as there is no way to set +- * the device state (MAC, MQ, etc) before starting the datapath. ++ * TODO: We cannot migrate devices with CVQ and no x-svq enabled as ++ * there is no way to set the device state (MAC, MQ, etc) before ++ * starting the datapath. + * + * Migration blocker ownership now belongs to s->vhost_vdpa. + */ +- error_setg(&s->vhost_vdpa.migration_blocker, +- "net vdpa cannot migrate with CVQ feature"); ++ if (!svq) { ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "net vdpa cannot migrate with CVQ feature"); ++ } + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch b/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fcc058025697677234cdc705e4a27ec0458c3c9 --- /dev/null +++ b/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch @@ -0,0 +1,35 @@ +From 17cd7f504c47c532eae6b8ecfc21b0e5796e08da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 21 Dec 2022 12:50:15 +0100 +Subject: [PATCH] vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So qemu emulates it even in case the device does not support it. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221221115015.1400889-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 48dd9d15f6..3dcf341722 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -72,7 +72,6 @@ const int vdpa_feature_bits[] = { + VIRTIO_F_RING_PACKED, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_HASH_REPORT, +- VIRTIO_NET_F_GUEST_ANNOUNCE, + VIRTIO_NET_F_STATUS, + VHOST_INVALID_FEATURE_BIT + }; +-- +2.27.0 + diff --git a/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch b/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch new file mode 100644 index 0000000000000000000000000000000000000000..e1b024471b53edc53e102e6e70226a336cb35e3b --- /dev/null +++ b/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch @@ -0,0 +1,74 @@ +From 556aa09e618b0fb40f038b11eafc69750c71f26e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:03 +0200 +Subject: [PATCH] vdpa: do not save failed dma maps in SVQ iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a map fails for whatever reason, it must not be saved in the tree. +Otherwise, qemu will try to unmap it in cleanup, leaving to more errors. + +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c551665f5d..02dab41c42 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -178,6 +178,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) + static void vhost_vdpa_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) + { ++ DMAMap mem_region = {}; + struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); + hwaddr iova; + Int128 llend, llsize; +@@ -214,13 +215,13 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + if (v->shadow_vqs_enabled) { +- DMAMap mem_region = { +- .translated_addr = (hwaddr)(uintptr_t)vaddr, +- .size = int128_get64(llsize) - 1, +- .perm = IOMMU_ACCESS_FLAG(true, section->readonly), +- }; ++ int r; + +- int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); ++ mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr, ++ mem_region.size = int128_get64(llsize) - 1, ++ mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly), ++ ++ r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); + if (unlikely(r != IOVA_OK)) { + error_report("Can't allocate a mapping (%d)", r); + goto fail; +@@ -234,11 +235,16 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + if (ret) { + error_report("vhost vdpa map fail!"); +- goto fail; ++ goto fail_map; + } + + return; + ++fail_map: ++ if (v->shadow_vqs_enabled) { ++ vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ } ++ + fail: + /* + * On the initfn path, store the first error in the container so we +-- +2.27.0 + diff --git a/vdpa-don-t-suspend-resume-device-when-vdpa-device-no.patch b/vdpa-don-t-suspend-resume-device-when-vdpa-device-no.patch new file mode 100644 index 0000000000000000000000000000000000000000..77e69328c28d92a81b9d25a3ab5e12724d717918 --- /dev/null +++ b/vdpa-don-t-suspend-resume-device-when-vdpa-device-no.patch @@ -0,0 +1,67 @@ +From daab4fa364c508d793ed28a920d50cd76efe7633 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Tue, 19 Dec 2023 20:32:00 +0800 +Subject: [PATCH] vdpa: don't suspend/resume device when vdpa device not + started + +When vdpa device not started, we don't need to suspend vdpa device +and send vdpa device state information. Therefore, add the suspended +flag of vdpa device to distinguish whether the device is suspended and +use it to determine whether the device needs to resume in dest qemu. + +Signed-off-by: jiangdongxu +--- + hw/virtio/vdpa-dev-mig.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index 4a45821892..9cd80f92eb 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -296,10 +296,13 @@ static int vdpa_save_complete_precopy(QEMUFile *f, void *opaque) + int ret; + + qemu_put_be64(f, VDPA_MIG_FLAG_DEV_CONFIG_STATE); +- ret = vhost_vdpa_dev_buffer_save(hdev, f); +- if (ret) { +- error_report("Save vdpa device buffer failed: %d\n", ret); +- return ret; ++ qemu_put_be16(f, (uint16_t)vdev->suspended); ++ if (vdev->suspended) { ++ ret = vhost_vdpa_dev_buffer_save(hdev, f); ++ if (ret) { ++ error_report("Save vdpa device buffer failed: %d\n", ret); ++ return ret; ++ } + } + qemu_put_be64(f, VDPA_MIG_FLAG_END_OF_STATE); + +@@ -313,6 +316,7 @@ static int vdpa_load_state(QEMUFile *f, void *opaque, int version_id) + + int ret; + uint64_t data; ++ uint16_t suspended; + + data = qemu_get_be64(f); + while (data != VDPA_MIG_FLAG_END_OF_STATE) { +@@ -325,10 +329,13 @@ static int vdpa_load_state(QEMUFile *f, void *opaque, int version_id) + return -EINVAL; + } + } else if (data == VDPA_MIG_FLAG_DEV_CONFIG_STATE) { +- ret = vhost_vdpa_dev_buffer_load(hdev, f); +- if (ret) { +- error_report("fail to restore device buffer.\n"); +- return ret; ++ suspended = qemu_get_be16(f); ++ if (suspended) { ++ ret = vhost_vdpa_dev_buffer_load(hdev, f); ++ if (ret) { ++ error_report("fail to restore device buffer.\n"); ++ return ret; ++ } + } + } + +-- +2.27.0 + diff --git a/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch b/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b2d4b509b66144b3bb4bd30346cd255f68aa19b --- /dev/null +++ b/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch @@ -0,0 +1,144 @@ +From af761da9860bd79bd9d214c15d2d30010e73aafa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:34 +0200 +Subject: [PATCH] vdpa: extract vhost_vdpa_net_cvq_add from + vhost_vdpa_net_handle_ctrl_avail +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So we can reuse it to inject state messages. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +-- +v7: +* Remove double free error + +v6: +* Do not assume in buffer sent to the device is sizeof(virtio_net_ctrl_ack) + +v5: +* Do not use an artificial !NULL VirtQueueElement +* Use only out size instead of iovec dev_buffers for these functions. + +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 59 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 38 insertions(+), 21 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 882f5ee89c..b24e0919d0 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -339,6 +339,38 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + } + } + ++static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, ++ size_t in_len) ++{ ++ /* Buffers for the device */ ++ const struct iovec out = { ++ .iov_base = s->cvq_cmd_out_buffer, ++ .iov_len = out_len, ++ }; ++ const struct iovec in = { ++ .iov_base = s->cvq_cmd_in_buffer, ++ .iov_len = sizeof(virtio_net_ctrl_ack), ++ }; ++ VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); ++ int r; ++ ++ r = vhost_svq_add(svq, &out, 1, &in, 1, NULL); ++ if (unlikely(r != 0)) { ++ if (unlikely(r == -ENOSPC)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", ++ __func__); ++ } ++ return r; ++ } ++ ++ /* ++ * We can poll here since we've had BQL from the time we sent the ++ * descriptor. Also, we need to take the answer before SVQ pulls by itself, ++ * when BQL is released ++ */ ++ return vhost_svq_poll(svq); ++} ++ + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), +@@ -395,23 +427,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + void *opaque) + { + VhostVDPAState *s = opaque; +- size_t in_len, dev_written; ++ size_t in_len; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; + /* Out buffer sent to both the vdpa device and the device model */ + struct iovec out = { + .iov_base = s->cvq_cmd_out_buffer, + }; +- /* In buffer sent to the device */ +- const struct iovec dev_in = { +- .iov_base = s->cvq_cmd_in_buffer, +- .iov_len = sizeof(virtio_net_ctrl_ack), +- }; + /* in buffer used for device model */ + const struct iovec in = { + .iov_base = &status, + .iov_len = sizeof(status), + }; +- int r = -EINVAL; ++ ssize_t dev_written = -EINVAL; + bool ok; + + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, +@@ -422,21 +449,11 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem); +- if (unlikely(r != 0)) { +- if (unlikely(r == -ENOSPC)) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +- __func__); +- } ++ dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); ++ if (unlikely(dev_written < 0)) { + goto out; + } + +- /* +- * We can poll here since we've had BQL from the time we sent the +- * descriptor. Also, we need to take the answer before SVQ pulls by itself, +- * when BQL is released +- */ +- dev_written = vhost_svq_poll(svq); + if (unlikely(dev_written < sizeof(status))) { + error_report("Insufficient written data (%zu)", dev_written); + goto out; +@@ -444,7 +461,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + + memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); + if (status != VIRTIO_NET_OK) { +- goto out; ++ return VIRTIO_NET_ERR; + } + + status = VIRTIO_NET_ERR; +@@ -461,7 +478,7 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); +- return r; ++ return dev_written < 0 ? dev_written : 0; + } + + static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { +-- +2.27.0 + diff --git a/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch b/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch new file mode 100644 index 0000000000000000000000000000000000000000..8695f98bfd06e9a19e14f0db38cb9d56fc58fc23 --- /dev/null +++ b/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch @@ -0,0 +1,106 @@ +From 2038b0811acd3255d315354c8468bc565a51a4af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:15 +0200 +Subject: [PATCH] vdpa: extract vhost_vdpa_net_load_mac from + vhost_vdpa_net_load +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since there may be many commands we need to issue to load the NIC +state, let's split them in individual functions + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 62 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 40 insertions(+), 22 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 2700ef656f..15cd38b52e 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -373,12 +373,47 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + return vhost_svq_poll(svq); + } + ++static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, ++ uint8_t cmd, const void *data, ++ size_t data_size) ++{ ++ const struct virtio_net_ctrl_hdr ctrl = { ++ .class = class, ++ .cmd = cmd, ++ }; ++ ++ assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); ++ ++ memcpy(s->cvq_cmd_out_buffer, &ctrl, sizeof(ctrl)); ++ memcpy(s->cvq_cmd_out_buffer + sizeof(ctrl), data, data_size); ++ ++ return vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + data_size, ++ sizeof(virtio_net_ctrl_ack)); ++} ++ ++static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) ++{ ++ uint64_t features = n->parent_obj.guest_features; ++ if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { ++ ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MAC, ++ VIRTIO_NET_CTRL_MAC_ADDR_SET, ++ n->mac, sizeof(n->mac)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *s->status != VIRTIO_NET_OK; ++ } ++ ++ return 0; ++} ++ + static int vhost_vdpa_net_load(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +- const struct vhost_vdpa *v = &s->vhost_vdpa; ++ struct vhost_vdpa *v = &s->vhost_vdpa; + const VirtIONet *n; +- uint64_t features; ++ int r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + +@@ -387,26 +422,9 @@ static int vhost_vdpa_net_load(NetClientState *nc) + } + + n = VIRTIO_NET(v->dev->vdev); +- features = n->parent_obj.guest_features; +- if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { +- const struct virtio_net_ctrl_hdr ctrl = { +- .class = VIRTIO_NET_CTRL_MAC, +- .cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET, +- }; +- char *cursor = s->cvq_cmd_out_buffer; +- ssize_t dev_written; +- +- memcpy(cursor, &ctrl, sizeof(ctrl)); +- cursor += sizeof(ctrl); +- memcpy(cursor, n->mac, sizeof(n->mac)); +- +- dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac), +- sizeof(virtio_net_ctrl_ack)); +- if (unlikely(dev_written < 0)) { +- return dev_written; +- } +- +- return *s->status != VIRTIO_NET_OK; ++ r = vhost_vdpa_net_load_mac(s, n); ++ if (unlikely(r < 0)) { ++ return r; + } + + return 0; +-- +2.27.0 + diff --git a/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch b/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2f2a8796d3214a54ecd7d62c069487126c11597 --- /dev/null +++ b/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch @@ -0,0 +1,38 @@ +From 404c9b2cb537a42be18a1b1aaf32df662ed951e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 17 Jan 2023 11:53:08 +0100 +Subject: [PATCH] vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VHOST_BACKEND_F_IOTLB_ASID is the feature bit, not the bitmask. Since +the device under test also provided VHOST_BACKEND_F_IOTLB_MSG_V2 and +VHOST_BACKEND_F_IOTLB_BATCH, this went unnoticed. + +Fixes: c1a1008685 ("vdpa: always start CVQ in SVQ mode if possible") +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index cdc54a7b54..a1b931ae2c 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -391,7 +391,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) + g_strerror(errno), errno); + return -1; + } +- if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || ++ if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) || + !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { + return 0; + } +-- +2.27.0 + diff --git a/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch b/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..4603f6ed097c552433e845a09309a55a65fe42ec --- /dev/null +++ b/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch @@ -0,0 +1,39 @@ +From 5da8eddfa24d42a3ef60e111becafa29549e7100 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 2 Jun 2023 19:34:51 +0200 +Subject: [PATCH] vdpa: fix not using CVQ buffer in case of error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bug introducing when refactoring. Otherway, the guest never received +the used buffer. + +Fixes: be4278b65fc1 ("vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail") +Signed-off-by: Eugenio Pérez +Message-Id: <20230602173451.1917999-1-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 94f74b54ae..afca8740bc 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -642,7 +642,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + } + + if (*s->status != VIRTIO_NET_OK) { +- return VIRTIO_NET_ERR; ++ goto out; + } + + status = VIRTIO_NET_ERR; +-- +2.27.0 + diff --git a/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch b/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch new file mode 100644 index 0000000000000000000000000000000000000000..7501a15d363d78f1eacb42a53db53fcf2554fab5 --- /dev/null +++ b/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch @@ -0,0 +1,51 @@ +From f6fa1b81efa3ac728a2c528b3c694d8cb5f932f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 21 Dec 2022 12:50:14 +0100 +Subject: [PATCH] vdpa: handle VIRTIO_NET_CTRL_ANNOUNCE in + vhost_vdpa_net_handle_ctrl_avail +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since this capability is emulated by qemu shadowed CVQ cannot forward it +to the device. Process all that command within qemu. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221221115015.1400889-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 24c4c2ef51..48dd9d15f6 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -623,9 +623,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); +- dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); +- if (unlikely(dev_written < 0)) { +- goto out; ++ if (*(uint8_t *)s->cvq_cmd_out_buffer == VIRTIO_NET_CTRL_ANNOUNCE) { ++ /* ++ * Guest announce capability is emulated by qemu, so don't forward to ++ * the device. ++ */ ++ dev_written = sizeof(status); ++ *s->status = VIRTIO_NET_OK; ++ } else { ++ dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); ++ if (unlikely(dev_written < 0)) { ++ goto out; ++ } + } + + if (unlikely(dev_written < sizeof(status))) { +-- +2.27.0 + diff --git a/vdpa-harden-the-error-path-if-get_iova_range-failed.patch b/vdpa-harden-the-error-path-if-get_iova_range-failed.patch new file mode 100644 index 0000000000000000000000000000000000000000..af79c277aebf3b147d85262bdfabd1c5115ca790 --- /dev/null +++ b/vdpa-harden-the-error-path-if-get_iova_range-failed.patch @@ -0,0 +1,39 @@ +From fe4dd977b4dec6a089992566bda4b29136ed62c9 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 24 Dec 2022 19:48:48 +0800 +Subject: [PATCH] vdpa: harden the error path if get_iova_range failed + +We should stop if the GET_IOVA_RANGE ioctl failed. + +Signed-off-by: Longpeng +Message-Id: <20221224114848.3062-3-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 3c370f2dc5..fd5dc8c6aa 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -812,7 +812,13 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + +- vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ r = vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ if (unlikely(r < 0)) { ++ error_setg(errp, "vhost-vdpa: get iova range failed: %s", ++ strerror(-r)); ++ goto err; ++ } ++ + if (opts->x_svq) { + if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; +-- +2.27.0 + diff --git a/vdpa-implement-vdpa-device-migration.patch b/vdpa-implement-vdpa-device-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffc1d79586d2f3d9d24b6b1fea57c12de8b04182 --- /dev/null +++ b/vdpa-implement-vdpa-device-migration.patch @@ -0,0 +1,77 @@ +From 722147da4fb76c0ee6e75957712073a820ab1d75 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:59:56 +0800 +Subject: [PATCH] vdpa: implement vdpa device migration + +Integrate the live migration code, call the registered live +migration function, and open the vdpa live migration prototype + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 254a213117..986b5d0a78 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -29,6 +29,8 @@ + #include "hw/virtio/vdpa-dev.h" + #include "sysemu/sysemu.h" + #include "sysemu/runstate.h" ++#include "hw/virtio/vdpa-dev-mig.h" ++#include "migration/migration.h" + + static void + vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) +@@ -155,6 +157,8 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + vhost_vdpa_device_dummy_handle_output); + } + ++ vdpa_migration_register(v); ++ + return; + + free_config: +@@ -174,6 +178,7 @@ static void vhost_vdpa_device_unrealize(DeviceState *dev) + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + int i; + ++ vdpa_migration_unregister(s); + virtio_set_status(vdev, 0); + + for (i = 0; i < s->num_queues; i++) { +@@ -306,6 +311,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev) + static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) + { + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); ++ MigrationState *ms = migrate_get_current(); + bool should_start = virtio_device_started(vdev, status); + Error *local_err = NULL; + int ret; +@@ -318,6 +324,11 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) + return; + } + ++ if (ms->state == RUN_STATE_PAUSED || ++ ms->state == RUN_STATE_RESTORE_VM) { ++ return; ++ } ++ + if (should_start) { + ret = vhost_vdpa_device_start(vdev, &local_err); + if (ret < 0) { +@@ -336,7 +347,7 @@ static Property vhost_vdpa_device_properties[] = { + + static const VMStateDescription vmstate_vhost_vdpa_device = { + .name = "vhost-vdpa-device", +- .unmigratable = 1, ++ .unmigratable = 0, + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { +-- +2.27.0 + diff --git a/vdpa-manual-forward-CVQ-buffers.patch b/vdpa-manual-forward-CVQ-buffers.patch new file mode 100644 index 0000000000000000000000000000000000000000..79e47ce9b3cd5b83abc3c77f70950f870d3a3ddc --- /dev/null +++ b/vdpa-manual-forward-CVQ-buffers.patch @@ -0,0 +1,146 @@ +From 1fd9319e66153dc18bc4a6adfd81f1a0bc6d3a2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:42 +0200 +Subject: [PATCH] vdpa: manual forward CVQ buffers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do a simple forwarding of CVQ buffers, the same work SVQ could do but +through callbacks. No functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 +- + include/hw/virtio/vhost-vdpa.h | 3 ++ + net/vhost-vdpa.c | 57 ++++++++++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8e962f511d..31b58aec59 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -421,7 +421,8 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + for (unsigned n = 0; n < hdev->nvqs; ++n) { + g_autoptr(VhostShadowVirtqueue) svq; + +- svq = vhost_svq_new(v->iova_tree, NULL, NULL); ++ svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, ++ v->shadow_vq_ops_opaque); + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); + return -1; +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 7214eb47dc..1111d85643 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -15,6 +15,7 @@ + #include + + #include "hw/virtio/vhost-iova-tree.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -35,6 +36,8 @@ typedef struct vhost_vdpa { + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; ++ const VhostShadowVirtqueueOps *shadow_vq_ops; ++ void *shadow_vq_ops_opaque; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 7201c79116..53a14bc756 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -11,11 +11,13 @@ + + #include "qemu/osdep.h" + #include "clients.h" ++#include "hw/virtio/virtio-net.h" + #include "net/vhost_net.h" + #include "net/vhost-vdpa.h" + #include "hw/virtio/vhost-vdpa.h" + #include "qemu/config-file.h" + #include "qemu/error-report.h" ++#include "qemu/log.h" + #include "qemu/option.h" + #include "qapi/error.h" + #include +@@ -195,6 +197,57 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++/** ++ * Forward buffer for the moment. ++ */ ++static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, ++ void *opaque) ++{ ++ unsigned int n = elem->out_num + elem->in_num; ++ g_autofree struct iovec *dev_buffers = g_new(struct iovec, n); ++ size_t in_len, dev_written; ++ virtio_net_ctrl_ack status = VIRTIO_NET_ERR; ++ int r; ++ ++ memcpy(dev_buffers, elem->out_sg, elem->out_num); ++ memcpy(dev_buffers + elem->out_num, elem->in_sg, elem->in_num); ++ ++ r = vhost_svq_add(svq, &dev_buffers[0], elem->out_num, &dev_buffers[1], ++ elem->in_num, elem); ++ if (unlikely(r != 0)) { ++ if (unlikely(r == -ENOSPC)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", ++ __func__); ++ } ++ goto out; ++ } ++ ++ /* ++ * We can poll here since we've had BQL from the time we sent the ++ * descriptor. Also, we need to take the answer before SVQ pulls by itself, ++ * when BQL is released ++ */ ++ dev_written = vhost_svq_poll(svq); ++ if (unlikely(dev_written < sizeof(status))) { ++ error_report("Insufficient written data (%zu)", dev_written); ++ } ++ ++out: ++ in_len = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, ++ sizeof(status)); ++ if (unlikely(in_len < sizeof(status))) { ++ error_report("Bad device CVQ written length"); ++ } ++ vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); ++ g_free(elem); ++ return r; ++} ++ ++static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { ++ .avail_handler = vhost_vdpa_net_handle_ctrl_avail, ++}; ++ + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + const char *device, + const char *name, +@@ -219,6 +272,10 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ if (!is_datapath) { ++ s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; ++ s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { + qemu_del_net_client(nc); +-- +2.27.0 + diff --git a/vdpa-move-SVQ-vring-features-check-to-net.patch b/vdpa-move-SVQ-vring-features-check-to-net.patch new file mode 100644 index 0000000000000000000000000000000000000000..f5eca1afa7f9ec5fe6ea2b6897075cf713895c83 --- /dev/null +++ b/vdpa-move-SVQ-vring-features-check-to-net.patch @@ -0,0 +1,110 @@ +From 1d56b9b5446b79613ed1668a1afea19a9a7df875 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:39 +0100 +Subject: [PATCH] vdpa: move SVQ vring features check to net/ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next patches will start control SVQ if possible. However, we don't +know if that will be possible at qemu boot anymore. + +Since the moved checks will be already evaluated at net/ to know if it +is ok to shadow CVQ, move them. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-8-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 32 ++------------------------------ + net/vhost-vdpa.c | 3 ++- + 2 files changed, 4 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c0e645ec13..59bfdbfc24 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -391,29 +391,9 @@ static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, + return ret; + } + +-static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, +- Error **errp) ++static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) + { + g_autoptr(GPtrArray) shadow_vqs = NULL; +- uint64_t dev_features, svq_features; +- int r; +- bool ok; +- +- if (!v->shadow_vqs_enabled) { +- return 0; +- } +- +- r = vhost_vdpa_get_dev_features(hdev, &dev_features); +- if (r != 0) { +- error_setg_errno(errp, -r, "Can't get vdpa device features"); +- return r; +- } +- +- svq_features = dev_features; +- ok = vhost_svq_valid_features(svq_features, errp); +- if (unlikely(!ok)) { +- return -1; +- } + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +@@ -425,7 +405,6 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + } + + v->shadow_vqs = g_steal_pointer(&shadow_vqs); +- return 0; + } + + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) +@@ -450,10 +429,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + dev->opaque = opaque ; + v->listener = vhost_vdpa_memory_listener; + v->msg_type = VHOST_IOTLB_MSG_V2; +- ret = vhost_vdpa_init_svq(dev, v, errp); +- if (ret) { +- goto err; +- } ++ vhost_vdpa_init_svq(dev, v); + + if (!vhost_vdpa_first_dev(dev)) { + return 0; +@@ -463,10 +439,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + VIRTIO_CONFIG_S_DRIVER); + + return 0; +- +-err: +- ram_block_discard_disable(false); +- return ret; + } + + static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index be056a2553..e250d34462 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -116,9 +116,10 @@ static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) + if (invalid_dev_features) { + error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, + invalid_dev_features); ++ return false; + } + +- return !invalid_dev_features; ++ return vhost_svq_valid_features(features, errp); + } + + static int vhost_vdpa_net_check_device_id(struct vhost_net *net) +-- +2.27.0 + diff --git a/vdpa-move-memory-listener-to-the-realize-stage.patch b/vdpa-move-memory-listener-to-the-realize-stage.patch new file mode 100644 index 0000000000000000000000000000000000000000..b762409f80c54c62452261f93903341edcbe8ff7 --- /dev/null +++ b/vdpa-move-memory-listener-to-the-realize-stage.patch @@ -0,0 +1,112 @@ +From 232ee383f3a2363bdc8f1bde873740375b5b92bb Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 16:01:16 +0800 +Subject: [PATCH] vdpa: move memory listener to the realize stage + +Move the memory listener registration of vdpa from the start stage +to the realize stage. Avoid that in the start phase, the memory +listener callback function has not yet been processed. + +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev.c | 4 ++++ + hw/virtio/vhost-vdpa.c | 8 -------- + 2 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 986b5d0a78..143dadc88d 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -31,6 +31,7 @@ + #include "sysemu/runstate.h" + #include "hw/virtio/vdpa-dev-mig.h" + #include "migration/migration.h" ++#include "exec/address-spaces.h" + + static void + vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) +@@ -126,6 +127,7 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + goto free_vqs; + } + ++ memory_listener_register(&v->vdpa.listener, &address_space_memory); + v->config_size = vhost_vdpa_device_get_u32(v->vhostfd, + VHOST_VDPA_GET_CONFIG_SIZE, + errp); +@@ -164,6 +166,7 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + free_config: + g_free(v->config); + vhost_cleanup: ++ memory_listener_unregister(&v->vdpa.listener); + vhost_dev_cleanup(&v->dev); + free_vqs: + g_free(vqs); +@@ -189,6 +192,7 @@ static void vhost_vdpa_device_unrealize(DeviceState *dev) + + g_free(s->config); + g_free(s->dev.vqs); ++ memory_listener_unregister(&s->vdpa.listener); + vhost_dev_cleanup(&s->dev); + qemu_close(s->vhostfd); + s->vhostfd = -1; +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 7688dc0eba..c7aaff7f20 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1100,7 +1100,6 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + { +- struct vhost_vdpa *v = dev->opaque; + bool ok; + trace_vhost_vdpa_dev_start(dev, started); + +@@ -1121,14 +1120,11 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + + if (started) { +- memory_listener_register(&v->listener, &address_space_memory); + return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + } else { + vhost_vdpa_reset_device(dev); + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); +- memory_listener_unregister(&v->listener); +- + return 0; + } + } +@@ -1320,7 +1316,6 @@ static unsigned int vhost_vdpa_get_used_memslots(void) + + static int vhost_vdpa_suspend_device(struct vhost_dev *dev) + { +- struct vhost_vdpa *v = dev->opaque; + int ret; + + vhost_vdpa_svqs_stop(dev); +@@ -1331,13 +1326,11 @@ static int vhost_vdpa_suspend_device(struct vhost_dev *dev) + } + + ret = vhost_vdpa_call(dev, VHOST_VDPA_SUSPEND, NULL); +- memory_listener_unregister(&v->listener); + return ret; + } + + static int vhost_vdpa_resume_device(struct vhost_dev *dev) + { +- struct vhost_vdpa *v = dev->opaque; + bool ok; + + vhost_vdpa_host_notifiers_init(dev); +@@ -1351,7 +1344,6 @@ static int vhost_vdpa_resume_device(struct vhost_dev *dev) + return 0; + } + +- memory_listener_register(&v->listener, &address_space_memory); + return vhost_vdpa_call(dev, VHOST_VDPA_RESUME, NULL); + } + +-- +2.27.0 + diff --git a/vdpa-net-block-migration-if-the-device-has-CVQ.patch b/vdpa-net-block-migration-if-the-device-has-CVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..a700f8d40ce368ca9620863ddc179cc23f25b6f8 --- /dev/null +++ b/vdpa-net-block-migration-if-the-device-has-CVQ.patch @@ -0,0 +1,70 @@ +From d97454d68f90b441d3fa19c496a7fe6916f50e31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 3 Mar 2023 18:24:41 +0100 +Subject: [PATCH] vdpa net: block migration if the device has CVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Devices with CVQ need to migrate state beyond vq state. Leaving this to +future series. + +Signed-off-by: Eugenio Pérez +Message-Id: <20230303172445.1089785-11-eperezma@redhat.com> +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 1 + + include/hw/virtio/vhost-vdpa.h | 1 + + net/vhost-vdpa.c | 9 +++++++++ + 3 files changed, 11 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f5d816f5ec..dd1ba8878c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -450,6 +450,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + v->msg_type = VHOST_IOTLB_MSG_V2; + vhost_vdpa_init_svq(dev, v); + ++ error_propagate(&dev->migration_blocker, v->migration_blocker); + if (!vhost_vdpa_first_dev(dev)) { + return 0; + } +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 7997f09a8d..620a0f70ab 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -48,6 +48,7 @@ typedef struct vhost_vdpa { + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; + struct vhost_dev *dev; ++ Error *migration_blocker; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 8192045735..dc1b4c4be2 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -721,6 +721,15 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ ++ /* ++ * TODO: We cannot migrate devices with CVQ as there is no way to set ++ * the device state (MAC, MQ, etc) before starting the datapath. ++ * ++ * Migration blocker ownership now belongs to s->vhost_vdpa. ++ */ ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "net vdpa cannot migrate with CVQ feature"); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-request-iova_range-only-once.patch b/vdpa-request-iova_range-only-once.patch new file mode 100644 index 0000000000000000000000000000000000000000..c9ce07a79a367e05fdf93ece448ef3f649c6a002 --- /dev/null +++ b/vdpa-request-iova_range-only-once.patch @@ -0,0 +1,137 @@ +From 5ff455d55b2d58a726d2557076e0f5401496de02 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:38 +0100 +Subject: [PATCH] vdpa: request iova_range only once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently iova range is requested once per queue pair in the case of +net. Reduce the number of ioctls asking it once at initialization and +reusing that value for each vhost_vdpa. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221215113144.322011-7-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 --------------- + net/vhost-vdpa.c | 27 ++++++++++++++------------- + 2 files changed, 14 insertions(+), 28 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 23e715b05c..c0e645ec13 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -367,19 +367,6 @@ static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + return 0; + } + +-static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) +-{ +- int ret = vhost_vdpa_call(v->dev, VHOST_VDPA_GET_IOVA_RANGE, +- &v->iova_range); +- if (ret != 0) { +- v->iova_range.first = 0; +- v->iova_range.last = UINT64_MAX; +- } +- +- trace_vhost_vdpa_get_iova_range(v->dev, v->iova_range.first, +- v->iova_range.last); +-} +- + /* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning +@@ -468,8 +455,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + goto err; + } + +- vhost_vdpa_get_iova_range(v); +- + if (!vhost_vdpa_first_dev(dev)) { + return 0; + } +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 217d2545c1..be056a2553 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -548,14 +548,15 @@ static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { + }; + + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, +- const char *device, +- const char *name, +- int vdpa_device_fd, +- int queue_pair_index, +- int nvqs, +- bool is_datapath, +- bool svq, +- VhostIOVATree *iova_tree) ++ const char *device, ++ const char *name, ++ int vdpa_device_fd, ++ int queue_pair_index, ++ int nvqs, ++ bool is_datapath, ++ bool svq, ++ struct vhost_vdpa_iova_range iova_range, ++ VhostIOVATree *iova_tree) + { + NetClientState *nc = NULL; + VhostVDPAState *s; +@@ -574,6 +575,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; + s->vhost_vdpa.shadow_vqs_enabled = svq; ++ s->vhost_vdpa.iova_range = iova_range; + s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, +@@ -653,6 +655,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; + g_autoptr(VhostIOVATree) iova_tree = NULL; ++ struct vhost_vdpa_iova_range iova_range; + NetClientState *nc; + int queue_pairs, r, i = 0, has_cvq = 0; + +@@ -696,14 +699,12 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + ++ vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); + if (opts->x_svq) { +- struct vhost_vdpa_iova_range iova_range; +- + if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; + } + +- vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); + iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last); + } + +@@ -712,7 +713,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + for (i = 0; i < queue_pairs; i++) { + ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, + vdpa_device_fd, i, 2, true, opts->x_svq, +- iova_tree); ++ iova_range, iova_tree); + if (!ncs[i]) + goto err; + } +@@ -720,7 +721,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (has_cvq) { + nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, + vdpa_device_fd, i, 1, false, +- opts->x_svq, iova_tree); ++ opts->x_svq, iova_range, iova_tree); + if (!nc) + goto err; + } +-- +2.27.0 + diff --git a/vdpa-set-vring-enable-only-if-the-vring-address-has-.patch b/vdpa-set-vring-enable-only-if-the-vring-address-has-.patch new file mode 100644 index 0000000000000000000000000000000000000000..f3bc7b5c071d57a7a6016280c73570cc2e1e73ab --- /dev/null +++ b/vdpa-set-vring-enable-only-if-the-vring-address-has-.patch @@ -0,0 +1,44 @@ +From 11c0e08a95c35adec07e3b40d1bd9452d7113236 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 14 Dec 2023 11:05:52 +0800 +Subject: [PATCH] vdpa: set vring enable only if the vring address has already + been set + +Currently, vhost-vdpa does not determine the status of each vring when +performing the enable operation on vring. When the vBIOS(EDK2) is running, +the driver will not enable all vrings. In this case, setting all vrings +to enable is isconsistent with the actual situation. + +Add logic when enabling vring, make a judement on the vring status. If the +vring address is not set, the vring will not enabled. + +Signed-off-by: jiangdongxu +--- + hw/virtio/vhost-vdpa.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c7aaff7f20..36ed0c9a99 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -714,8 +714,17 @@ static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) + static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) + { + int i; ++ int idx; ++ hwaddr addr; ++ + trace_vhost_vdpa_set_vring_ready(dev); + for (i = 0; i < dev->nvqs; ++i) { ++ idx = vhost_vdpa_get_vq_index(dev, dev->vq_index + i); ++ addr = virtio_queue_get_desc_addr(dev->vdev, idx); ++ if (addr == 0) { ++ continue; ++ } ++ + struct vhost_vring_state state = { + .index = dev->vq_index + i, + .num = 1, +-- +2.27.0 + diff --git a/vdpa-stop-all-svq-on-device-deletion.patch b/vdpa-stop-all-svq-on-device-deletion.patch new file mode 100644 index 0000000000000000000000000000000000000000..a6cb17e1ceb2b3c29d73c1ee89429e5f006cfa10 --- /dev/null +++ b/vdpa-stop-all-svq-on-device-deletion.patch @@ -0,0 +1,73 @@ +From 6b9c4a2607b88faf611da724ead81dc89a7b185b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 9 Feb 2023 18:00:04 +0100 +Subject: [PATCH] vdpa: stop all svq on device deletion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Not stopping them leave the device in a bad state when virtio-net +fronted device is unplugged with device_del monitor command. + +This is not triggable in regular poweroff or qemu forces shutdown +because cleanup is called right after vhost_vdpa_dev_start(false). But +devices hot unplug does not call vdpa device cleanups. This lead to all +the vhost_vdpa devices without stop the SVQ but the last. + +Fix it and clean the code, making it symmetric with +vhost_vdpa_svqs_start. + +Fixes: dff4426fa656 ("vhost: Add Shadow VirtQueue kick forwarding capabilities") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Message-Id: <20230209170004.899472-1-eperezma@redhat.com> +Tested-by: Laurent Vivier +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index dd1ba8878c..986fc795bf 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -692,26 +692,11 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + return ret; + } + +-static void vhost_vdpa_reset_svq(struct vhost_vdpa *v) +-{ +- if (!v->shadow_vqs_enabled) { +- return; +- } +- +- for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +- vhost_svq_stop(svq); +- } +-} +- + static int vhost_vdpa_reset_device(struct vhost_dev *dev) + { +- struct vhost_vdpa *v = dev->opaque; + int ret; + uint8_t status = 0; + +- vhost_vdpa_reset_svq(v); +- + ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); + trace_vhost_vdpa_reset_device(dev, status); + return ret; +@@ -1103,6 +1088,8 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ ++ vhost_svq_stop(svq); + vhost_vdpa_svq_unmap_rings(dev, svq); + + event_notifier_cleanup(&svq->hdev_kick); +-- +2.27.0 + diff --git a/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch b/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch new file mode 100644 index 0000000000000000000000000000000000000000..96f5eae20d9c684c507cad2afd32ad0b59478cbf --- /dev/null +++ b/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch @@ -0,0 +1,54 @@ +From 7a2278d9cdd9ac2a74bb9745fdf555395ff8dcd7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:42 +0100 +Subject: [PATCH] vdpa: store x-svq parameter in VhostVDPAState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CVQ can be shadowed two ways: +- Device has x-svq=on parameter (current way) +- The device can isolate CVQ in its own vq group + +QEMU needs to check for the second condition dynamically, because CVQ +index is not known before the driver ack the features. Since this is +dynamic, the CVQ isolation could vary with different conditions, making +it possible to go from "not isolated group" to "isolated". + +Saving the cmdline parameter in an extra field so we never disable CVQ +SVQ in case the device was started with x-svq cmdline. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-11-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index cb1cc2523d..7adba2c2b6 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -37,6 +37,8 @@ typedef struct VhostVDPAState { + void *cvq_cmd_out_buffer; + virtio_net_ctrl_ack *status; + ++ /* The device always have SVQ enabled */ ++ bool always_svq; + bool started; + } VhostVDPAState; + +@@ -575,6 +577,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ s->always_svq = svq; + s->vhost_vdpa.shadow_vqs_enabled = svq; + s->vhost_vdpa.iova_range = iova_range; + s->vhost_vdpa.iova_tree = iova_tree; +-- +2.27.0 + diff --git a/vdpa-support-vdpa-device-suspend-resume.patch b/vdpa-support-vdpa-device-suspend-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c94e7a3981817194eadeafebf100a7798dbdeba --- /dev/null +++ b/vdpa-support-vdpa-device-suspend-resume.patch @@ -0,0 +1,119 @@ +From 06bb2d68ef70813167a633aa00779acf61c784b0 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Tue, 19 Dec 2023 20:18:03 +0800 +Subject: [PATCH] vdpa: support vdpa device suspend/resume + +commit a21603f7ecfa 'vhost: implement vhost_vdpa_device_suspend/resume' +only implement suspend and resume interface used for migration. The +current implementation still has bugs when suspend/resume a virtual +machine. Fix it. + +Signed-off-by: jiangdongxu +--- + hw/virtio/vdpa-dev-mig.c | 16 +++++++++++----- + hw/virtio/vdpa-dev.c | 8 +------- + include/hw/virtio/vdpa-dev.h | 1 + + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index c71e71fd64..4a45821892 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -149,6 +149,7 @@ static int vhost_vdpa_device_suspend(VhostVdpaDevice *vdpa) + } + + vdpa->started = false; ++ vdpa->suspended = true; + + ret = vhost_dev_suspend(&vdpa->dev, vdev, false); + if (ret) { +@@ -171,6 +172,7 @@ set_guest_notifiers_fail: + } + + suspend_fail: ++ vdpa->suspended = false; + vdpa->started = true; + return ret; + } +@@ -207,6 +209,7 @@ static int vhost_vdpa_device_resume(VhostVdpaDevice *vdpa) + goto err_guest_notifiers; + } + vdpa->started = true; ++ vdpa->suspended = false; + + /* + * guest_notifier_mask/pending not used yet, so just unmask +@@ -247,7 +250,7 @@ static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) + MigrationIncomingState *mis = migration_incoming_get_current(); + + if (!running) { +- if (ms->state == RUN_STATE_PAUSED) { ++ if (ms->state == MIGRATION_STATUS_ACTIVE || state == RUN_STATE_PAUSED) { + ret = vhost_vdpa_device_suspend(vdpa); + if (ret) { + error_report("suspend vdpa device failed: %d\n", ret); +@@ -257,16 +260,19 @@ static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) + } + } + } else { +- if (ms->state == RUN_STATE_RESTORE_VM) { ++ if (vdpa->suspended) { + ret = vhost_vdpa_device_resume(vdpa); + if (ret) { +- error_report("migration dest resume device failed, abort!\n"); +- exit(EXIT_FAILURE); ++ error_report("vhost vdpa device resume failed: %d\n", ret); + } + } + + if (mis->state == RUN_STATE_RESTORE_VM) { +- vhost_vdpa_call(hdev, VHOST_VDPA_RESUME, NULL); ++ ret = vhost_vdpa_call(hdev, VHOST_VDPA_RESUME, NULL); ++ if (ret) { ++ error_report("migration dest resume device failed: %d\n", ret); ++ exit(EXIT_FAILURE); ++ } + /* post resume */ + mis->bh = qemu_bh_new(vdpa_dev_migration_handle_incoming_bh, + hdev); +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 143dadc88d..04d8e96a5d 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -315,7 +315,6 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev) + static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) + { + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); +- MigrationState *ms = migrate_get_current(); + bool should_start = virtio_device_started(vdev, status); + Error *local_err = NULL; + int ret; +@@ -324,12 +323,7 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) + should_start = false; + } + +- if (s->started == should_start) { +- return; +- } +- +- if (ms->state == RUN_STATE_PAUSED || +- ms->state == RUN_STATE_RESTORE_VM) { ++ if (s->started == should_start || s->suspended) { + return; + } + +diff --git a/include/hw/virtio/vdpa-dev.h b/include/hw/virtio/vdpa-dev.h +index 20f50c76c6..60e9c3f3fe 100644 +--- a/include/hw/virtio/vdpa-dev.h ++++ b/include/hw/virtio/vdpa-dev.h +@@ -37,6 +37,7 @@ struct VhostVdpaDevice { + int config_size; + uint16_t queue_size; + bool started; ++ bool suspended; + int (*post_init)(VhostVdpaDevice *v, Error **errp); + VMChangeStateEntry *vmstate; + Notifier migration_state; +-- +2.27.0 + diff --git a/vdpa-suspend-function-return-0-when-the-vdpa-device-.patch b/vdpa-suspend-function-return-0-when-the-vdpa-device-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c3c44a10a0957a8d9dcb9e74f74a8b947071a56 --- /dev/null +++ b/vdpa-suspend-function-return-0-when-the-vdpa-device-.patch @@ -0,0 +1,45 @@ +From bd3f62a0df7be244dcd7dab0632883354c476f17 Mon Sep 17 00:00:00 2001 +From: jiangdongxu +Date: Thu, 21 Dec 2023 11:03:37 +0800 +Subject: [PATCH] vdpa: suspend function return 0 when the vdpa device is + stopped + +When vhost vdpa device is stopped(vdpa->started is false), suspend +operation do nothing and return success, instead of return failure. + +The same goes for resume function. + +Signed-off-by: jiangdongxu +--- + hw/virtio/vdpa-dev-mig.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index 9cd80f92eb..679d37b182 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -140,8 +140,8 @@ static int vhost_vdpa_device_suspend(VhostVdpaDevice *vdpa) + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + +- if (!vdpa->started) { +- return -EFAULT; ++ if (!vdpa->started || vdpa->suspended) { ++ return 0; + } + + if (!k->set_guest_notifiers) { +@@ -184,6 +184,10 @@ static int vhost_vdpa_device_resume(VhostVdpaDevice *vdpa) + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int i, ret; + ++ if (vdpa->started || !vdpa->suspended) { ++ return 0; ++ } ++ + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers\n"); + return -ENOSYS; +-- +2.27.0 + diff --git a/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch b/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b22c8e5daceef0d56ccbbb9de8e621e9caed1ec --- /dev/null +++ b/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch @@ -0,0 +1,50 @@ +From f2a41f2f0f16402772009efc8eac5e9a08fea0b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:33 +0100 +Subject: [PATCH] vdpa: use v->shadow_vqs_enabled in vhost_vdpa_svqs_start & + stop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function used to trust in v->shadow_vqs != NULL to know if it must +start svq or not. + +This is not going to be valid anymore, as qemu is going to allocate svq +array unconditionally (but it will only start them conditionally). + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 0f07c85b91..08f92bf781 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1031,7 +1031,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + Error *err = NULL; + unsigned i; + +- if (!v->shadow_vqs) { ++ if (!v->shadow_vqs_enabled) { + return true; + } + +@@ -1084,7 +1084,7 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + +- if (!v->shadow_vqs) { ++ if (!v->shadow_vqs_enabled) { + return; + } + +-- +2.27.0 + diff --git a/vdpa-validate-MQ-CVQ-commands.patch b/vdpa-validate-MQ-CVQ-commands.patch new file mode 100644 index 0000000000000000000000000000000000000000..42627c177e37d5f16813ba172c191d57c7aa512a --- /dev/null +++ b/vdpa-validate-MQ-CVQ-commands.patch @@ -0,0 +1,41 @@ +From c9aa596ad26ee9fa1d4f7433485a668e3485d4ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:17 +0200 +Subject: [PATCH] vdpa: validate MQ CVQ commands +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So we are sure we can update the device model properly before sending to +the device. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b32fe5e68a..831709a270 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -494,6 +494,15 @@ static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) + __func__, ctrl.cmd); + }; + break; ++ case VIRTIO_NET_CTRL_MQ: ++ switch (ctrl.cmd) { ++ case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: ++ return true; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n", ++ __func__, ctrl.cmd); ++ }; ++ break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", + __func__, ctrl.class); +-- +2.27.0 + diff --git a/vfio-Add-VM-state-change-handler-to-know-state-of-VM.patch b/vfio-Add-VM-state-change-handler-to-know-state-of-VM.patch deleted file mode 100644 index eb8fb5d8f84b88bed1e48516050af5546dfae1cb..0000000000000000000000000000000000000000 --- a/vfio-Add-VM-state-change-handler-to-know-state-of-VM.patch +++ /dev/null @@ -1,258 +0,0 @@ -From 3a875293ae00266e1c82a5c382066efc4acc64ce Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:15 +0530 -Subject: [PATCH] vfio: Add VM state change handler to know state of VM - -VM state change handler is called on change in VM's state. Based on -VM state, VFIO device state should be changed. -Added read/write helper functions for migration region. -Added function to set device_state. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Cornelia Huck -[aw: lx -> HWADDR_PRIx, remove redundant parens] -Signed-off-by: Alex Williamson -Signed-off-by: Shenming Lu ---- - hw/vfio/migration.c | 160 ++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 2 + - include/hw/vfio/vfio-common.h | 4 + - 3 files changed, 166 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index fd7faf423c..ca82c78536 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -10,6 +10,7 @@ - #include "qemu/osdep.h" - #include - -+#include "sysemu/sysemu.h" - #include "hw/vfio/vfio-common.h" - #include "cpu.h" - #include "migration/migration.h" -@@ -22,6 +23,157 @@ - #include "exec/ram_addr.h" - #include "pci.h" - #include "trace.h" -+#include "hw/hw.h" -+ -+static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, -+ off_t off, bool iswrite) -+{ -+ int ret; -+ -+ ret = iswrite ? pwrite(vbasedev->fd, val, count, off) : -+ pread(vbasedev->fd, val, count, off); -+ if (ret < count) { -+ error_report("vfio_mig_%s %d byte %s: failed at offset 0x%" -+ HWADDR_PRIx", err: %s", iswrite ? "write" : "read", count, -+ vbasedev->name, off, strerror(errno)); -+ return (ret < 0) ? ret : -EINVAL; -+ } -+ return 0; -+} -+ -+static int vfio_mig_rw(VFIODevice *vbasedev, __u8 *buf, size_t count, -+ off_t off, bool iswrite) -+{ -+ int ret, done = 0; -+ __u8 *tbuf = buf; -+ -+ while (count) { -+ int bytes = 0; -+ -+ if (count >= 8 && !(off % 8)) { -+ bytes = 8; -+ } else if (count >= 4 && !(off % 4)) { -+ bytes = 4; -+ } else if (count >= 2 && !(off % 2)) { -+ bytes = 2; -+ } else { -+ bytes = 1; -+ } -+ -+ ret = vfio_mig_access(vbasedev, tbuf, bytes, off, iswrite); -+ if (ret) { -+ return ret; -+ } -+ -+ count -= bytes; -+ done += bytes; -+ off += bytes; -+ tbuf += bytes; -+ } -+ return done; -+} -+ -+#define vfio_mig_read(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, false) -+#define vfio_mig_write(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, true) -+ -+#define VFIO_MIG_STRUCT_OFFSET(f) \ -+ offsetof(struct vfio_device_migration_info, f) -+/* -+ * Change the device_state register for device @vbasedev. Bits set in @mask -+ * are preserved, bits set in @value are set, and bits not set in either @mask -+ * or @value are cleared in device_state. If the register cannot be accessed, -+ * the resulting state would be invalid, or the device enters an error state, -+ * an error is returned. -+ */ -+ -+static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, -+ uint32_t value) -+{ -+ VFIOMigration *migration = vbasedev->migration; -+ VFIORegion *region = &migration->region; -+ off_t dev_state_off = region->fd_offset + -+ VFIO_MIG_STRUCT_OFFSET(device_state); -+ uint32_t device_state; -+ int ret; -+ -+ ret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), -+ dev_state_off); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ device_state = (device_state & mask) | value; -+ -+ if (!VFIO_DEVICE_STATE_VALID(device_state)) { -+ return -EINVAL; -+ } -+ -+ ret = vfio_mig_write(vbasedev, &device_state, sizeof(device_state), -+ dev_state_off); -+ if (ret < 0) { -+ int rret; -+ -+ rret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), -+ dev_state_off); -+ -+ if ((rret < 0) || (VFIO_DEVICE_STATE_IS_ERROR(device_state))) { -+ hw_error("%s: Device in error state 0x%x", vbasedev->name, -+ device_state); -+ return rret ? rret : -EIO; -+ } -+ return ret; -+ } -+ -+ migration->device_state = device_state; -+ trace_vfio_migration_set_state(vbasedev->name, device_state); -+ return 0; -+} -+ -+static void vfio_vmstate_change(void *opaque, int running, RunState state) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ uint32_t value, mask; -+ int ret; -+ -+ if (vbasedev->migration->vm_running == running) { -+ return; -+ } -+ -+ if (running) { -+ /* -+ * Here device state can have one of _SAVING, _RESUMING or _STOP bit. -+ * Transition from _SAVING to _RUNNING can happen if there is migration -+ * failure, in that case clear _SAVING bit. -+ * Transition from _RESUMING to _RUNNING occurs during resuming -+ * phase, in that case clear _RESUMING bit. -+ * In both the above cases, set _RUNNING bit. -+ */ -+ mask = ~VFIO_DEVICE_STATE_MASK; -+ value = VFIO_DEVICE_STATE_RUNNING; -+ } else { -+ /* -+ * Here device state could be either _RUNNING or _SAVING|_RUNNING. Reset -+ * _RUNNING bit -+ */ -+ mask = ~VFIO_DEVICE_STATE_RUNNING; -+ value = 0; -+ } -+ -+ ret = vfio_migration_set_state(vbasedev, mask, value); -+ if (ret) { -+ /* -+ * Migration should be aborted in this case, but vm_state_notify() -+ * currently does not support reporting failures. -+ */ -+ error_report("%s: Failed to set device state 0x%x", vbasedev->name, -+ (migration->device_state & mask) | value); -+ qemu_file_set_error(migrate_get_current()->to_dst_file, ret); -+ } -+ vbasedev->migration->vm_running = running; -+ trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), -+ (migration->device_state & mask) | value); -+} - - static void vfio_migration_exit(VFIODevice *vbasedev) - { -@@ -38,6 +190,7 @@ static int vfio_migration_init(VFIODevice *vbasedev, - { - int ret; - Object *obj; -+ VFIOMigration *migration; - - if (!vbasedev->ops->vfio_get_object) { - return -EINVAL; -@@ -64,6 +217,10 @@ static int vfio_migration_init(VFIODevice *vbasedev, - ret = -EINVAL; - goto err; - } -+ -+ migration = vbasedev->migration; -+ migration->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change, -+ vbasedev); - return 0; - - err: -@@ -111,6 +268,9 @@ add_blocker: - void vfio_migration_finalize(VFIODevice *vbasedev) - { - if (vbasedev->migration) { -+ VFIOMigration *migration = vbasedev->migration; -+ -+ qemu_del_vm_change_state_handler(migration->vm_state); - vfio_migration_exit(vbasedev); - } - -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index fd034ac536..1626862315 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -146,3 +146,5 @@ vfio_display_edid_write_error(void) "" - - # migration.c - vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" -+vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" -+vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index e0482c2bac..533d6737ac 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -29,6 +29,7 @@ - #ifdef CONFIG_LINUX - #include - #endif -+#include "sysemu/sysemu.h" - - #define VFIO_MSG_PREFIX "vfio %s: " - -@@ -58,7 +59,10 @@ typedef struct VFIORegion { - } VFIORegion; - - typedef struct VFIOMigration { -+ VMChangeStateEntry *vm_state; - VFIORegion region; -+ uint32_t device_state; -+ int vm_running; - } VFIOMigration; - - typedef struct VFIOAddressSpace { --- -2.27.0 - diff --git a/vfio-Add-function-to-start-and-stop-dirty-pages-trac.patch b/vfio-Add-function-to-start-and-stop-dirty-pages-trac.patch deleted file mode 100644 index b15a1c4bfbeb108bc5a098df8d68aef288b5e9c2..0000000000000000000000000000000000000000 --- a/vfio-Add-function-to-start-and-stop-dirty-pages-trac.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 4363ea5cded9c6d2838a9564b067f583a6ef077f Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:22 +0530 -Subject: [PATCH] vfio: Add function to start and stop dirty pages tracking - -Call VFIO_IOMMU_DIRTY_PAGES ioctl to start and stop dirty pages tracking -for VFIO devices. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 0d2bd9e5cd..0bdf6a1820 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -11,6 +11,7 @@ - #include "qemu/main-loop.h" - #include "qemu/cutils.h" - #include -+#include - - #include "sysemu/sysemu.h" - #include "hw/vfio/vfio-common.h" -@@ -391,10 +392,40 @@ static int vfio_load_device_config_state(QEMUFile *f, void *opaque) - return qemu_file_get_error(f); - } - -+static int vfio_set_dirty_page_tracking(VFIODevice *vbasedev, bool start) -+{ -+ int ret; -+ VFIOMigration *migration = vbasedev->migration; -+ VFIOContainer *container = vbasedev->group->container; -+ struct vfio_iommu_type1_dirty_bitmap dirty = { -+ .argsz = sizeof(dirty), -+ }; -+ -+ if (start) { -+ if (migration->device_state & VFIO_DEVICE_STATE_SAVING) { -+ dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; -+ } else { -+ return -EINVAL; -+ } -+ } else { -+ dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; -+ } -+ -+ ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); -+ if (ret) { -+ error_report("Failed to set dirty tracking flag 0x%x errno: %d", -+ dirty.flags, errno); -+ return -errno; -+ } -+ return ret; -+} -+ - static void vfio_migration_cleanup(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; - -+ vfio_set_dirty_page_tracking(vbasedev, false); -+ - if (migration->region.mmaps) { - vfio_region_unmap(&migration->region); - } -@@ -435,6 +466,11 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) - return ret; - } - -+ ret = vfio_set_dirty_page_tracking(vbasedev, true); -+ if (ret) { -+ return ret; -+ } -+ - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - - ret = qemu_file_get_error(f); --- -2.27.0 - diff --git a/vfio-Add-function-to-unmap-VFIO-region.patch b/vfio-Add-function-to-unmap-VFIO-region.patch deleted file mode 100644 index 2cdd76a09bd44c73b42f4294055b935a31446b7e..0000000000000000000000000000000000000000 --- a/vfio-Add-function-to-unmap-VFIO-region.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 68cc2be61588d14de2313342ee87eb0bb2b990e0 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:11 +0530 -Subject: [PATCH] vfio: Add function to unmap VFIO region - -This function will be used for migration region. -Migration region is mmaped when migration starts and will be unmapped when -migration is complete. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Cornelia Huck -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 32 ++++++++++++++++++++++++++++---- - hw/vfio/trace-events | 1 + - include/hw/vfio/vfio-common.h | 1 + - 3 files changed, 30 insertions(+), 4 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index a859298fda..4c32b1bb99 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -906,6 +906,18 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, - return 0; - } - -+static void vfio_subregion_unmap(VFIORegion *region, int index) -+{ -+ trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), -+ region->mmaps[index].offset, -+ region->mmaps[index].offset + -+ region->mmaps[index].size - 1); -+ memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); -+ munmap(region->mmaps[index].mmap, region->mmaps[index].size); -+ object_unparent(OBJECT(®ion->mmaps[index].mem)); -+ region->mmaps[index].mmap = NULL; -+} -+ - int vfio_region_mmap(VFIORegion *region) - { - int i, prot = 0; -@@ -936,10 +948,7 @@ int vfio_region_mmap(VFIORegion *region) - region->mmaps[i].mmap = NULL; - - for (i--; i >= 0; i--) { -- memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); -- munmap(region->mmaps[i].mmap, region->mmaps[i].size); -- object_unparent(OBJECT(®ion->mmaps[i].mem)); -- region->mmaps[i].mmap = NULL; -+ vfio_subregion_unmap(region, i); - } - - return ret; -@@ -964,6 +973,21 @@ int vfio_region_mmap(VFIORegion *region) - return 0; - } - -+void vfio_region_unmap(VFIORegion *region) -+{ -+ int i; -+ -+ if (!region->mem) { -+ return; -+ } -+ -+ for (i = 0; i < region->nr_mmaps; i++) { -+ if (region->mmaps[i].mmap) { -+ vfio_subregion_unmap(region, i); -+ } -+ } -+} -+ - void vfio_region_exit(VFIORegion *region) - { - int i; -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index b1ef55a33f..8cdc27946c 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -111,6 +111,7 @@ vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Reg - vfio_region_exit(const char *name, int index) "Device %s, region %d" - vfio_region_finalize(const char *name, int index) "Device %s, region %d" - vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d" -+vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Region %s unmap [0x%lx - 0x%lx]" - vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" - vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" - vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 9107bd41c0..93493891ba 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -171,6 +171,7 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, - int index, const char *name); - int vfio_region_mmap(VFIORegion *region); - void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); -+void vfio_region_unmap(VFIORegion *region); - void vfio_region_exit(VFIORegion *region); - void vfio_region_finalize(VFIORegion *region); - void vfio_reset_handler(void *opaque); --- -2.27.0 - diff --git a/vfio-Add-ioctl-to-get-dirty-pages-bitmap-during-dma-.patch b/vfio-Add-ioctl-to-get-dirty-pages-bitmap-during-dma-.patch deleted file mode 100644 index 2831e94ca260e5753f2bcd0007ab036cba387b33..0000000000000000000000000000000000000000 --- a/vfio-Add-ioctl-to-get-dirty-pages-bitmap-during-dma-.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 1333031bd3b488ed4904a61fd292cd5aa93f8c5b Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:25 +0530 -Subject: [PATCH] vfio: Add ioctl to get dirty pages bitmap during dma unmap - -With vIOMMU, IO virtual address range can get unmapped while in pre-copy -phase of migration. In that case, unmap ioctl should return pages pinned -in that range and QEMU should find its correcponding guest physical -addresses and report those dirty. - -Suggested-by: Alex Williamson -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -[aw: fix error_report types, fix cpu_physical_memory_set_dirty_lebitmap() cast] -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 93 insertions(+), 4 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 8773b998ac..4ce1c10734 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -320,11 +320,95 @@ static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) - return true; - } - -+static bool vfio_devices_all_running_and_saving(VFIOContainer *container) -+{ -+ VFIOGroup *group; -+ VFIODevice *vbasedev; -+ MigrationState *ms = migrate_get_current(); -+ -+ if (!migration_is_setup_or_active(ms->state)) { -+ return false; -+ } -+ -+ QLIST_FOREACH(group, &container->group_list, container_next) { -+ QLIST_FOREACH(vbasedev, &group->device_list, next) { -+ VFIOMigration *migration = vbasedev->migration; -+ -+ if (!migration) { -+ return false; -+ } -+ -+ if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && -+ (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { -+ continue; -+ } else { -+ return false; -+ } -+ } -+ } -+ return true; -+} -+ -+static int vfio_dma_unmap_bitmap(VFIOContainer *container, -+ hwaddr iova, ram_addr_t size, -+ IOMMUTLBEntry *iotlb) -+{ -+ struct vfio_iommu_type1_dma_unmap *unmap; -+ struct vfio_bitmap *bitmap; -+ uint64_t pages = TARGET_PAGE_ALIGN(size) >> TARGET_PAGE_BITS; -+ int ret; -+ -+ unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); -+ -+ unmap->argsz = sizeof(*unmap) + sizeof(*bitmap); -+ unmap->iova = iova; -+ unmap->size = size; -+ unmap->flags |= VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP; -+ bitmap = (struct vfio_bitmap *)&unmap->data; -+ -+ /* -+ * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -+ * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap_pgsize to -+ * TARGET_PAGE_SIZE. -+ */ -+ -+ bitmap->pgsize = TARGET_PAGE_SIZE; -+ bitmap->size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / -+ BITS_PER_BYTE; -+ -+ if (bitmap->size > container->max_dirty_bitmap_size) { -+ error_report("UNMAP: Size of bitmap too big 0x%"PRIx64, -+ (uint64_t)bitmap->size); -+ ret = -E2BIG; -+ goto unmap_exit; -+ } -+ -+ bitmap->data = g_try_malloc0(bitmap->size); -+ if (!bitmap->data) { -+ ret = -ENOMEM; -+ goto unmap_exit; -+ } -+ -+ ret = ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, unmap); -+ if (!ret) { -+ cpu_physical_memory_set_dirty_lebitmap((unsigned long *)bitmap->data, -+ iotlb->translated_addr, pages); -+ } else { -+ error_report("VFIO_UNMAP_DMA with DIRTY_BITMAP : %m"); -+ } -+ -+ g_free(bitmap->data); -+unmap_exit: -+ g_free(unmap); -+ return ret; -+} -+ - /* - * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 - */ - static int vfio_dma_unmap(VFIOContainer *container, -- hwaddr iova, ram_addr_t size) -+ hwaddr iova, ram_addr_t size, -+ IOMMUTLBEntry *iotlb) - { - struct vfio_iommu_type1_dma_unmap unmap = { - .argsz = sizeof(unmap), -@@ -333,6 +417,11 @@ static int vfio_dma_unmap(VFIOContainer *container, - .size = size, - }; - -+ if (iotlb && container->dirty_pages_supported && -+ vfio_devices_all_running_and_saving(container)) { -+ return vfio_dma_unmap_bitmap(container, iova, size, iotlb); -+ } -+ - while (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { - /* - * The type1 backend has an off-by-one bug in the kernel (71a7d3d78e3c -@@ -380,7 +469,7 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, - * the VGA ROM space. - */ - if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || -- (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 && -+ (errno == EBUSY && vfio_dma_unmap(container, iova, size, NULL) == 0 && - ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { - return 0; - } -@@ -530,7 +619,7 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) - iotlb->addr_mask + 1, vaddr, ret); - } - } else { -- ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1); -+ ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1, iotlb); - if (ret) { - error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx") = %d (%m)", -@@ -816,7 +905,7 @@ static void vfio_listener_region_del(MemoryListener *listener, - } - - if (try_unmap) { -- ret = vfio_dma_unmap(container, iova, int128_get64(llsize)); -+ ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); - if (ret) { - error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx") = %d (%m)", --- -2.27.0 - diff --git a/vfio-Add-load-state-functions-to-SaveVMHandlers.patch b/vfio-Add-load-state-functions-to-SaveVMHandlers.patch deleted file mode 100644 index d70caeeef043b6c6cb53f09c9adb67b40b344862..0000000000000000000000000000000000000000 --- a/vfio-Add-load-state-functions-to-SaveVMHandlers.patch +++ /dev/null @@ -1,266 +0,0 @@ -From ddef5d5257987f2f415ce41fdc482feda61aa796 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:19 +0530 -Subject: [PATCH] vfio: Add load state functions to SaveVMHandlers - -Sequence during _RESUMING device state: -While data for this device is available, repeat below steps: -a. read data_offset from where user application should write data. -b. write data of data_size to migration region from data_offset. -c. write data_size which indicates vendor driver that data is written in - staging buffer. - -For user, data is opaque. User should write data in the same order as -received. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Yan Zhao -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 195 +++++++++++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 4 + - 2 files changed, 199 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index f78a77e1e3..954c064435 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -257,6 +257,77 @@ static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) - return ret; - } - -+static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, -+ uint64_t data_size) -+{ -+ VFIORegion *region = &vbasedev->migration->region; -+ uint64_t data_offset = 0, size, report_size; -+ int ret; -+ -+ do { -+ ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), -+ region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ if (data_offset + data_size > region->size) { -+ /* -+ * If data_size is greater than the data section of migration region -+ * then iterate the write buffer operation. This case can occur if -+ * size of migration region at destination is smaller than size of -+ * migration region at source. -+ */ -+ report_size = size = region->size - data_offset; -+ data_size -= size; -+ } else { -+ report_size = size = data_size; -+ data_size = 0; -+ } -+ -+ trace_vfio_load_state_device_data(vbasedev->name, data_offset, size); -+ -+ while (size) { -+ void *buf; -+ uint64_t sec_size; -+ bool buf_alloc = false; -+ -+ buf = get_data_section_size(region, data_offset, size, &sec_size); -+ -+ if (!buf) { -+ buf = g_try_malloc(sec_size); -+ if (!buf) { -+ error_report("%s: Error allocating buffer ", __func__); -+ return -ENOMEM; -+ } -+ buf_alloc = true; -+ } -+ -+ qemu_get_buffer(f, buf, sec_size); -+ -+ if (buf_alloc) { -+ ret = vfio_mig_write(vbasedev, buf, sec_size, -+ region->fd_offset + data_offset); -+ g_free(buf); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ } -+ size -= sec_size; -+ data_offset += sec_size; -+ } -+ -+ ret = vfio_mig_write(vbasedev, &report_size, sizeof(report_size), -+ region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); -+ if (ret < 0) { -+ return ret; -+ } -+ } while (data_size); -+ -+ return 0; -+} -+ - static int vfio_update_pending(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; -@@ -293,6 +364,33 @@ static int vfio_save_device_config_state(QEMUFile *f, void *opaque) - return qemu_file_get_error(f); - } - -+static int vfio_load_device_config_state(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ uint64_t data; -+ -+ if (vbasedev->ops && vbasedev->ops->vfio_load_config) { -+ int ret; -+ -+ ret = vbasedev->ops->vfio_load_config(vbasedev, f); -+ if (ret) { -+ error_report("%s: Failed to load device config space", -+ vbasedev->name); -+ return ret; -+ } -+ } -+ -+ data = qemu_get_be64(f); -+ if (data != VFIO_MIG_FLAG_END_OF_STATE) { -+ error_report("%s: Failed loading device config space, " -+ "end flag incorrect 0x%"PRIx64, vbasedev->name, data); -+ return -EINVAL; -+ } -+ -+ trace_vfio_load_device_config_state(vbasedev->name); -+ return qemu_file_get_error(f); -+} -+ - static void vfio_migration_cleanup(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; -@@ -483,12 +581,109 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) - return ret; - } - -+static int vfio_load_setup(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ int ret = 0; -+ -+ if (migration->region.mmaps) { -+ ret = vfio_region_mmap(&migration->region); -+ if (ret) { -+ error_report("%s: Failed to mmap VFIO migration region %d: %s", -+ vbasedev->name, migration->region.nr, -+ strerror(-ret)); -+ error_report("%s: Falling back to slow path", vbasedev->name); -+ } -+ } -+ -+ ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, -+ VFIO_DEVICE_STATE_RESUMING); -+ if (ret) { -+ error_report("%s: Failed to set state RESUMING", vbasedev->name); -+ if (migration->region.mmaps) { -+ vfio_region_unmap(&migration->region); -+ } -+ } -+ return ret; -+} -+ -+static int vfio_load_cleanup(void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ -+ vfio_migration_cleanup(vbasedev); -+ trace_vfio_load_cleanup(vbasedev->name); -+ return 0; -+} -+ -+static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) -+{ -+ VFIODevice *vbasedev = opaque; -+ int ret = 0; -+ uint64_t data; -+ -+ data = qemu_get_be64(f); -+ while (data != VFIO_MIG_FLAG_END_OF_STATE) { -+ -+ trace_vfio_load_state(vbasedev->name, data); -+ -+ switch (data) { -+ case VFIO_MIG_FLAG_DEV_CONFIG_STATE: -+ { -+ ret = vfio_load_device_config_state(f, opaque); -+ if (ret) { -+ return ret; -+ } -+ break; -+ } -+ case VFIO_MIG_FLAG_DEV_SETUP_STATE: -+ { -+ data = qemu_get_be64(f); -+ if (data == VFIO_MIG_FLAG_END_OF_STATE) { -+ return ret; -+ } else { -+ error_report("%s: SETUP STATE: EOS not found 0x%"PRIx64, -+ vbasedev->name, data); -+ return -EINVAL; -+ } -+ break; -+ } -+ case VFIO_MIG_FLAG_DEV_DATA_STATE: -+ { -+ uint64_t data_size = qemu_get_be64(f); -+ -+ if (data_size) { -+ ret = vfio_load_buffer(f, vbasedev, data_size); -+ if (ret < 0) { -+ return ret; -+ } -+ } -+ break; -+ } -+ default: -+ error_report("%s: Unknown tag 0x%"PRIx64, vbasedev->name, data); -+ return -EINVAL; -+ } -+ -+ data = qemu_get_be64(f); -+ ret = qemu_file_get_error(f); -+ if (ret) { -+ return ret; -+ } -+ } -+ return ret; -+} -+ - static SaveVMHandlers savevm_vfio_handlers = { - .save_setup = vfio_save_setup, - .save_cleanup = vfio_save_cleanup, - .save_live_pending = vfio_save_pending, - .save_live_iterate = vfio_save_iterate, - .save_live_complete_precopy = vfio_save_complete_precopy, -+ .load_setup = vfio_load_setup, -+ .load_cleanup = vfio_load_cleanup, -+ .load_state = vfio_load_state, - }; - - /* ---------------------------------------------------------------------- */ -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 9a1c5e17d9..4f08f5a633 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -157,3 +157,7 @@ vfio_save_device_config_state(const char *name) " (%s)" - vfio_save_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 - vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" - vfio_save_complete_precopy(const char *name) " (%s)" -+vfio_load_device_config_state(const char *name) " (%s)" -+vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 -+vfio_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 -+vfio_load_cleanup(const char *name) " (%s)" --- -2.27.0 - diff --git a/vfio-Add-migration-region-initialization-and-finaliz.patch b/vfio-Add-migration-region-initialization-and-finaliz.patch deleted file mode 100644 index c804f1f6c353143ca74fe05889d5e163ab9dc8c3..0000000000000000000000000000000000000000 --- a/vfio-Add-migration-region-initialization-and-finaliz.patch +++ /dev/null @@ -1,209 +0,0 @@ -From b7128f8aa03482634c07691cef69e7ed2d35200e Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:14 +0530 -Subject: [PATCH] vfio: Add migration region initialization and finalize - function - -Whether the VFIO device supports migration or not is decided based of -migration region query. If migration region query is successful and migration -region initialization is successful then migration is supported else -migration is blocked. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Acked-by: Dr. David Alan Gilbert -Reviewed-by: Cornelia Huck -Signed-off-by: Alex Williamson -Signed-off-by: Shenming Lu ---- - hw/vfio/Makefile.objs | 2 +- - hw/vfio/migration.c | 122 ++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 3 + - include/hw/vfio/vfio-common.h | 9 +++ - 4 files changed, 135 insertions(+), 1 deletion(-) - create mode 100644 hw/vfio/migration.c - -diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs -index abad8b818c..36033d1437 100644 ---- a/hw/vfio/Makefile.objs -+++ b/hw/vfio/Makefile.objs -@@ -1,4 +1,4 @@ --obj-y += common.o spapr.o -+obj-y += common.o spapr.o migration.o - obj-$(CONFIG_VFIO_PCI) += pci.o pci-quirks.o display.o - obj-$(CONFIG_VFIO_CCW) += ccw.o - obj-$(CONFIG_VFIO_PLATFORM) += platform.o -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -new file mode 100644 -index 0000000000..fd7faf423c ---- /dev/null -+++ b/hw/vfio/migration.c -@@ -0,0 +1,122 @@ -+/* -+ * Migration support for VFIO devices -+ * -+ * Copyright NVIDIA, Inc. 2020 -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2. See -+ * the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include "hw/vfio/vfio-common.h" -+#include "cpu.h" -+#include "migration/migration.h" -+#include "migration/qemu-file.h" -+#include "migration/register.h" -+#include "migration/blocker.h" -+#include "migration/misc.h" -+#include "qapi/error.h" -+#include "exec/ramlist.h" -+#include "exec/ram_addr.h" -+#include "pci.h" -+#include "trace.h" -+ -+static void vfio_migration_exit(VFIODevice *vbasedev) -+{ -+ VFIOMigration *migration = vbasedev->migration; -+ -+ vfio_region_exit(&migration->region); -+ vfio_region_finalize(&migration->region); -+ g_free(vbasedev->migration); -+ vbasedev->migration = NULL; -+} -+ -+static int vfio_migration_init(VFIODevice *vbasedev, -+ struct vfio_region_info *info) -+{ -+ int ret; -+ Object *obj; -+ -+ if (!vbasedev->ops->vfio_get_object) { -+ return -EINVAL; -+ } -+ -+ obj = vbasedev->ops->vfio_get_object(vbasedev); -+ if (!obj) { -+ return -EINVAL; -+ } -+ -+ vbasedev->migration = g_new0(VFIOMigration, 1); -+ -+ ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, -+ info->index, "migration"); -+ if (ret) { -+ error_report("%s: Failed to setup VFIO migration region %d: %s", -+ vbasedev->name, info->index, strerror(-ret)); -+ goto err; -+ } -+ -+ if (!vbasedev->migration->region.size) { -+ error_report("%s: Invalid zero-sized VFIO migration region %d", -+ vbasedev->name, info->index); -+ ret = -EINVAL; -+ goto err; -+ } -+ return 0; -+ -+err: -+ vfio_migration_exit(vbasedev); -+ return ret; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) -+{ -+ struct vfio_region_info *info = NULL; -+ Error *local_err = NULL; -+ int ret; -+ -+ ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_MIGRATION, -+ VFIO_REGION_SUBTYPE_MIGRATION, &info); -+ if (ret) { -+ goto add_blocker; -+ } -+ -+ ret = vfio_migration_init(vbasedev, info); -+ if (ret) { -+ goto add_blocker; -+ } -+ -+ g_free(info); -+ trace_vfio_migration_probe(vbasedev->name, info->index); -+ return 0; -+ -+add_blocker: -+ error_setg(&vbasedev->migration_blocker, -+ "VFIO device doesn't support migration"); -+ g_free(info); -+ -+ ret = migrate_add_blocker(vbasedev->migration_blocker, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ error_free(vbasedev->migration_blocker); -+ vbasedev->migration_blocker = NULL; -+ } -+ return ret; -+} -+ -+void vfio_migration_finalize(VFIODevice *vbasedev) -+{ -+ if (vbasedev->migration) { -+ vfio_migration_exit(vbasedev); -+ } -+ -+ if (vbasedev->migration_blocker) { -+ migrate_del_blocker(vbasedev->migration_blocker); -+ error_free(vbasedev->migration_blocker); -+ vbasedev->migration_blocker = NULL; -+ } -+} -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 8cdc27946c..fd034ac536 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -143,3 +143,6 @@ vfio_display_edid_link_up(void) "" - vfio_display_edid_link_down(void) "" - vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u" - vfio_display_edid_write_error(void) "" -+ -+# migration.c -+vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 6ea4898c4d..e0482c2bac 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -57,6 +57,10 @@ typedef struct VFIORegion { - uint8_t nr; /* cache the region number for debug */ - } VFIORegion; - -+typedef struct VFIOMigration { -+ VFIORegion region; -+} VFIOMigration; -+ - typedef struct VFIOAddressSpace { - AddressSpace *as; - QLIST_HEAD(, VFIOContainer) containers; -@@ -113,6 +117,8 @@ typedef struct VFIODevice { - unsigned int num_irqs; - unsigned int num_regions; - unsigned int flags; -+ VFIOMigration *migration; -+ Error *migration_blocker; - } VFIODevice; - - struct VFIODeviceOps { -@@ -204,4 +210,7 @@ int vfio_spapr_create_window(VFIOContainer *container, - int vfio_spapr_remove_window(VFIOContainer *container, - hwaddr offset_within_address_space); - -+int vfio_migration_probe(VFIODevice *vbasedev, Error **errp); -+void vfio_migration_finalize(VFIODevice *vbasedev); -+ - #endif /* HW_VFIO_VFIO_COMMON_H */ --- -2.27.0 - diff --git a/vfio-Add-migration-state-change-notifier.patch b/vfio-Add-migration-state-change-notifier.patch deleted file mode 100644 index 5fe73a4cb18cd401d8d63ec8440cc361bbae60d9..0000000000000000000000000000000000000000 --- a/vfio-Add-migration-state-change-notifier.patch +++ /dev/null @@ -1,104 +0,0 @@ -From b61729a5e0ab89d29f041202b50d042405076e62 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:16 +0530 -Subject: [PATCH] vfio: Add migration state change notifier - -Added migration state change notifier to get notification on migration state -change. These states are translated to VFIO device state and conveyed to -vendor driver. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Cornelia Huck -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 28 ++++++++++++++++++++++++++++ - hw/vfio/trace-events | 1 + - include/hw/vfio/vfio-common.h | 2 ++ - 3 files changed, 31 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index ca82c78536..0c6c9b655f 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -175,6 +175,30 @@ static void vfio_vmstate_change(void *opaque, int running, RunState state) - (migration->device_state & mask) | value); - } - -+static void vfio_migration_state_notifier(Notifier *notifier, void *data) -+{ -+ MigrationState *s = data; -+ VFIOMigration *migration = container_of(notifier, VFIOMigration, -+ migration_state); -+ VFIODevice *vbasedev = migration->vbasedev; -+ int ret; -+ -+ trace_vfio_migration_state_notifier(vbasedev->name, -+ MigrationStatus_str(s->state)); -+ -+ switch (s->state) { -+ case MIGRATION_STATUS_CANCELLING: -+ case MIGRATION_STATUS_CANCELLED: -+ case MIGRATION_STATUS_FAILED: -+ ret = vfio_migration_set_state(vbasedev, -+ ~(VFIO_DEVICE_STATE_SAVING | VFIO_DEVICE_STATE_RESUMING), -+ VFIO_DEVICE_STATE_RUNNING); -+ if (ret) { -+ error_report("%s: Failed to set state RUNNING", vbasedev->name); -+ } -+ } -+} -+ - static void vfio_migration_exit(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; -@@ -219,8 +243,11 @@ static int vfio_migration_init(VFIODevice *vbasedev, - } - - migration = vbasedev->migration; -+ migration->vbasedev = vbasedev; - migration->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change, - vbasedev); -+ migration->migration_state.notify = vfio_migration_state_notifier; -+ add_migration_state_change_notifier(&migration->migration_state); - return 0; - - err: -@@ -270,6 +297,7 @@ void vfio_migration_finalize(VFIODevice *vbasedev) - if (vbasedev->migration) { - VFIOMigration *migration = vbasedev->migration; - -+ remove_migration_state_change_notifier(&migration->migration_state); - qemu_del_vm_change_state_handler(migration->vm_state); - vfio_migration_exit(vbasedev); - } -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 1626862315..bd3d47b005 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -148,3 +148,4 @@ vfio_display_edid_write_error(void) "" - vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" - vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" - vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" -+vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 533d6737ac..efff0590ae 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -59,10 +59,12 @@ typedef struct VFIORegion { - } VFIORegion; - - typedef struct VFIOMigration { -+ struct VFIODevice *vbasedev; - VMChangeStateEntry *vm_state; - VFIORegion region; - uint32_t device_state; - int vm_running; -+ Notifier migration_state; - } VFIOMigration; - - typedef struct VFIOAddressSpace { --- -2.27.0 - diff --git a/vfio-Add-save-and-load-functions-for-VFIO-PCI-device.patch b/vfio-Add-save-and-load-functions-for-VFIO-PCI-device.patch deleted file mode 100644 index 232efcf5dbcc072f358e3fec5a5f1186a1a97b55..0000000000000000000000000000000000000000 --- a/vfio-Add-save-and-load-functions-for-VFIO-PCI-device.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 92f104ca6e35acae079ca3bb432f24452058d483 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:13 +0530 -Subject: [PATCH] vfio: Add save and load functions for VFIO PCI devices - -Added functions to save and restore PCI device specific data, -specifically config space of PCI device. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Signed-off-by: Alex Williamson ---- - hw/vfio/pci.c | 51 +++++++++++++++++++++++++++++++++++ - include/hw/vfio/vfio-common.h | 2 ++ - 2 files changed, 53 insertions(+) - -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index de0d286fc9..b9fae3ad28 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -35,6 +35,7 @@ - #include "pci.h" - #include "trace.h" - #include "qapi/error.h" -+#include "migration/qemu-file.h" - - #define TYPE_VFIO_PCI "vfio-pci" - #define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI) -@@ -2395,11 +2396,61 @@ static Object *vfio_pci_get_object(VFIODevice *vbasedev) - return OBJECT(vdev); - } - -+static bool vfio_msix_present(void *opaque, int version_id) -+{ -+ PCIDevice *pdev = opaque; -+ -+ return msix_present(pdev); -+} -+ -+const VMStateDescription vmstate_vfio_pci_config = { -+ .name = "VFIOPCIDevice", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_PCI_DEVICE(pdev, VFIOPCIDevice), -+ VMSTATE_MSIX_TEST(pdev, VFIOPCIDevice, vfio_msix_present), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void vfio_pci_save_config(VFIODevice *vbasedev, QEMUFile *f) -+{ -+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); -+ -+ vmstate_save_state(f, &vmstate_vfio_pci_config, vdev, NULL); -+} -+ -+static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f) -+{ -+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); -+ PCIDevice *pdev = &vdev->pdev; -+ int ret; -+ -+ ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1); -+ if (ret) { -+ return ret; -+ } -+ -+ vfio_pci_write_config(pdev, PCI_COMMAND, -+ pci_get_word(pdev->config + PCI_COMMAND), 2); -+ -+ if (msi_enabled(pdev)) { -+ vfio_msi_enable(vdev); -+ } else if (msix_enabled(pdev)) { -+ vfio_msix_enable(vdev); -+ } -+ -+ return ret; -+} -+ - static VFIODeviceOps vfio_pci_ops = { - .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, - .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, - .vfio_eoi = vfio_intx_eoi, - .vfio_get_object = vfio_pci_get_object, -+ .vfio_save_config = vfio_pci_save_config, -+ .vfio_load_config = vfio_pci_load_config, - }; - - int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 771b6d59a3..6ea4898c4d 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -120,6 +120,8 @@ struct VFIODeviceOps { - int (*vfio_hot_reset_multi)(VFIODevice *vdev); - void (*vfio_eoi)(VFIODevice *vdev); - Object *(*vfio_get_object)(VFIODevice *vdev); -+ void (*vfio_save_config)(VFIODevice *vdev, QEMUFile *f); -+ int (*vfio_load_config)(VFIODevice *vdev, QEMUFile *f); - }; - - typedef struct VFIOGroup { --- -2.27.0 - diff --git a/vfio-Add-save-state-functions-to-SaveVMHandlers.patch b/vfio-Add-save-state-functions-to-SaveVMHandlers.patch deleted file mode 100644 index 14047fd8a474c07c71fa4ba622e1fb33d043b02d..0000000000000000000000000000000000000000 --- a/vfio-Add-save-state-functions-to-SaveVMHandlers.patch +++ /dev/null @@ -1,380 +0,0 @@ -From 94f106f95e887d1d706e8f771fd6ad287ddac2dc Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:18 +0530 -Subject: [PATCH] vfio: Add save state functions to SaveVMHandlers - -Added .save_live_pending, .save_live_iterate and .save_live_complete_precopy -functions. These functions handles pre-copy and stop-and-copy phase. - -In _SAVING|_RUNNING device state or pre-copy phase: -- read pending_bytes. If pending_bytes > 0, go through below steps. -- read data_offset - indicates kernel driver to write data to staging - buffer. -- read data_size - amount of data in bytes written by vendor driver in - migration region. -- read data_size bytes of data from data_offset in the migration region. -- Write data packet to file stream as below: -{VFIO_MIG_FLAG_DEV_DATA_STATE, data_size, actual data, -VFIO_MIG_FLAG_END_OF_STATE } - -In _SAVING device state or stop-and-copy phase -a. read config space of device and save to migration file stream. This - doesn't need to be from vendor driver. Any other special config state - from driver can be saved as data in following iteration. -b. read pending_bytes. If pending_bytes > 0, go through below steps. -c. read data_offset - indicates kernel driver to write data to staging - buffer. -d. read data_size - amount of data in bytes written by vendor driver in - migration region. -e. read data_size bytes of data from data_offset in the migration region. -f. Write data packet as below: - {VFIO_MIG_FLAG_DEV_DATA_STATE, data_size, actual data} -g. iterate through steps b to f while (pending_bytes > 0) -h. Write {VFIO_MIG_FLAG_END_OF_STATE} - -When data region is mapped, its user's responsibility to read data from -data_offset of data_size before moving to next steps. - -Added fix suggested by Artem Polyakov to reset pending_bytes in -vfio_save_iterate(). -Added fix suggested by Zhi Wang to add 0 as data size in migration stream and -add END_OF_STATE delimiter to indicate phase complete. - -Suggested-by: Artem Polyakov -Suggested-by: Zhi Wang -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Yan Zhao -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 276 ++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 6 + - include/hw/vfio/vfio-common.h | 1 + - 3 files changed, 283 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 405228fc5a..f78a77e1e3 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -148,6 +148,151 @@ static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, - return 0; - } - -+static void *get_data_section_size(VFIORegion *region, uint64_t data_offset, -+ uint64_t data_size, uint64_t *size) -+{ -+ void *ptr = NULL; -+ uint64_t limit = 0; -+ int i; -+ -+ if (!region->mmaps) { -+ if (size) { -+ *size = MIN(data_size, region->size - data_offset); -+ } -+ return ptr; -+ } -+ -+ for (i = 0; i < region->nr_mmaps; i++) { -+ VFIOMmap *map = region->mmaps + i; -+ -+ if ((data_offset >= map->offset) && -+ (data_offset < map->offset + map->size)) { -+ -+ /* check if data_offset is within sparse mmap areas */ -+ ptr = map->mmap + data_offset - map->offset; -+ if (size) { -+ *size = MIN(data_size, map->offset + map->size - data_offset); -+ } -+ break; -+ } else if ((data_offset < map->offset) && -+ (!limit || limit > map->offset)) { -+ /* -+ * data_offset is not within sparse mmap areas, find size of -+ * non-mapped area. Check through all list since region->mmaps list -+ * is not sorted. -+ */ -+ limit = map->offset; -+ } -+ } -+ -+ if (!ptr && size) { -+ *size = limit ? MIN(data_size, limit - data_offset) : data_size; -+ } -+ return ptr; -+} -+ -+static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) -+{ -+ VFIOMigration *migration = vbasedev->migration; -+ VFIORegion *region = &migration->region; -+ uint64_t data_offset = 0, data_size = 0, sz; -+ int ret; -+ -+ ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), -+ region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ ret = vfio_mig_read(vbasedev, &data_size, sizeof(data_size), -+ region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ trace_vfio_save_buffer(vbasedev->name, data_offset, data_size, -+ migration->pending_bytes); -+ -+ qemu_put_be64(f, data_size); -+ sz = data_size; -+ -+ while (sz) { -+ void *buf; -+ uint64_t sec_size; -+ bool buf_allocated = false; -+ -+ buf = get_data_section_size(region, data_offset, sz, &sec_size); -+ -+ if (!buf) { -+ buf = g_try_malloc(sec_size); -+ if (!buf) { -+ error_report("%s: Error allocating buffer ", __func__); -+ return -ENOMEM; -+ } -+ buf_allocated = true; -+ -+ ret = vfio_mig_read(vbasedev, buf, sec_size, -+ region->fd_offset + data_offset); -+ if (ret < 0) { -+ g_free(buf); -+ return ret; -+ } -+ } -+ -+ qemu_put_buffer(f, buf, sec_size); -+ -+ if (buf_allocated) { -+ g_free(buf); -+ } -+ sz -= sec_size; -+ data_offset += sec_size; -+ } -+ -+ ret = qemu_file_get_error(f); -+ -+ if (!ret && size) { -+ *size = data_size; -+ } -+ -+ return ret; -+} -+ -+static int vfio_update_pending(VFIODevice *vbasedev) -+{ -+ VFIOMigration *migration = vbasedev->migration; -+ VFIORegion *region = &migration->region; -+ uint64_t pending_bytes = 0; -+ int ret; -+ -+ ret = vfio_mig_read(vbasedev, &pending_bytes, sizeof(pending_bytes), -+ region->fd_offset + VFIO_MIG_STRUCT_OFFSET(pending_bytes)); -+ if (ret < 0) { -+ migration->pending_bytes = 0; -+ return ret; -+ } -+ -+ migration->pending_bytes = pending_bytes; -+ trace_vfio_update_pending(vbasedev->name, pending_bytes); -+ return 0; -+} -+ -+static int vfio_save_device_config_state(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_CONFIG_STATE); -+ -+ if (vbasedev->ops && vbasedev->ops->vfio_save_config) { -+ vbasedev->ops->vfio_save_config(vbasedev, f); -+ } -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); -+ -+ trace_vfio_save_device_config_state(vbasedev->name); -+ -+ return qemu_file_get_error(f); -+} -+ - static void vfio_migration_cleanup(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; -@@ -210,9 +355,140 @@ static void vfio_save_cleanup(void *opaque) - trace_vfio_save_cleanup(vbasedev->name); - } - -+static void vfio_save_pending(QEMUFile *f, void *opaque, -+ uint64_t threshold_size, -+ uint64_t *res_precopy_only, -+ uint64_t *res_compatible, -+ uint64_t *res_postcopy_only) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ int ret; -+ -+ ret = vfio_update_pending(vbasedev); -+ if (ret) { -+ return; -+ } -+ -+ *res_precopy_only += migration->pending_bytes; -+ -+ trace_vfio_save_pending(vbasedev->name, *res_precopy_only, -+ *res_postcopy_only, *res_compatible); -+} -+ -+static int vfio_save_iterate(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ uint64_t data_size; -+ int ret; -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); -+ -+ if (migration->pending_bytes == 0) { -+ ret = vfio_update_pending(vbasedev); -+ if (ret) { -+ return ret; -+ } -+ -+ if (migration->pending_bytes == 0) { -+ qemu_put_be64(f, 0); -+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); -+ /* indicates data finished, goto complete phase */ -+ return 1; -+ } -+ } -+ -+ ret = vfio_save_buffer(f, vbasedev, &data_size); -+ if (ret) { -+ error_report("%s: vfio_save_buffer failed %s", vbasedev->name, -+ strerror(errno)); -+ return ret; -+ } -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); -+ -+ ret = qemu_file_get_error(f); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Reset pending_bytes as .save_live_pending is not called during savevm or -+ * snapshot case, in such case vfio_update_pending() at the start of this -+ * function updates pending_bytes. -+ */ -+ migration->pending_bytes = 0; -+ trace_vfio_save_iterate(vbasedev->name, data_size); -+ return 0; -+} -+ -+static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ uint64_t data_size; -+ int ret; -+ -+ ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_RUNNING, -+ VFIO_DEVICE_STATE_SAVING); -+ if (ret) { -+ error_report("%s: Failed to set state STOP and SAVING", -+ vbasedev->name); -+ return ret; -+ } -+ -+ ret = vfio_save_device_config_state(f, opaque); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = vfio_update_pending(vbasedev); -+ if (ret) { -+ return ret; -+ } -+ -+ while (migration->pending_bytes > 0) { -+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); -+ ret = vfio_save_buffer(f, vbasedev, &data_size); -+ if (ret < 0) { -+ error_report("%s: Failed to save buffer", vbasedev->name); -+ return ret; -+ } -+ -+ if (data_size == 0) { -+ break; -+ } -+ -+ ret = vfio_update_pending(vbasedev); -+ if (ret) { -+ return ret; -+ } -+ } -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); -+ -+ ret = qemu_file_get_error(f); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_SAVING, 0); -+ if (ret) { -+ error_report("%s: Failed to set state STOPPED", vbasedev->name); -+ return ret; -+ } -+ -+ trace_vfio_save_complete_precopy(vbasedev->name); -+ return ret; -+} -+ - static SaveVMHandlers savevm_vfio_handlers = { - .save_setup = vfio_save_setup, - .save_cleanup = vfio_save_cleanup, -+ .save_live_pending = vfio_save_pending, -+ .save_live_iterate = vfio_save_iterate, -+ .save_live_complete_precopy = vfio_save_complete_precopy, - }; - - /* ---------------------------------------------------------------------- */ -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 86c18def01..9a1c5e17d9 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -151,3 +151,9 @@ vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t - vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" - vfio_save_setup(const char *name) " (%s)" - vfio_save_cleanup(const char *name) " (%s)" -+vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 -+vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 -+vfio_save_device_config_state(const char *name) " (%s)" -+vfio_save_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 -+vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" -+vfio_save_complete_precopy(const char *name) " (%s)" -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index efff0590ae..c825524606 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -65,6 +65,7 @@ typedef struct VFIOMigration { - uint32_t device_state; - int vm_running; - Notifier migration_state; -+ uint64_t pending_bytes; - } VFIOMigration; - - typedef struct VFIOAddressSpace { --- -2.27.0 - diff --git a/vfio-Add-vfio_get_object-callback-to-VFIODeviceOps.patch b/vfio-Add-vfio_get_object-callback-to-VFIODeviceOps.patch deleted file mode 100644 index e13a1daf40d518a550e8af5618b2d2b537cb43cc..0000000000000000000000000000000000000000 --- a/vfio-Add-vfio_get_object-callback-to-VFIODeviceOps.patch +++ /dev/null @@ -1,55 +0,0 @@ -From c1de789d89132b66243fbfe253f10764ce514a08 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:12 +0530 -Subject: [PATCH] vfio: Add vfio_get_object callback to VFIODeviceOps - -Hook vfio_get_object callback for PCI devices. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Suggested-by: Cornelia Huck -Reviewed-by: Cornelia Huck -Signed-off-by: Alex Williamson ---- - hw/vfio/pci.c | 8 ++++++++ - include/hw/vfio/vfio-common.h | 1 + - 2 files changed, 9 insertions(+) - -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index d7a4e1875c..de0d286fc9 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -2388,10 +2388,18 @@ static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev) - } - } - -+static Object *vfio_pci_get_object(VFIODevice *vbasedev) -+{ -+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); -+ -+ return OBJECT(vdev); -+} -+ - static VFIODeviceOps vfio_pci_ops = { - .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, - .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, - .vfio_eoi = vfio_intx_eoi, -+ .vfio_get_object = vfio_pci_get_object, - }; - - int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 93493891ba..771b6d59a3 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -119,6 +119,7 @@ struct VFIODeviceOps { - void (*vfio_compute_needs_reset)(VFIODevice *vdev); - int (*vfio_hot_reset_multi)(VFIODevice *vdev); - void (*vfio_eoi)(VFIODevice *vdev); -+ Object *(*vfio_get_object)(VFIODevice *vdev); - }; - - typedef struct VFIOGroup { --- -2.27.0 - diff --git a/vfio-Add-vfio_listener_log_sync-to-mark-dirty-pages.patch b/vfio-Add-vfio_listener_log_sync-to-mark-dirty-pages.patch deleted file mode 100644 index 6479a2550592f6eff10e6c244ed3648d887ed1a6..0000000000000000000000000000000000000000 --- a/vfio-Add-vfio_listener_log_sync-to-mark-dirty-pages.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 3ac0647003d192579bcb6c1081b75d9c8ada78e0 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:23 +0530 -Subject: [PATCH] vfio: Add vfio_listener_log_sync to mark dirty pages - -vfio_listener_log_sync gets list of dirty pages from container using -VFIO_IOMMU_GET_DIRTY_BITMAP ioctl and mark those pages dirty when all -devices are stopped and saving state. -Return early for the RAM block section of mapped MMIO region. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -[aw: fix error_report types, fix cpu_physical_memory_set_dirty_lebitmap() cast] -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 116 +++++++++++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 1 + - 2 files changed, 117 insertions(+) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 35168b8f3e..4d2828fc97 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -29,6 +29,7 @@ - #include "hw/vfio/vfio.h" - #include "exec/address-spaces.h" - #include "exec/memory.h" -+#include "exec/ram_addr.h" - #include "hw/hw.h" - #include "qemu/error-report.h" - #include "qemu/range.h" -@@ -36,6 +37,7 @@ - #include "sysemu/kvm.h" - #include "trace.h" - #include "qapi/error.h" -+#include "migration/migration.h" - - VFIOGroupList vfio_group_list = - QLIST_HEAD_INITIALIZER(vfio_group_list); -@@ -285,6 +287,39 @@ const MemoryRegionOps vfio_region_ops = { - }, - }; - -+/* -+ * Device state interfaces -+ */ -+ -+static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) -+{ -+ VFIOGroup *group; -+ VFIODevice *vbasedev; -+ MigrationState *ms = migrate_get_current(); -+ -+ if (!migration_is_setup_or_active(ms->state)) { -+ return false; -+ } -+ -+ QLIST_FOREACH(group, &container->group_list, container_next) { -+ QLIST_FOREACH(vbasedev, &group->device_list, next) { -+ VFIOMigration *migration = vbasedev->migration; -+ -+ if (!migration) { -+ return false; -+ } -+ -+ if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && -+ !(migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { -+ continue; -+ } else { -+ return false; -+ } -+ } -+ } -+ return true; -+} -+ - /* - * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 - */ -@@ -794,9 +829,90 @@ static void vfio_listener_region_del(MemoryListener *listener, - } - } - -+static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, -+ uint64_t size, ram_addr_t ram_addr) -+{ -+ struct vfio_iommu_type1_dirty_bitmap *dbitmap; -+ struct vfio_iommu_type1_dirty_bitmap_get *range; -+ uint64_t pages; -+ int ret; -+ -+ dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); -+ -+ dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); -+ dbitmap->flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP; -+ range = (struct vfio_iommu_type1_dirty_bitmap_get *)&dbitmap->data; -+ range->iova = iova; -+ range->size = size; -+ -+ /* -+ * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -+ * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap's pgsize to -+ * TARGET_PAGE_SIZE. -+ */ -+ range->bitmap.pgsize = TARGET_PAGE_SIZE; -+ -+ pages = TARGET_PAGE_ALIGN(range->size) >> TARGET_PAGE_BITS; -+ range->bitmap.size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / -+ BITS_PER_BYTE; -+ range->bitmap.data = g_try_malloc0(range->bitmap.size); -+ if (!range->bitmap.data) { -+ ret = -ENOMEM; -+ goto err_out; -+ } -+ -+ ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, dbitmap); -+ if (ret) { -+ error_report("Failed to get dirty bitmap for iova: 0x%"PRIx64 -+ " size: 0x%"PRIx64" err: %d", (uint64_t)range->iova, -+ (uint64_t)range->size, errno); -+ goto err_out; -+ } -+ -+ cpu_physical_memory_set_dirty_lebitmap((unsigned long *)range->bitmap.data, -+ ram_addr, pages); -+ -+ trace_vfio_get_dirty_bitmap(container->fd, range->iova, range->size, -+ range->bitmap.size, ram_addr); -+err_out: -+ g_free(range->bitmap.data); -+ g_free(dbitmap); -+ -+ return ret; -+} -+ -+static int vfio_sync_dirty_bitmap(VFIOContainer *container, -+ MemoryRegionSection *section) -+{ -+ ram_addr_t ram_addr; -+ -+ ram_addr = memory_region_get_ram_addr(section->mr) + -+ section->offset_within_region; -+ -+ return vfio_get_dirty_bitmap(container, -+ TARGET_PAGE_ALIGN(section->offset_within_address_space), -+ int128_get64(section->size), ram_addr); -+} -+ -+static void vfio_listerner_log_sync(MemoryListener *listener, -+ MemoryRegionSection *section) -+{ -+ VFIOContainer *container = container_of(listener, VFIOContainer, listener); -+ -+ if (vfio_listener_skipped_section(section) || -+ !container->dirty_pages_supported) { -+ return; -+ } -+ -+ if (vfio_devices_all_stopped_and_saving(container)) { -+ vfio_sync_dirty_bitmap(container, section); -+ } -+} -+ - static const MemoryListener vfio_memory_listener = { - .region_add = vfio_listener_region_add, - .region_del = vfio_listener_region_del, -+ .log_sync = vfio_listerner_log_sync, - }; - - static void vfio_listener_release(VFIOContainer *container) -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 4f08f5a633..4167f35d64 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -161,3 +161,4 @@ vfio_load_device_config_state(const char *name) " (%s)" - vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 - vfio_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 - vfio_load_cleanup(const char *name) " (%s)" -+vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 --- -2.27.0 - diff --git a/vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch b/vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch index 289638a9e3c453dfe9fa9e863209ddbd5ea0489f..962266210c9ed50027a893c453b59313f4fedc56 100644 --- a/vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch +++ b/vfio-Add-vfio_prereg_listener_global_log_start-stop-.patch @@ -1,4 +1,4 @@ -From 6aa770f4b83ca068d0c8f3102edda32666a8404d Mon Sep 17 00:00:00 2001 +From 287c63ab540533f1f9642e753c091caa7e6e2511 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 11 May 2021 10:08:15 +0800 Subject: [PATCH] vfio: Add vfio_prereg_listener_global_log_start/stop in @@ -18,10 +18,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 24 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index b5f9ba816e..fb7ca63748 100644 +index 20c820aa74..65f3979492 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1239,6 +1239,17 @@ static void vfio_listener_log_global_start(MemoryListener *listener) +@@ -1501,6 +1501,17 @@ static void vfio_listener_log_global_start(MemoryListener *listener) { VFIOContainer *container = container_of(listener, VFIOContainer, listener); @@ -39,7 +39,7 @@ index b5f9ba816e..fb7ca63748 100644 vfio_set_dirty_page_tracking(container, true); } -@@ -1246,6 +1257,17 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) +@@ -1508,6 +1519,17 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) { VFIOContainer *container = container_of(listener, VFIOContainer, listener); @@ -57,7 +57,7 @@ index b5f9ba816e..fb7ca63748 100644 vfio_set_dirty_page_tracking(container, false); } -@@ -1614,6 +1636,8 @@ static const MemoryListener vfio_memory_listener = { +@@ -1922,6 +1944,8 @@ static const MemoryListener vfio_memory_listener = { static MemoryListener vfio_memory_prereg_listener = { .region_add = vfio_prereg_listener_region_add, .region_del = vfio_prereg_listener_region_del, diff --git a/vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch b/vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch index e4da89bd477558ea9e58538c75b0c198d27e3d21..a055ed555f3a7fa213a8c16b4983a139de590ec0 100644 --- a/vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch +++ b/vfio-Add-vfio_prereg_listener_log_clear-to-re-enable.patch @@ -1,4 +1,4 @@ -From f959faa36fc100894a44f2e6cd7e02a183ba142a Mon Sep 17 00:00:00 2001 +From 7086df6d90cd698a3e20cf4cf6e9a834f168cd8f Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Sat, 31 Jul 2021 09:40:24 +0800 Subject: [PATCH] vfio: Add vfio_prereg_listener_log_clear to re-enable mark @@ -15,10 +15,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 6b00bd4c2f..b5f9ba816e 100644 +index 2506cd57ee..20c820aa74 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1550,6 +1550,43 @@ static int vfio_physical_log_clear(VFIOContainer *container, +@@ -1857,6 +1857,43 @@ static int vfio_physical_log_clear(VFIOContainer *container, return ret; } @@ -62,7 +62,7 @@ index 6b00bd4c2f..b5f9ba816e 100644 static void vfio_listener_log_clear(MemoryListener *listener, MemoryRegionSection *section) { -@@ -1561,7 +1598,7 @@ static void vfio_listener_log_clear(MemoryListener *listener, +@@ -1868,7 +1905,7 @@ static void vfio_listener_log_clear(MemoryListener *listener, } if (vfio_devices_all_dirty_tracking(container)) { @@ -71,7 +71,7 @@ index 6b00bd4c2f..b5f9ba816e 100644 } } -@@ -1578,6 +1615,7 @@ static MemoryListener vfio_memory_prereg_listener = { +@@ -1886,6 +1923,7 @@ static MemoryListener vfio_memory_prereg_listener = { .region_add = vfio_prereg_listener_region_add, .region_del = vfio_prereg_listener_region_del, .log_sync = vfio_prereg_listener_log_sync, diff --git a/vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch b/vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch index 77a0c8a14d29280b369466b1fa9b55dc62c26228..b1df5a3801a75edaedde9968fbb8db92713dfbd5 100644 --- a/vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch +++ b/vfio-Add-vfio_prereg_listener_log_sync-in-nested-sta.patch @@ -1,4 +1,4 @@ -From 4c5350044ac2f61ab8088278b59eb6388ca49ff1 Mon Sep 17 00:00:00 2001 +From f4523389bf57593484308124e06d67855bb79315 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 11 May 2021 10:08:14 +0800 Subject: [PATCH] vfio: Add vfio_prereg_listener_log_sync in nested stage @@ -18,10 +18,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 27 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 5176fd3a3d..6b00bd4c2f 100644 +index 6136b1ef61..2506cd57ee 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1317,6 +1317,22 @@ static int vfio_dma_sync_ram_section_dirty_bitmap(VFIOContainer *container, +@@ -1579,6 +1579,22 @@ static int vfio_dma_sync_ram_section_dirty_bitmap(VFIOContainer *container, int128_get64(section->size), ram_addr); } @@ -44,7 +44,7 @@ index 5176fd3a3d..6b00bd4c2f 100644 typedef struct { IOMMUNotifier n; VFIOGuestIOMMU *giommu; -@@ -1361,6 +1377,16 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, +@@ -1666,6 +1682,16 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, if (memory_region_is_iommu(section->mr)) { VFIOGuestIOMMU *giommu; @@ -61,7 +61,7 @@ index 5176fd3a3d..6b00bd4c2f 100644 QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { if (MEMORY_REGION(giommu->iommu) == section->mr && giommu->n.start == section->offset_within_region) { -@@ -1551,6 +1577,7 @@ static const MemoryListener vfio_memory_listener = { +@@ -1859,6 +1885,7 @@ static const MemoryListener vfio_memory_listener = { static MemoryListener vfio_memory_prereg_listener = { .region_add = vfio_prereg_listener_region_add, .region_del = vfio_prereg_listener_region_del, diff --git a/vfio-Avoid-disabling-and-enabling-vectors-repeatedly.patch b/vfio-Avoid-disabling-and-enabling-vectors-repeatedly.patch deleted file mode 100644 index e65b3a8fe54f0fbc3fc5a00949632e67798ce788..0000000000000000000000000000000000000000 --- a/vfio-Avoid-disabling-and-enabling-vectors-repeatedly.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 8113fdcf0c1383ae5b9542563656bea3753d834e Mon Sep 17 00:00:00 2001 -From: Shenming Lu -Date: Wed, 10 Mar 2021 11:02:33 +0800 -Subject: [PATCH] vfio: Avoid disabling and enabling vectors repeatedly in VFIO - migration - -In VFIO migration resume phase and some guest startups, there are -already unmasked vectors in the vector table when calling -vfio_msix_enable(). So in order to avoid inefficiently disabling -and enabling vectors repeatedly, let's allocate all needed vectors -first and then enable these unmasked vectors one by one without -disabling. - -Signed-off-by: Shenming Lu -Message-Id: <20210310030233.1133-4-lushenming@huawei.com> -Signed-off-by: Alex Williamson ---- - hw/vfio/pci.c | 20 +++++++++++++++++--- - 1 file changed, 17 insertions(+), 3 deletions(-) - -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index a637c35e7a..da7c740bce 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -563,6 +563,9 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) - - static void vfio_msix_enable(VFIOPCIDevice *vdev) - { -+ PCIDevice *pdev = &vdev->pdev; -+ unsigned int nr, max_vec = 0; -+ - vfio_disable_interrupts(vdev); - - vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries); -@@ -581,11 +584,22 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) - * triggering to userspace, then immediately release the vector, leaving - * the physical device with no vectors enabled, but MSI-X enabled, just - * like the guest view. -+ * If there are already unmasked vectors (in migration resume phase and -+ * some guest startups) which will be enabled soon, we can allocate all -+ * of them here to avoid inefficiently disabling and enabling vectors -+ * repeatedly later. - */ -- vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); -- vfio_msix_vector_release(&vdev->pdev, 0); -+ if (!pdev->msix_function_masked) { -+ for (nr = 0; nr < msix_nr_vectors_allocated(pdev); nr++) { -+ if (!msix_is_masked(pdev, nr)) { -+ max_vec = nr; -+ } -+ } -+ } -+ vfio_msix_vector_do_use(pdev, max_vec, NULL, NULL); -+ vfio_msix_vector_release(pdev, max_vec); - -- if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, -+ if (msix_set_vector_notifiers(pdev, vfio_msix_vector_use, - vfio_msix_vector_release, NULL)) { - error_report("vfio: msix_set_vector_notifiers failed"); - } --- -2.27.0 - diff --git a/vfio-Change-default-dirty-pages-tracking-behavior-du.patch b/vfio-Change-default-dirty-pages-tracking-behavior-du.patch deleted file mode 100644 index d34f0541c8589124e35a10bb220be59e64f21e53..0000000000000000000000000000000000000000 --- a/vfio-Change-default-dirty-pages-tracking-behavior-du.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 69d1cc17c0a77dbd0d8e811cfaa899b01bf2e5bc Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 23 Nov 2020 19:53:19 +0530 -Subject: [PATCH] vfio: Change default dirty pages tracking behavior during - migration - -By default dirty pages tracking is enabled during iterative phase -(pre-copy phase). -Added per device opt-out option 'x-pre-copy-dirty-page-tracking' to -disable dirty pages tracking during iterative phase. If the option -'x-pre-copy-dirty-page-tracking=off' is set for any VFIO device, dirty -pages tracking during iterative phase will be disabled. - -Signed-off-by: Kirti Wankhede -Signed-off-by: Alex Williamson -Signed-off-by: Kunkun Jiang ---- - hw/vfio/common.c | 11 +++++++---- - hw/vfio/pci.c | 3 +++ - include/hw/vfio/vfio-common.h | 1 + - 3 files changed, 11 insertions(+), 4 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index a86a4c4506..d9cc3509ef 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -310,7 +310,7 @@ bool vfio_mig_active(void) - return true; - } - --static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) -+static bool vfio_devices_all_saving(VFIOContainer *container) - { - VFIOGroup *group; - VFIODevice *vbasedev; -@@ -328,8 +328,11 @@ static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) - return false; - } - -- if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && -- !(migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { -+ if (migration->device_state & VFIO_DEVICE_STATE_SAVING) { -+ if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) -+ && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { -+ return false; -+ } - continue; - } else { - return false; -@@ -1088,7 +1091,7 @@ static void vfio_listerner_log_sync(MemoryListener *listener, - return; - } - -- if (vfio_devices_all_stopped_and_saving(container)) { -+ if (vfio_devices_all_saving(container)) { - vfio_sync_dirty_bitmap(container, section); - } - } -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 2795b8bd12..3641ad0c5c 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -3180,6 +3180,9 @@ static void vfio_instance_init(Object *obj) - static Property vfio_pci_dev_properties[] = { - DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), - DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev), -+ DEFINE_PROP_ON_OFF_AUTO("x-pre-copy-dirty-page-tracking", VFIOPCIDevice, -+ vbasedev.pre_copy_dirty_page_tracking, -+ ON_OFF_AUTO_ON), - DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice, - display, ON_OFF_AUTO_OFF), - DEFINE_PROP_UINT32("xres", VFIOPCIDevice, display_xres, 0), -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 7398631d4c..475aa9fb40 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -130,6 +130,7 @@ typedef struct VFIODevice { - unsigned int flags; - VFIOMigration *migration; - Error *migration_blocker; -+ OnOffAuto pre_copy_dirty_page_tracking; - } VFIODevice; - - struct VFIODeviceOps { --- -2.27.0 - diff --git a/vfio-Dirty-page-tracking-when-vIOMMU-is-enabled.patch b/vfio-Dirty-page-tracking-when-vIOMMU-is-enabled.patch deleted file mode 100644 index 65949f079ed1eb2baea2e626fbd4d6140d23350c..0000000000000000000000000000000000000000 --- a/vfio-Dirty-page-tracking-when-vIOMMU-is-enabled.patch +++ /dev/null @@ -1,162 +0,0 @@ -From a400753d0f1a008367165aadf375abfe86a66ed7 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:24 +0530 -Subject: [PATCH] vfio: Dirty page tracking when vIOMMU is enabled - -When vIOMMU is enabled, register MAP notifier from log_sync when all -devices in container are in stop and copy phase of migration. Call replay -and get dirty pages from notifier callback. - -Suggested-by: Alex Williamson -Signed-off-by: Kirti Wankhede -Reviewed-by: Yan Zhao -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 88 +++++++++++++++++++++++++++++++++++++++++--- - hw/vfio/trace-events | 1 + - 2 files changed, 83 insertions(+), 6 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 4d2828fc97..8773b998ac 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -441,8 +441,8 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) - } - - /* Called with rcu_read_lock held. */ --static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, -- bool *read_only) -+static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, -+ ram_addr_t *ram_addr, bool *read_only) - { - MemoryRegion *mr; - hwaddr xlat; -@@ -473,8 +473,17 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, - return false; - } - -- *vaddr = memory_region_get_ram_ptr(mr) + xlat; -- *read_only = !writable || mr->readonly; -+ if (vaddr) { -+ *vaddr = memory_region_get_ram_ptr(mr) + xlat; -+ } -+ -+ if (ram_addr) { -+ *ram_addr = memory_region_get_ram_addr(mr) + xlat; -+ } -+ -+ if (read_only) { -+ *read_only = !writable || mr->readonly; -+ } - - return true; - } -@@ -484,7 +493,6 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) - VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); - VFIOContainer *container = giommu->container; - hwaddr iova = iotlb->iova + giommu->iommu_offset; -- bool read_only; - void *vaddr; - int ret; - -@@ -500,7 +508,9 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) - rcu_read_lock(); - - if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { -- if (!vfio_get_vaddr(iotlb, &vaddr, &read_only)) { -+ bool read_only; -+ -+ if (!vfio_get_xlat_addr(iotlb, &vaddr, NULL, &read_only)) { - goto out; - } - /* -@@ -881,11 +891,77 @@ err_out: - return ret; - } - -+typedef struct { -+ IOMMUNotifier n; -+ VFIOGuestIOMMU *giommu; -+} vfio_giommu_dirty_notifier; -+ -+static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) -+{ -+ vfio_giommu_dirty_notifier *gdn = container_of(n, -+ vfio_giommu_dirty_notifier, n); -+ VFIOGuestIOMMU *giommu = gdn->giommu; -+ VFIOContainer *container = giommu->container; -+ hwaddr iova = iotlb->iova + giommu->iommu_offset; -+ ram_addr_t translated_addr; -+ -+ trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); -+ -+ if (iotlb->target_as != &address_space_memory) { -+ error_report("Wrong target AS \"%s\", only system memory is allowed", -+ iotlb->target_as->name ? iotlb->target_as->name : "none"); -+ return; -+ } -+ -+ rcu_read_lock(); -+ if (vfio_get_xlat_addr(iotlb, NULL, &translated_addr, NULL)) { -+ int ret; -+ -+ ret = vfio_get_dirty_bitmap(container, iova, iotlb->addr_mask + 1, -+ translated_addr); -+ if (ret) { -+ error_report("vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " -+ "0x%"HWADDR_PRIx") = %d (%m)", -+ container, iova, -+ iotlb->addr_mask + 1, ret); -+ } -+ } -+ rcu_read_unlock(); -+} -+ - static int vfio_sync_dirty_bitmap(VFIOContainer *container, - MemoryRegionSection *section) - { - ram_addr_t ram_addr; - -+ if (memory_region_is_iommu(section->mr)) { -+ VFIOGuestIOMMU *giommu; -+ -+ QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { -+ if (MEMORY_REGION(giommu->iommu) == section->mr && -+ giommu->n.start == section->offset_within_region) { -+ Int128 llend; -+ vfio_giommu_dirty_notifier gdn = { .giommu = giommu }; -+ int idx = memory_region_iommu_attrs_to_index(giommu->iommu, -+ MEMTXATTRS_UNSPECIFIED); -+ -+ llend = int128_add(int128_make64(section->offset_within_region), -+ section->size); -+ llend = int128_sub(llend, int128_one()); -+ -+ iommu_notifier_init(&gdn.n, -+ vfio_iommu_map_dirty_notify, -+ IOMMU_NOTIFIER_MAP, -+ section->offset_within_region, -+ int128_get64(llend), -+ idx); -+ memory_region_iommu_replay(giommu->iommu, &gdn.n); -+ break; -+ } -+ } -+ return 0; -+ } -+ - ram_addr = memory_region_get_ram_addr(section->mr) + - section->offset_within_region; - -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 4167f35d64..575ebde6e0 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -162,3 +162,4 @@ vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 - vfio_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 - vfio_load_cleanup(const char *name) " (%s)" - vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 -+vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 --- -2.27.0 - diff --git a/vfio-Fix-unregister-SaveVMHandler-in-vfio_migration_.patch b/vfio-Fix-unregister-SaveVMHandler-in-vfio_migration_.patch deleted file mode 100644 index 47d59923070d7827152f59a60304ef708bcc1c62..0000000000000000000000000000000000000000 --- a/vfio-Fix-unregister-SaveVMHandler-in-vfio_migration_.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8dc6e7ccc5712aee457ffb1f6cf1bf3f80e778d5 Mon Sep 17 00:00:00 2001 -From: Kunkun Jiang -Date: Thu, 27 May 2021 20:31:01 +0800 -Subject: [PATCH] vfio: Fix unregister SaveVMHandler in vfio_migration_finalize - -In the vfio_migration_init(), the SaveVMHandler is registered for -VFIO device. But it lacks the operation of 'unregister'. It will -lead to 'Segmentation fault (core dumped)' in -qemu_savevm_state_setup(), if performing live migration after a -VFIO device is hot deleted. - -Fixes: cd5b58f2ba (vfio: Register SaveVMHandlers for VFIO device) -Reported-by: Qixin Gan -Signed-off-by: Kunkun Jiang -Message-Id: <20210527123101.289-1-jiangkunkun@huawei.com> -Reviewed by: Kirti Wankhede -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index f1f006d584..d9e0e12824 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -893,6 +893,7 @@ void vfio_migration_finalize(VFIODevice *vbasedev) - - remove_migration_state_change_notifier(&migration->migration_state); - qemu_del_vm_change_state_handler(migration->vm_state); -+ unregister_savevm(vbasedev->dev, "vfio", vbasedev); - vfio_migration_exit(vbasedev); - } - --- -2.27.0 - diff --git a/vfio-Fix-vfio_get_dev_region-trace-event.patch b/vfio-Fix-vfio_get_dev_region-trace-event.patch new file mode 100644 index 0000000000000000000000000000000000000000..c165db9ba7e653d02893c32fb10a8adda6b255a0 --- /dev/null +++ b/vfio-Fix-vfio_get_dev_region-trace-event.patch @@ -0,0 +1,41 @@ +From e2ceb2def76cc917d3165a804025e630c3bedad1 Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Wed, 2 Aug 2023 19:08:05 -0700 +Subject: [PATCH] vfio: Fix vfio_get_dev_region() trace event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 969dae5448eaa2914be5b974f9e0311b3f95ee2c + +Simply transpose 'x8' to fix the typo and remove the ending '8' + +Fixes: e61a424f05 ("vfio: Create device specific region info helper") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1526 +Signed-off-by: Cédric Le Goater +Reviewed-by: Philippe Mathieu-Daudé +Link: https://lore.kernel.org/r/20230303074330.2609377-1-clg@kaod.org +[aw: commit log s/revert/transpose/] +Signed-off-by: Alex Williamson + +Signed-off-by: Wanghe Xiao +--- + hw/vfio/trace-events | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index 0ef1b5f4a6..f4b74a3e81 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -116,7 +116,7 @@ vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps e + vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Region %s unmap [0x%lx - 0x%lx]" + vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" + vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" +-vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" ++vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" + vfio_dma_unmap_overflow_workaround(void) "" + + # platform.c +-- +2.41.0.windows.1 + diff --git a/vfio-Fix-vfio_listener_log_sync-function-name-typo.patch b/vfio-Fix-vfio_listener_log_sync-function-name-typo.patch deleted file mode 100644 index 6a2324b57811f6d375bbc7f795dc07f78baa42e2..0000000000000000000000000000000000000000 --- a/vfio-Fix-vfio_listener_log_sync-function-name-typo.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 094aca3a87e63a0e6ae01b22f382c21dd91bb03e Mon Sep 17 00:00:00 2001 -From: Zenghui Yu -Date: Fri, 4 Dec 2020 09:42:40 +0800 -Subject: [PATCH] vfio: Fix vfio_listener_log_sync function name typo - -There is an obvious typo in the function name of the .log_sync() callback. -Spell it correctly. - -Signed-off-by: Zenghui Yu -Message-Id: <20201204014240.772-1-yuzenghui@huawei.com> -Signed-off-by: Alex Williamson -Signed-off-by: Kunkun Jiang ---- - hw/vfio/common.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index d9cc3509ef..ebd701faa0 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -1081,7 +1081,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, - int128_get64(section->size), ram_addr); - } - --static void vfio_listerner_log_sync(MemoryListener *listener, -+static void vfio_listener_log_sync(MemoryListener *listener, - MemoryRegionSection *section) - { - VFIOContainer *container = container_of(listener, VFIOContainer, listener); -@@ -1099,7 +1099,7 @@ static void vfio_listerner_log_sync(MemoryListener *listener, - static const MemoryListener vfio_memory_listener = { - .region_add = vfio_listener_region_add, - .region_del = vfio_listener_region_del, -- .log_sync = vfio_listerner_log_sync, -+ .log_sync = vfio_listener_log_sync, - }; - - static void vfio_listener_release(VFIOContainer *container) --- -2.27.0 - diff --git a/vfio-Force-nested-if-iommu-requires-it.patch b/vfio-Force-nested-if-iommu-requires-it.patch index 6a6b9da3f1ebd6c44f6a298a9c456351a8a93fcd..d580ae5007f6ae7be2adb090d9e6774eeeb323db 100644 --- a/vfio-Force-nested-if-iommu-requires-it.patch +++ b/vfio-Force-nested-if-iommu-requires-it.patch @@ -1,4 +1,4 @@ -From e4122a95a30cd58e1cd6e1742928e68aa94fd7ee Mon Sep 17 00:00:00 2001 +From e7eef5af743a53f0415267ebe9bba2e5f0e05816 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 28 Aug 2018 16:16:20 +0200 Subject: [PATCH] vfio: Force nested if iommu requires it @@ -15,10 +15,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index fefa2ccfdf..c78b58d365 100644 +index 6cb91e7ffd..d7533637c9 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1683,27 +1683,38 @@ static void vfio_put_address_space(VFIOAddressSpace *space) +@@ -2045,27 +2045,38 @@ static void vfio_put_address_space(VFIOAddressSpace *space) * vfio_get_iommu_type - selects the richest iommu_type (v2 first) */ static int vfio_get_iommu_type(VFIOContainer *container, @@ -64,7 +64,7 @@ index fefa2ccfdf..c78b58d365 100644 if (iommu_type < 0) { return iommu_type; } -@@ -1815,6 +1826,14 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, +@@ -2177,6 +2188,14 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, VFIOContainer *container; int ret, fd; VFIOAddressSpace *space; @@ -79,8 +79,8 @@ index fefa2ccfdf..c78b58d365 100644 space = vfio_get_address_space(as); -@@ -1879,13 +1898,14 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - QLIST_INIT(&container->hostwin_list); +@@ -2257,7 +2276,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + QLIST_INIT(&container->vrdl_list); QLIST_INIT(&container->dma_list); - ret = vfio_init_container(container, group->fd, errp); @@ -88,7 +88,8 @@ index fefa2ccfdf..c78b58d365 100644 if (ret) { goto free_container_exit; } - trace_vfio_connect_new_container(group->groupid, container->fd); +@@ -2269,6 +2288,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + } switch (container->iommu_type) { + case VFIO_TYPE1_NESTING_IOMMU: diff --git a/vfio-Get-migration-capability-flags-for-container.patch b/vfio-Get-migration-capability-flags-for-container.patch deleted file mode 100644 index 88b9bb7e6fdfe4f4a75808bbdcb5ec45d354ae15..0000000000000000000000000000000000000000 --- a/vfio-Get-migration-capability-flags-for-container.patch +++ /dev/null @@ -1,186 +0,0 @@ -From fc49c9cbf2deba53370f48ad9db2adc5f6ceb3ba Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:21 +0530 -Subject: [PATCH] vfio: Get migration capability flags for container - -Added helper functions to get IOMMU info capability chain. -Added function to get migration capability information from that -capability chain for IOMMU container. - -Similar change was proposed earlier: -https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg03759.html - -Disable migration for devices if IOMMU module doesn't support migration -capability. - -Signed-off-by: Kirti Wankhede -Cc: Shameer Kolothum -Cc: Eric Auger -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 90 +++++++++++++++++++++++++++++++---- - hw/vfio/migration.c | 7 ++- - include/hw/vfio/vfio-common.h | 3 ++ - 3 files changed, 91 insertions(+), 9 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 4c32b1bb99..35168b8f3e 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -1210,6 +1210,75 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, - return 0; - } - -+static int vfio_get_iommu_info(VFIOContainer *container, -+ struct vfio_iommu_type1_info **info) -+{ -+ -+ size_t argsz = sizeof(struct vfio_iommu_type1_info); -+ -+ *info = g_new0(struct vfio_iommu_type1_info, 1); -+again: -+ (*info)->argsz = argsz; -+ -+ if (ioctl(container->fd, VFIO_IOMMU_GET_INFO, *info)) { -+ g_free(*info); -+ *info = NULL; -+ return -errno; -+ } -+ -+ if (((*info)->argsz > argsz)) { -+ argsz = (*info)->argsz; -+ *info = g_realloc(*info, argsz); -+ goto again; -+ } -+ -+ return 0; -+} -+ -+static struct vfio_info_cap_header * -+vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) -+{ -+ struct vfio_info_cap_header *hdr; -+ void *ptr = info; -+ -+ if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { -+ return NULL; -+ } -+ -+ for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { -+ if (hdr->id == id) { -+ return hdr; -+ } -+ } -+ -+ return NULL; -+} -+ -+static void vfio_get_iommu_info_migration(VFIOContainer *container, -+ struct vfio_iommu_type1_info *info) -+{ -+ struct vfio_info_cap_header *hdr; -+ struct vfio_iommu_type1_info_cap_migration *cap_mig; -+ -+ hdr = vfio_get_iommu_info_cap(info, VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION); -+ if (!hdr) { -+ return; -+ } -+ -+ cap_mig = container_of(hdr, struct vfio_iommu_type1_info_cap_migration, -+ header); -+ -+ /* -+ * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -+ * TARGET_PAGE_SIZE to mark those dirty. -+ */ -+ if (cap_mig->pgsize_bitmap & TARGET_PAGE_SIZE) { -+ container->dirty_pages_supported = true; -+ container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; -+ container->dirty_pgsizes = cap_mig->pgsize_bitmap; -+ } -+} -+ - static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - Error **errp) - { -@@ -1273,6 +1342,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - container = g_malloc0(sizeof(*container)); - container->space = space; - container->fd = fd; -+ container->dirty_pages_supported = false; - QLIST_INIT(&container->giommu_list); - QLIST_INIT(&container->hostwin_list); - -@@ -1285,7 +1355,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - case VFIO_TYPE1v2_IOMMU: - case VFIO_TYPE1_IOMMU: - { -- struct vfio_iommu_type1_info info; -+ struct vfio_iommu_type1_info *info; - - /* - * FIXME: This assumes that a Type1 IOMMU can map any 64-bit -@@ -1294,15 +1364,19 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - * existing Type1 IOMMUs generally support any IOVA we're - * going to actually try in practice. - */ -- info.argsz = sizeof(info); -- ret = ioctl(fd, VFIO_IOMMU_GET_INFO, &info); -- /* Ignore errors */ -- if (ret || !(info.flags & VFIO_IOMMU_INFO_PGSIZES)) { -+ ret = vfio_get_iommu_info(container, &info); -+ -+ if (ret || !(info->flags & VFIO_IOMMU_INFO_PGSIZES)) { - /* Assume 4k IOVA page size */ -- info.iova_pgsizes = 4096; -+ info->iova_pgsizes = 4096; - } -- vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); -- container->pgsizes = info.iova_pgsizes; -+ vfio_host_win_add(container, 0, (hwaddr)-1, info->iova_pgsizes); -+ container->pgsizes = info->iova_pgsizes; -+ -+ if (!ret) { -+ vfio_get_iommu_info_migration(container, info); -+ } -+ g_free(info); - break; - } - case VFIO_SPAPR_TCE_v2_IOMMU: -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 954c064435..0d2bd9e5cd 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -832,9 +832,14 @@ err: - - int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) - { -+ VFIOContainer *container = vbasedev->group->container; - struct vfio_region_info *info = NULL; - Error *local_err = NULL; -- int ret; -+ int ret = -ENOTSUP; -+ -+ if (!container->dirty_pages_supported) { -+ goto add_blocker; -+ } - - ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_MIGRATION, - VFIO_REGION_SUBTYPE_MIGRATION, &info); -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index c825524606..8fd0212264 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -84,6 +84,9 @@ typedef struct VFIOContainer { - unsigned iommu_type; - int error; - bool initialized; -+ bool dirty_pages_supported; -+ uint64_t dirty_pgsizes; -+ uint64_t max_dirty_bitmap_size; - unsigned long pgsizes; - QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; - QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; --- -2.27.0 - diff --git a/vfio-Helper-to-get-IRQ-info-including-capabilities.patch b/vfio-Helper-to-get-IRQ-info-including-capabilities.patch index 16f16d32faa4d793056700a52ef33b23716801c1..3d4b1667692bf76a3c89c71cd363db5090641986 100644 --- a/vfio-Helper-to-get-IRQ-info-including-capabilities.patch +++ b/vfio-Helper-to-get-IRQ-info-including-capabilities.patch @@ -1,4 +1,4 @@ -From 43fd039dcfee221eb3f86a2cf7deb287cc04e5ad Mon Sep 17 00:00:00 2001 +From a4336765c99a876743c0ead89997ad6f97d7b442 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 20 Jun 2019 16:39:57 +0200 Subject: [PATCH] vfio: Helper to get IRQ info including capabilities @@ -15,11 +15,11 @@ Signed-off-by: Kunkun Jiang 3 files changed, 105 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index db9af3b0e5..98dc9e6f84 100644 +index 1f78af121d..d05a485808 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1565,6 +1565,25 @@ vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) - return NULL; +@@ -1919,6 +1919,25 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + return true; } +struct vfio_info_cap_header * @@ -44,7 +44,7 @@ index db9af3b0e5..98dc9e6f84 100644 static int vfio_setup_region_sparse_mmaps(VFIORegion *region, struct vfio_region_info *info) { -@@ -2499,6 +2518,33 @@ retry: +@@ -2887,6 +2906,33 @@ retry: return 0; } @@ -78,7 +78,7 @@ index db9af3b0e5..98dc9e6f84 100644 int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info) { -@@ -2534,6 +2580,42 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, +@@ -2922,6 +2968,42 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, return -ENODEV; } @@ -121,7 +121,7 @@ index db9af3b0e5..98dc9e6f84 100644 bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) { struct vfio_region_info *info = NULL; -@@ -2549,6 +2631,21 @@ bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +@@ -2937,6 +3019,21 @@ bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) return ret; } @@ -144,7 +144,7 @@ index db9af3b0e5..98dc9e6f84 100644 * Interfaces for IBM EEH (Enhanced Error Handling) */ diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 247b72c1eb..54e10046f5 100644 +index 35bd415d6d..f5fe201ab5 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -117,6 +117,7 @@ vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Re @@ -156,13 +156,13 @@ index 247b72c1eb..54e10046f5 100644 vfio_iommu_addr_inv_iotlb(int asid, uint64_t addr, uint64_t size, uint64_t nb_granules, bool leaf) "nested IOTLB invalidate asid=%d, addr=0x%"PRIx64" granule_size=0x%"PRIx64" nb_granules=0x%"PRIx64" leaf=%d" vfio_iommu_asid_inv_iotlb(int asid) "nested IOTLB invalidate asid=%d" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index b175158138..a82962ab16 100644 +index a838a939e4..7fdca26fa0 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h -@@ -238,6 +238,13 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); +@@ -254,6 +254,13 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + unsigned int *avail); struct vfio_info_cap_header * - vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id); + vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); +int vfio_get_irq_info(VFIODevice *vbasedev, int index, + struct vfio_irq_info **info); +int vfio_get_dev_irq_info(VFIODevice *vbasedev, uint32_t type, diff --git a/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch b/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch index 124587d1e081a65740786aefbd1033d895678245..fd6deffd16ce01ee2a97e4061ac358e974a49320 100644 --- a/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch +++ b/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch @@ -1,4 +1,4 @@ -From eb3bfdb61025efe2891ce6732b8829a48dd75e2d Mon Sep 17 00:00:00 2001 +From dab969657d8ff8b175856f91b035b74849cf69ba Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 30 Aug 2018 15:04:25 +0200 Subject: [PATCH] vfio: Introduce helpers to DMA map/unmap a RAM section @@ -11,20 +11,20 @@ structure may be clearer. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - hw/vfio/common.c | 187 +++++++++++++++++++++++++++---------------- + hw/vfio/common.c | 206 +++++++++++++++++++++++++------------------ hw/vfio/trace-events | 4 +- - 2 files changed, 119 insertions(+), 72 deletions(-) + 2 files changed, 123 insertions(+), 87 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index a8db784ac5..8837d33c57 100644 +index d358789f19..b3dc090840 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -709,13 +709,126 @@ hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end) +@@ -922,13 +922,130 @@ hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end) return NULL; } +static int vfio_dma_map_ram_section(VFIOContainer *container, -+ MemoryRegionSection *section) ++ MemoryRegionSection *section, Error **err) +{ + VFIOHostDMAWindow *hostwin; + Int128 llend, llsize; @@ -46,9 +46,8 @@ index a8db784ac5..8837d33c57 100644 + + hostwin = hostwin_from_range(container, iova, end); + if (!hostwin) { -+ error_report("vfio: IOMMU Container %p can't map guest IOVA region" -+ " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, -+ container, iova, end); ++ error_setg(err, "Container %p can't map guest IOVA region" ++ " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); + return -EFAULT; + } + @@ -72,11 +71,12 @@ index a8db784ac5..8837d33c57 100644 + ret = vfio_dma_map(container, iova, int128_get64(llsize), + vaddr, section->readonly); + if (ret) { -+ error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " -+ "0x%"HWADDR_PRIx", %p) = %d (%m)", -+ container, iova, int128_get64(llsize), vaddr, ret); ++ error_setg(err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", " ++ "0x%"HWADDR_PRIx", %p) = %d (%m)", ++ container, iova, int128_get64(llsize), vaddr, ret); + if (memory_region_is_ram_device(section->mr)) { + /* Allow unexpected mappings not to be fatal for RAM devices */ ++ error_report_err(*err); + return 0; + } + return ret; @@ -114,6 +114,10 @@ index a8db784ac5..8837d33c57 100644 + + pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; + try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); ++ } else if (memory_region_has_ram_discard_manager(section->mr)) { ++ vfio_unregister_ram_discard_listener(container, section); ++ /* Unregistering will trigger an unmap. */ ++ try_unmap = false; + } + + if (try_unmap) { @@ -147,12 +151,11 @@ index a8db784ac5..8837d33c57 100644 + Int128 llend; int ret; VFIOHostDMAWindow *hostwin; - -@@ -842,38 +955,7 @@ static void vfio_listener_region_add(MemoryListener *listener, + Error *err = NULL; +@@ -1092,38 +1209,7 @@ static void vfio_listener_region_add(MemoryListener *listener, + return; } - /* Here we assume that memory_region_is_ram(section->mr)==true */ -- - vaddr = memory_region_get_ram_ptr(section->mr) + - section->offset_within_region + - (iova - section->offset_within_address_space); @@ -177,18 +180,19 @@ index a8db784ac5..8837d33c57 100644 - ret = vfio_dma_map(container, iova, int128_get64(llsize), - vaddr, section->readonly); - if (ret) { -- error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " -- "0x%"HWADDR_PRIx", %p) = %d (%m)", -- container, iova, int128_get64(llsize), vaddr, ret); +- error_setg(&err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", " +- "0x%"HWADDR_PRIx", %p) = %d (%m)", +- container, iova, int128_get64(llsize), vaddr, ret); - if (memory_region_is_ram_device(section->mr)) { - /* Allow unexpected mappings not to be fatal for RAM devices */ +- error_report_err(err); - return; - } -+ if (vfio_dma_map_ram_section(container, section)) { ++ if (vfio_dma_map_ram_section(container, section, &err)) { goto fail; } -@@ -902,10 +984,6 @@ static void vfio_listener_region_del(MemoryListener *listener, +@@ -1157,10 +1243,6 @@ static void vfio_listener_region_del(MemoryListener *listener, MemoryRegionSection *section) { VFIOContainer *container = container_of(listener, VFIOContainer, listener); @@ -199,7 +203,7 @@ index a8db784ac5..8837d33c57 100644 if (vfio_listener_skipped_section(section)) { trace_vfio_listener_region_del_skip( -@@ -945,38 +1023,7 @@ static void vfio_listener_region_del(MemoryListener *listener, +@@ -1200,53 +1282,7 @@ static void vfio_listener_region_del(MemoryListener *listener, */ } @@ -225,9 +229,24 @@ index a8db784ac5..8837d33c57 100644 - - pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; - try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); +- } else if (memory_region_has_ram_discard_manager(section->mr)) { +- vfio_unregister_ram_discard_listener(container, section); +- /* Unregistering will trigger an unmap. */ +- try_unmap = false; - } - - if (try_unmap) { +- if (int128_eq(llsize, int128_2_64())) { +- /* The unmap ioctl doesn't accept a full 64-bit span. */ +- llsize = int128_rshift(llsize, 1); +- ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); +- if (ret) { +- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " +- "0x%"HWADDR_PRIx") = %d (%m)", +- container, iova, int128_get64(llsize), ret); +- } +- iova += int128_get64(llsize); +- } - ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); - if (ret) { - error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " @@ -240,10 +259,10 @@ index a8db784ac5..8837d33c57 100644 memory_region_unref(section->mr); diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 561dc6e758..9b6c7ca61b 100644 +index 0ef1b5f4a6..a37563a315 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events -@@ -97,10 +97,10 @@ vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "i +@@ -99,10 +99,10 @@ vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "i vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add 0x%"PRIx64" - 0x%"PRIx64 vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 @@ -254,8 +273,8 @@ index 561dc6e758..9b6c7ca61b 100644 -vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 +vfio_dma_unmap_ram(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_disconnect_container(int fd) "close container->fd=%d" - vfio_connect_existing_container(int groupid, int container_fd) "group=%d existing container fd=%d" - vfio_connect_new_container(int groupid, int container_fd) "group=%d new container fd=%d" + vfio_put_group(int fd) "close group->fd=%d" + vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" -- 2.27.0 diff --git a/vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch b/vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch index 274a0c08a92bfa268f3fab8a5d7842cdbab9d273..e77dd1d64b4bdfb606e7987df653d5e365c27c98 100644 --- a/vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch +++ b/vfio-Introduce-helpers-to-mark-dirty-pages-of-a-RAM-.patch @@ -1,4 +1,4 @@ -From ff9c1f7e3e17cc2afe1b2dfa545065e91941db8b Mon Sep 17 00:00:00 2001 +From 1675d767aa9bd496178b4d74e01a40dbbd97eccb Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 11 May 2021 10:08:13 +0800 Subject: [PATCH] vfio: Introduce helpers to mark dirty pages of a RAM section @@ -13,10 +13,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 21a866e545..5176fd3a3d 100644 +index bdfcc854fe..6136b1ef61 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1304,6 +1304,19 @@ err_out: +@@ -1566,6 +1566,19 @@ err_out: return ret; } @@ -36,7 +36,7 @@ index 21a866e545..5176fd3a3d 100644 typedef struct { IOMMUNotifier n; VFIOGuestIOMMU *giommu; -@@ -1345,8 +1358,6 @@ static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +@@ -1650,8 +1663,6 @@ static int vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainer *container, static int vfio_sync_dirty_bitmap(VFIOContainer *container, MemoryRegionSection *section) { @@ -45,8 +45,8 @@ index 21a866e545..5176fd3a3d 100644 if (memory_region_is_iommu(section->mr)) { VFIOGuestIOMMU *giommu; -@@ -1375,12 +1386,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, - return 0; +@@ -1682,12 +1693,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, + return vfio_sync_ram_discard_listener_dirty_bitmap(container, section); } - ram_addr = memory_region_get_ram_addr(section->mr) + diff --git a/vfio-Introduce-hostwin_from_range-helper.patch b/vfio-Introduce-hostwin_from_range-helper.patch index b9a7099de2a6eeaa9265be66c8818ffc852e6583..c8c8ab76922a95fbcfdec74b92b11dc688ce2745 100644 --- a/vfio-Introduce-hostwin_from_range-helper.patch +++ b/vfio-Introduce-hostwin_from_range-helper.patch @@ -1,4 +1,4 @@ -From 25336cd596ff551293f1be6e108ad9277d80be0f Mon Sep 17 00:00:00 2001 +From 85232739b4852f1a51dde58c9007ed0deb17c2f2 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 22 Mar 2019 18:05:23 +0100 Subject: [PATCH] vfio: Introduce hostwin_from_range helper @@ -16,11 +16,11 @@ Signed-off-by: Kunkun Jiang 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index c78b58d365..a8db784ac5 100644 +index d7533637c9..d358789f19 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -696,6 +696,19 @@ out: - rcu_read_unlock(); +@@ -909,6 +909,19 @@ static void vfio_unregister_ram_discard_listener(VFIOContainer *container, + g_free(vrdl); } +static VFIOHostDMAWindow * @@ -39,15 +39,15 @@ index c78b58d365..a8db784ac5 100644 static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { -@@ -705,7 +718,6 @@ static void vfio_listener_region_add(MemoryListener *listener, +@@ -918,7 +931,6 @@ static void vfio_listener_region_add(MemoryListener *listener, void *vaddr; int ret; VFIOHostDMAWindow *hostwin; - bool hostwin_found; + Error *err = NULL; if (vfio_listener_skipped_section(section)) { - trace_vfio_listener_region_add_skip( -@@ -783,15 +795,8 @@ static void vfio_listener_region_add(MemoryListener *listener, +@@ -1011,15 +1023,8 @@ static void vfio_listener_region_add(MemoryListener *listener, #endif } @@ -62,10 +62,10 @@ index c78b58d365..a8db784ac5 100644 - if (!hostwin_found) { + hostwin = hostwin_from_range(container, iova, end); + if (!hostwin) { - error_report("vfio: IOMMU container %p can't map guest IOVA region" - " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, - container, iova, end); -@@ -956,16 +961,9 @@ static void vfio_listener_region_del(MemoryListener *listener, + error_setg(&err, "Container %p can't map guest IOVA region" + " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); + goto fail; +@@ -1211,16 +1216,9 @@ static void vfio_listener_region_del(MemoryListener *listener, if (memory_region_is_ram_device(section->mr)) { hwaddr pgmask; diff --git a/vfio-Maintain-DMA-mapping-range-for-the-container.patch b/vfio-Maintain-DMA-mapping-range-for-the-container.patch index 901a5e38ea78a2c490875611f12658151da661b9..ba8abb431c5606de905890d5be95e37f4d0ccf8e 100644 --- a/vfio-Maintain-DMA-mapping-range-for-the-container.patch +++ b/vfio-Maintain-DMA-mapping-range-for-the-container.patch @@ -1,4 +1,4 @@ -From 90a6a1ec65d55d27faf79341b2dd9418d99da187 Mon Sep 17 00:00:00 2001 +From ac1bf3edcd2b807cf81ada500716f13b1394d58e Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Sat, 8 May 2021 17:31:04 +0800 Subject: [PATCH] vfio: Maintain DMA mapping range for the container @@ -36,10 +36,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 245e32df5b..c33c4c539d 100644 +index 080046e3f5..86ea784919 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -420,6 +420,29 @@ unmap_exit: +@@ -445,6 +445,29 @@ unmap_exit: return ret; } @@ -69,7 +69,7 @@ index 245e32df5b..c33c4c539d 100644 /* * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 */ -@@ -433,12 +456,29 @@ static int vfio_dma_unmap(VFIOContainer *container, +@@ -458,12 +481,29 @@ static int vfio_dma_unmap(VFIOContainer *container, .iova = iova, .size = size, }; @@ -99,7 +99,7 @@ index 245e32df5b..c33c4c539d 100644 while (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { /* * The type1 backend has an off-by-one bug in the kernel (71a7d3d78e3c -@@ -475,6 +515,14 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, +@@ -500,6 +540,14 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, .iova = iova, .size = size, }; @@ -114,7 +114,7 @@ index 245e32df5b..c33c4c539d 100644 if (!readonly) { map.flags |= VFIO_DMA_MAP_FLAG_WRITE; -@@ -986,9 +1034,14 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, +@@ -1256,9 +1304,14 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, { struct vfio_iommu_type1_dirty_bitmap *dbitmap; struct vfio_iommu_type1_dirty_bitmap_get *range; @@ -129,7 +129,7 @@ index 245e32df5b..c33c4c539d 100644 dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); -@@ -1007,11 +1060,8 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, +@@ -1277,11 +1330,8 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, pages = REAL_HOST_PAGE_ALIGN(range->size) / qemu_real_host_page_size; range->bitmap.size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / BITS_PER_BYTE; @@ -143,7 +143,7 @@ index 245e32df5b..c33c4c539d 100644 ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, dbitmap); if (ret) { -@@ -1027,7 +1077,6 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, +@@ -1297,7 +1347,6 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, trace_vfio_get_dirty_bitmap(container->fd, range->iova, range->size, range->bitmap.size, ram_addr); err_out: @@ -151,16 +151,16 @@ index 245e32df5b..c33c4c539d 100644 g_free(dbitmap); return ret; -@@ -1681,6 +1730,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - container->dirty_pages_supported = false; +@@ -2061,6 +2110,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, QLIST_INIT(&container->giommu_list); QLIST_INIT(&container->hostwin_list); + QLIST_INIT(&container->vrdl_list); + QLIST_INIT(&container->dma_list); ret = vfio_init_container(container, group->fd, errp); if (ret) { diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 475aa9fb40..2853dc861e 100644 +index 8af11b0a76..20b9c8a1d3 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -76,6 +76,14 @@ typedef struct VFIOAddressSpace { @@ -178,10 +178,10 @@ index 475aa9fb40..2853dc861e 100644 typedef struct VFIOContainer { VFIOAddressSpace *space; int fd; /* /dev/vfio/vfio, empowered by the attached groups */ -@@ -91,6 +99,7 @@ typedef struct VFIOContainer { - QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; +@@ -93,6 +101,7 @@ typedef struct VFIOContainer { QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; QLIST_HEAD(, VFIOGroup) group_list; + QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; + QLIST_HEAD(, VFIODMARange) dma_list; QLIST_ENTRY(VFIOContainer) next; } VFIOContainer; diff --git a/vfio-Make-migration-support-experimental.patch b/vfio-Make-migration-support-experimental.patch deleted file mode 100644 index 3bf32ecaf443b40929932743cd3d9f3b951011b2..0000000000000000000000000000000000000000 --- a/vfio-Make-migration-support-experimental.patch +++ /dev/null @@ -1,72 +0,0 @@ -From d0a8ba1957743c55547ec2ccd8cb09b84a3354d2 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Mon, 9 Nov 2020 11:56:02 -0700 -Subject: [PATCH] vfio: Make migration support experimental - -Support for migration of vfio devices is still in flux. Developers -are attempting to add support for new devices and new architectures, -but none are yet readily available for validation. We have concerns -whether we're transferring device resources at the right point in the -migration, whether we're guaranteeing that updates during pre-copy are -migrated, and whether we can provide bit-stream compatibility should -any of this change. Even the question of whether devices should -participate in dirty page tracking during pre-copy seems contentious. -In short, migration support has not had enough soak time and it feels -premature to mark it as supported. - -Create an experimental option such that we can continue to develop. - -[Retaining previous acks/reviews for a previously identical code - change with different specifics in the commit log.] - -Reviewed-by: Dr. David Alan Gilbert -Acked-by: Cornelia Huck -Signed-off-by: Alex Williamson -Signed-off-by: Kunkun Jiang ---- - hw/vfio/migration.c | 2 +- - hw/vfio/pci.c | 2 ++ - include/hw/vfio/vfio-common.h | 1 + - 3 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 8546075706..033cb2b0c9 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -888,7 +888,7 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) - Error *local_err = NULL; - int ret = -ENOTSUP; - -- if (!container->dirty_pages_supported) { -+ if (!vbasedev->enable_migration || !container->dirty_pages_supported) { - goto add_blocker; - } - -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index da7c740bce..2795b8bd12 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -3192,6 +3192,8 @@ static Property vfio_pci_dev_properties[] = { - VFIO_FEATURE_ENABLE_REQ_BIT, true), - DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features, - VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false), -+ DEFINE_PROP_BOOL("x-enable-migration", VFIOPCIDevice, -+ vbasedev.enable_migration, false), - DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false), - DEFINE_PROP_BOOL("x-balloon-allowed", VFIOPCIDevice, - vbasedev.balloon_allowed, false), -diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 048731e81f..7398631d4c 100644 ---- a/include/hw/vfio/vfio-common.h -+++ b/include/hw/vfio/vfio-common.h -@@ -123,6 +123,7 @@ typedef struct VFIODevice { - bool needs_reset; - bool no_mmap; - bool balloon_allowed; -+ bool enable_migration; - VFIODeviceOps *ops; - unsigned int num_irqs; - unsigned int num_regions; --- -2.27.0 - diff --git a/vfio-Make-vfio-pci-device-migration-capable.patch b/vfio-Make-vfio-pci-device-migration-capable.patch deleted file mode 100644 index 7e87ec7d7820b8ee4be0de5d55039336c47988fd..0000000000000000000000000000000000000000 --- a/vfio-Make-vfio-pci-device-migration-capable.patch +++ /dev/null @@ -1,73 +0,0 @@ -From b20bf027d44809dd6c6376cf0b77e5c5b2057cba Mon Sep 17 00:00:00 2001 -From: Jens Freimann -Date: Tue, 29 Oct 2019 12:49:05 +0100 -Subject: [PATCH] vfio: Make vfio-pci device migration capable - -If the device is not a failover primary device, call -vfio_migration_probe() and vfio_migration_finalize() to enable -migration support for those devices that support it respectively to -tear it down again. -Removed migration blocker from VFIO PCI device specific structure and use -migration blocker from generic structure of VFIO device. - -Note: Since the current version don't add the failover feature for assigned -PCI devices, just remove the failover related code in the original patch for -simplicity. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Cornelia Huck -Signed-off-by: Alex Williamson -Signed-off-by: Shenming Lu ---- - hw/vfio/pci.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index b9fae3ad28..a637c35e7a 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -3049,6 +3049,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) - } - } - -+ ret = vfio_migration_probe(&vdev->vbasedev, errp); -+ if (ret) { -+ error_report("%s: Migration disabled", vdev->vbasedev.name); -+ } -+ - vfio_register_err_notifier(vdev); - vfio_register_req_notifier(vdev); - vfio_setup_resetfn_quirk(vdev); -@@ -3096,6 +3101,7 @@ static void vfio_exitfn(PCIDevice *pdev) - } - vfio_teardown_msi(vdev); - vfio_bars_exit(vdev); -+ vfio_migration_finalize(&vdev->vbasedev); - } - - static void vfio_pci_reset(DeviceState *dev) -@@ -3204,11 +3210,6 @@ static Property vfio_pci_dev_properties[] = { - DEFINE_PROP_END_OF_LIST(), - }; - --static const VMStateDescription vfio_pci_vmstate = { -- .name = "vfio-pci", -- .unmigratable = 1, --}; -- - static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) - { - DeviceClass *dc = DEVICE_CLASS(klass); -@@ -3216,7 +3217,6 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) - - dc->reset = vfio_pci_reset; - dc->props = vfio_pci_dev_properties; -- dc->vmsd = &vfio_pci_vmstate; - dc->desc = "VFIO-based PCI device assignment"; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - pdc->realize = vfio_realize; --- -2.27.0 - diff --git a/vfio-Move-the-saving-of-the-config-space-to-the-righ.patch b/vfio-Move-the-saving-of-the-config-space-to-the-righ.patch deleted file mode 100644 index 438c426803c4f77ea21220e6917ecf27ab566857..0000000000000000000000000000000000000000 --- a/vfio-Move-the-saving-of-the-config-space-to-the-righ.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 483baf4c668fbd2da76e6948576e13eded1c54ec Mon Sep 17 00:00:00 2001 -From: Shenming Lu -Date: Wed, 10 Mar 2021 11:02:31 +0800 -Subject: [PATCH] vfio: Move the saving of the config space to the right place - in VFIO migration - -On ARM64 the VFIO SET_IRQS ioctl is dependent on the VM interrupt -setup, if the restoring of the VFIO PCI device config space is -before the VGIC, an error might occur in the kernel. - -So we move the saving of the config space to the non-iterable -process, thus it will be called after the VGIC according to -their priorities. - -As for the possible dependence of the device specific migration -data on it's config space, we can let the vendor driver to -include any config info it needs in its own data stream. - -Signed-off-by: Shenming Lu -Reviewed-by: Kirti Wankhede -Message-Id: <20210310030233.1133-2-lushenming@huawei.com> -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 25 +++++++++++++++---------- - 1 file changed, 15 insertions(+), 10 deletions(-) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index b77c66557e..ea36ae5225 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -575,11 +575,6 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) - return ret; - } - -- ret = vfio_save_device_config_state(f, opaque); -- if (ret) { -- return ret; -- } -- - ret = vfio_update_pending(vbasedev); - if (ret) { - return ret; -@@ -620,6 +615,19 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) - return ret; - } - -+static void vfio_save_state(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ int ret; -+ -+ ret = vfio_save_device_config_state(f, opaque); -+ if (ret) { -+ error_report("%s: Failed to save device config space", -+ vbasedev->name); -+ qemu_file_set_error(f, ret); -+ } -+} -+ - static int vfio_load_setup(QEMUFile *f, void *opaque) - { - VFIODevice *vbasedev = opaque; -@@ -670,11 +678,7 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) - switch (data) { - case VFIO_MIG_FLAG_DEV_CONFIG_STATE: - { -- ret = vfio_load_device_config_state(f, opaque); -- if (ret) { -- return ret; -- } -- break; -+ return vfio_load_device_config_state(f, opaque); - } - case VFIO_MIG_FLAG_DEV_SETUP_STATE: - { -@@ -720,6 +724,7 @@ static SaveVMHandlers savevm_vfio_handlers = { - .save_live_pending = vfio_save_pending, - .save_live_iterate = vfio_save_iterate, - .save_live_complete_precopy = vfio_save_complete_precopy, -+ .save_state = vfio_save_state, - .load_setup = vfio_load_setup, - .load_cleanup = vfio_load_cleanup, - .load_state = vfio_load_state, --- -2.27.0 - diff --git a/vfio-Pass-stage-1-MSI-bindings-to-the-host.patch b/vfio-Pass-stage-1-MSI-bindings-to-the-host.patch index 1ad94b06ad73ccf44d049daa2b8ff35b3624d539..bed28007ce19c71e58690d3ceb7ce5c9dd87a9d4 100644 --- a/vfio-Pass-stage-1-MSI-bindings-to-the-host.patch +++ b/vfio-Pass-stage-1-MSI-bindings-to-the-host.patch @@ -1,4 +1,4 @@ -From 1729ae16dc557c0ad54cab3096b5cb6649d181ae Mon Sep 17 00:00:00 2001 +From 8b4fbe869f8a1f510896c86067d2e4fc3dc82eb9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 14 Aug 2018 08:08:11 -0400 Subject: [PATCH] vfio: Pass stage 1 MSI bindings to the host @@ -16,10 +16,10 @@ Signed-off-by: Kunkun Jiang 4 files changed, 147 insertions(+), 2 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index cc50efdbc1..db9af3b0e5 100644 +index 58f8a43a43..1f78af121d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -709,6 +709,65 @@ static void vfio_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +@@ -774,6 +774,65 @@ static void vfio_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) } } @@ -86,10 +86,10 @@ index cc50efdbc1..db9af3b0e5 100644 { VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 6c90ec9278..bbcba3fd16 100644 +index ae5e014e5d..99c52a0944 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -360,6 +360,65 @@ static void vfio_msi_interrupt(void *opaque) +@@ -365,6 +365,65 @@ static void vfio_msi_interrupt(void *opaque) notify(&vdev->pdev, nr); } @@ -155,7 +155,7 @@ index 6c90ec9278..bbcba3fd16 100644 static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) { struct vfio_irq_set *irq_set; -@@ -377,7 +436,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) +@@ -382,7 +441,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) fds = (int32_t *)&irq_set->data; for (i = 0; i < vdev->nr_vectors; i++) { @@ -164,7 +164,7 @@ index 6c90ec9278..bbcba3fd16 100644 /* * MSI vs MSI-X - The guest has direct access to MSI mask and pending -@@ -386,6 +445,12 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) +@@ -391,6 +450,12 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) * KVM signaling path only when configured and unmasked. */ if (vdev->msi_vectors[i].use) { @@ -177,7 +177,7 @@ index 6c90ec9278..bbcba3fd16 100644 if (vdev->msi_vectors[i].virq < 0 || (msix && msix_is_masked(&vdev->pdev, i))) { fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt); -@@ -399,6 +464,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) +@@ -404,6 +469,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); @@ -185,7 +185,7 @@ index 6c90ec9278..bbcba3fd16 100644 g_free(irq_set); return ret; -@@ -712,7 +778,8 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) +@@ -718,7 +784,8 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) static void vfio_msix_disable(VFIOPCIDevice *vdev) { @@ -195,7 +195,7 @@ index 6c90ec9278..bbcba3fd16 100644 msix_unset_vector_notifiers(&vdev->pdev); -@@ -724,6 +791,11 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) +@@ -730,6 +797,11 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) if (vdev->msi_vectors[i].use) { vfio_msix_vector_release(&vdev->pdev, i); msix_vector_unuse(&vdev->pdev, i); @@ -208,7 +208,7 @@ index 6c90ec9278..bbcba3fd16 100644 } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index ee9a67d3ef..247b72c1eb 100644 +index 20069935f5..35bd415d6d 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -120,6 +120,8 @@ vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype @@ -221,7 +221,7 @@ index ee9a67d3ef..247b72c1eb 100644 # platform.c vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 1277914ca8..b175158138 100644 +index 0234f5e1b1..a838a939e4 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -74,6 +74,14 @@ typedef struct VFIOAddressSpace { @@ -239,15 +239,15 @@ index 1277914ca8..b175158138 100644 struct VFIOGroup; typedef struct VFIODMARange { -@@ -101,6 +109,7 @@ typedef struct VFIOContainer { - QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; +@@ -103,6 +111,7 @@ typedef struct VFIOContainer { QLIST_HEAD(, VFIOGroup) group_list; + QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; QLIST_HEAD(, VFIODMARange) dma_list; + QLIST_HEAD(, VFIOMSIBinding) msibinding_list; QLIST_ENTRY(VFIOContainer) next; } VFIOContainer; -@@ -210,6 +219,9 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); +@@ -222,6 +231,9 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); void vfio_put_group(VFIOGroup *group); int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vbasedev, Error **errp); diff --git a/vfio-Register-SaveVMHandlers-for-VFIO-device.patch b/vfio-Register-SaveVMHandlers-for-VFIO-device.patch deleted file mode 100644 index 8e12cd2bb2bbfede3be871fb31a3a96562fedc15..0000000000000000000000000000000000000000 --- a/vfio-Register-SaveVMHandlers-for-VFIO-device.patch +++ /dev/null @@ -1,183 +0,0 @@ -From cd5b58f2ba20e59f2c29d955b8bbd7f5016030b7 Mon Sep 17 00:00:00 2001 -From: Kirti Wankhede -Date: Mon, 26 Oct 2020 15:06:17 +0530 -Subject: [PATCH] vfio: Register SaveVMHandlers for VFIO device - -Define flags to be used as delimiter in migration stream for VFIO devices. -Added .save_setup and .save_cleanup functions. Map & unmap migration -region from these functions at source during saving or pre-copy phase. - -Set VFIO device state depending on VM's state. During live migration, VM is -running when .save_setup is called, _SAVING | _RUNNING state is set for VFIO -device. During save-restore, VM is paused, _SAVING state is set for VFIO device. - -Signed-off-by: Kirti Wankhede -Reviewed-by: Neo Jia -Reviewed-by: Cornelia Huck -Reviewed-by: Yan Zhao -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 102 +++++++++++++++++++++++++++++++++++++++++++ - hw/vfio/trace-events | 2 + - 2 files changed, 104 insertions(+) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 0c6c9b655f..405228fc5a 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -8,12 +8,15 @@ - */ - - #include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "qemu/cutils.h" - #include - - #include "sysemu/sysemu.h" - #include "hw/vfio/vfio-common.h" - #include "cpu.h" - #include "migration/migration.h" -+#include "migration/vmstate.h" - #include "migration/qemu-file.h" - #include "migration/register.h" - #include "migration/blocker.h" -@@ -25,6 +28,22 @@ - #include "trace.h" - #include "hw/hw.h" - -+/* -+ * Flags to be used as unique delimiters for VFIO devices in the migration -+ * stream. These flags are composed as: -+ * 0xffffffff => MSB 32-bit all 1s -+ * 0xef10 => Magic ID, represents emulated (virtual) function IO -+ * 0x0000 => 16-bits reserved for flags -+ * -+ * The beginning of state information is marked by _DEV_CONFIG_STATE, -+ * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a -+ * certain state information is marked by _END_OF_STATE. -+ */ -+#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL) -+#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL) -+#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) -+#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) -+ - static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, - off_t off, bool iswrite) - { -@@ -129,6 +148,75 @@ static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, - return 0; - } - -+static void vfio_migration_cleanup(VFIODevice *vbasedev) -+{ -+ VFIOMigration *migration = vbasedev->migration; -+ -+ if (migration->region.mmaps) { -+ vfio_region_unmap(&migration->region); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int vfio_save_setup(QEMUFile *f, void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ VFIOMigration *migration = vbasedev->migration; -+ int ret; -+ -+ trace_vfio_save_setup(vbasedev->name); -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE); -+ -+ if (migration->region.mmaps) { -+ /* -+ * Calling vfio_region_mmap() from migration thread. Memory API called -+ * from this function require locking the iothread when called from -+ * outside the main loop thread. -+ */ -+ qemu_mutex_lock_iothread(); -+ ret = vfio_region_mmap(&migration->region); -+ qemu_mutex_unlock_iothread(); -+ if (ret) { -+ error_report("%s: Failed to mmap VFIO migration region: %s", -+ vbasedev->name, strerror(-ret)); -+ error_report("%s: Falling back to slow path", vbasedev->name); -+ } -+ } -+ -+ ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, -+ VFIO_DEVICE_STATE_SAVING); -+ if (ret) { -+ error_report("%s: Failed to set state SAVING", vbasedev->name); -+ return ret; -+ } -+ -+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); -+ -+ ret = qemu_file_get_error(f); -+ if (ret) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void vfio_save_cleanup(void *opaque) -+{ -+ VFIODevice *vbasedev = opaque; -+ -+ vfio_migration_cleanup(vbasedev); -+ trace_vfio_save_cleanup(vbasedev->name); -+} -+ -+static SaveVMHandlers savevm_vfio_handlers = { -+ .save_setup = vfio_save_setup, -+ .save_cleanup = vfio_save_cleanup, -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ - static void vfio_vmstate_change(void *opaque, int running, RunState state) - { - VFIODevice *vbasedev = opaque; -@@ -215,6 +303,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, - int ret; - Object *obj; - VFIOMigration *migration; -+ char id[256] = ""; -+ g_autofree char *path = NULL, *oid = NULL; - - if (!vbasedev->ops->vfio_get_object) { - return -EINVAL; -@@ -244,6 +334,18 @@ static int vfio_migration_init(VFIODevice *vbasedev, - - migration = vbasedev->migration; - migration->vbasedev = vbasedev; -+ -+ oid = vmstate_if_get_id(VMSTATE_IF(DEVICE(obj))); -+ if (oid) { -+ path = g_strdup_printf("%s/vfio", oid); -+ } else { -+ path = g_strdup("vfio"); -+ } -+ strpadcpy(id, sizeof(id), path, '\0'); -+ -+ register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, &savevm_vfio_handlers, -+ vbasedev); -+ - migration->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change, - vbasedev); - migration->migration_state.notify = vfio_migration_state_notifier; -diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index bd3d47b005..86c18def01 100644 ---- a/hw/vfio/trace-events -+++ b/hw/vfio/trace-events -@@ -149,3 +149,5 @@ vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" - vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" - vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" - vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" -+vfio_save_setup(const char *name) " (%s)" -+vfio_save_cleanup(const char *name) " (%s)" --- -2.27.0 - diff --git a/vfio-Set-the-priority-of-the-VFIO-VM-state-change-ha.patch b/vfio-Set-the-priority-of-the-VFIO-VM-state-change-ha.patch deleted file mode 100644 index d2138b57e71e494198068253be7d7229b510e598..0000000000000000000000000000000000000000 --- a/vfio-Set-the-priority-of-the-VFIO-VM-state-change-ha.patch +++ /dev/null @@ -1,41 +0,0 @@ -From b9d74bcf6aefe8ab607439ad1c518a453053ccee Mon Sep 17 00:00:00 2001 -From: Shenming Lu -Date: Wed, 10 Mar 2021 11:02:32 +0800 -Subject: [PATCH] vfio: Set the priority of the VFIO VM state change handler - explicitly - -In the VFIO VM state change handler when stopping the VM, the _RUNNING -bit in device_state is cleared which makes the VFIO device stop, including -no longer generating interrupts. Then we can save the pending states of -all interrupts in the GIC VM state change handler (on ARM). - -So we have to set the priority of the VFIO VM state change handler -explicitly (like virtio devices) to ensure it is called before the -GIC's in saving. - -Signed-off-by: Shenming Lu -Reviewed-by: Kirti Wankhede -Reviewed-by: Cornelia Huck -Message-Id: <20210310030233.1133-3-lushenming@huawei.com> -Signed-off-by: Alex Williamson ---- - hw/vfio/migration.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index ea36ae5225..1a97784486 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -862,7 +862,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, - register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, &savevm_vfio_handlers, - vbasedev); - -- migration->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change, -+ migration->vm_state = qdev_add_vm_change_state_handler(vbasedev->dev, -+ vfio_vmstate_change, - vbasedev); - migration->migration_state.notify = vfio_migration_state_notifier; - add_migration_state_change_notifier(&migration->migration_state); --- -2.27.0 - diff --git a/vfio-Set-up-nested-stage-mappings.patch b/vfio-Set-up-nested-stage-mappings.patch index 66659e81a8dacc392f4f6a56ab988c36a52af8a2..c6d87f97be54c3c76b2890ee978723ee946146c6 100644 --- a/vfio-Set-up-nested-stage-mappings.patch +++ b/vfio-Set-up-nested-stage-mappings.patch @@ -1,4 +1,4 @@ -From a65c40f9d1025a9843dec38070d9f26792b00892 Mon Sep 17 00:00:00 2001 +From 96581a5ee46e89dbc9e1ebe247b00adefb1c7a41 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 29 Aug 2018 18:10:12 +0200 Subject: [PATCH] vfio: Set up nested stage mappings @@ -22,16 +22,16 @@ notifier. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang --- - hw/vfio/common.c | 136 +++++++++++++++++++++++++++++++++++++++++-- + hw/vfio/common.c | 139 +++++++++++++++++++++++++++++++++++++++++-- hw/vfio/pci.c | 21 +++++++ hw/vfio/trace-events | 2 + - 3 files changed, 154 insertions(+), 5 deletions(-) + 3 files changed, 157 insertions(+), 5 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 8837d33c57..cc50efdbc1 100644 +index b3dc090840..58f8a43a43 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -642,6 +642,73 @@ static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, +@@ -707,6 +707,73 @@ static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, return true; } @@ -105,7 +105,7 @@ index 8837d33c57..cc50efdbc1 100644 static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) { VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); -@@ -823,6 +890,32 @@ static void vfio_dma_unmap_ram_section(VFIOContainer *container, +@@ -1040,6 +1107,35 @@ static void vfio_dma_unmap_ram_section(VFIOContainer *container, } } @@ -114,14 +114,17 @@ index 8837d33c57..cc50efdbc1 100644 +{ + VFIOContainer *container = + container_of(listener, VFIOContainer, prereg_listener); ++ Error *err = NULL; + + if (!memory_region_is_ram(section->mr)) { + return; + } + -+ vfio_dma_map_ram_section(container, section); ++ vfio_dma_map_ram_section(container, section, &err); ++ if (err) { ++ error_report_err(err); ++ } +} -+ +static void vfio_prereg_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ @@ -138,7 +141,7 @@ index 8837d33c57..cc50efdbc1 100644 static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { -@@ -920,9 +1013,10 @@ static void vfio_listener_region_add(MemoryListener *listener, +@@ -1150,9 +1246,10 @@ static void vfio_listener_region_add(MemoryListener *listener, memory_region_ref(section->mr); if (memory_region_is_iommu(section->mr)) { @@ -150,12 +153,12 @@ index 8837d33c57..cc50efdbc1 100644 trace_vfio_listener_region_add_iommu(iova, end); /* -@@ -941,15 +1035,27 @@ static void vfio_listener_region_add(MemoryListener *listener, +@@ -1171,8 +1268,18 @@ static void vfio_listener_region_add(MemoryListener *listener, llend = int128_sub(llend, int128_one()); iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, MEMTXATTRS_UNSPECIFIED); - iommu_notifier_init(&giommu->n, vfio_iommu_map_notify, -- IOMMU_NOTIFIER_ALL, +- IOMMU_NOTIFIER_IOTLB_EVENTS, + + if (container->iommu_type == VFIO_TYPE1_NESTING_IOMMU) { + /* IOTLB unmap notifier to propagate guest IOTLB invalidations */ @@ -163,7 +166,7 @@ index 8837d33c57..cc50efdbc1 100644 + notify = vfio_iommu_unmap_notify; + } else { + /* MAP/UNMAP IOTLB notifier */ -+ flags = IOMMU_NOTIFIER_ALL; ++ flags = IOMMU_NOTIFIER_IOTLB_EVENTS; + notify = vfio_iommu_map_notify; + } + @@ -171,9 +174,10 @@ index 8837d33c57..cc50efdbc1 100644 section->offset_within_region, int128_get64(llend), iommu_idx); +@@ -1192,7 +1299,9 @@ static void vfio_listener_region_add(MemoryListener *listener, + goto fail; + } QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); - - memory_region_register_iommu_notifier(section->mr, &giommu->n); - memory_region_iommu_replay(giommu->iommu, &giommu->n); + if (flags & IOMMU_NOTIFIER_MAP) { + memory_region_iommu_replay(giommu->iommu, &giommu->n); @@ -181,7 +185,7 @@ index 8837d33c57..cc50efdbc1 100644 return; } -@@ -1367,10 +1473,16 @@ static const MemoryListener vfio_memory_listener = { +@@ -1672,10 +1781,16 @@ static const MemoryListener vfio_memory_listener = { .log_clear = vfio_listener_log_clear, }; @@ -199,7 +203,7 @@ index 8837d33c57..cc50efdbc1 100644 memory_listener_unregister(&container->prereg_listener); } } -@@ -1976,6 +2088,20 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, +@@ -2351,6 +2466,20 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, vfio_get_iommu_info_migration(container, info); } g_free(info); @@ -210,10 +214,10 @@ index 8837d33c57..cc50efdbc1 100644 + &address_space_memory); + if (container->error) { + memory_listener_unregister(&container->prereg_listener); -+ ret = container->error; -+ error_setg(errp, -+ "RAM memory listener initialization failed " -+ "for container"); ++ ret = -1; ++ error_propagate_prepend(errp, container->error, ++ "RAM memory listener initialization failed " ++ "for container"); + goto free_container_exit; + } + } @@ -221,10 +225,10 @@ index 8837d33c57..cc50efdbc1 100644 } case VFIO_SPAPR_TCE_v2_IOMMU: diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 3641ad0c5c..6c90ec9278 100644 +index 7b45353ce2..ae5e014e5d 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -2766,6 +2766,25 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) +@@ -2797,6 +2797,25 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) vdev->req_enabled = false; } @@ -249,8 +253,8 @@ index 3641ad0c5c..6c90ec9278 100644 + static void vfio_realize(PCIDevice *pdev, Error **errp) { - VFIOPCIDevice *vdev = PCI_VFIO(pdev); -@@ -3072,6 +3091,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + VFIOPCIDevice *vdev = VFIO_PCI(pdev); +@@ -3108,6 +3127,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_register_req_notifier(vdev); vfio_setup_resetfn_quirk(vdev); @@ -258,9 +262,9 @@ index 3641ad0c5c..6c90ec9278 100644 + return; - out_teardown: + out_deregister: diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events -index 9b6c7ca61b..ee9a67d3ef 100644 +index a37563a315..20069935f5 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -118,6 +118,8 @@ vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Devic diff --git a/vfio-Support-host-translation-granule-size.patch b/vfio-Support-host-translation-granule-size.patch deleted file mode 100644 index d5eab65155770160c38615d038ea66264e284acb..0000000000000000000000000000000000000000 --- a/vfio-Support-host-translation-granule-size.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 594cba5943b3e8bf1bd5720b1fa20d4662920ae0 Mon Sep 17 00:00:00 2001 -From: Kunkun Jiang -Date: Thu, 4 Mar 2021 21:34:46 +0800 -Subject: [PATCH] vfio: Support host translation granule size - -The cpu_physical_memory_set_dirty_lebitmap() can quickly deal with -the dirty pages of memory by bitmap-traveling, regardless of whether -the bitmap is aligned correctly or not. - -cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of -host page size. So it'd better to set bitmap_pgsize to host page size -to support more translation granule sizes. - -[aw: The Fixes commit below introduced code to restrict migration -support to configurations where the target page size intersects the -host dirty page support. For example, a 4K guest on a 4K host. -Due to the above flexibility in bitmap handling, this restriction -unnecessarily prevents mixed target/host pages size that could -otherwise be supported. Use host page size for dirty bitmap.] - -Fixes: fc49c9cbf2 ("vfio: Get migration capability flags for container") -Signed-off-by: Kunkun Jiang -Message-Id: <20210304133446.1521-1-jiangkunkun@huawei.com> -Signed-off-by: Alex Williamson ---- - hw/vfio/common.c | 48 +++++++++++++++++++++++++----------------------- - 1 file changed, 25 insertions(+), 23 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index ebd701faa0..a7817c90cc 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -377,7 +377,7 @@ static int vfio_dma_unmap_bitmap(VFIOContainer *container, - { - struct vfio_iommu_type1_dma_unmap *unmap; - struct vfio_bitmap *bitmap; -- uint64_t pages = TARGET_PAGE_ALIGN(size) >> TARGET_PAGE_BITS; -+ uint64_t pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size; - int ret; - - unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); -@@ -389,12 +389,12 @@ static int vfio_dma_unmap_bitmap(VFIOContainer *container, - bitmap = (struct vfio_bitmap *)&unmap->data; - - /* -- * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -- * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap_pgsize to -- * TARGET_PAGE_SIZE. -+ * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of -+ * qemu_real_host_page_size to mark those dirty. Hence set bitmap_pgsize -+ * to qemu_real_host_page_size. - */ - -- bitmap->pgsize = TARGET_PAGE_SIZE; -+ bitmap->pgsize = qemu_real_host_page_size; - bitmap->size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / - BITS_PER_BYTE; - -@@ -672,16 +672,17 @@ static void vfio_listener_region_add(MemoryListener *listener, - return; - } - -- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != -- (section->offset_within_region & ~TARGET_PAGE_MASK))) { -+ if (unlikely((section->offset_within_address_space & -+ ~qemu_real_host_page_mask) != -+ (section->offset_within_region & ~qemu_real_host_page_mask))) { - error_report("%s received unaligned region", __func__); - return; - } - -- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); -+ 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_and(llend, int128_exts64(TARGET_PAGE_MASK)); -+ llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); - - if (int128_ge(int128_make64(iova), llend)) { - return; -@@ -866,8 +867,9 @@ static void vfio_listener_region_del(MemoryListener *listener, - return; - } - -- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != -- (section->offset_within_region & ~TARGET_PAGE_MASK))) { -+ if (unlikely((section->offset_within_address_space & -+ ~qemu_real_host_page_mask) != -+ (section->offset_within_region & ~qemu_real_host_page_mask))) { - error_report("%s received unaligned region", __func__); - return; - } -@@ -895,10 +897,10 @@ static void vfio_listener_region_del(MemoryListener *listener, - */ - } - -- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); -+ 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_and(llend, int128_exts64(TARGET_PAGE_MASK)); -+ llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); - - if (int128_ge(int128_make64(iova), llend)) { - return; -@@ -967,13 +969,13 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - range->size = size; - - /* -- * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -- * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap's pgsize to -- * TARGET_PAGE_SIZE. -+ * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of -+ * qemu_real_host_page_size to mark those dirty. Hence set bitmap's pgsize -+ * to qemu_real_host_page_size. - */ -- range->bitmap.pgsize = TARGET_PAGE_SIZE; -+ range->bitmap.pgsize = qemu_real_host_page_size; - -- pages = TARGET_PAGE_ALIGN(range->size) >> TARGET_PAGE_BITS; -+ pages = REAL_HOST_PAGE_ALIGN(range->size) / qemu_real_host_page_size; - range->bitmap.size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / - BITS_PER_BYTE; - range->bitmap.data = g_try_malloc0(range->bitmap.size); -@@ -1077,8 +1079,8 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, - section->offset_within_region; - - return vfio_get_dirty_bitmap(container, -- TARGET_PAGE_ALIGN(section->offset_within_address_space), -- int128_get64(section->size), ram_addr); -+ REAL_HOST_PAGE_ALIGN(section->offset_within_address_space), -+ int128_get64(section->size), ram_addr); - } - - static void vfio_listener_log_sync(MemoryListener *listener, -@@ -1572,10 +1574,10 @@ static void vfio_get_iommu_info_migration(VFIOContainer *container, - header); - - /* -- * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of -- * TARGET_PAGE_SIZE to mark those dirty. -+ * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of -+ * qemu_real_host_page_size to mark those dirty. - */ -- if (cap_mig->pgsize_bitmap & TARGET_PAGE_SIZE) { -+ if (cap_mig->pgsize_bitmap & qemu_real_host_page_size) { - container->dirty_pages_supported = true; - container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; - container->dirty_pgsizes = cap_mig->pgsize_bitmap; --- -2.27.0 - diff --git a/vfio-add-quirk-device-write-method.patch b/vfio-add-quirk-device-write-method.patch deleted file mode 100644 index d7e2c99dc212605291627dac4dee0512e1b34f86..0000000000000000000000000000000000000000 --- a/vfio-add-quirk-device-write-method.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 95ee5273e25ed606aa86f8a154c06887efc20494 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Mar 2021 17:12:57 +0800 -Subject: [PATCH] vfio: add quirk device write method - ---- - hw/vfio/pci-quirks.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c -index b35a640030..9ce790bdd2 100644 ---- a/hw/vfio/pci-quirks.c -+++ b/hw/vfio/pci-quirks.c -@@ -12,6 +12,7 @@ - - #include "qemu/osdep.h" - #include "qemu/units.h" -+#include "qemu/log.h" - #include "qemu/error-report.h" - #include "qemu/main-loop.h" - #include "qemu/module.h" -@@ -275,8 +276,15 @@ static uint64_t vfio_ati_3c3_quirk_read(void *opaque, - return data; - } - -+static void vfio_ati_3c3_quirk_write(void *opaque, hwaddr addr, -+ uint64_t data, unsigned size) -+{ -+ qemu_log_mask(LOG_GUEST_ERROR, "%s not implemented\n", __func__); -+} -+ - static const MemoryRegionOps vfio_ati_3c3_quirk = { - .read = vfio_ati_3c3_quirk_read, -+ .write = vfio_ati_3c3_quirk_write, - .endianness = DEVICE_LITTLE_ENDIAN, - }; - --- -2.27.0 - diff --git a/vfio-common-Add-address-alignment-check-in-vfio_list.patch b/vfio-common-Add-address-alignment-check-in-vfio_list.patch new file mode 100644 index 0000000000000000000000000000000000000000..288f28482314f60dd0396228b35b17c0f9d67b8e --- /dev/null +++ b/vfio-common-Add-address-alignment-check-in-vfio_list.patch @@ -0,0 +1,53 @@ +From 00c553f53657bf4bc165d859187215dba7110246 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Tue, 14 Sep 2021 14:21:46 +0800 +Subject: [PATCH] vfio/common: Add address alignment check in + vfio_listener_region_del + +Both vfio_listener_region_add and vfio_listener_region_del have +reference counting operations on ram section->mr. If the 'iova' +and 'llend' of the ram section do not pass the alignment +check, the ram section should not be mapped or unmapped. It means +that the reference counting should not be changed. + +However, the address alignment check is missing in +vfio_listener_region_del. This makes memory_region_unref will +be unconditional called and causes unintended problems in some +scenarios. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/common.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 89c49f5508..4d45c2b625 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1411,6 +1411,8 @@ static void vfio_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) + { + VFIOContainer *container = container_of(listener, VFIOContainer, listener); ++ hwaddr iova; ++ Int128 llend; + + if (vfio_listener_skipped_section(section)) { + trace_vfio_listener_region_del_skip( +@@ -1460,6 +1462,14 @@ static void vfio_listener_region_del(MemoryListener *listener, + */ + } + ++ 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_and(llend, int128_exts64(qemu_real_host_page_mask)); ++ if (int128_ge(int128_make64(iova), llend)) { ++ return; ++ } ++ + vfio_dma_unmap_ram_section(container, section); + + memory_region_unref(section->mr); +-- +2.27.0 + diff --git a/vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch b/vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch index efcbd1fd03162efd34a1c11bc169e39da757da6b..71302b2d21e9840a0591d2960452de622cd60731 100644 --- a/vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch +++ b/vfio-common-Avoid-unmap-ram-section-at-vfio_listener.patch @@ -1,4 +1,4 @@ -From 55f3bdd0866be2b1a6223bacf9e00a032daf957c Mon Sep 17 00:00:00 2001 +From 9d7b782a0b2c5288e82f3064b4c5b7bf18887280 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Sat, 31 Jul 2021 10:02:18 +0800 Subject: [PATCH] vfio/common: Avoid unmap ram section at @@ -14,10 +14,10 @@ Signed-off-by: Kunkun Jiang 1 file changed, 10 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 98dc9e6f84..21a866e545 100644 +index d05a485808..bdfcc854fe 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1179,6 +1179,16 @@ static void vfio_listener_region_del(MemoryListener *listener, +@@ -1441,6 +1441,16 @@ static void vfio_listener_region_del(MemoryListener *listener, } } diff --git a/vfio-common-Fix-incorrect-address-alignment-in-vfio_.patch b/vfio-common-Fix-incorrect-address-alignment-in-vfio_.patch new file mode 100644 index 0000000000000000000000000000000000000000..d61408e6242adbb0c7e95b4cd94ec70fcca19c22 --- /dev/null +++ b/vfio-common-Fix-incorrect-address-alignment-in-vfio_.patch @@ -0,0 +1,40 @@ +From c2a4ce033db6ab74256e28da382c797a98047d4b Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Tue, 7 Sep 2021 15:14:12 +0800 +Subject: [PATCH] vfio/common: Fix incorrect address alignment in + vfio_dma_map_ram_section + +The 'iova' will be passed to host kernel for mapping with the +HPA. It is related to the host page size. So TARGET_PAGE_ALIGN +should be replaced by REAL_HOST_PAGE_ALIGN. In the case of +large granularity (64K), it may return early when map MMIO RAM +section. And because of the inconsistency with +vfio_dma_unmap_ram_section, it may cause 'assert(qrange)' +in vfio_dma_unmap. + +Signed-off-by: Kunkun Jiang +Signed-off-by: Zenghui Yu +--- + hw/vfio/common.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 65f3979492..89c49f5508 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1059,10 +1059,10 @@ static int vfio_dma_map_ram_section(VFIOContainer *container, + + assert(memory_region_is_ram(section->mr)); + +- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); ++ 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_and(llend, int128_exts64(TARGET_PAGE_MASK)); ++ llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); + end = int128_get64(int128_sub(llend, int128_one())); + + vaddr = memory_region_get_ram_ptr(section->mr) + +-- +2.27.0 + diff --git a/vfio-migrate-Move-switch-of-dirty-tracking-into-vfio.patch b/vfio-migrate-Move-switch-of-dirty-tracking-into-vfio.patch deleted file mode 100644 index 5f543b40bdb7e93d671edbd834b4279dec69c8c9..0000000000000000000000000000000000000000 --- a/vfio-migrate-Move-switch-of-dirty-tracking-into-vfio.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 74b651428e6ed65177354d80bd888e842a4a5077 Mon Sep 17 00:00:00 2001 -From: Keqian Zhu -Date: Tue, 9 Mar 2021 11:19:13 +0800 -Subject: [PATCH] vfio/migrate: Move switch of dirty tracking into - vfio_memory_listener - -For now the switch of vfio dirty page tracking is integrated into -@vfio_save_handler. The reason is that some PCI vendor driver may -start to track dirty base on _SAVING state of device, so if dirty -tracking is started before setting device state, vfio will report -full-dirty to QEMU. - -However, the dirty bmap of all ramblocks are fully set when setup -ram saving, so it's not matter whether the device is in _SAVING -state when start vfio dirty tracking. - -Moreover, this logic causes some problems [1]. The object of dirty -tracking is guest memory, but the object of @vfio_save_handler is -device state, which produces unnecessary coupling and conflicts: - -1. Coupling: Their saving granule is different (perVM vs perDevice). - vfio will enable dirty_page_tracking for each devices, actually - once is enough. - -2. Conflicts: The ram_save_setup() traverses all memory_listeners - to execute their log_start() and log_sync() hooks to get the - first round dirty bitmap, which is used by the bulk stage of - ram saving. However, as vfio dirty tracking is not yet started, - it can't get dirty bitmap from vfio. Then we give up the chance - to handle vfio dirty page at bulk stage. - -Move the switch of vfio dirty_page_tracking into vfio_memory_listener -can solve above problems. Besides, Do not require devices in SAVING -state for vfio_sync_dirty_bitmap(). - -[1] https://www.spinics.net/lists/kvm/msg229967.html - -Reported-by: Zenghui Yu -Signed-off-by: Keqian Zhu -Suggested-by: Paolo Bonzini -Message-Id: <20210309031913.11508-1-zhukeqian1@huawei.com> -Signed-off-by: Alex Williamson -Signed-off-by: Kunkun Jiang ---- - hw/vfio/common.c | 49 ++++++++++++++++++++++++++++++++++++--------- - hw/vfio/migration.c | 35 -------------------------------- - 2 files changed, 40 insertions(+), 44 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index a7817c90cc..245e32df5b 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -310,7 +310,7 @@ bool vfio_mig_active(void) - return true; - } - --static bool vfio_devices_all_saving(VFIOContainer *container) -+static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) - { - VFIOGroup *group; - VFIODevice *vbasedev; -@@ -328,13 +328,8 @@ static bool vfio_devices_all_saving(VFIOContainer *container) - return false; - } - -- if (migration->device_state & VFIO_DEVICE_STATE_SAVING) { -- if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) -- && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { -- return false; -- } -- continue; -- } else { -+ if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) -+ && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { - return false; - } - } -@@ -952,6 +947,40 @@ static void vfio_listener_region_del(MemoryListener *listener, - } - } - -+static void vfio_set_dirty_page_tracking(VFIOContainer *container, bool start) -+{ -+ int ret; -+ struct vfio_iommu_type1_dirty_bitmap dirty = { -+ .argsz = sizeof(dirty), -+ }; -+ -+ if (start) { -+ dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; -+ } else { -+ dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; -+ } -+ -+ ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); -+ if (ret) { -+ error_report("Failed to set dirty tracking flag 0x%x errno: %d", -+ dirty.flags, errno); -+ } -+} -+ -+static void vfio_listener_log_global_start(MemoryListener *listener) -+{ -+ VFIOContainer *container = container_of(listener, VFIOContainer, listener); -+ -+ vfio_set_dirty_page_tracking(container, true); -+} -+ -+static void vfio_listener_log_global_stop(MemoryListener *listener) -+{ -+ VFIOContainer *container = container_of(listener, VFIOContainer, listener); -+ -+ vfio_set_dirty_page_tracking(container, false); -+} -+ - static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - uint64_t size, ram_addr_t ram_addr) - { -@@ -1093,7 +1122,7 @@ static void vfio_listener_log_sync(MemoryListener *listener, - return; - } - -- if (vfio_devices_all_saving(container)) { -+ if (vfio_devices_all_dirty_tracking(container)) { - vfio_sync_dirty_bitmap(container, section); - } - } -@@ -1101,6 +1130,8 @@ static void vfio_listener_log_sync(MemoryListener *listener, - static const MemoryListener vfio_memory_listener = { - .region_add = vfio_listener_region_add, - .region_del = vfio_listener_region_del, -+ .log_global_start = vfio_listener_log_global_start, -+ .log_global_stop = vfio_listener_log_global_stop, - .log_sync = vfio_listener_log_sync, - }; - -diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c -index 033cb2b0c9..f1f006d584 100644 ---- a/hw/vfio/migration.c -+++ b/hw/vfio/migration.c -@@ -395,40 +395,10 @@ static int vfio_load_device_config_state(QEMUFile *f, void *opaque) - return qemu_file_get_error(f); - } - --static int vfio_set_dirty_page_tracking(VFIODevice *vbasedev, bool start) --{ -- int ret; -- VFIOMigration *migration = vbasedev->migration; -- VFIOContainer *container = vbasedev->group->container; -- struct vfio_iommu_type1_dirty_bitmap dirty = { -- .argsz = sizeof(dirty), -- }; -- -- if (start) { -- if (migration->device_state & VFIO_DEVICE_STATE_SAVING) { -- dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; -- } else { -- return -EINVAL; -- } -- } else { -- dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; -- } -- -- ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); -- if (ret) { -- error_report("Failed to set dirty tracking flag 0x%x errno: %d", -- dirty.flags, errno); -- return -errno; -- } -- return ret; --} -- - static void vfio_migration_cleanup(VFIODevice *vbasedev) - { - VFIOMigration *migration = vbasedev->migration; - -- vfio_set_dirty_page_tracking(vbasedev, false); -- - if (migration->region.mmaps) { - vfio_region_unmap(&migration->region); - } -@@ -469,11 +439,6 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) - return ret; - } - -- ret = vfio_set_dirty_page_tracking(vbasedev, true); -- if (ret) { -- return ret; -- } -- - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - - ret = qemu_file_get_error(f); --- -2.27.0 - diff --git a/vfio-migration-Add-support-for-manual-clear-vfio-dir.patch b/vfio-migration-Add-support-for-manual-clear-vfio-dir.patch index c59bc4e1ff70f6993557329480505c4300ff6aa0..0a5ff88f995220f5c3128eb8e56c86afeffe53e2 100644 --- a/vfio-migration-Add-support-for-manual-clear-vfio-dir.patch +++ b/vfio-migration-Add-support-for-manual-clear-vfio-dir.patch @@ -1,4 +1,4 @@ -From f9574b63bf5e940d794db2c3aaf928bde36d9521 Mon Sep 17 00:00:00 2001 +From 815258f81a660ad87272191dca4a9726cb2bf5b2 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Sat, 8 May 2021 17:31:05 +0800 Subject: [PATCH] vfio/migration: Add support for manual clear vfio dirty log @@ -20,10 +20,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index c33c4c539d..206fb83e28 100644 +index 86ea784919..6cb91e7ffd 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c -@@ -1045,7 +1045,9 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, +@@ -1315,7 +1315,9 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); @@ -34,7 +34,7 @@ index c33c4c539d..206fb83e28 100644 range = (struct vfio_iommu_type1_dirty_bitmap_get *)&dbitmap->data; range->iova = iova; range->size = size; -@@ -1176,12 +1178,148 @@ static void vfio_listener_log_sync(MemoryListener *listener, +@@ -1491,6 +1493,141 @@ static void vfio_listener_log_sync(MemoryListener *listener, } } @@ -174,8 +174,9 @@ index c33c4c539d..206fb83e28 100644 +} + static const MemoryListener vfio_memory_listener = { + .name = "vfio", .region_add = vfio_listener_region_add, - .region_del = vfio_listener_region_del, +@@ -1498,6 +1635,7 @@ static const MemoryListener vfio_memory_listener = { .log_global_start = vfio_listener_log_global_start, .log_global_stop = vfio_listener_log_global_stop, .log_sync = vfio_listener_log_sync, @@ -183,7 +184,7 @@ index c33c4c539d..206fb83e28 100644 }; static void vfio_listener_release(VFIOContainer *container) -@@ -1563,7 +1701,7 @@ static int vfio_get_iommu_type(VFIOContainer *container, +@@ -1925,7 +2063,7 @@ static int vfio_get_iommu_type(VFIOContainer *container, static int vfio_init_container(VFIOContainer *container, int group_fd, Error **errp) { @@ -192,7 +193,7 @@ index c33c4c539d..206fb83e28 100644 iommu_type = vfio_get_iommu_type(container, errp); if (iommu_type < 0) { -@@ -1592,6 +1730,13 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, +@@ -1954,6 +2092,13 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, } container->iommu_type = iommu_type; @@ -207,11 +208,11 @@ index c33c4c539d..206fb83e28 100644 } diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h -index 2853dc861e..1277914ca8 100644 +index 20b9c8a1d3..0234f5e1b1 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -93,6 +93,7 @@ typedef struct VFIOContainer { - int error; + Error *error; bool initialized; bool dirty_pages_supported; + bool dirty_log_manual_clear; diff --git a/vfio-migration-Fix-incorrect-initialization-value-fo.patch b/vfio-migration-Fix-incorrect-initialization-value-fo.patch new file mode 100644 index 0000000000000000000000000000000000000000..378fa7d74d481f1952c8f67537e2285c6a2bbaf7 --- /dev/null +++ b/vfio-migration-Fix-incorrect-initialization-value-fo.patch @@ -0,0 +1,37 @@ +From d57f2527fd747d2b51ad18dc38fa9d0c25ebc8a7 Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Mon, 11 Jul 2022 09:46:51 +0800 +Subject: [PATCH 2/3] vfio/migration: Fix incorrect initialization value for + parameters in VFIOMigration + +The structure VFIOMigration of a VFIODevice is allocated and initialized +in vfio_migration_init(). "device_state" and "vm_running" are initialized +to 0, indicating that VFIO device is_STOP and VM is not-running. The +initialization value is incorrect. According to the agreement, default +state of VFIO device is _RUNNING. And if a VFIO device is hot-plugged +while the VM is running, "vm_running" should be 1. This patch fixes it. + +Fixes: 02a7e71b1e5b ("vfio: Add VM state change handler to know state of VM") +Signed-off-by: Kunkun Jiang +Link: https://lore.kernel.org/r/20220711014651.1327-1-jiangkunkun@huawei.com +Signed-off-by: Alex Williamson +--- + hw/vfio/migration.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c +index ff6b45de6b..e69b5f2e42 100644 +--- a/hw/vfio/migration.c ++++ b/hw/vfio/migration.c +@@ -805,6 +805,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, + } + + vbasedev->migration = g_new0(VFIOMigration, 1); ++ vbasedev->migration->device_state = VFIO_DEVICE_STATE_RUNNING; ++ vbasedev->migration->vm_running = runstate_is_running(); + + ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, + info->index, "migration"); +-- +2.27.0 + diff --git a/vfio-pci-Ascend310-need-4Bytes-quirk-in-bar4.patch b/vfio-pci-Ascend310-need-4Bytes-quirk-in-bar4.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3ea4c233b747fac21f166edb4b65717b1998cb1 --- /dev/null +++ b/vfio-pci-Ascend310-need-4Bytes-quirk-in-bar4.patch @@ -0,0 +1,105 @@ +From eee7ff398496524881225d503309a9853972c5df Mon Sep 17 00:00:00 2001 +From: Binfeng Wu +Date: Tue, 8 Feb 2022 17:00:39 +0800 +Subject: [PATCH 3/5] vfio/pci: Ascend310 need 4Bytes quirk in bar4 + +--- + hw/vfio/pci-quirks.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index 0cf69a8c6d..d86bcaf309 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1209,6 +1209,80 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, + return 0; + } + ++#define PCI_VENDOR_ID_HUAWEI 0x19e5 ++#define PCI_DEVICE_ID_ASCEND310 0xd100 ++#define ASCEND310_XLOADER_SIZE 4 ++#define ASCEND310_XLOADER_OFFSET 0x400 ++ ++typedef struct VFIOAscendBarQuirk { ++ struct VFIOPCIDevice *vdev; ++ pcibus_t offset; ++ uint8_t bar; ++ MemoryRegion *mem; ++} VFIOAscendBarQuirk; ++ ++static uint64_t vfio_ascend_quirk_read(void *opaque, ++ hwaddr addr, unsigned size) ++{ ++ VFIOAscendBarQuirk *quirk = opaque; ++ VFIOPCIDevice *vdev = quirk->vdev; ++ ++ qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n", ++ addr + quirk->offset, size); ++ ++ return vfio_region_read(&vdev->bars[quirk->bar].region, ++ addr + quirk->offset, size); ++} ++ ++static void vfio_ascend_quirk_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ VFIOAscendBarQuirk *quirk = opaque; ++ ++ qemu_log("modifying RO region is not allowed! addr=0x%" ++ HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n", ++ addr + quirk->offset, data, size); ++} ++ ++static const MemoryRegionOps vfio_ascend_intercept_regs_quirk = { ++ .read = vfio_ascend_quirk_read, ++ .write = vfio_ascend_quirk_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr) ++{ ++ VFIOQuirk *quirk; ++ VFIOAscendBarQuirk *bar4_quirk; ++ ++ if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 || ++ vdev->device_id != PCI_DEVICE_ID_ASCEND310) { ++ return; ++ } ++ ++ quirk = g_malloc0(sizeof(*quirk)); ++ quirk->nr_mem = 1; ++ quirk->mem = g_new0(MemoryRegion, quirk->nr_mem); ++ bar4_quirk = quirk->data = g_new0(typeof(*bar4_quirk), quirk->nr_mem); ++ bar4_quirk[0].vdev = vdev; ++ bar4_quirk[0].offset = ASCEND310_XLOADER_OFFSET; ++ bar4_quirk[0].bar = nr; ++ ++ /* ++ * intercept w/r to the xloader-updating register, ++ * so the vm can't enable xloader-updating ++ */ ++ memory_region_init_io(&quirk->mem[0], OBJECT(vdev), ++ &vfio_ascend_intercept_regs_quirk, ++ &bar4_quirk[0], ++ "vfio-ascend310-bar4-intercept-regs-quirk", ++ ASCEND310_XLOADER_SIZE); ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, ++ bar4_quirk[0].offset, ++ &quirk->mem[0], 1); ++ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); ++} ++ + /* + * Common quirk probe entry points. + */ +@@ -1261,6 +1335,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + #ifdef CONFIG_VFIO_IGD + vfio_probe_igd_bar4_quirk(vdev, nr); + #endif ++ vfio_probe_ascend310_bar4_quirk(vdev, nr); + } + + void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr) +-- +2.27.0 + diff --git a/vfio-pci-Ascend710-change-to-bar2-quirk.patch b/vfio-pci-Ascend710-change-to-bar2-quirk.patch new file mode 100644 index 0000000000000000000000000000000000000000..0039aaead4b93c0358021828277acf118b66e3ef --- /dev/null +++ b/vfio-pci-Ascend710-change-to-bar2-quirk.patch @@ -0,0 +1,125 @@ +From ce59c78060b5eb13026ca1cbbc046e90ea01a607 Mon Sep 17 00:00:00 2001 +From: Wu Binfeng +Date: Mon, 25 Apr 2022 15:17:48 +0800 +Subject: [PATCH] vfio/pci: Ascend710 change to bar2 quirk + +Change Ascend710's quirk regions to bar2 for internal causes. +And support Ascend710 2P format now. +--- + hw/vfio/pci-quirks.c | 64 +++++++++++++++++++++++++++++++++++--------- + 1 file changed, 51 insertions(+), 13 deletions(-) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index 2457a61196..1222ccff0b 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1213,10 +1213,17 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, + #define PCI_DEVICE_ID_ASCEND910 0xd801 + #define PCI_DEVICE_ID_ASCEND710 0xd500 + #define PCI_DEVICE_ID_ASCEND310 0xd100 ++#define PCI_SUB_DEVICE_ID_ASCEND710_1P_MIN 0x100 ++#define PCI_SUB_DEVICE_ID_ASCEND710_1P_MAX 0x10f ++#define PCI_SUB_DEVICE_ID_ASCEND710_2P_MIN 0x110 ++#define PCI_SUB_DEVICE_ID_ASCEND710_2P_MAX 0x11f + #define ASCEND910_XLOADER_SIZE 4 + #define ASCEND910_XLOADER_OFFSET 0x80400 ++#define ASCEND710_2P_BASE (128 * 1024 * 1024) ++#define ASCEND710_1P_DEVNUM 1 ++#define ASCEND710_2P_DEVNUM 2 + #define ASCEND710_XLOADER_SIZE 4 +-#define ASCEND710_XLOADER_OFFSET 0x20430 ++#define ASCEND710_XLOADER_OFFSET 0x100430 + #define ASCEND310_XLOADER_SIZE 4 + #define ASCEND310_XLOADER_OFFSET 0x400 + +@@ -1289,23 +1296,38 @@ static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr) + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + } + +-static void vfio_probe_ascend710_bar0_quirk(VFIOPCIDevice *vdev, int nr) ++static void vfio_probe_ascend710_bar2_quirk(VFIOPCIDevice *vdev, int nr) + { + VFIOQuirk *quirk; +- VFIOAscendBarQuirk *bar0_quirk; ++ VFIOAscendBarQuirk *bar2_quirk; ++ int sub_device_id; ++ int devnum = 0; + +- if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 || ++ if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 || + vdev->device_id != PCI_DEVICE_ID_ASCEND710) { + return; + } + ++ sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID); ++ if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND710_1P_MIN && ++ sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND710_1P_MAX) { ++ devnum = ASCEND710_1P_DEVNUM; ++ } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND710_2P_MIN && ++ sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND710_2P_MAX) { ++ devnum = ASCEND710_2P_DEVNUM; ++ } ++ ++ if (devnum != ASCEND710_1P_DEVNUM && devnum != ASCEND710_2P_DEVNUM) { ++ return; ++ } ++ + quirk = g_malloc0(sizeof(*quirk)); +- quirk->nr_mem = 1; ++ quirk->nr_mem = devnum; + quirk->mem = g_new0(MemoryRegion, quirk->nr_mem); +- bar0_quirk = quirk->data = g_new0(typeof(*bar0_quirk), quirk->nr_mem); +- bar0_quirk[0].vdev = vdev; +- bar0_quirk[0].offset = ASCEND710_XLOADER_OFFSET; +- bar0_quirk[0].bar = nr; ++ bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem); ++ bar2_quirk[0].vdev = vdev; ++ bar2_quirk[0].offset = ASCEND710_XLOADER_OFFSET; ++ bar2_quirk[0].bar = nr; + + /* + * intercept w/r to the xloader-updating register, +@@ -1313,12 +1335,28 @@ static void vfio_probe_ascend710_bar0_quirk(VFIOPCIDevice *vdev, int nr) + */ + memory_region_init_io(&quirk->mem[0], OBJECT(vdev), + &vfio_ascend_intercept_regs_quirk, +- &bar0_quirk[0], +- "vfio-ascend710-bar0-intercept-regs-quirk", ++ &bar2_quirk[0], ++ "vfio-ascend710-bar2-1p-intercept-regs-quirk", + ASCEND710_XLOADER_SIZE); + memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, +- bar0_quirk[0].offset, ++ bar2_quirk[0].offset, + &quirk->mem[0], 1); ++ ++ if (devnum == ASCEND710_2P_DEVNUM) { ++ bar2_quirk[1].vdev = vdev; ++ bar2_quirk[1].offset = (ASCEND710_2P_BASE + ASCEND710_XLOADER_OFFSET); ++ bar2_quirk[1].bar = nr; ++ ++ memory_region_init_io(&quirk->mem[1], OBJECT(vdev), ++ &vfio_ascend_intercept_regs_quirk, ++ &bar2_quirk[1], ++ "vfio-ascend710-bar2-2p-intercept-regs-quirk", ++ ASCEND710_XLOADER_SIZE); ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, ++ bar2_quirk[1].offset, ++ &quirk->mem[1], 1); ++ } ++ + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + } + +@@ -1408,7 +1446,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + vfio_probe_igd_bar4_quirk(vdev, nr); + #endif + vfio_probe_ascend910_bar0_quirk(vdev, nr); +- vfio_probe_ascend710_bar0_quirk(vdev, nr); ++ vfio_probe_ascend710_bar2_quirk(vdev, nr); + vfio_probe_ascend310_bar4_quirk(vdev, nr); + } + +-- +2.27.0 + diff --git a/vfio-pci-Ascend710-need-4Bytes-quirk-in-bar0.patch b/vfio-pci-Ascend710-need-4Bytes-quirk-in-bar0.patch new file mode 100644 index 0000000000000000000000000000000000000000..93d7b2584b41a640d2b3615f7495d4734a47ac72 --- /dev/null +++ b/vfio-pci-Ascend710-need-4Bytes-quirk-in-bar0.patch @@ -0,0 +1,75 @@ +From bcc63ff3975cca783308fac7517a7911c29bd7c1 Mon Sep 17 00:00:00 2001 +From: Binfeng Wu +Date: Tue, 8 Feb 2022 17:16:04 +0800 +Subject: [PATCH 4/5] vfio/pci: Ascend710 need 4Bytes quirk in bar0 + +--- + hw/vfio/pci-quirks.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index d86bcaf309..6a9fc0afc5 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1210,7 +1210,10 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, + } + + #define PCI_VENDOR_ID_HUAWEI 0x19e5 ++#define PCI_DEVICE_ID_ASCEND710 0xd500 + #define PCI_DEVICE_ID_ASCEND310 0xd100 ++#define ASCEND710_XLOADER_SIZE 4 ++#define ASCEND710_XLOADER_OFFSET 0x20430 + #define ASCEND310_XLOADER_SIZE 4 + #define ASCEND310_XLOADER_OFFSET 0x400 + +@@ -1250,6 +1253,39 @@ static const MemoryRegionOps vfio_ascend_intercept_regs_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + ++static void vfio_probe_ascend710_bar0_quirk(VFIOPCIDevice *vdev, int nr) ++{ ++ VFIOQuirk *quirk; ++ VFIOAscendBarQuirk *bar0_quirk; ++ ++ if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 || ++ vdev->device_id != PCI_DEVICE_ID_ASCEND710) { ++ return; ++ } ++ ++ quirk = g_malloc0(sizeof(*quirk)); ++ quirk->nr_mem = 1; ++ quirk->mem = g_new0(MemoryRegion, quirk->nr_mem); ++ bar0_quirk = quirk->data = g_new0(typeof(*bar0_quirk), quirk->nr_mem); ++ bar0_quirk[0].vdev = vdev; ++ bar0_quirk[0].offset = ASCEND710_XLOADER_OFFSET; ++ bar0_quirk[0].bar = nr; ++ ++ /* ++ * intercept w/r to the xloader-updating register, ++ * so the vm can't enable xloader-updating ++ */ ++ memory_region_init_io(&quirk->mem[0], OBJECT(vdev), ++ &vfio_ascend_intercept_regs_quirk, ++ &bar0_quirk[0], ++ "vfio-ascend710-bar0-intercept-regs-quirk", ++ ASCEND710_XLOADER_SIZE); ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, ++ bar0_quirk[0].offset, ++ &quirk->mem[0], 1); ++ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); ++} ++ + static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr) + { + VFIOQuirk *quirk; +@@ -1335,6 +1371,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + #ifdef CONFIG_VFIO_IGD + vfio_probe_igd_bar4_quirk(vdev, nr); + #endif ++ vfio_probe_ascend710_bar0_quirk(vdev, nr); + vfio_probe_ascend310_bar4_quirk(vdev, nr); + } + +-- +2.27.0 + diff --git a/vfio-pci-Ascend910-need-4Bytes-quirk-in-bar0.patch b/vfio-pci-Ascend910-need-4Bytes-quirk-in-bar0.patch new file mode 100644 index 0000000000000000000000000000000000000000..34b835d9b297aa8f532ff8498374dd8341d6861f --- /dev/null +++ b/vfio-pci-Ascend910-need-4Bytes-quirk-in-bar0.patch @@ -0,0 +1,76 @@ +From 4cf7d00e43c4e90327e13afa3cbc9c7ca3657c9f Mon Sep 17 00:00:00 2001 +From: Binfeng Wu +Date: Tue, 8 Feb 2022 19:20:36 +0800 +Subject: [PATCH 5/5] vfio/pci: Ascend910 need 4Bytes quirk in bar0 + +--- + hw/vfio/pci-quirks.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c +index 6a9fc0afc5..2457a61196 100644 +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -1210,8 +1210,11 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, + } + + #define PCI_VENDOR_ID_HUAWEI 0x19e5 ++#define PCI_DEVICE_ID_ASCEND910 0xd801 + #define PCI_DEVICE_ID_ASCEND710 0xd500 + #define PCI_DEVICE_ID_ASCEND310 0xd100 ++#define ASCEND910_XLOADER_SIZE 4 ++#define ASCEND910_XLOADER_OFFSET 0x80400 + #define ASCEND710_XLOADER_SIZE 4 + #define ASCEND710_XLOADER_OFFSET 0x20430 + #define ASCEND310_XLOADER_SIZE 4 +@@ -1253,6 +1256,39 @@ static const MemoryRegionOps vfio_ascend_intercept_regs_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + ++static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr) ++{ ++ VFIOQuirk *quirk; ++ VFIOAscendBarQuirk *bar0_quirk; ++ ++ if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 || ++ vdev->device_id != PCI_DEVICE_ID_ASCEND910) { ++ return; ++ } ++ ++ quirk = g_malloc0(sizeof(*quirk)); ++ quirk->nr_mem = 1; ++ quirk->mem = g_new0(MemoryRegion, quirk->nr_mem); ++ bar0_quirk = quirk->data = g_new0(typeof(*bar0_quirk), quirk->nr_mem); ++ bar0_quirk[0].vdev = vdev; ++ bar0_quirk[0].offset = ASCEND910_XLOADER_OFFSET; ++ bar0_quirk[0].bar = nr; ++ ++ /* ++ * intercept w/r to the xloader-updating register, ++ * so the vm can't enable xloader-updating ++ */ ++ memory_region_init_io(&quirk->mem[0], OBJECT(vdev), ++ &vfio_ascend_intercept_regs_quirk, ++ &bar0_quirk[0], ++ "vfio-ascend910-bar0-intercept-regs-quirk", ++ ASCEND910_XLOADER_SIZE); ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, ++ bar0_quirk[0].offset, ++ &quirk->mem[0], 1); ++ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); ++} ++ + static void vfio_probe_ascend710_bar0_quirk(VFIOPCIDevice *vdev, int nr) + { + VFIOQuirk *quirk; +@@ -1371,6 +1407,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + #ifdef CONFIG_VFIO_IGD + vfio_probe_igd_bar4_quirk(vdev, nr); + #endif ++ vfio_probe_ascend910_bar0_quirk(vdev, nr); + vfio_probe_ascend710_bar0_quirk(vdev, nr); + vfio_probe_ascend310_bar4_quirk(vdev, nr); + } +-- +2.27.0 + diff --git a/vfio-pci-Fix-a-segfault-in-vfio_realize.patch b/vfio-pci-Fix-a-segfault-in-vfio_realize.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ac8a6de98527eb53df815813f4fcf06907a85e2 --- /dev/null +++ b/vfio-pci-Fix-a-segfault-in-vfio_realize.patch @@ -0,0 +1,54 @@ +From 22e8d7076800d7c62e41e8c69fc01444cf00d451 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Fri, 30 Jun 2023 21:05:23 +0800 +Subject: [PATCH] vfio/pci: Fix a segfault in vfio_realize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The kvm irqchip notifier is only registered if the device supports +INTx, however it's unconditionally removed in vfio realize error +path. If the assigned device does not support INTx, this will cause +QEMU to crash when vfio realize fails. Change it to conditionally +remove the notifier only if the notify hook is setup. + +Before fix: +(qemu) device_add vfio-pci,host=81:11.1,id=vfio1,bus=root1,xres=1 +Connection closed by foreign host. + +After fix: +(qemu) device_add vfio-pci,host=81:11.1,id=vfio1,bus=root1,xres=1 +Error: vfio 0000:81:11.1: xres and yres properties require display=on +(qemu) + +Fixes: c5478fea27ac ("vfio/pci: Respond to KVM irqchip change notifier") + +cheery-pick from 357bd7932a136613d700ee8bc83e9165f059d1f7 + +Signed-off-by: jipengfei_yewu +Signed-off-by: Zhenzhong Duan +Reviewed-by: Cédric Le Goater +Reviewed-by: Joao Martins +Signed-off-by: Cédric Le Goater +--- + hw/vfio/pci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 7b45353ce2..b085389ff8 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -3112,7 +3112,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + + out_deregister: + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); +- kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); ++ if (vdev->irqchip_change_notifier.notify) { ++ kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); ++ } + out_teardown: + vfio_teardown_msi(vdev); + vfio_bars_exit(vdev); +-- +2.41.0.windows.1 + diff --git a/vfio-pci-Implement-return_page_response-page-respons.patch b/vfio-pci-Implement-return_page_response-page-respons.patch index 721512e4095c6385efe44279e7e44744ea781899..21d88a363a4ddb9305b9990424a121e8ccb68623 100644 --- a/vfio-pci-Implement-return_page_response-page-respons.patch +++ b/vfio-pci-Implement-return_page_response-page-respons.patch @@ -1,4 +1,4 @@ -From dab7c3ad6d51e9f0c65d864d6128f62697db4604 Mon Sep 17 00:00:00 2001 +From 6bbf810edebdb89a6958519ee3adfb1888520231 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 6 Nov 2020 12:03:29 -0500 Subject: [PATCH] vfio/pci: Implement return_page_response page response @@ -18,10 +18,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 125 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index d1198c8a23..6f4083aec8 100644 +index c54e62fe8f..8e24f9c7d1 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -2662,6 +2662,61 @@ out: +@@ -2693,6 +2693,61 @@ out: g_free(fault_region_info); } @@ -83,7 +83,7 @@ index d1198c8a23..6f4083aec8 100644 static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) { VFIODevice *vbasedev = &vdev->vbasedev; -@@ -2737,6 +2792,12 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) +@@ -2768,6 +2823,12 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) return; } @@ -96,7 +96,7 @@ index d1198c8a23..6f4083aec8 100644 irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); -@@ -2915,8 +2976,68 @@ static int vfio_iommu_set_pasid_table(PCIBus *bus, int32_t devfn, +@@ -2946,8 +3007,68 @@ static int vfio_iommu_set_pasid_table(PCIBus *bus, int32_t devfn, return ioctl(container->fd, VFIO_IOMMU_SET_PASID_TABLE, &info); } @@ -165,7 +165,7 @@ index d1198c8a23..6f4083aec8 100644 }; static void vfio_dma_fault_notifier_handler(void *opaque) -@@ -3373,6 +3494,7 @@ static void vfio_instance_finalize(Object *obj) +@@ -3411,6 +3532,7 @@ static void vfio_instance_finalize(Object *obj) vfio_display_finalize(vdev); vfio_bars_finalize(vdev); vfio_region_finalize(&vdev->dma_fault_region); @@ -173,19 +173,19 @@ index d1198c8a23..6f4083aec8 100644 g_free(vdev->emulated_config_bits); g_free(vdev->rom); /* -@@ -3394,6 +3516,7 @@ static void vfio_exitfn(PCIDevice *pdev) +@@ -3432,6 +3554,7 @@ static void vfio_exitfn(PCIDevice *pdev) vfio_unregister_err_notifier(vdev); vfio_unregister_ext_irq_notifiers(vdev); vfio_region_exit(&vdev->dma_fault_region); + vfio_region_exit(&vdev->dma_fault_response_region); pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); - vfio_disable_interrupts(vdev); - if (vdev->intx.mmap_timer) { + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index e31bc0173a..7fdcfa0dc8 100644 +index 03ac8919ef..61b3bf1303 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h -@@ -143,6 +143,8 @@ typedef struct VFIOPCIDevice { +@@ -147,6 +147,8 @@ struct VFIOPCIDevice { VFIOPCIExtIRQ *ext_irqs; VFIORegion dma_fault_region; uint32_t fault_tail_index; diff --git a/vfio-pci-Implement-the-DMA-fault-handler.patch b/vfio-pci-Implement-the-DMA-fault-handler.patch index ca61b01c4469cd30c3b4b781c2cc527b48c45e80..7d7349c9088662d0e38aa22c0b0ecbea3e0f7506 100644 --- a/vfio-pci-Implement-the-DMA-fault-handler.patch +++ b/vfio-pci-Implement-the-DMA-fault-handler.patch @@ -1,4 +1,4 @@ -From 139d0b3474c29427fea4a0ed47f51c01a76a8636 Mon Sep 17 00:00:00 2001 +From d33cc7eccb68c6a1488804c94ff5c1197ee0fc6e Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 5 Mar 2019 16:35:32 +0100 Subject: [PATCH] vfio/pci: Implement the DMA fault handler @@ -15,10 +15,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 51 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 0db7d68258..d1198c8a23 100644 +index 76bc9d3506..c54e62fe8f 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -2922,10 +2922,60 @@ static PCIPASIDOps vfio_pci_pasid_ops = { +@@ -2953,10 +2953,60 @@ static PCIPASIDOps vfio_pci_pasid_ops = { static void vfio_dma_fault_notifier_handler(void *opaque) { VFIOPCIExtIRQ *ext_irq = opaque; @@ -80,10 +80,10 @@ index 0db7d68258..d1198c8a23 100644 static int vfio_register_ext_irq_handler(VFIOPCIDevice *vdev, diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index 815154656c..e31bc0173a 100644 +index eef91065f1..03ac8919ef 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h -@@ -142,6 +142,7 @@ typedef struct VFIOPCIDevice { +@@ -146,6 +146,7 @@ struct VFIOPCIDevice { EventNotifier req_notifier; VFIOPCIExtIRQ *ext_irqs; VFIORegion dma_fault_region; diff --git a/vfio-pci-Register-handler-for-iommu-fault.patch b/vfio-pci-Register-handler-for-iommu-fault.patch index feea0a347baad96a592cefba3dd6957947d1505d..7209a807ee0911af0f6af7e01e29a9ff389944dc 100644 --- a/vfio-pci-Register-handler-for-iommu-fault.patch +++ b/vfio-pci-Register-handler-for-iommu-fault.patch @@ -1,4 +1,4 @@ -From 65b96da46d2c5dfdcf3a4618cf75ca94345164d7 Mon Sep 17 00:00:00 2001 +From 574455d1363e818905e05cd23ef0948e83a16a51 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 13 Dec 2018 04:39:30 -0500 Subject: [PATCH] vfio/pci: Register handler for iommu fault @@ -19,10 +19,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index bbcba3fd16..f5c05d508d 100644 +index 99c52a0944..37a70932c6 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -2857,6 +2857,76 @@ static PCIPASIDOps vfio_pci_pasid_ops = { +@@ -2888,6 +2888,76 @@ static PCIPASIDOps vfio_pci_pasid_ops = { .set_pasid_table = vfio_iommu_set_pasid_table, }; @@ -98,8 +98,8 @@ index bbcba3fd16..f5c05d508d 100644 + static void vfio_realize(PCIDevice *pdev, Error **errp) { - VFIOPCIDevice *vdev = PCI_VFIO(pdev); -@@ -2867,7 +2937,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + VFIOPCIDevice *vdev = VFIO_PCI(pdev); +@@ -2898,7 +2968,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) ssize_t len; struct stat st; int groupid; @@ -108,7 +108,7 @@ index bbcba3fd16..f5c05d508d 100644 bool is_mdev; if (!vdev->vbasedev.sysfsdev) { -@@ -2955,6 +3025,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) +@@ -2986,6 +3056,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } @@ -120,7 +120,7 @@ index bbcba3fd16..f5c05d508d 100644 vfio_populate_device(vdev, &err); if (err) { error_propagate(errp, err); -@@ -3161,6 +3236,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) +@@ -3197,6 +3272,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_register_err_notifier(vdev); vfio_register_req_notifier(vdev); @@ -130,19 +130,19 @@ index bbcba3fd16..f5c05d508d 100644 vfio_setup_resetfn_quirk(vdev); pci_setup_pasid_ops(pdev, &vfio_pci_pasid_ops); -@@ -3201,6 +3279,7 @@ static void vfio_exitfn(PCIDevice *pdev) +@@ -3239,6 +3317,7 @@ static void vfio_exitfn(PCIDevice *pdev) vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); + vfio_unregister_ext_irq_notifiers(vdev); pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); - vfio_disable_interrupts(vdev); - if (vdev->intx.mmap_timer) { + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index 834a90d646..893d074375 100644 +index 64777516d1..a8b06737fb 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h -@@ -113,6 +113,12 @@ typedef struct VFIOMSIXInfo { +@@ -114,6 +114,12 @@ typedef struct VFIOMSIXInfo { unsigned long *pending; } VFIOMSIXInfo; @@ -152,10 +152,10 @@ index 834a90d646..893d074375 100644 + uint32_t index; +} VFIOPCIExtIRQ; + - typedef struct VFIOPCIDevice { - PCIDevice pdev; - VFIODevice vbasedev; -@@ -134,6 +140,7 @@ typedef struct VFIOPCIDevice { + #define TYPE_VFIO_PCI "vfio-pci" + OBJECT_DECLARE_SIMPLE_TYPE(VFIOPCIDevice, VFIO_PCI) + +@@ -138,6 +144,7 @@ struct VFIOPCIDevice { PCIHostDeviceAddress host; EventNotifier err_notifier; EventNotifier req_notifier; diff --git a/vfio-pci-Set-up-the-DMA-FAULT-region.patch b/vfio-pci-Set-up-the-DMA-FAULT-region.patch index ae70a0696cb8310e2669b7e75d2e12bf8e9911f8..9a4757dc7bbd03571a7d7e5981828ad817da5654 100644 --- a/vfio-pci-Set-up-the-DMA-FAULT-region.patch +++ b/vfio-pci-Set-up-the-DMA-FAULT-region.patch @@ -1,4 +1,4 @@ -From e44d9cc377848f0a560b6d114561852e95fab557 Mon Sep 17 00:00:00 2001 +From e701d0fef4fbb7935d6aa7d22d82eb2dcfee2431 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 13 Dec 2018 10:57:53 -0500 Subject: [PATCH] vfio/pci: Set up the DMA FAULT region @@ -15,10 +15,10 @@ Signed-off-by: Kunkun Jiang 2 files changed, 65 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index f5c05d508d..0db7d68258 100644 +index 37a70932c6..76bc9d3506 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -2607,11 +2607,67 @@ int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) +@@ -2638,11 +2638,67 @@ int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) return 0; } @@ -86,7 +86,7 @@ index f5c05d508d..0db7d68258 100644 int i, ret = -1; /* Sanity check device */ -@@ -2675,6 +2731,12 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) +@@ -2706,6 +2762,12 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) } } @@ -99,7 +99,7 @@ index f5c05d508d..0db7d68258 100644 irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); -@@ -3260,6 +3322,7 @@ static void vfio_instance_finalize(Object *obj) +@@ -3298,6 +3360,7 @@ static void vfio_instance_finalize(Object *obj) vfio_display_finalize(vdev); vfio_bars_finalize(vdev); @@ -107,19 +107,19 @@ index f5c05d508d..0db7d68258 100644 g_free(vdev->emulated_config_bits); g_free(vdev->rom); /* -@@ -3280,6 +3343,7 @@ static void vfio_exitfn(PCIDevice *pdev) +@@ -3318,6 +3381,7 @@ static void vfio_exitfn(PCIDevice *pdev) vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); vfio_unregister_ext_irq_notifiers(vdev); + vfio_region_exit(&vdev->dma_fault_region); pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); - vfio_disable_interrupts(vdev); - if (vdev->intx.mmap_timer) { + if (vdev->irqchip_change_notifier.notify) { + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index 893d074375..815154656c 100644 +index a8b06737fb..eef91065f1 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h -@@ -141,6 +141,7 @@ typedef struct VFIOPCIDevice { +@@ -145,6 +145,7 @@ struct VFIOPCIDevice { EventNotifier err_notifier; EventNotifier req_notifier; VFIOPCIExtIRQ *ext_irqs; diff --git a/vfio.h-and-iommu.h-header-update-against-5.10.patch b/vfio.h-and-iommu.h-header-update-against-5.10.patch index 721f2b6fcbc9de84c77b59ddf68da60d3d1fd255..8272a6793eb1b672efe3980f4abc3ca61cb39732 100644 --- a/vfio.h-and-iommu.h-header-update-against-5.10.patch +++ b/vfio.h-and-iommu.h-header-update-against-5.10.patch @@ -1,4 +1,4 @@ -From 95435c6778f38dee9ed6f3ee6fd9e022107315d7 Mon Sep 17 00:00:00 2001 +From 36b65d7312a343cb636e6963b8262dce9420ebc6 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Fri, 30 Jul 2021 09:15:31 +0800 Subject: [PATCH] vfio.h and iommu.h header update against 5.10 @@ -6,8 +6,8 @@ Subject: [PATCH] vfio.h and iommu.h header update against 5.10 Signed-off-by: Kunkun Jiang --- linux-headers/linux/iommu.h | 395 ++++++++++++++++++++++++++++++++++++ - linux-headers/linux/vfio.h | 249 ++++++++++++++++++++++- - 2 files changed, 641 insertions(+), 3 deletions(-) + linux-headers/linux/vfio.h | 220 +++++++++++++++++++- + 2 files changed, 613 insertions(+), 2 deletions(-) create mode 100644 linux-headers/linux/iommu.h diff --git a/linux-headers/linux/iommu.h b/linux-headers/linux/iommu.h @@ -412,7 +412,7 @@ index 0000000000..773b7dc2d6 + +#endif /* _UAPI_IOMMU_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h -index 120387ba58..d6edfbd2f5 100644 +index f4ff038e8c..cf8e208fac 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -14,6 +14,7 @@ @@ -423,35 +423,7 @@ index 120387ba58..d6edfbd2f5 100644 #define VFIO_API_VERSION 0 -@@ -211,8 +212,11 @@ struct vfio_device_info { - #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */ - #define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */ - #define VFIO_DEVICE_FLAGS_AP (1 << 5) /* vfio-ap device */ -+#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 6) /* vfio-fsl-mc device */ -+#define VFIO_DEVICE_FLAGS_CAPS (1 << 7) /* Info supports caps */ - __u32 num_regions; /* Max region index + 1 */ - __u32 num_irqs; /* Max IRQ index + 1 */ -+ __u32 cap_offset; /* Offset within info struct of first cap */ - }; - #define VFIO_DEVICE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 7) - -@@ -228,6 +232,15 @@ struct vfio_device_info { - #define VFIO_DEVICE_API_CCW_STRING "vfio-ccw" - #define VFIO_DEVICE_API_AP_STRING "vfio-ap" - -+/* -+ * The following capabilities are unique to s390 zPCI devices. Their contents -+ * are further-defined in vfio_zdev.h -+ */ -+#define VFIO_DEVICE_INFO_CAP_ZPCI_BASE 1 -+#define VFIO_DEVICE_INFO_CAP_ZPCI_GROUP 2 -+#define VFIO_DEVICE_INFO_CAP_ZPCI_UTIL 3 -+#define VFIO_DEVICE_INFO_CAP_ZPCI_PFIP 4 -+ - /** - * VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8, - * struct vfio_region_info) -@@ -316,6 +329,7 @@ struct vfio_region_info_cap_type { +@@ -334,6 +335,7 @@ struct vfio_region_info_cap_type { #define VFIO_REGION_TYPE_GFX (1) #define VFIO_REGION_TYPE_CCW (2) #define VFIO_REGION_TYPE_MIGRATION (3) @@ -459,7 +431,7 @@ index 120387ba58..d6edfbd2f5 100644 /* sub-types for VFIO_REGION_TYPE_PCI_* */ -@@ -340,6 +354,10 @@ struct vfio_region_info_cap_type { +@@ -362,6 +364,10 @@ struct vfio_region_info_cap_type { /* sub-types for VFIO_REGION_TYPE_GFX */ #define VFIO_REGION_SUBTYPE_GFX_EDID (1) @@ -470,16 +442,7 @@ index 120387ba58..d6edfbd2f5 100644 /** * struct vfio_region_gfx_edid - EDID region layout. * -@@ -472,7 +490,7 @@ struct vfio_region_gfx_edid { - * 5. Resumed - * |--------->| - * -- * 0. Default state of VFIO device is _RUNNNG when the user application starts. -+ * 0. Default state of VFIO device is _RUNNING when the user application starts. - * 1. During normal shutdown of the user application, the user application may - * optionally change the VFIO device state from _RUNNING to _STOP. This - * transition is optional. The vendor driver must support this transition but -@@ -695,11 +713,30 @@ struct vfio_irq_info { +@@ -721,11 +727,30 @@ struct vfio_irq_info { #define VFIO_IRQ_INFO_MASKABLE (1 << 1) #define VFIO_IRQ_INFO_AUTOMASKED (1 << 2) #define VFIO_IRQ_INFO_NORESIZE (1 << 3) @@ -510,7 +473,7 @@ index 120387ba58..d6edfbd2f5 100644 /** * VFIO_DEVICE_SET_IRQS - _IOW(VFIO_TYPE, VFIO_BASE + 10, struct vfio_irq_set) * -@@ -801,7 +838,8 @@ enum { +@@ -827,7 +852,8 @@ enum { VFIO_PCI_MSIX_IRQ_INDEX, VFIO_PCI_ERR_IRQ_INDEX, VFIO_PCI_REQ_IRQ_INDEX, @@ -520,7 +483,7 @@ index 120387ba58..d6edfbd2f5 100644 }; /* -@@ -985,6 +1023,68 @@ struct vfio_device_feature { +@@ -1012,6 +1038,68 @@ struct vfio_device_feature { */ #define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) @@ -589,29 +552,7 @@ index 120387ba58..d6edfbd2f5 100644 /* -------- API for Type1 VFIO IOMMU -------- */ /** -@@ -1049,6 +1149,21 @@ struct vfio_iommu_type1_info_cap_migration { - __u64 max_dirty_bitmap_size; /* in bytes */ - }; - -+/* -+ * The DMA available capability allows to report the current number of -+ * simultaneously outstanding DMA mappings that are allowed. -+ * -+ * The structure below defines version 1 of this capability. -+ * -+ * avail: specifies the current number of outstanding DMA mappings allowed. -+ */ -+#define VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL 3 -+ -+struct vfio_iommu_type1_info_dma_avail { -+ struct vfio_info_cap_header header; -+ __u32 avail; -+}; -+ - #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) - - /** -@@ -1072,7 +1187,7 @@ struct vfio_iommu_type1_dma_map { +@@ -1124,7 +1212,7 @@ struct vfio_iommu_type1_dma_map { struct vfio_bitmap { __u64 pgsize; /* page size for bitmap in bytes */ __u64 size; /* in bytes */ @@ -620,7 +561,7 @@ index 120387ba58..d6edfbd2f5 100644 }; /** -@@ -1188,6 +1303,134 @@ struct vfio_iommu_type1_dirty_bitmap_get { +@@ -1250,6 +1338,134 @@ struct vfio_iommu_type1_dirty_bitmap_get { #define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) diff --git a/vga-avoid-crash-if-no-default-vga-card.patch b/vga-avoid-crash-if-no-default-vga-card.patch new file mode 100644 index 0000000000000000000000000000000000000000..829bcae46235e3d63cbee2cfdf9c28893c6374f2 --- /dev/null +++ b/vga-avoid-crash-if-no-default-vga-card.patch @@ -0,0 +1,41 @@ +From 70b0d16c684364594443520fba504e665f167cc4 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:38:56 +0000 +Subject: [PATCH] vga: avoid crash if no default vga card mainline inclusion + commit 6985d8ede92494f3b791de01e8ee9306eb6d5e4a category: bugfix + +--------------------------------------------------------------- + +QEMU in some arch will crash when executing -vga help command, because +there is no default vga model. Add check to this case and avoid crash. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/978 + +Signed-off-by: Guo Zhi +Reviewed-by: Thomas Huth +Tested-by: Thomas Huth +Message-Id: <20220503091724.970009-1-qtxuning1999@sjtu.edu.cn> +Signed-off-by: Laurent Vivier + +Signed-off-by: tangbinzy +--- + softmmu/vl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/softmmu/vl.c b/softmmu/vl.c +index d8996f3d6e..e34c8a0646 100644 +--- a/softmmu/vl.c ++++ b/softmmu/vl.c +@@ -974,7 +974,8 @@ static void select_vgahw(const MachineClass *machine_class, const char *p) + + if (vga_interface_available(t) && ti->opt_name) { + printf("%-20s %s%s\n", ti->opt_name, ti->name ?: "", +- g_str_equal(ti->opt_name, def) ? " (default)" : ""); ++ (def && g_str_equal(ti->opt_name, def)) ? ++ " (default)" : ""); + } + } + exit(0); +-- +2.27.0 + diff --git a/vhost-Add-SVQDescState.patch b/vhost-Add-SVQDescState.patch new file mode 100644 index 0000000000000000000000000000000000000000..748d3266f8274b1ef46ac1af4952a58272447b27 --- /dev/null +++ b/vhost-Add-SVQDescState.patch @@ -0,0 +1,116 @@ +From f8caeca478eb902982879ecd7fad9ffa518ad3bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:34 +0200 +Subject: [PATCH] vhost: Add SVQDescState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will allow SVQ to add context to the different queue elements. + +This patch only store the actual element, no functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 16 ++++++++-------- + hw/virtio/vhost-shadow-virtqueue.h | 8 ++++++-- + 2 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 00f5ccddfb..5ddc04e9d6 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -255,7 +255,7 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + return -EINVAL; + } + +- svq->ring_id_maps[qemu_head] = elem; ++ svq->desc_state[qemu_head].elem = elem; + vhost_svq_kick(svq); + return 0; + } +@@ -410,21 +410,21 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- if (unlikely(!svq->ring_id_maps[used_elem.id])) { ++ if (unlikely(!svq->desc_state[used_elem.id].elem)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Device %s says index %u is used, but it was not available", + svq->vdev->name, used_elem.id); + return NULL; + } + +- num = svq->ring_id_maps[used_elem.id]->in_num + +- svq->ring_id_maps[used_elem.id]->out_num; ++ num = svq->desc_state[used_elem.id].elem->in_num + ++ svq->desc_state[used_elem.id].elem->out_num; + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +- return g_steal_pointer(&svq->ring_id_maps[used_elem.id]); ++ return g_steal_pointer(&svq->desc_state[used_elem.id].elem); + } + + static void vhost_svq_flush(VhostShadowVirtqueue *svq, +@@ -594,7 +594,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + memset(svq->vring.desc, 0, driver_size); + svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); + memset(svq->vring.used, 0, device_size); +- svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ svq->desc_state = g_new0(SVQDescState, svq->vring.num); + svq->desc_next = g_new0(uint16_t, svq->vring.num); + for (unsigned i = 0; i < svq->vring.num - 1; i++) { + svq->desc_next[i] = cpu_to_le16(i + 1); +@@ -619,7 +619,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + + for (unsigned i = 0; i < svq->vring.num; ++i) { + g_autofree VirtQueueElement *elem = NULL; +- elem = g_steal_pointer(&svq->ring_id_maps[i]); ++ elem = g_steal_pointer(&svq->desc_state[i].elem); + if (elem) { + virtqueue_detach_element(svq->vq, elem, 0); + } +@@ -631,7 +631,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + } + svq->vq = NULL; + g_free(svq->desc_next); +- g_free(svq->ring_id_maps); ++ g_free(svq->desc_state); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); + } +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index c132c994e9..d646c35054 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -15,6 +15,10 @@ + #include "standard-headers/linux/vhost_types.h" + #include "hw/virtio/vhost-iova-tree.h" + ++typedef struct SVQDescState { ++ VirtQueueElement *elem; ++} SVQDescState; ++ + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { + /* Shadow vring */ +@@ -47,8 +51,8 @@ typedef struct VhostShadowVirtqueue { + /* IOVA mapping */ + VhostIOVATree *iova_tree; + +- /* Map for use the guest's descriptors */ +- VirtQueueElement **ring_id_maps; ++ /* SVQ vring descriptors state */ ++ SVQDescState *desc_state; + + /* Next VirtQueue element that guest made available */ + VirtQueueElement *next_guest_avail_elem; +-- +2.27.0 + diff --git a/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch b/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch new file mode 100644 index 0000000000000000000000000000000000000000..41fe5cf437a502fd1a8b12c8646a5f2264c3c0dd --- /dev/null +++ b/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch @@ -0,0 +1,168 @@ +From 6ff532ef853499a16307e09d8bab18c57c03ecae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:43 +0100 +Subject: [PATCH] vhost: Add Shadow VirtQueue call forwarding capabilities +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will make qemu aware of the device used buffers, allowing it to +write the guest memory with its contents if needed. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 38 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 4 ++++ + hw/virtio/vhost-vdpa.c | 31 ++++++++++++++++++++++-- + 3 files changed, 71 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index e5da907b8e..55cb5414ef 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -26,6 +26,42 @@ static void vhost_handle_guest_kick(EventNotifier *n) + event_notifier_set(&svq->hdev_kick); + } + ++/** ++ * Forward vhost notifications ++ * ++ * @n: hdev call event notifier, the one that device set to notify svq. ++ */ ++static void vhost_svq_handle_call(EventNotifier *n) ++{ ++ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, ++ hdev_call); ++ event_notifier_test_and_clear(n); ++ event_notifier_set(&svq->svq_call); ++} ++ ++/** ++ * Set the call notifier for the SVQ to call the guest ++ * ++ * @svq: Shadow virtqueue ++ * @call_fd: call notifier ++ * ++ * Called on BQL context. ++ */ ++void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) ++{ ++ if (call_fd == VHOST_FILE_UNBIND) { ++ /* ++ * Fail event_notifier_set if called handling device call. ++ * ++ * SVQ still needs device notifications, since it needs to keep ++ * forwarding used buffers even with the unbind. ++ */ ++ memset(&svq->svq_call, 0, sizeof(svq->svq_call)); ++ } else { ++ event_notifier_init_fd(&svq->svq_call, call_fd); ++ } ++} ++ + /** + * Set a new file descriptor for the guest to kick the SVQ and notify for avail + * +@@ -93,6 +129,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + } + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); ++ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + return g_steal_pointer(&svq); + + err_init_hdev_call: +@@ -112,6 +149,7 @@ void vhost_svq_free(gpointer pvq) + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); ++ event_notifier_set_handler(&vq->hdev_call, NULL); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 1cbc87d5d8..cbc5213579 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -28,9 +28,13 @@ typedef struct VhostShadowVirtqueue { + * So shadow virtqueue must not clean it, or we would lose VirtQueue one. + */ + EventNotifier svq_kick; ++ ++ /* Guest's call notifier, where the SVQ calls guest. */ ++ EventNotifier svq_call; + } VhostShadowVirtqueue; + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); ++void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 7331c8ee04..29c720308f 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -727,6 +727,13 @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); + } + ++static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev, ++ struct vhost_vring_file *file) ++{ ++ trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); ++} ++ + /** + * Set the shadow virtqueue descriptors to the device + * +@@ -734,6 +741,9 @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + * @svq: The shadow virtqueue + * @idx: The index of the virtqueue in the vhost device + * @errp: Error ++ * ++ * Note that this function does not rewind kick file descriptor if cannot set ++ * call one. + */ + static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + VhostShadowVirtqueue *svq, unsigned idx, +@@ -749,6 +759,14 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); ++ return false; ++ } ++ ++ event_notifier = &svq->hdev_call; ++ file.fd = event_notifier_get_fd(event_notifier); ++ r = vhost_vdpa_set_vring_dev_call(dev, &file); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Can't set device call fd"); + } + + return r == 0; +@@ -874,8 +892,17 @@ static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +- trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ int vdpa_idx = file->index - dev->vq_index; ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); ++ ++ vhost_svq_set_svq_call_fd(svq, file->fd); ++ return 0; ++ } else { ++ return vhost_vdpa_set_vring_dev_call(dev, file); ++ } + } + + static int vhost_vdpa_get_features(struct vhost_dev *dev, +-- +2.27.0 + diff --git a/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch b/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch new file mode 100644 index 0000000000000000000000000000000000000000..fc8469e37fabcfeb73e5d7399cf6b2236333f4d4 --- /dev/null +++ b/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch @@ -0,0 +1,395 @@ +From 41585669f68a3896d6d8a5bea868f192b30fad76 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:42 +0100 +Subject: [PATCH] vhost: Add Shadow VirtQueue kick forwarding capabilities +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +At this mode no buffer forwarding will be performed in SVQ mode: Qemu +will just forward the guest's kicks to the device. + +Host memory notifiers regions are left out for simplicity, and they will +not be addressed in this series. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 55 +++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 14 +++ + hw/virtio/vhost-vdpa.c | 144 ++++++++++++++++++++++++++++- + include/hw/virtio/vhost-vdpa.h | 4 + + 4 files changed, 215 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c1db02c53e..e5da907b8e 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -11,6 +11,59 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + + #include "qemu/error-report.h" ++#include "qemu/main-loop.h" ++#include "linux-headers/linux/vhost.h" ++ ++/** ++ * Forward guest notifications. ++ * ++ * @n: guest kick event notifier, the one that guest set to notify svq. ++ */ ++static void vhost_handle_guest_kick(EventNotifier *n) ++{ ++ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick); ++ event_notifier_test_and_clear(n); ++ event_notifier_set(&svq->hdev_kick); ++} ++ ++/** ++ * Set a new file descriptor for the guest to kick the SVQ and notify for avail ++ * ++ * @svq: The svq ++ * @svq_kick_fd: The svq kick fd ++ * ++ * Note that the SVQ will never close the old file descriptor. ++ */ ++void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) ++{ ++ EventNotifier *svq_kick = &svq->svq_kick; ++ bool poll_stop = VHOST_FILE_UNBIND != event_notifier_get_fd(svq_kick); ++ bool poll_start = svq_kick_fd != VHOST_FILE_UNBIND; ++ ++ if (poll_stop) { ++ event_notifier_set_handler(svq_kick, NULL); ++ } ++ ++ /* ++ * event_notifier_set_handler already checks for guest's notifications if ++ * they arrive at the new file descriptor in the switch, so there is no ++ * need to explicitly check for them. ++ */ ++ if (poll_start) { ++ event_notifier_init_fd(svq_kick, svq_kick_fd); ++ event_notifier_set(svq_kick); ++ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick); ++ } ++} ++ ++/** ++ * Stop the shadow virtqueue operation. ++ * @svq: Shadow Virtqueue ++ */ ++void vhost_svq_stop(VhostShadowVirtqueue *svq) ++{ ++ event_notifier_set_handler(&svq->svq_kick, NULL); ++} + + /** + * Creates vhost shadow virtqueue, and instructs the vhost device to use the +@@ -39,6 +92,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + goto err_init_hdev_call; + } + ++ event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + return g_steal_pointer(&svq); + + err_init_hdev_call: +@@ -56,6 +110,7 @@ err_init_hdev_kick: + void vhost_svq_free(gpointer pvq) + { + VhostShadowVirtqueue *vq = pvq; ++ vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index f1519e3c7b..1cbc87d5d8 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -18,8 +18,22 @@ typedef struct VhostShadowVirtqueue { + EventNotifier hdev_kick; + /* Shadow call notifier, sent to vhost */ + EventNotifier hdev_call; ++ ++ /* ++ * Borrowed virtqueue's guest to host notifier. To borrow it in this event ++ * notifier allows to recover the VhostShadowVirtqueue from the event loop ++ * easily. If we use the VirtQueue's one, we don't have an easy way to ++ * retrieve VhostShadowVirtqueue. ++ * ++ * So shadow virtqueue must not clean it, or we would lose VirtQueue one. ++ */ ++ EventNotifier svq_kick; + } VhostShadowVirtqueue; + ++void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); ++ ++void vhost_svq_stop(VhostShadowVirtqueue *svq); ++ + VhostShadowVirtqueue *vhost_svq_new(void); + + void vhost_svq_free(gpointer vq); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 25a2f570a2..7331c8ee04 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -17,12 +17,14 @@ + #include "hw/virtio/vhost.h" + #include "hw/virtio/vhost-backend.h" + #include "hw/virtio/virtio-net.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/vhost-vdpa.h" + #include "exec/address-spaces.h" + #include "qemu/main-loop.h" + #include "cpu.h" + #include "trace.h" + #include "qemu-common.h" ++#include "qapi/error.h" + + static unsigned int vhost_vdpa_used_memslots; + +@@ -344,6 +346,30 @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) + return v->index != 0; + } + ++static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, ++ Error **errp) ++{ ++ g_autoptr(GPtrArray) shadow_vqs = NULL; ++ ++ if (!v->shadow_vqs_enabled) { ++ return 0; ++ } ++ ++ shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); ++ for (unsigned n = 0; n < hdev->nvqs; ++n) { ++ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); ++ ++ if (unlikely(!svq)) { ++ error_setg(errp, "Cannot create svq %u", n); ++ return -1; ++ } ++ g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq)); ++ } ++ ++ v->shadow_vqs = g_steal_pointer(&shadow_vqs); ++ return 0; ++} ++ + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + { + struct vhost_vdpa *v; +@@ -366,6 +392,10 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + dev->opaque = opaque ; + v->listener = vhost_vdpa_memory_listener; + v->msg_type = VHOST_IOTLB_MSG_V2; ++ ret = vhost_vdpa_init_svq(dev, v, errp); ++ if (ret) { ++ goto err; ++ } + + vhost_vdpa_get_iova_range(v); + +@@ -377,6 +407,10 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + VIRTIO_CONFIG_S_DRIVER); + + return 0; ++ ++err: ++ ram_block_discard_disable(false); ++ return ret; + } + + static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, +@@ -447,8 +481,14 @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) + + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + { ++ struct vhost_vdpa *v = dev->opaque; + int i; + ++ if (v->shadow_vqs_enabled) { ++ /* FIXME SVQ is not compatible with host notifiers mr */ ++ return; ++ } ++ + for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) { + if (vhost_vdpa_host_notifier_init(dev, i)) { + goto err; +@@ -462,6 +502,21 @@ err: + return; + } + ++static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ size_t idx; ++ ++ if (!v->shadow_vqs) { ++ return; ++ } ++ ++ for (idx = 0; idx < v->shadow_vqs->len; ++idx) { ++ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx)); ++ } ++ g_ptr_array_free(v->shadow_vqs, true); ++} ++ + static int vhost_vdpa_cleanup(struct vhost_dev *dev) + { + struct vhost_vdpa *v; +@@ -470,6 +525,7 @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev) + trace_vhost_vdpa_cleanup(dev, v); + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + memory_listener_unregister(&v->listener); ++ vhost_vdpa_svq_cleanup(dev); + + dev->opaque = NULL; + ram_block_discard_disable(false); +@@ -561,11 +617,26 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + return ret; + } + ++static void vhost_vdpa_reset_svq(struct vhost_vdpa *v) ++{ ++ if (!v->shadow_vqs_enabled) { ++ return; ++ } ++ ++ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ vhost_svq_stop(svq); ++ } ++} ++ + static int vhost_vdpa_reset_device(struct vhost_dev *dev) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + uint8_t status = 0; + ++ vhost_vdpa_reset_svq(v); ++ + ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); + trace_vhost_vdpa_reset_device(dev, status); + return ret; +@@ -649,13 +720,74 @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, + return ret; + } + ++static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, ++ struct vhost_vring_file *file) ++{ ++ trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); ++} ++ ++/** ++ * Set the shadow virtqueue descriptors to the device ++ * ++ * @dev: The vhost device model ++ * @svq: The shadow virtqueue ++ * @idx: The index of the virtqueue in the vhost device ++ * @errp: Error ++ */ ++static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) ++{ ++ struct vhost_vring_file file = { ++ .index = dev->vq_index + idx, ++ }; ++ const EventNotifier *event_notifier = &svq->hdev_kick; ++ int r; ++ ++ file.fd = event_notifier_get_fd(event_notifier); ++ r = vhost_vdpa_set_vring_dev_kick(dev, &file); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Can't set device kick fd"); ++ } ++ ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ Error *err = NULL; ++ unsigned i; ++ ++ if (!v->shadow_vqs) { ++ return true; ++ } ++ ++ for (i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); ++ if (unlikely(!ok)) { ++ error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + { + struct vhost_vdpa *v = dev->opaque; ++ bool ok; + trace_vhost_vdpa_dev_start(dev, started); + + if (started) { + vhost_vdpa_host_notifiers_init(dev); ++ ok = vhost_vdpa_svqs_start(dev); ++ if (unlikely(!ok)) { ++ return -1; ++ } + vhost_vdpa_set_vring_ready(dev); + } else { + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); +@@ -727,8 +859,16 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +- trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); ++ struct vhost_vdpa *v = dev->opaque; ++ int vdpa_idx = file->index - dev->vq_index; ++ ++ if (v->shadow_vqs_enabled) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); ++ vhost_svq_set_svq_kick_fd(svq, file->fd); ++ return 0; ++ } else { ++ return vhost_vdpa_set_vring_dev_kick(dev, file); ++ } + } + + static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 3ce79a646d..009a9f3b6b 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -12,6 +12,8 @@ + #ifndef HW_VIRTIO_VHOST_VDPA_H + #define HW_VIRTIO_VHOST_VDPA_H + ++#include ++ + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -27,6 +29,8 @@ typedef struct vhost_vdpa { + bool iotlb_batch_begin_sent; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; ++ bool shadow_vqs_enabled; ++ GPtrArray *shadow_vqs; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; +-- +2.27.0 + diff --git a/vhost-Add-VhostIOVATree.patch b/vhost-Add-VhostIOVATree.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f78f901a8c601bafb623ca546949a42ca4283e3 --- /dev/null +++ b/vhost-Add-VhostIOVATree.patch @@ -0,0 +1,200 @@ +From c938dd769a872c569c3985f06c8b5854231ed74c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:50 +0100 +Subject: [PATCH] vhost: Add VhostIOVATree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This tree is able to look for a translated address from an IOVA address. + +At first glance it is similar to util/iova-tree. However, SVQ working on +devices with limited IOVA space need more capabilities, like allocating +IOVA chunks or performing reverse translations (qemu addresses to iova). + +The allocation capability, as "assign a free IOVA address to this chunk +of memory in qemu's address space" allows shadow virtqueue to create a +new address space that is not restricted by guest's addressable one, so +we can allocate shadow vqs vrings outside of it. + +It duplicates the tree so it can search efficiently in both directions, +and it will signal overlap if iova or the translated address is present +in any tree. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 2 +- + hw/virtio/vhost-iova-tree.c | 110 ++++++++++++++++++++++++++++++++++++ + hw/virtio/vhost-iova-tree.h | 27 +++++++++ + 3 files changed, 138 insertions(+), 1 deletion(-) + create mode 100644 hw/virtio/vhost-iova-tree.c + create mode 100644 hw/virtio/vhost-iova-tree.h + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index eb46c05a25..c2e193f56d 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,7 +11,7 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) +diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c +new file mode 100644 +index 0000000000..55fed1fefb +--- /dev/null ++++ b/hw/virtio/vhost-iova-tree.c +@@ -0,0 +1,110 @@ ++/* ++ * vhost software live migration iova tree ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/iova-tree.h" ++#include "vhost-iova-tree.h" ++ ++#define iova_min_addr qemu_real_host_page_size ++ ++/** ++ * VhostIOVATree, able to: ++ * - Translate iova address ++ * - Reverse translate iova address (from translated to iova) ++ * - Allocate IOVA regions for translated range (linear operation) ++ */ ++struct VhostIOVATree { ++ /* First addressable iova address in the device */ ++ uint64_t iova_first; ++ ++ /* Last addressable iova address in the device */ ++ uint64_t iova_last; ++ ++ /* IOVA address to qemu memory maps. */ ++ IOVATree *iova_taddr_map; ++}; ++ ++/** ++ * Create a new IOVA tree ++ * ++ * Returns the new IOVA tree ++ */ ++VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last) ++{ ++ VhostIOVATree *tree = g_new(VhostIOVATree, 1); ++ ++ /* Some devices do not like 0 addresses */ ++ tree->iova_first = MAX(iova_first, iova_min_addr); ++ tree->iova_last = iova_last; ++ ++ tree->iova_taddr_map = iova_tree_new(); ++ return tree; ++} ++ ++/** ++ * Delete an iova tree ++ */ ++void vhost_iova_tree_delete(VhostIOVATree *iova_tree) ++{ ++ iova_tree_destroy(iova_tree->iova_taddr_map); ++ g_free(iova_tree); ++} ++ ++/** ++ * Find the IOVA address stored from a memory address ++ * ++ * @tree: The iova tree ++ * @map: The map with the memory address ++ * ++ * Return the stored mapping, or NULL if not found. ++ */ ++const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree, ++ const DMAMap *map) ++{ ++ return iova_tree_find_iova(tree->iova_taddr_map, map); ++} ++ ++/** ++ * Allocate a new mapping ++ * ++ * @tree: The iova tree ++ * @map: The iova map ++ * ++ * Returns: ++ * - IOVA_OK if the map fits in the container ++ * - IOVA_ERR_INVALID if the map does not make sense (like size overflow) ++ * - IOVA_ERR_NOMEM if tree cannot allocate more space. ++ * ++ * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK. ++ */ ++int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) ++{ ++ /* Some vhost devices do not like addr 0. Skip first page */ ++ hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size; ++ ++ if (map->translated_addr + map->size < map->translated_addr || ++ map->perm == IOMMU_NONE) { ++ return IOVA_ERR_INVALID; ++ } ++ ++ /* Allocate a node in IOVA address */ ++ return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first, ++ tree->iova_last); ++} ++ ++/** ++ * Remove existing mappings from iova tree ++ * ++ * @iova_tree: The vhost iova tree ++ * @map: The map to remove ++ */ ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map) ++{ ++ iova_tree_remove(iova_tree->iova_taddr_map, map); ++} +diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h +new file mode 100644 +index 0000000000..6a4f24e0f9 +--- /dev/null ++++ b/hw/virtio/vhost-iova-tree.h +@@ -0,0 +1,27 @@ ++/* ++ * vhost software live migration iova tree ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef HW_VIRTIO_VHOST_IOVA_TREE_H ++#define HW_VIRTIO_VHOST_IOVA_TREE_H ++ ++#include "qemu/iova-tree.h" ++#include "exec/memory.h" ++ ++typedef struct VhostIOVATree VhostIOVATree; ++ ++VhostIOVATree *vhost_iova_tree_new(uint64_t iova_first, uint64_t iova_last); ++void vhost_iova_tree_delete(VhostIOVATree *iova_tree); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete); ++ ++const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree, ++ const DMAMap *map); ++int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map); ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map); ++ ++#endif +-- +2.27.0 + diff --git a/vhost-Add-VhostShadowVirtqueue.patch b/vhost-Add-VhostShadowVirtqueue.patch new file mode 100644 index 0000000000000000000000000000000000000000..b4c668b4b8e1ab46fe1137540d26eebaed87f121 --- /dev/null +++ b/vhost-Add-VhostShadowVirtqueue.patch @@ -0,0 +1,147 @@ +From 6f38bfce3fc45c1c68329412d146913a155962c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:41 +0100 +Subject: [PATCH] vhost: Add VhostShadowVirtqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Vhost shadow virtqueue (SVQ) is an intermediate jump for virtqueue +notifications and buffers, allowing qemu to track them. While qemu is +forwarding the buffers and virtqueue changes, it is able to commit the +memory it's being dirtied, the same way regular qemu's VirtIO devices +do. + +This commit only exposes basic SVQ allocation and free. Next patches of +the series add functionality like notifications and buffers forwarding. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 2 +- + hw/virtio/vhost-shadow-virtqueue.c | 62 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 28 ++++++++++++++ + 3 files changed, 91 insertions(+), 1 deletion(-) + create mode 100644 hw/virtio/vhost-shadow-virtqueue.c + create mode 100644 hw/virtio/vhost-shadow-virtqueue.h + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index 8e8943e20b..eb46c05a25 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,7 +11,7 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +new file mode 100644 +index 0000000000..c1db02c53e +--- /dev/null ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -0,0 +1,62 @@ ++/* ++ * vhost shadow virtqueue ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" ++ ++#include "qemu/error-report.h" ++ ++/** ++ * Creates vhost shadow virtqueue, and instructs the vhost device to use the ++ * shadow methods and file descriptors. ++ * ++ * Returns the new virtqueue or NULL. ++ * ++ * In case of error, reason is reported through error_report. ++ */ ++VhostShadowVirtqueue *vhost_svq_new(void) ++{ ++ g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); ++ int r; ++ ++ r = event_notifier_init(&svq->hdev_kick, 0); ++ if (r != 0) { ++ error_report("Couldn't create kick event notifier: %s (%d)", ++ g_strerror(errno), errno); ++ goto err_init_hdev_kick; ++ } ++ ++ r = event_notifier_init(&svq->hdev_call, 0); ++ if (r != 0) { ++ error_report("Couldn't create call event notifier: %s (%d)", ++ g_strerror(errno), errno); ++ goto err_init_hdev_call; ++ } ++ ++ return g_steal_pointer(&svq); ++ ++err_init_hdev_call: ++ event_notifier_cleanup(&svq->hdev_kick); ++ ++err_init_hdev_kick: ++ return NULL; ++} ++ ++/** ++ * Free the resources of the shadow virtqueue. ++ * ++ * @pvq: gpointer to SVQ so it can be used by autofree functions. ++ */ ++void vhost_svq_free(gpointer pvq) ++{ ++ VhostShadowVirtqueue *vq = pvq; ++ event_notifier_cleanup(&vq->hdev_kick); ++ event_notifier_cleanup(&vq->hdev_call); ++ g_free(vq); ++} +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +new file mode 100644 +index 0000000000..f1519e3c7b +--- /dev/null ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -0,0 +1,28 @@ ++/* ++ * vhost shadow virtqueue ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef VHOST_SHADOW_VIRTQUEUE_H ++#define VHOST_SHADOW_VIRTQUEUE_H ++ ++#include "qemu/event_notifier.h" ++ ++/* Shadow virtqueue to relay notifications */ ++typedef struct VhostShadowVirtqueue { ++ /* Shadow kick notifier, sent to vhost */ ++ EventNotifier hdev_kick; ++ /* Shadow call notifier, sent to vhost */ ++ EventNotifier hdev_call; ++} VhostShadowVirtqueue; ++ ++VhostShadowVirtqueue *vhost_svq_new(void); ++ ++void vhost_svq_free(gpointer vq); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); ++ ++#endif +-- +2.27.0 + diff --git a/vhost-Add-names-to-section-rounded-warning.patch b/vhost-Add-names-to-section-rounded-warning.patch deleted file mode 100644 index 09c36eda5b8f7063d3543ec1adab3349bf87ba7b..0000000000000000000000000000000000000000 --- a/vhost-Add-names-to-section-rounded-warning.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 437a9d2c7e48495ffc467808eece045579956c79 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 16 Jan 2020 20:24:13 +0000 -Subject: [PATCH] vhost: Add names to section rounded warning - -Add the memory region names to section rounding/alignment -warnings. - -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20200116202414.157959-2-dgilbert@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/virtio/vhost.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 9c16f0d107..ae61c33c15 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -591,9 +591,10 @@ static void vhost_region_add_section(struct vhost_dev *dev, - * match up in the same RAMBlock if they do. - */ - if (mrs_gpa < prev_gpa_start) { -- error_report("%s:Section rounded to %"PRIx64 -- " prior to previous %"PRIx64, -- __func__, mrs_gpa, prev_gpa_start); -+ error_report("%s:Section '%s' rounded to %"PRIx64 -+ " prior to previous '%s' %"PRIx64, -+ __func__, section->mr->name, mrs_gpa, -+ prev_sec->mr->name, prev_gpa_start); - /* A way to cleanly fail here would be better */ - return; - } --- -2.27.0 - diff --git a/vhost-Add-svq-avail_handler-callback.patch b/vhost-Add-svq-avail_handler-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..b288a39d877ad5582df3642e0a591a325cc53ee8 --- /dev/null +++ b/vhost-Add-svq-avail_handler-callback.patch @@ -0,0 +1,145 @@ +From 14cc79b8bda66ace21616adccf6c2ccd65b7256a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:39 +0200 +Subject: [PATCH] vhost: Add svq avail_handler callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external handlers to be aware of new buffers that the guest +places in the virtqueue. + +When this callback is defined the ownership of the guest's virtqueue +element is transferred to the callback. This means that if the user +wants to forward the descriptor it needs to manually inject it. The +callback is also free to process the command by itself and use the +element with svq_push. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 14 ++++++++++++-- + hw/virtio/vhost-shadow-virtqueue.h | 31 +++++++++++++++++++++++++++++- + hw/virtio/vhost-vdpa.c | 3 ++- + 3 files changed, 44 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index d2676b94e0..ae443f54fe 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -305,7 +305,11 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- r = vhost_svq_add_element(svq, elem); ++ if (svq->ops) { ++ r = svq->ops->avail_handler(svq, elem, svq->ops_opaque); ++ } else { ++ r = vhost_svq_add_element(svq, elem); ++ } + if (unlikely(r != 0)) { + if (r == -ENOSPC) { + /* +@@ -684,12 +688,16 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * shadow methods and file descriptors. + * + * @iova_tree: Tree to perform descriptors translations ++ * @ops: SVQ owner callbacks ++ * @ops_opaque: ops opaque pointer + * + * Returns the new virtqueue or NULL. + * + * In case of error, reason is reported through error_report. + */ +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, ++ const VhostShadowVirtqueueOps *ops, ++ void *ops_opaque) + { + g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + int r; +@@ -711,6 +719,8 @@ VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->iova_tree = iova_tree; ++ svq->ops = ops; ++ svq->ops_opaque = ops_opaque; + return g_steal_pointer(&svq); + + err_init_hdev_call: +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index cf442f7dea..d04c34a589 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -25,6 +25,27 @@ typedef struct SVQDescState { + unsigned int ndescs; + } SVQDescState; + ++typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; ++ ++/** ++ * Callback to handle an avail buffer. ++ * ++ * @svq: Shadow virtqueue ++ * @elem: Element placed in the queue by the guest ++ * @vq_callback_opaque: Opaque ++ * ++ * Returns 0 if the vq is running as expected. ++ * ++ * Note that ownership of elem is transferred to the callback. ++ */ ++typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, ++ void *vq_callback_opaque); ++ ++typedef struct VhostShadowVirtqueueOps { ++ VirtQueueAvailCallback avail_handler; ++} VhostShadowVirtqueueOps; ++ + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { + /* Shadow vring */ +@@ -69,6 +90,12 @@ typedef struct VhostShadowVirtqueue { + */ + uint16_t *desc_next; + ++ /* Caller callbacks */ ++ const VhostShadowVirtqueueOps *ops; ++ ++ /* Caller callbacks opaque */ ++ void *ops_opaque; ++ + /* Next head to expose to the device */ + uint16_t shadow_avail_idx; + +@@ -102,7 +129,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree); ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, ++ const VhostShadowVirtqueueOps *ops, ++ void *ops_opaque); + + void vhost_svq_free(gpointer vq); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 73ff599f2b..a8d42655f0 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -420,8 +420,9 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree); ++ g_autoptr(VhostShadowVirtqueue) svq; + ++ svq = vhost_svq_new(v->iova_tree, NULL, NULL); + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); + return -1; +-- +2.27.0 + diff --git a/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch b/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch new file mode 100644 index 0000000000000000000000000000000000000000..53bb3be9dd255adcc401071854858cf5b1b20c8f --- /dev/null +++ b/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch @@ -0,0 +1,133 @@ +From 2f41ff8e23ed358890fb66b6f524627a9747cc14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:44 +0100 +Subject: [PATCH] vhost: Add vhost_svq_valid_features to shadow vq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows SVQ to negotiate features with the guest and the device. For +the device, SVQ is a driver. While this function bypasses all +non-transport features, it needs to disable the features that SVQ does +not support when forwarding buffers. This includes packed vq layout, +indirect descriptors or event idx. + +Future changes can add support to offer more features to the guest, +since the use of VirtQueue gives this for free. This is left out at the +moment for simplicity. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 44 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 2 ++ + hw/virtio/vhost-vdpa.c | 15 ++++++++++ + 3 files changed, 61 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 55cb5414ef..519328445c 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -11,9 +11,53 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + + #include "qemu/error-report.h" ++#include "qapi/error.h" + #include "qemu/main-loop.h" + #include "linux-headers/linux/vhost.h" + ++/** ++ * Validate the transport device features that both guests can use with the SVQ ++ * and SVQs can use with the device. ++ * ++ * @dev_features: The features ++ * @errp: Error pointer ++ */ ++bool vhost_svq_valid_features(uint64_t features, Error **errp) ++{ ++ bool ok = true; ++ uint64_t svq_features = features; ++ ++ for (uint64_t b = VIRTIO_TRANSPORT_F_START; b <= VIRTIO_TRANSPORT_F_END; ++ ++b) { ++ switch (b) { ++ case VIRTIO_F_ANY_LAYOUT: ++ continue; ++ ++ case VIRTIO_F_ACCESS_PLATFORM: ++ /* SVQ trust in the host's IOMMU to translate addresses */ ++ case VIRTIO_F_VERSION_1: ++ /* SVQ trust that the guest vring is little endian */ ++ if (!(svq_features & BIT_ULL(b))) { ++ svq_features |= BIT_ULL(b); ++ ok = false; ++ } ++ continue; ++ ++ default: ++ if (svq_features & BIT_ULL(b)) { ++ svq_features &= ~BIT_ULL(b); ++ ok = false; ++ } ++ } ++ } ++ ++ if (!ok) { ++ error_setg(errp, "SVQ Invalid device feature flags, offer: 0x%"PRIx64 ++ ", ok: 0x%"PRIx64, features, svq_features); ++ } ++ return ok; ++} ++ + /** + * Forward guest notifications. + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index cbc5213579..9e12f77201 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -33,6 +33,8 @@ typedef struct VhostShadowVirtqueue { + EventNotifier svq_call; + } VhostShadowVirtqueue; + ++bool vhost_svq_valid_features(uint64_t features, Error **errp); ++ + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 29c720308f..8ee63933a8 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -350,11 +350,26 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + Error **errp) + { + g_autoptr(GPtrArray) shadow_vqs = NULL; ++ uint64_t dev_features, svq_features; ++ int r; ++ bool ok; + + if (!v->shadow_vqs_enabled) { + return 0; + } + ++ r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Can't get vdpa device features"); ++ return r; ++ } ++ ++ svq_features = dev_features; ++ ok = vhost_svq_valid_features(svq_features, errp); ++ if (unlikely(!ok)) { ++ return -1; ++ } ++ + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { + g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); +-- +2.27.0 + diff --git a/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch b/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch new file mode 100644 index 0000000000000000000000000000000000000000..e013942d9dcd70522150393094a7f72628cf620a --- /dev/null +++ b/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch @@ -0,0 +1,57 @@ +From 42cdf9d4b5c4ec0a6fbbebd79c21e5c39d831a48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:07 +0200 +Subject: [PATCH] vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can unbind twice a file descriptor if we call twice +vhost_svq_set_svq_kick_fd because of this. Since it comes from vhost and +not from SVQ, that file descriptor could be a different thing that +guest's vhost notifier. + +Likewise, it can happens the same if a guest start and stop the device +multiple times. + +Reported-by: Lei Yang +Fixes: dff4426fa6 ("vhost: Add Shadow VirtQueue kick forwarding capabilities") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 47e831667c..1ea7b5cf59 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -601,13 +601,13 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + event_notifier_set_handler(svq_kick, NULL); + } + ++ event_notifier_init_fd(svq_kick, svq_kick_fd); + /* + * event_notifier_set_handler already checks for guest's notifications if + * they arrive at the new file descriptor in the switch, so there is no + * need to explicitly check for them. + */ + if (poll_start) { +- event_notifier_init_fd(svq_kick, svq_kick_fd); + event_notifier_set(svq_kick); + event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier); + } +@@ -655,7 +655,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + */ + void vhost_svq_stop(VhostShadowVirtqueue *svq) + { +- event_notifier_set_handler(&svq->svq_kick, NULL); ++ vhost_svq_set_svq_kick_fd(svq, VHOST_FILE_UNBIND); + g_autofree VirtQueueElement *next_avail_elem = NULL; + + if (!svq->vq) { +-- +2.27.0 + diff --git a/vhost-Check-for-queue-full-at-vhost_svq_add.patch b/vhost-Check-for-queue-full-at-vhost_svq_add.patch new file mode 100644 index 0000000000000000000000000000000000000000..98f4f8e14e139abf15d0d6ead303fe14f88254a7 --- /dev/null +++ b/vhost-Check-for-queue-full-at-vhost_svq_add.patch @@ -0,0 +1,115 @@ +From 53e6a3ff0ad77689e8cfb79b2e97ca30058949a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:32 +0200 +Subject: [PATCH] vhost: Check for queue full at vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The series need to expose vhost_svq_add with full functionality, +including checking for full queue. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 59 +++++++++++++++++------------- + 1 file changed, 33 insertions(+), 26 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index b99630acee..7104004a81 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -232,21 +232,29 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * Add an element to a SVQ. + * + * The caller must check that there is enough slots for the new element. It +- * takes ownership of the element: In case of failure, it is free and the SVQ +- * is considered broken. ++ * takes ownership of the element: In case of failure not ENOSPC, it is free. ++ * ++ * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + { + unsigned qemu_head; +- bool ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ unsigned ndescs = elem->in_num + elem->out_num; ++ bool ok; ++ ++ if (unlikely(ndescs > vhost_svq_available_slots(svq))) { ++ return -ENOSPC; ++ } ++ ++ ok = vhost_svq_add_split(svq, elem, &qemu_head); + if (unlikely(!ok)) { + g_free(elem); +- return false; ++ return -EINVAL; + } + + svq->ring_id_maps[qemu_head] = elem; + vhost_svq_kick(svq); +- return true; ++ return 0; + } + + /** +@@ -273,7 +281,7 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + + while (true) { + VirtQueueElement *elem; +- bool ok; ++ int r; + + if (svq->next_guest_avail_elem) { + elem = g_steal_pointer(&svq->next_guest_avail_elem); +@@ -285,25 +293,24 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) { +- /* +- * This condition is possible since a contiguous buffer in GPA +- * does not imply a contiguous buffer in qemu's VA +- * scatter-gather segments. If that happens, the buffer exposed +- * to the device needs to be a chain of descriptors at this +- * moment. +- * +- * SVQ cannot hold more available buffers if we are here: +- * queue the current guest descriptor and ignore further kicks +- * until some elements are used. +- */ +- svq->next_guest_avail_elem = elem; +- return; +- } +- +- ok = vhost_svq_add(svq, elem); +- if (unlikely(!ok)) { +- /* VQ is broken, just return and ignore any other kicks */ ++ r = vhost_svq_add(svq, elem); ++ if (unlikely(r != 0)) { ++ if (r == -ENOSPC) { ++ /* ++ * This condition is possible since a contiguous buffer in ++ * GPA does not imply a contiguous buffer in qemu's VA ++ * scatter-gather segments. If that happens, the buffer ++ * exposed to the device needs to be a chain of descriptors ++ * at this moment. ++ * ++ * SVQ cannot hold more available buffers if we are here: ++ * queue the current guest descriptor and ignore kicks ++ * until some elements are used. ++ */ ++ svq->next_guest_avail_elem = elem; ++ } ++ ++ /* VQ is full or broken, just return and ignore kicks */ + return; + } + } +-- +2.27.0 + diff --git a/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch b/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch new file mode 100644 index 0000000000000000000000000000000000000000..298fe6ac3d9c41e3ba6f6e74cad21f6c8c268053 --- /dev/null +++ b/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch @@ -0,0 +1,119 @@ +From 1f484df7fb48cdf24e619118ddf67b8cd4e02231 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:33 +0200 +Subject: [PATCH] vhost: Decouple vhost_svq_add from VirtQueueElement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VirtQueueElement comes from the guest, but we're heading SVQ to be able +to modify the element presented to the device without the guest's +knowledge. + +To do so, make SVQ accept sg buffers directly, instead of using +VirtQueueElement. + +Add vhost_svq_add_element to maintain element convenience. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 33 ++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 7104004a81..00f5ccddfb 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -171,30 +171,31 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +- VirtQueueElement *elem, unsigned *head) ++ const struct iovec *out_sg, size_t out_num, ++ const struct iovec *in_sg, size_t in_num, ++ unsigned *head) + { + unsigned avail_idx; + vring_avail_t *avail = svq->vring.avail; + bool ok; +- g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num)); ++ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(out_num, in_num)); + + *head = svq->free_head; + + /* We need some descriptors here */ +- if (unlikely(!elem->out_num && !elem->in_num)) { ++ if (unlikely(!out_num && !in_num)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Guest provided element with no descriptors"); + return false; + } + +- ok = vhost_svq_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, +- elem->in_num > 0, false); ++ ok = vhost_svq_vring_write_descs(svq, sgs, out_sg, out_num, in_num > 0, ++ false); + if (unlikely(!ok)) { + return false; + } + +- ok = vhost_svq_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, +- true); ++ ok = vhost_svq_vring_write_descs(svq, sgs, in_sg, in_num, false, true); + if (unlikely(!ok)) { + return false; + } +@@ -236,17 +237,19 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * + * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, ++ size_t in_num, VirtQueueElement *elem) + { + unsigned qemu_head; +- unsigned ndescs = elem->in_num + elem->out_num; ++ unsigned ndescs = in_num + out_num; + bool ok; + + if (unlikely(ndescs > vhost_svq_available_slots(svq))) { + return -ENOSPC; + } + +- ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head); + if (unlikely(!ok)) { + g_free(elem); + return -EINVAL; +@@ -257,6 +260,14 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + return 0; + } + ++/* Convenience wrapper to add a guest's element to SVQ */ ++static int vhost_svq_add_element(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem) ++{ ++ return vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->in_sg, ++ elem->in_num, elem); ++} ++ + /** + * Forward available buffers. + * +@@ -293,7 +304,7 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- r = vhost_svq_add(svq, elem); ++ r = vhost_svq_add_element(svq, elem); + if (unlikely(r != 0)) { + if (r == -ENOSPC) { + /* +-- +2.27.0 + diff --git a/vhost-Drop-unused-eventfd_add-del-hooks.patch b/vhost-Drop-unused-eventfd_add-del-hooks.patch new file mode 100644 index 0000000000000000000000000000000000000000..672c23595ab84b3304a0e7b791e1c18a896db22c --- /dev/null +++ b/vhost-Drop-unused-eventfd_add-del-hooks.patch @@ -0,0 +1,63 @@ +From e1c5d60311a7b6dba60284f07fad92dfab688605 Mon Sep 17 00:00:00 2001 +From: xiaowanghe +Date: Sun, 13 Aug 2023 23:18:07 -0700 +Subject: [PATCH] vhost: Drop unused eventfd_add|del hooks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 560a997535937df2ea3716ba56bcbe38be37682f + +These hooks were introduced in: + +80a1ea3748 ("memory: move ioeventfd ops to MemoryListener", 2012-02-29) + +But they seem to be never used. Drop them. + +Cc: Richard Henderson +Signed-off-by: Peter Xu +Message-Id: <20230306193209.516011-1-peterx@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Wanghe Xiao +--- + hw/virtio/vhost.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 3ac6cfde03..2d11e3c2f8 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1268,18 +1268,6 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, + 0, virtio_queue_get_desc_size(vdev, idx)); + } + +-static void vhost_eventfd_add(MemoryListener *listener, +- MemoryRegionSection *section, +- bool match_data, uint64_t data, EventNotifier *e) +-{ +-} +- +-static void vhost_eventfd_del(MemoryListener *listener, +- MemoryRegionSection *section, +- bool match_data, uint64_t data, EventNotifier *e) +-{ +-} +- + static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, + int n, uint32_t timeout) + { +@@ -1413,8 +1401,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + .log_sync = vhost_log_sync, + .log_global_start = vhost_log_global_start, + .log_global_stop = vhost_log_global_stop, +- .eventfd_add = vhost_eventfd_add, +- .eventfd_del = vhost_eventfd_del, + .priority = 10 + }; + +-- +2.41.0.windows.1 + diff --git a/vhost-Expose-vhost_svq_add.patch b/vhost-Expose-vhost_svq_add.patch new file mode 100644 index 0000000000000000000000000000000000000000..d514ec4ee25a260514228ca2dd82bdde2626b9c5 --- /dev/null +++ b/vhost-Expose-vhost_svq_add.patch @@ -0,0 +1,54 @@ +From 9e4727140479522c62070069d552b378c73864f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:37 +0200 +Subject: [PATCH] vhost: Expose vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external parts of SVQ to forward custom buffers to the +device. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 6 +++--- + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 3b5d3bd3f3..5a85365478 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -237,9 +237,9 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * + * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, +- size_t out_num, const struct iovec *in_sg, +- size_t in_num, VirtQueueElement *elem) ++int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, size_t in_num, ++ VirtQueueElement *elem) + { + unsigned qemu_head; + unsigned ndescs = in_num + out_num; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d9fc1f1799..dd78f4bec2 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -86,6 +86,9 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp); + + void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + const VirtQueueElement *elem, uint32_t len); ++int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, size_t in_num, ++ VirtQueueElement *elem); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); +-- +2.27.0 + diff --git a/vhost-Fix-device-s-used-descriptor-dequeue.patch b/vhost-Fix-device-s-used-descriptor-dequeue.patch new file mode 100644 index 0000000000000000000000000000000000000000..f1f751e6aa5018ab2750320e29dae61a141748c9 --- /dev/null +++ b/vhost-Fix-device-s-used-descriptor-dequeue.patch @@ -0,0 +1,64 @@ +From a704fb13777c6820cb8a451dbe0b082f6840f9ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:43 +0200 +Subject: [PATCH] vhost: Fix device's used descriptor dequeue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only the first one of them were properly enqueued back. + +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-3-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 6057a437df..0b394694de 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -333,12 +333,22 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) + svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + } + ++static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq, ++ uint16_t num, uint16_t i) ++{ ++ for (uint16_t j = 0; j < (num - 1); ++j) { ++ i = le16_to_cpu(svq->desc_next[i]); ++ } ++ ++ return i; ++} ++ + static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + uint32_t *len) + { + const vring_used_t *used = svq->vring.used; + vring_used_elem_t used_elem; +- uint16_t last_used; ++ uint16_t last_used, last_used_chain, num; + + if (!vhost_svq_more_used(svq)) { + return NULL; +@@ -364,7 +374,10 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- svq->desc_next[used_elem.id] = svq->free_head; ++ num = svq->ring_id_maps[used_elem.id]->in_num + ++ svq->ring_id_maps[used_elem.id]->out_num; ++ last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); ++ svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +-- +2.27.0 + diff --git a/vhost-Fix-element-in-vhost_svq_add-failure.patch b/vhost-Fix-element-in-vhost_svq_add-failure.patch new file mode 100644 index 0000000000000000000000000000000000000000..bad4669e61b347080f86c50e6fbe1e2a5c3db351 --- /dev/null +++ b/vhost-Fix-element-in-vhost_svq_add-failure.patch @@ -0,0 +1,49 @@ +From 3f2c58f4a5abda763c2d4627c7da252ecf604bbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:47 +0200 +Subject: [PATCH] vhost: Fix element in vhost_svq_add failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Coverity rightly reports that is not free in that case. + +Fixes: Coverity CID 1487559 +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-7-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 0b394694de..cea2c3f8dd 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -198,11 +198,19 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return true; + } + ++/** ++ * Add an element to a SVQ. ++ * ++ * The caller must check that there is enough slots for the new element. It ++ * takes ownership of the element: In case of failure, it is free and the SVQ ++ * is considered broken. ++ */ + static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + { + unsigned qemu_head; + bool ok = vhost_svq_add_split(svq, elem, &qemu_head); + if (unlikely(!ok)) { ++ g_free(elem); + return false; + } + +-- +2.27.0 + diff --git a/vhost-Fix-false-positive-out-of-bounds.patch b/vhost-Fix-false-positive-out-of-bounds.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a6687eb5402622cc1f4d3628d923c84a0127860 --- /dev/null +++ b/vhost-Fix-false-positive-out-of-bounds.patch @@ -0,0 +1,49 @@ +From 9c38d583be2704d7cb5a40e25c9ba0227cbe70cd Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Fri, 7 Jul 2023 23:27:31 +0800 +Subject: [PATCH] vhost: Fix false positive out-of-bounds + +QEMU uses vhost_svq_translate_addr() to translate addresses +between the QEMU's virtual address and the SVQ IOVA. In order +to validate this translation, QEMU checks whether the translated +range falls within the mapped range. + +Yet the problem is that, the value of `needle_last`, which is calculated +by `needle.translated_addr + iovec[i].iov_len`, should represent the +exclusive boundary of the translated range, rather than the last +inclusive addresses of the range. Consequently, QEMU fails the check +when the translated range matches the size of the mapped range. + +This patch solves this problem by fixing the `needle_last` value to +the last inclusive address of the translated range. + +Note that this bug cannot be triggered at the moment, because QEMU +is unable to translate such a big range due to the truncation of +the CVQ command in vhost_vdpa_net_handle_ctrl_avail(). + +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Hawkins Jiawei +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 8d99edb196..8b5902a8a5 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -109,7 +109,7 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, + addrs[i] = map->iova + off; + + needle_last = int128_add(int128_make64(needle.translated_addr), +- int128_make64(iovec[i].iov_len)); ++ int128_makes64(iovec[i].iov_len - 1)); + map_last = int128_make64(map->translated_addr + map->size); + if (unlikely(int128_gt(needle_last, map_last))) { + qemu_log_mask(LOG_GUEST_ERROR, +-- +2.27.0 + diff --git a/vhost-Fix-memory-region-section-comparison.patch b/vhost-Fix-memory-region-section-comparison.patch deleted file mode 100644 index f96bbb3795f3b4e8ee72bc8b6c6dd2ccd91aee18..0000000000000000000000000000000000000000 --- a/vhost-Fix-memory-region-section-comparison.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 8df0aa6ebb27fcf535a7d28cfdc006cd9a34a041 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 14 Aug 2019 18:55:35 +0100 -Subject: [PATCH] vhost: Fix memory region section comparison - -Using memcmp to compare structures wasn't safe, -as I found out on ARM when I was getting falce miscompares. - -Use the helper function for comparing the MRSs. - -Fixes: ade6d081fc33948e56e6 ("vhost: Regenerate region list from changed sections list") -Cc: qemu-stable@nongnu.org -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20190814175535.2023-4-dgilbert@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 3fc4a64cbaed2ddee4c60ddc06740b320e18ab82) -Signed-off-by: Michael Roth ---- - hw/virtio/vhost.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 6d3a013..221e635 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -451,8 +451,13 @@ static void vhost_commit(MemoryListener *listener) - changed = true; - } else { - /* Same size, lets check the contents */ -- changed = n_old_sections && memcmp(dev->mem_sections, old_sections, -- n_old_sections * sizeof(old_sections[0])) != 0; -+ for (int i = 0; i < n_old_sections; i++) { -+ if (!MemoryRegionSection_eq(&old_sections[i], -+ &dev->mem_sections[i])) { -+ changed = true; -+ break; -+ } -+ } - } - - trace_vhost_commit(dev->started, changed); --- -1.8.3.1 - diff --git a/vhost-Get-vring-base-from-vq-not-svq.patch b/vhost-Get-vring-base-from-vq-not-svq.patch new file mode 100644 index 0000000000000000000000000000000000000000..d388ff1974bf5c1a4dfe4694b25feb8c657affd8 --- /dev/null +++ b/vhost-Get-vring-base-from-vq-not-svq.patch @@ -0,0 +1,78 @@ +From a11196160aaf5ba1102ba324c5a7926e83548f6b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 18 Jul 2022 14:05:45 +0200 +Subject: [PATCH] vhost: Get vring base from vq, not svq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SVQ vring used idx usually match with the guest visible one, as long +as all the guest buffers (GPA) maps to exactly one buffer within qemu's +VA. However, as we can see in virtqueue_map_desc, a single guest buffer +could map to many buffers in SVQ vring. + +Also, its also a mistake to rewind them at the source of migration. +Since VirtQueue is able to migrate the inflight descriptors, its +responsability of the destination to perform the rewind just in case it +cannot report the inflight descriptors to the device. + +This makes easier to migrate between backends or to recover them in +vhost devices that support set in flight descriptors. + +Fixes: 6d0b22266633 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 5956ff4660..6304f174c2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1181,7 +1181,18 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; ++ VirtQueue *vq = virtio_get_queue(dev->vdev, ring->index); + ++ /* ++ * vhost-vdpa devices does not support in-flight requests. Set all of them ++ * as available. ++ * ++ * TODO: This is ok for networking, but other kinds of devices might ++ * have problems with these retransmissions. ++ */ ++ while (virtqueue_rewind(vq, 1)) { ++ continue; ++ } + if (v->shadow_vqs_enabled) { + /* + * Device vring base was set at device start. SVQ base is handled by +@@ -1197,21 +1208,10 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; +- int vdpa_idx = ring->index - dev->vq_index; + int ret; + + if (v->shadow_vqs_enabled) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); +- +- /* +- * Setting base as last used idx, so destination will see as available +- * all the entries that the device did not use, including the in-flight +- * processing ones. +- * +- * TODO: This is ok for networking, but other kinds of devices might +- * have problems with these retransmissions. +- */ +- ring->num = svq->last_used_idx; ++ ring->num = virtio_queue_get_last_avail_idx(dev->vdev, ring->index); + return 0; + } + +-- +2.27.0 + diff --git a/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch b/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch new file mode 100644 index 0000000000000000000000000000000000000000..5636e942f004ab54fabbb996e44c063e794e540d --- /dev/null +++ b/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch @@ -0,0 +1,42 @@ +From ebce19945a9bbe3144affa6f5f4129b914e749a0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:31 +0200 +Subject: [PATCH] vhost: Move vhost_svq_kick call to vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The series needs to expose vhost_svq_add with full functionality, +including kick + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 1ba863b802..b99630acee 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -245,6 +245,7 @@ static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + } + + svq->ring_id_maps[qemu_head] = elem; ++ vhost_svq_kick(svq); + return true; + } + +@@ -305,7 +306,6 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + /* VQ is broken, just return and ignore any other kicks */ + return; + } +- vhost_svq_kick(svq); + } + + virtio_queue_set_notification(svq->vq, true); +-- +2.27.0 + diff --git a/vhost-Reorder-vhost_svq_kick.patch b/vhost-Reorder-vhost_svq_kick.patch new file mode 100644 index 0000000000000000000000000000000000000000..459e354786353ab0691c2b00431f1049bc1f11af --- /dev/null +++ b/vhost-Reorder-vhost_svq_kick.patch @@ -0,0 +1,69 @@ +From 5bf30b401a5fa16189589381d42bfc5f6cf8cf9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:30 +0200 +Subject: [PATCH] vhost: Reorder vhost_svq_kick +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Future code needs to call it from vhost_svq_add. + +No functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index acf50a9a0b..1ba863b802 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -214,6 +214,20 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return true; + } + ++static void vhost_svq_kick(VhostShadowVirtqueue *svq) ++{ ++ /* ++ * We need to expose the available array entries before checking the used ++ * flags ++ */ ++ smp_mb(); ++ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { ++ return; ++ } ++ ++ event_notifier_set(&svq->hdev_kick); ++} ++ + /** + * Add an element to a SVQ. + * +@@ -234,20 +248,6 @@ static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + return true; + } + +-static void vhost_svq_kick(VhostShadowVirtqueue *svq) +-{ +- /* +- * We need to expose the available array entries before checking the used +- * flags +- */ +- smp_mb(); +- if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { +- return; +- } +- +- event_notifier_set(&svq->hdev_kick); +-} +- + /** + * Forward available buffers. + * +-- +2.27.0 + diff --git a/vhost-Shadow-virtqueue-buffers-forwarding.patch b/vhost-Shadow-virtqueue-buffers-forwarding.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d38f7a8fd8d7d552f2e8fac7cb08438e8fd525a --- /dev/null +++ b/vhost-Shadow-virtqueue-buffers-forwarding.patch @@ -0,0 +1,684 @@ +From bb7c23fd4979edaeeedf05e05cfed0d086430500 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:47 +0100 +Subject: [PATCH] vhost: Shadow virtqueue buffers forwarding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initial version of shadow virtqueue that actually forward buffers. There +is no iommu support at the moment, and that will be addressed in future +patches of this series. Since all vhost-vdpa devices use forced IOMMU, +this means that SVQ is not usable at this point of the series on any +device. + +For simplicity it only supports modern devices, that expects vring +in little endian, with split ring and no event idx or indirect +descriptors. Support for them will not be added in this series. + +It reuses the VirtQueue code for the device part. The driver part is +based on Linux's virtio_ring driver, but with stripped functionality +and optimizations so it's easier to review. + +However, forwarding buffers have some particular pieces: One of the most +unexpected ones is that a guest's buffer can expand through more than +one descriptor in SVQ. While this is handled gracefully by qemu's +emulated virtio devices, it may cause unexpected SVQ queue full. This +patch also solves it by checking for this condition at both guest's +kicks and device's calls. The code may be more elegant in the future if +SVQ code runs in its own iocontext. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 351 ++++++++++++++++++++++++++++- + hw/virtio/vhost-shadow-virtqueue.h | 26 +++ + hw/virtio/vhost-vdpa.c | 155 ++++++++++++- + 3 files changed, 521 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 573ac0d9cf..46e94f0861 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -13,6 +13,7 @@ + #include "qemu/error-report.h" + #include "qapi/error.h" + #include "qemu/main-loop.h" ++#include "qemu/log.h" + #include "linux-headers/linux/vhost.h" + + /** +@@ -59,28 +60,307 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) + } + + /** +- * Forward guest notifications. ++ * Number of descriptors that the SVQ can make available from the guest. ++ * ++ * @svq: The svq ++ */ ++static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) ++{ ++ return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); ++} ++ ++static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, ++ const struct iovec *iovec, size_t num, ++ bool more_descs, bool write) ++{ ++ uint16_t i = svq->free_head, last = svq->free_head; ++ unsigned n; ++ uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0; ++ vring_desc_t *descs = svq->vring.desc; ++ ++ if (num == 0) { ++ return; ++ } ++ ++ for (n = 0; n < num; n++) { ++ if (more_descs || (n + 1 < num)) { ++ descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); ++ } else { ++ descs[i].flags = flags; ++ } ++ descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base); ++ descs[i].len = cpu_to_le32(iovec[n].iov_len); ++ ++ last = i; ++ i = cpu_to_le16(descs[i].next); ++ } ++ ++ svq->free_head = le16_to_cpu(descs[last].next); ++} ++ ++static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, unsigned *head) ++{ ++ unsigned avail_idx; ++ vring_avail_t *avail = svq->vring.avail; ++ ++ *head = svq->free_head; ++ ++ /* We need some descriptors here */ ++ if (unlikely(!elem->out_num && !elem->in_num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Guest provided element with no descriptors"); ++ return false; ++ } ++ ++ vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0, ++ false); ++ vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true); ++ ++ /* ++ * Put the entry in the available array (but don't update avail->idx until ++ * they do sync). ++ */ ++ avail_idx = svq->shadow_avail_idx & (svq->vring.num - 1); ++ avail->ring[avail_idx] = cpu_to_le16(*head); ++ svq->shadow_avail_idx++; ++ ++ /* Update the avail index after write the descriptor */ ++ smp_wmb(); ++ avail->idx = cpu_to_le16(svq->shadow_avail_idx); ++ ++ return true; ++} ++ ++static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++{ ++ unsigned qemu_head; ++ bool ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ svq->ring_id_maps[qemu_head] = elem; ++ return true; ++} ++ ++static void vhost_svq_kick(VhostShadowVirtqueue *svq) ++{ ++ /* ++ * We need to expose the available array entries before checking the used ++ * flags ++ */ ++ smp_mb(); ++ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { ++ return; ++ } ++ ++ event_notifier_set(&svq->hdev_kick); ++} ++ ++/** ++ * Forward available buffers. ++ * ++ * @svq: Shadow VirtQueue ++ * ++ * Note that this function does not guarantee that all guest's available ++ * buffers are available to the device in SVQ avail ring. The guest may have ++ * exposed a GPA / GIOVA contiguous buffer, but it may not be contiguous in ++ * qemu vaddr. ++ * ++ * If that happens, guest's kick notifications will be disabled until the ++ * device uses some buffers. ++ */ ++static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) ++{ ++ /* Clear event notifier */ ++ event_notifier_test_and_clear(&svq->svq_kick); ++ ++ /* Forward to the device as many available buffers as possible */ ++ do { ++ virtio_queue_set_notification(svq->vq, false); ++ ++ while (true) { ++ VirtQueueElement *elem; ++ bool ok; ++ ++ if (svq->next_guest_avail_elem) { ++ elem = g_steal_pointer(&svq->next_guest_avail_elem); ++ } else { ++ elem = virtqueue_pop(svq->vq, sizeof(*elem)); ++ } ++ ++ if (!elem) { ++ break; ++ } ++ ++ if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) { ++ /* ++ * This condition is possible since a contiguous buffer in GPA ++ * does not imply a contiguous buffer in qemu's VA ++ * scatter-gather segments. If that happens, the buffer exposed ++ * to the device needs to be a chain of descriptors at this ++ * moment. ++ * ++ * SVQ cannot hold more available buffers if we are here: ++ * queue the current guest descriptor and ignore further kicks ++ * until some elements are used. ++ */ ++ svq->next_guest_avail_elem = elem; ++ return; ++ } ++ ++ ok = vhost_svq_add(svq, elem); ++ if (unlikely(!ok)) { ++ /* VQ is broken, just return and ignore any other kicks */ ++ return; ++ } ++ vhost_svq_kick(svq); ++ } ++ ++ virtio_queue_set_notification(svq->vq, true); ++ } while (!virtio_queue_empty(svq->vq)); ++} ++ ++/** ++ * Handle guest's kick. + * + * @n: guest kick event notifier, the one that guest set to notify svq. + */ +-static void vhost_handle_guest_kick(EventNotifier *n) ++static void vhost_handle_guest_kick_notifier(EventNotifier *n) + { + VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick); + event_notifier_test_and_clear(n); +- event_notifier_set(&svq->hdev_kick); ++ vhost_handle_guest_kick(svq); ++} ++ ++static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) ++{ ++ if (svq->last_used_idx != svq->shadow_used_idx) { ++ return true; ++ } ++ ++ svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx); ++ ++ return svq->last_used_idx != svq->shadow_used_idx; + } + + /** +- * Forward vhost notifications ++ * Enable vhost device calls after disable them. ++ * ++ * @svq: The svq ++ * ++ * It returns false if there are pending used buffers from the vhost device, ++ * avoiding the possible races between SVQ checking for more work and enabling ++ * callbacks. True if SVQ used vring has no more pending buffers. ++ */ ++static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq) ++{ ++ svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); ++ /* Make sure the flag is written before the read of used_idx */ ++ smp_mb(); ++ return !vhost_svq_more_used(svq); ++} ++ ++static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) ++{ ++ svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); ++} ++ ++static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, ++ uint32_t *len) ++{ ++ vring_desc_t *descs = svq->vring.desc; ++ const vring_used_t *used = svq->vring.used; ++ vring_used_elem_t used_elem; ++ uint16_t last_used; ++ ++ if (!vhost_svq_more_used(svq)) { ++ return NULL; ++ } ++ ++ /* Only get used array entries after they have been exposed by dev */ ++ smp_rmb(); ++ last_used = svq->last_used_idx & (svq->vring.num - 1); ++ used_elem.id = le32_to_cpu(used->ring[last_used].id); ++ used_elem.len = le32_to_cpu(used->ring[last_used].len); ++ ++ svq->last_used_idx++; ++ if (unlikely(used_elem.id >= svq->vring.num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used", ++ svq->vdev->name, used_elem.id); ++ return NULL; ++ } ++ ++ if (unlikely(!svq->ring_id_maps[used_elem.id])) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Device %s says index %u is used, but it was not available", ++ svq->vdev->name, used_elem.id); ++ return NULL; ++ } ++ ++ descs[used_elem.id].next = svq->free_head; ++ svq->free_head = used_elem.id; ++ ++ *len = used_elem.len; ++ return g_steal_pointer(&svq->ring_id_maps[used_elem.id]); ++} ++ ++static void vhost_svq_flush(VhostShadowVirtqueue *svq, ++ bool check_for_avail_queue) ++{ ++ VirtQueue *vq = svq->vq; ++ ++ /* Forward as many used buffers as possible. */ ++ do { ++ unsigned i = 0; ++ ++ vhost_svq_disable_notification(svq); ++ while (true) { ++ uint32_t len; ++ g_autofree VirtQueueElement *elem = vhost_svq_get_buf(svq, &len); ++ if (!elem) { ++ break; ++ } ++ ++ if (unlikely(i >= svq->vring.num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "More than %u used buffers obtained in a %u size SVQ", ++ i, svq->vring.num); ++ virtqueue_fill(vq, elem, len, i); ++ virtqueue_flush(vq, i); ++ return; ++ } ++ virtqueue_fill(vq, elem, len, i++); ++ } ++ ++ virtqueue_flush(vq, i); ++ event_notifier_set(&svq->svq_call); ++ ++ if (check_for_avail_queue && svq->next_guest_avail_elem) { ++ /* ++ * Avail ring was full when vhost_svq_flush was called, so it's a ++ * good moment to make more descriptors available if possible. ++ */ ++ vhost_handle_guest_kick(svq); ++ } ++ } while (!vhost_svq_enable_notification(svq)); ++} ++ ++/** ++ * Forward used buffers. + * + * @n: hdev call event notifier, the one that device set to notify svq. ++ * ++ * Note that we are not making any buffers available in the loop, there is no ++ * way that it runs more than virtqueue size times. + */ + static void vhost_svq_handle_call(EventNotifier *n) + { + VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, + hdev_call); + event_notifier_test_and_clear(n); +- event_notifier_set(&svq->svq_call); ++ vhost_svq_flush(svq, true); + } + + /** +@@ -161,7 +441,41 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + if (poll_start) { + event_notifier_init_fd(svq_kick, svq_kick_fd); + event_notifier_set(svq_kick); +- event_notifier_set_handler(svq_kick, vhost_handle_guest_kick); ++ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier); ++ } ++} ++ ++/** ++ * Start the shadow virtqueue operation. ++ * ++ * @svq: Shadow Virtqueue ++ * @vdev: VirtIO device ++ * @vq: Virtqueue to shadow ++ */ ++void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, ++ VirtQueue *vq) ++{ ++ size_t desc_size, driver_size, device_size; ++ ++ svq->next_guest_avail_elem = NULL; ++ svq->shadow_avail_idx = 0; ++ svq->shadow_used_idx = 0; ++ svq->last_used_idx = 0; ++ svq->vdev = vdev; ++ svq->vq = vq; ++ ++ svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); ++ driver_size = vhost_svq_driver_area_size(svq); ++ device_size = vhost_svq_device_area_size(svq); ++ svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size); ++ desc_size = sizeof(vring_desc_t) * svq->vring.num; ++ svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size); ++ memset(svq->vring.desc, 0, driver_size); ++ svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); ++ memset(svq->vring.used, 0, device_size); ++ svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ for (unsigned i = 0; i < svq->vring.num - 1; i++) { ++ svq->vring.desc[i].next = cpu_to_le16(i + 1); + } + } + +@@ -172,6 +486,31 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + void vhost_svq_stop(VhostShadowVirtqueue *svq) + { + event_notifier_set_handler(&svq->svq_kick, NULL); ++ g_autofree VirtQueueElement *next_avail_elem = NULL; ++ ++ if (!svq->vq) { ++ return; ++ } ++ ++ /* Send all pending used descriptors to guest */ ++ vhost_svq_flush(svq, false); ++ ++ for (unsigned i = 0; i < svq->vring.num; ++i) { ++ g_autofree VirtQueueElement *elem = NULL; ++ elem = g_steal_pointer(&svq->ring_id_maps[i]); ++ if (elem) { ++ virtqueue_detach_element(svq->vq, elem, 0); ++ } ++ } ++ ++ next_avail_elem = g_steal_pointer(&svq->next_guest_avail_elem); ++ if (next_avail_elem) { ++ virtqueue_detach_element(svq->vq, next_avail_elem, 0); ++ } ++ svq->vq = NULL; ++ g_free(svq->ring_id_maps); ++ qemu_vfree(svq->vring.desc); ++ qemu_vfree(svq->vring.used); + } + + /** +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 82cea1c3fa..38b3b91ca7 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -36,6 +36,30 @@ typedef struct VhostShadowVirtqueue { + + /* Guest's call notifier, where the SVQ calls guest. */ + EventNotifier svq_call; ++ ++ /* Virtio queue shadowing */ ++ VirtQueue *vq; ++ ++ /* Virtio device */ ++ VirtIODevice *vdev; ++ ++ /* Map for use the guest's descriptors */ ++ VirtQueueElement **ring_id_maps; ++ ++ /* Next VirtQueue element that guest made available */ ++ VirtQueueElement *next_guest_avail_elem; ++ ++ /* Next head to expose to the device */ ++ uint16_t shadow_avail_idx; ++ ++ /* Next free descriptor */ ++ uint16_t free_head; ++ ++ /* Last seen used idx */ ++ uint16_t shadow_used_idx; ++ ++ /* Next head to consume from the device */ ++ uint16_t last_used_idx; + } VhostShadowVirtqueue; + + bool vhost_svq_valid_features(uint64_t features, Error **errp); +@@ -47,6 +71,8 @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, + size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); + size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + ++void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, ++ VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + + VhostShadowVirtqueue *vhost_svq_new(void); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 2f0e6a9bef..db34f26246 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -779,9 +779,9 @@ static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev, + * Note that this function does not rewind kick file descriptor if cannot set + * call one. + */ +-static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, +- VhostShadowVirtqueue *svq, unsigned idx, +- Error **errp) ++static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) + { + struct vhost_vring_file file = { + .index = dev->vq_index + idx, +@@ -793,7 +793,7 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); +- return false; ++ return r; + } + + event_notifier = &svq->hdev_call; +@@ -803,6 +803,95 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + error_setg_errno(errp, -r, "Can't set device call fd"); + } + ++ return r; ++} ++ ++/** ++ * Unmap a SVQ area in the device ++ */ ++static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova, ++ hwaddr size) ++{ ++ int r; ++ ++ size = ROUND_UP(size, qemu_real_host_page_size); ++ r = vhost_vdpa_dma_unmap(v, iova, size); ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, ++ const VhostShadowVirtqueue *svq) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ struct vhost_vring_addr svq_addr; ++ size_t device_size = vhost_svq_device_area_size(svq); ++ size_t driver_size = vhost_svq_driver_area_size(svq); ++ bool ok; ++ ++ vhost_svq_get_vring_addr(svq, &svq_addr); ++ ++ ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size); ++} ++ ++/** ++ * Map the shadow virtqueue rings in the device ++ * ++ * @dev: The vhost device ++ * @svq: The shadow virtqueue ++ * @addr: Assigned IOVA addresses ++ * @errp: Error pointer ++ */ ++static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, ++ const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr, ++ Error **errp) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ size_t device_size = vhost_svq_device_area_size(svq); ++ size_t driver_size = vhost_svq_driver_area_size(svq); ++ int r; ++ ++ ERRP_GUARD(); ++ vhost_svq_get_vring_addr(svq, addr); ++ ++ r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size, ++ (void *)(uintptr_t)addr->desc_user_addr, true); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot create vq driver region: "); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size, ++ (void *)(intptr_t)addr->used_user_addr, false); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot create vq device region: "); ++ } ++ ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) ++{ ++ uint16_t vq_index = dev->vq_index + idx; ++ struct vhost_vring_state s = { ++ .index = vq_index, ++ }; ++ int r; ++ ++ r = vhost_vdpa_set_dev_vring_base(dev, &s); ++ if (unlikely(r)) { ++ error_setg_errno(errp, -r, "Cannot set vring base"); ++ return false; ++ } ++ ++ r = vhost_vdpa_svq_set_fds(dev, svq, idx, errp); + return r == 0; + } + +@@ -817,10 +906,62 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + } + + for (i = 0; i < v->shadow_vqs->len; ++i) { ++ VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ struct vhost_vring_addr addr = { ++ .index = i, ++ }; ++ int r; + bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); + if (unlikely(!ok)) { +- error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ goto err; ++ } ++ ++ vhost_svq_start(svq, dev->vdev, vq); ++ ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err); ++ if (unlikely(!ok)) { ++ goto err_map; ++ } ++ ++ /* Override vring GPA set by vhost subsystem */ ++ r = vhost_vdpa_set_vring_dev_addr(dev, &addr); ++ if (unlikely(r != 0)) { ++ error_setg_errno(&err, -r, "Cannot set device address"); ++ goto err_set_addr; ++ } ++ } ++ ++ return true; ++ ++err_set_addr: ++ vhost_vdpa_svq_unmap_rings(dev, g_ptr_array_index(v->shadow_vqs, i)); ++ ++err_map: ++ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, i)); ++ ++err: ++ error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ for (unsigned j = 0; j < i; ++j) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, j); ++ vhost_vdpa_svq_unmap_rings(dev, svq); ++ vhost_svq_stop(svq); ++ } ++ ++ return false; ++} ++ ++static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (!v->shadow_vqs) { ++ return true; ++ } ++ ++ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ bool ok = vhost_vdpa_svq_unmap_rings(dev, svq); ++ if (unlikely(!ok)) { + return false; + } + } +@@ -842,6 +983,10 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + vhost_vdpa_set_vring_ready(dev); + } else { ++ ok = vhost_vdpa_svqs_stop(dev); ++ if (unlikely(!ok)) { ++ return -1; ++ } + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + } + +-- +2.27.0 + diff --git a/vhost-Track-descriptor-chain-in-private-at-SVQ.patch b/vhost-Track-descriptor-chain-in-private-at-SVQ.patch new file mode 100644 index 0000000000000000000000000000000000000000..dbcdb74321eecc722f2b89b20c6727d5310b0751 --- /dev/null +++ b/vhost-Track-descriptor-chain-in-private-at-SVQ.patch @@ -0,0 +1,104 @@ +From de3c31598e00c4bcee42f3921f714b0928716535 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:42 +0200 +Subject: [PATCH] vhost: Track descriptor chain in private at SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The device could have access to modify them, and it definitely have +access when we implement packed vq. Harden SVQ maintaining a private +copy of the descriptor chain. Other fields like buffer addresses are +already maintained sepparatedly. + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 12 +++++++----- + hw/virtio/vhost-shadow-virtqueue.h | 6 ++++++ + 2 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c38b6b6ab5..6057a437df 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -137,6 +137,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + for (n = 0; n < num; n++) { + if (more_descs || (n + 1 < num)) { + descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); ++ descs[i].next = cpu_to_le16(svq->desc_next[i]); + } else { + descs[i].flags = flags; + } +@@ -144,10 +145,10 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + descs[i].len = cpu_to_le32(iovec[n].iov_len); + + last = i; +- i = cpu_to_le16(descs[i].next); ++ i = cpu_to_le16(svq->desc_next[i]); + } + +- svq->free_head = le16_to_cpu(descs[last].next); ++ svq->free_head = le16_to_cpu(svq->desc_next[last]); + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +@@ -335,7 +336,6 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) + static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + uint32_t *len) + { +- vring_desc_t *descs = svq->vring.desc; + const vring_used_t *used = svq->vring.used; + vring_used_elem_t used_elem; + uint16_t last_used; +@@ -364,7 +364,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- descs[used_elem.id].next = svq->free_head; ++ svq->desc_next[used_elem.id] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +@@ -539,8 +539,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); + memset(svq->vring.used, 0, device_size); + svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ svq->desc_next = g_new0(uint16_t, svq->vring.num); + for (unsigned i = 0; i < svq->vring.num - 1; i++) { +- svq->vring.desc[i].next = cpu_to_le16(i + 1); ++ svq->desc_next[i] = cpu_to_le16(i + 1); + } + } + +@@ -573,6 +574,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + virtqueue_detach_element(svq->vq, next_avail_elem, 0); + } + svq->vq = NULL; ++ g_free(svq->desc_next); + g_free(svq->ring_id_maps); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index e5e24c536d..c132c994e9 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -53,6 +53,12 @@ typedef struct VhostShadowVirtqueue { + /* Next VirtQueue element that guest made available */ + VirtQueueElement *next_guest_avail_elem; + ++ /* ++ * Backup next field for each descriptor so we can recover securely, not ++ * needing to trust the device access. ++ */ ++ uint16_t *desc_next; ++ + /* Next head to expose to the device */ + uint16_t shadow_avail_idx; + +-- +2.27.0 + diff --git a/vhost-Track-number-of-descs-in-SVQDescState.patch b/vhost-Track-number-of-descs-in-SVQDescState.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c247898e54198d1693d7a316613f05be71eba96 --- /dev/null +++ b/vhost-Track-number-of-descs-in-SVQDescState.patch @@ -0,0 +1,62 @@ +From d76e2c5a5213d51dd8c48315e26c277423ade99f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:35 +0200 +Subject: [PATCH] vhost: Track number of descs in SVQDescState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A guest's buffer continuos on GPA may need multiple descriptors on +qemu's VA, so SVQ should track its length sepparatedly. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + hw/virtio/vhost-shadow-virtqueue.h | 6 ++++++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 5ddc04e9d6..c10c74b91f 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -256,6 +256,7 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + } + + svq->desc_state[qemu_head].elem = elem; ++ svq->desc_state[qemu_head].ndescs = ndescs; + vhost_svq_kick(svq); + return 0; + } +@@ -417,8 +418,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- num = svq->desc_state[used_elem.id].elem->in_num + +- svq->desc_state[used_elem.id].elem->out_num; ++ num = svq->desc_state[used_elem.id].ndescs; + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d646c35054..5c7e7cbab6 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -17,6 +17,12 @@ + + typedef struct SVQDescState { + VirtQueueElement *elem; ++ ++ /* ++ * Number of descriptors exposed to the device. May or may not match ++ * guest's ++ */ ++ unsigned int ndescs; + } SVQDescState; + + /* Shadow virtqueue to relay notifications */ +-- +2.27.0 + diff --git a/vhost-add-support-for-configure-interrupt-new.patch b/vhost-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..0be96f2765e2b740fbcedab5ccd048979c1f07b4 --- /dev/null +++ b/vhost-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,172 @@ +From 59957a4caee59e0c82b8d02ed1c1820db523ae64 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:48 +0800 +Subject: [PATCH] vhost: add support for configure interrupt + +Add functions to support configure interrupt. +The configure interrupt process will start in vhost_dev_start +and stop in vhost_dev_stop. + +Also add the functions to support vhost_config_pending and +vhost_config_mask. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-8-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 78 ++++++++++++++++++++++++++++++++++++++- + include/hw/virtio/vhost.h | 4 ++ + 2 files changed, 81 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 19ea9aef69..490c97424b 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1627,7 +1627,68 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); + r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); + if (r < 0) { +- VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); ++ error_report("vhost_set_vring_call failed %d", -r); ++ } ++} ++ ++bool vhost_config_pending(struct vhost_dev *hdev) ++{ ++ assert(hdev->vhost_ops); ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return false; ++ } ++ ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ return event_notifier_test_and_clear(notifier); ++} ++ ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) ++{ ++ int fd; ++ int r; ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ EventNotifier *config_notifier = &vdev->config_notifier; ++ assert(hdev->vhost_ops); ++ ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return; ++ } ++ if (mask) { ++ assert(vdev->use_guest_notifier_mask); ++ fd = event_notifier_get_fd(notifier); ++ } else { ++ fd = event_notifier_get_fd(config_notifier); ++ } ++ r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); ++ if (r < 0) { ++ error_report("vhost_set_config_call failed %d", -r); ++ } ++} ++ ++static void vhost_stop_config_intr(struct vhost_dev *dev) ++{ ++ int fd = -1; ++ assert(dev->vhost_ops); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ dev->vhost_ops->vhost_set_config_call(dev, fd); ++ } ++} ++ ++static void vhost_start_config_intr(struct vhost_dev *dev) ++{ ++ int r; ++ ++ assert(dev->vhost_ops); ++ int fd = event_notifier_get_fd(&dev->vdev->config_notifier); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ r = dev->vhost_ops->vhost_set_config_call(dev, fd); ++ if (!r) { ++ event_notifier_set(&dev->vdev->config_notifier); ++ } + } + } + +@@ -1867,6 +1928,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + } + } + ++ r = event_notifier_init( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ if (!vdev->use_guest_notifier_mask) { ++ vhost_config_mask(hdev, vdev, true); ++ } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1905,6 +1976,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } ++ vhost_start_config_intr(hdev); + return 0; + fail_start: + if (vrings) { +@@ -1934,6 +2006,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ event_notifier_test_and_clear(&vdev->config_notifier); + + trace_vhost_dev_stop(hdev, vdev->name, vrings); + +@@ -1956,6 +2031,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + } + memory_listener_unregister(&hdev->iommu_listener); + } ++ vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + vdev->vhost_started = false; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 662e0f4370..420f93e5cd 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -32,6 +32,7 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; ++ EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -40,6 +41,7 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) ++#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -163,6 +165,8 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + * Disable direct notifications to vhost device. + */ + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++bool vhost_config_pending(struct vhost_dev *hdev); ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /** + * vhost_dev_start() - start the vhost device +-- +2.27.0 + diff --git a/vhost-add-support-for-configure-interrupt.patch b/vhost-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8916c37b3e8ce0b112fcbca42b9a993ee7debe3 --- /dev/null +++ b/vhost-add-support-for-configure-interrupt.patch @@ -0,0 +1,170 @@ +From 9823b7bb536cea50c9750320436511fd60b797cd Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:52 +0800 +Subject: [PATCH] vhost: add support for configure interrupt + +Add functions to support configure interrupt. +The configure interrupt process will start in vhost_dev_start +and stop in vhost_dev_stop. + +Also add the functions to support vhost_config_pending and +vhost_config_mask, for masked_config_notifier, we only +use the notifier saved in vq 0. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-8-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 76 +++++++++++++++++++++++++++++++++++++++ + include/hw/virtio/vhost.h | 4 +++ + 2 files changed, 80 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2d11e3c2f8..c3f375f276 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1588,6 +1588,67 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + } + } + ++bool vhost_config_pending(struct vhost_dev *hdev) ++{ ++ assert(hdev->vhost_ops); ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return false; ++ } ++ ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ return event_notifier_test_and_clear(notifier); ++} ++ ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) ++{ ++ int fd; ++ int r; ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ EventNotifier *config_notifier = &vdev->config_notifier; ++ assert(hdev->vhost_ops); ++ ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return; ++ } ++ if (mask) { ++ assert(vdev->use_guest_notifier_mask); ++ fd = event_notifier_get_fd(notifier); ++ } else { ++ fd = event_notifier_get_fd(config_notifier); ++ } ++ r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); ++ if (r < 0) { ++ VHOST_OPS_DEBUG("vhost_set_config_call failed"); ++ } ++} ++ ++static void vhost_stop_config_intr(struct vhost_dev *dev) ++{ ++ int fd = -1; ++ assert(dev->vhost_ops); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ dev->vhost_ops->vhost_set_config_call(dev, fd); ++ } ++} ++ ++static void vhost_start_config_intr(struct vhost_dev *dev) ++{ ++ int r; ++ ++ assert(dev->vhost_ops); ++ int fd = event_notifier_get_fd(&dev->vdev->config_notifier); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ r = dev->vhost_ops->vhost_set_config_call(dev, fd); ++ if (!r) { ++ event_notifier_set(&dev->vdev->config_notifier); ++ } ++ } ++} ++ + uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features) + { +@@ -1800,6 +1861,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + ++ r = event_notifier_init( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ if (!vdev->use_guest_notifier_mask) { ++ vhost_config_mask(hdev, vdev, true); ++ } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1833,6 +1904,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } ++ vhost_start_config_intr(hdev); + return 0; + fail_log: + vhost_log_put(hdev, false); +@@ -1858,6 +1930,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ event_notifier_test_and_clear(&vdev->config_notifier); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); +@@ -1875,6 +1950,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + memory_listener_unregister(&hdev->iommu_listener); + } ++ vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + hdev->vdev = NULL; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 86f36f0106..2ae5c3bfd8 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -29,6 +29,7 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; ++ EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -37,6 +38,7 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) ++#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -116,6 +118,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++bool vhost_config_pending(struct vhost_dev *hdev); ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. +-- +2.27.0 + diff --git a/vhost-add-vhost_dev_suspend-resume_op.patch b/vhost-add-vhost_dev_suspend-resume_op.patch new file mode 100644 index 0000000000000000000000000000000000000000..e09763177b5fb22aba7309292ae5bfcee21b2811 --- /dev/null +++ b/vhost-add-vhost_dev_suspend-resume_op.patch @@ -0,0 +1,64 @@ +From 745bbf64b2a1e74366550bffbb68da1df2a9f378 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:13:41 +0800 +Subject: [PATCH] vhost: add vhost_dev_suspend/resume_op + +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + include/hw/virtio/vhost-backend.h | 5 +++++ + linux-headers/linux/vhost.h | 17 +++++++++++++++++ + 2 files changed, 22 insertions(+) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index 86154dd0b2..2ca6250567 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -135,6 +135,9 @@ typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + ++typedef int (*vhost_dev_suspend_op)(struct vhost_dev *dev); ++typedef int (*vhost_dev_resume_op)(struct vhost_dev *dev); ++ + typedef struct VhostOps { + VhostBackendType backend_type; + vhost_backend_init vhost_backend_init; +@@ -186,6 +189,8 @@ typedef struct VhostOps { + vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; ++ vhost_dev_suspend_op vhost_dev_suspend; ++ vhost_dev_resume_op vhost_dev_resume; + } VhostOps; + + int vhost_backend_update_device_iotlb(struct vhost_dev *dev, +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index 65c6b49788..9b3f71b20f 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -175,4 +175,21 @@ + #define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ + struct vhost_vring_state) + ++/* Suspend a device so it does not process virtqueue requests anymore ++ * ++ * After the return of ioctl the device must preserve all the necessary state ++ * (the virtqueue vring base plus the possible device specific states) that is ++ * required for restoring in the future. The device must not change its ++ * configuration after that point. ++ */ ++#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D) ++ ++/* Resume a device so it can resume processing virtqueue requests ++ * ++ * After the return of this ioctl the device will have restored all the ++ * necessary states and it is fully operational to continue processing the ++ * virtqueue descriptors. ++ */ ++#define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) ++ + #endif +-- +2.27.0 + diff --git a/vhost-add-vhost_svq_poll.patch b/vhost-add-vhost_svq_poll.patch new file mode 100644 index 0000000000000000000000000000000000000000..90b430ab1149edec4c8bcc543bc454876839d8a2 --- /dev/null +++ b/vhost-add-vhost_svq_poll.patch @@ -0,0 +1,73 @@ +From 65869116f29f0c92a394af2308c154c855938923 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:38 +0200 +Subject: [PATCH] vhost: add vhost_svq_poll +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It allows the Shadow Control VirtQueue to wait for the device to use the +available buffers. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 27 +++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 1 + + 2 files changed, 28 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 5a85365478..d2676b94e0 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -484,6 +484,33 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, + } while (!vhost_svq_enable_notification(svq)); + } + ++/** ++ * Poll the SVQ for one device used buffer. ++ * ++ * This function race with main event loop SVQ polling, so extra ++ * synchronization is needed. ++ * ++ * Return the length written by the device. ++ */ ++size_t vhost_svq_poll(VhostShadowVirtqueue *svq) ++{ ++ int64_t start_us = g_get_monotonic_time(); ++ do { ++ uint32_t len; ++ VirtQueueElement *elem = vhost_svq_get_buf(svq, &len); ++ if (elem) { ++ return len; ++ } ++ ++ if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { ++ return 0; ++ } ++ ++ /* Make sure we read new used_idx */ ++ smp_rmb(); ++ } while (true); ++} ++ + /** + * Forward used buffers. + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index dd78f4bec2..cf442f7dea 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -89,6 +89,7 @@ void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + size_t out_num, const struct iovec *in_sg, size_t in_num, + VirtQueueElement *elem); ++size_t vhost_svq_poll(VhostShadowVirtqueue *svq); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); +-- +2.27.0 + diff --git a/vhost-add-vhost_svq_push_elem.patch b/vhost-add-vhost_svq_push_elem.patch new file mode 100644 index 0000000000000000000000000000000000000000..395d975ad4eb6374397347f9c516609789e325b1 --- /dev/null +++ b/vhost-add-vhost_svq_push_elem.patch @@ -0,0 +1,64 @@ +From ac243c5186493f41c9ff0d60558dabb651c56983 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:36 +0200 +Subject: [PATCH] vhost: add vhost_svq_push_elem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function allows external SVQ users to return guest's available +buffers. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 16 ++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 19 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c10c74b91f..3b5d3bd3f3 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -427,6 +427,22 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return g_steal_pointer(&svq->desc_state[used_elem.id].elem); + } + ++/** ++ * Push an element to SVQ, returning it to the guest. ++ */ ++void vhost_svq_push_elem(VhostShadowVirtqueue *svq, ++ const VirtQueueElement *elem, uint32_t len) ++{ ++ virtqueue_push(svq->vq, elem, len); ++ if (svq->next_guest_avail_elem) { ++ /* ++ * Avail ring was full when vhost_svq_flush was called, so it's a ++ * good moment to make more descriptors available if possible. ++ */ ++ vhost_handle_guest_kick(svq); ++ } ++} ++ + static void vhost_svq_flush(VhostShadowVirtqueue *svq, + bool check_for_avail_queue) + { +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 5c7e7cbab6..d9fc1f1799 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -84,6 +84,9 @@ typedef struct VhostShadowVirtqueue { + + bool vhost_svq_valid_features(uint64_t features, Error **errp); + ++void vhost_svq_push_elem(VhostShadowVirtqueue *svq, ++ const VirtQueueElement *elem, uint32_t len); ++ + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, +-- +2.27.0 + diff --git a/vhost-allocate-SVQ-device-file-descriptors-at-device.patch b/vhost-allocate-SVQ-device-file-descriptors-at-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b85e7293d8d67c988d0cc86426ceb84d8fb9df8 --- /dev/null +++ b/vhost-allocate-SVQ-device-file-descriptors-at-device.patch @@ -0,0 +1,162 @@ +From 539c46ecb41417007840c750d364b5332cbdc5b5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:35 +0100 +Subject: [PATCH] vhost: allocate SVQ device file descriptors at device start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next patches will start control SVQ if possible. However, we don't +know if that will be possible at qemu boot anymore. + +Delay device file descriptors until we know it at device start. This +will avoid to create them if the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 31 ++------------------------ + hw/virtio/vhost-vdpa.c | 35 ++++++++++++++++++++++++------ + 2 files changed, 30 insertions(+), 36 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index bc12bb42f3..47e831667c 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -692,43 +692,18 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * @iova_tree: Tree to perform descriptors translations + * @ops: SVQ owner callbacks + * @ops_opaque: ops opaque pointer +- * +- * Returns the new virtqueue or NULL. +- * +- * In case of error, reason is reported through error_report. + */ + VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, + const VhostShadowVirtqueueOps *ops, + void *ops_opaque) + { +- g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); +- int r; +- +- r = event_notifier_init(&svq->hdev_kick, 0); +- if (r != 0) { +- error_report("Couldn't create kick event notifier: %s (%d)", +- g_strerror(errno), errno); +- goto err_init_hdev_kick; +- } +- +- r = event_notifier_init(&svq->hdev_call, 0); +- if (r != 0) { +- error_report("Couldn't create call event notifier: %s (%d)", +- g_strerror(errno), errno); +- goto err_init_hdev_call; +- } ++ VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; +- return g_steal_pointer(&svq); +- +-err_init_hdev_call: +- event_notifier_cleanup(&svq->hdev_kick); +- +-err_init_hdev_kick: +- return NULL; ++ return svq; + } + + /** +@@ -740,7 +715,5 @@ void vhost_svq_free(gpointer pvq) + { + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); +- event_notifier_cleanup(&vq->hdev_kick); +- event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 08f92bf781..23e715b05c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -430,15 +430,11 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq; ++ VhostShadowVirtqueue *svq; + + svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, + v->shadow_vq_ops_opaque); +- if (unlikely(!svq)) { +- error_setg(errp, "Cannot create svq %u", n); +- return -1; +- } +- g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq)); ++ g_ptr_array_add(shadow_vqs, svq); + } + + v->shadow_vqs = g_steal_pointer(&shadow_vqs); +@@ -866,11 +862,23 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + const EventNotifier *event_notifier = &svq->hdev_kick; + int r; + ++ r = event_notifier_init(&svq->hdev_kick, 0); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Couldn't create kick event notifier"); ++ goto err_init_hdev_kick; ++ } ++ ++ r = event_notifier_init(&svq->hdev_call, 0); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Couldn't create call event notifier"); ++ goto err_init_hdev_call; ++ } ++ + file.fd = event_notifier_get_fd(event_notifier); + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); +- return r; ++ goto err_init_set_dev_fd; + } + + event_notifier = &svq->hdev_call; +@@ -878,8 +886,18 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_call(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device call fd"); ++ goto err_init_set_dev_fd; + } + ++ return 0; ++ ++err_init_set_dev_fd: ++ event_notifier_set_handler(&svq->hdev_call, NULL); ++ ++err_init_hdev_call: ++ event_notifier_cleanup(&svq->hdev_kick); ++ ++err_init_hdev_kick: + return r; + } + +@@ -1091,6 +1109,9 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + vhost_vdpa_svq_unmap_rings(dev, svq); ++ ++ event_notifier_cleanup(&svq->hdev_kick); ++ event_notifier_cleanup(&svq->hdev_call); + } + } + +-- +2.27.0 + diff --git a/vhost-also-check-queue-state-in-the-vhost_dev_set_lo.patch b/vhost-also-check-queue-state-in-the-vhost_dev_set_lo.patch new file mode 100644 index 0000000000000000000000000000000000000000..4299b2662d393d56a577c6a19ae9848febe31a5d --- /dev/null +++ b/vhost-also-check-queue-state-in-the-vhost_dev_set_lo.patch @@ -0,0 +1,39 @@ +From cb16f58f6db98113f9079b27e7e313c91060e6e4 Mon Sep 17 00:00:00 2001 +From: Ni Xun +Date: Thu, 9 Jun 2022 21:10:12 +0800 +Subject: [PATCH 3/5] vhost: also check queue state in the vhost_dev_set_log + error routine + +When check queue state in the vhost_dev_set_log routine, it miss the error +routine check, this patch also check queue state in error case. + +Fixes: 1e5a050f5798 ("check queue state in the vhost_dev_set_log routine") +Signed-off-by: Ni Xun +Reviewed-by: Zhigang Lu +Message-Id: +Reviewed-by: Michael S. Tsirkin +Acked-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: zhangxinhao +--- + hw/virtio/vhost.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 4c4072951c..3ac6cfde03 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -900,6 +900,10 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) + err_vq: + for (; i >= 0; --i) { + idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i); ++ addr = virtio_queue_get_desc_addr(dev->vdev, idx); ++ if (!addr) { ++ continue; ++ } + vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, + dev->log_enabled); + } +-- +2.27.0 + diff --git a/vhost-cancel-migration-when-vhost-user-restarted.patch b/vhost-cancel-migration-when-vhost-user-restarted-dur.patch similarity index 79% rename from vhost-cancel-migration-when-vhost-user-restarted.patch rename to vhost-cancel-migration-when-vhost-user-restarted-dur.patch index 38557753ce28b7120f23d21bc4f87fae22160d44..d34d1249ceb70069cd9881bf14765044dc97b3a0 100644 --- a/vhost-cancel-migration-when-vhost-user-restarted.patch +++ b/vhost-cancel-migration-when-vhost-user-restarted-dur.patch @@ -1,8 +1,8 @@ -From 750328e01afe4776eaddacde406063978dbf1291 Mon Sep 17 00:00:00 2001 -From: Ying Fang +From d41206e959717f68a31da4a2d875d33035baeb9f Mon Sep 17 00:00:00 2001 +From: Chuan Zheng Date: Mon, 29 Jul 2019 16:22:12 +0800 -Subject: [PATCH] vhost: cancel migration when vhost-user restarted during - migraiton +Subject: [PATCH 08/14] vhost: cancel migration when vhost-user restarted + during migraiton Qemu will abort when vhost-user process is restarted during migration when vhost_log_global_start/stop is called. The reason is clear that @@ -17,18 +17,18 @@ Reviewed-by: Gonglei 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 7f61018f..f302c506 100644 +index 437347ad01..dafb23c481 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c -@@ -26,6 +26,7 @@ - #include "hw/virtio/virtio-bus.h" +@@ -25,6 +25,7 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" + #include "migration/qemu-file-types.h" +#include "migration/migration.h" #include "sysemu/dma.h" + #include "sysemu/tcg.h" #include "trace.h" - -@@ -808,20 +809,24 @@ static int vhost_migration_log(MemoryListener *listener, int enable) +@@ -947,20 +948,24 @@ check_dev_state: static void vhost_log_global_start(MemoryListener *listener) { int r; @@ -56,5 +56,5 @@ index 7f61018f..f302c506 100644 } -- -2.19.1 +2.27.0 diff --git a/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch b/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch new file mode 100644 index 0000000000000000000000000000000000000000..51fdba4323e66287ce1408fb04885362903eb43f --- /dev/null +++ b/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch @@ -0,0 +1,453 @@ +From f0586baaa57c4042135b6d8f4d940da8a99e3737 Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Wed, 30 Nov 2022 11:24:36 +0000 +Subject: [PATCH] vhost: enable vrings in vhost_dev_start() for vhost-user + devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 02b61f38d3 ("hw/virtio: incorporate backend features in features") +properly negotiates VHOST_USER_F_PROTOCOL_FEATURES with the vhost-user +backend, but we forgot to enable vrings as specified in +docs/interop/vhost-user.rst: + + If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the + ring starts directly in the enabled state. + + If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is + initialized in a disabled state and is enabled by + ``VHOST_USER_SET_VRING_ENABLE`` with parameter 1. + +Some vhost-user front-ends already did this by calling +vhost_ops.vhost_set_vring_enable() directly: +- backends/cryptodev-vhost.c +- hw/net/virtio-net.c +- hw/virtio/vhost-user-gpio.c + +But most didn't do that, so we would leave the vrings disabled and some +backends would not work. We observed this issue with the rust version of +virtiofsd [1], which uses the event loop [2] provided by the +vhost-user-backend crate where requests are not processed if vring is +not enabled. + +Let's fix this issue by enabling the vrings in vhost_dev_start() for +vhost-user front-ends that don't already do this directly. Same thing +also in vhost_dev_stop() where we disable vrings. + +[1] https://gitlab.com/virtio-fs/virtiofsd +[2] https://github.com/rust-vmm/vhost/blob/240fc2966/crates/vhost-user-backend/src/event_loop.rs#L217 + +Fixes: 02b61f38d3 ("hw/virtio: incorporate backend features in features") +Reported-by: German Maglione +Tested-by: German Maglione +Signed-off-by: Stefano Garzarella +Acked-by: Raphael Norwitz +Message-Id: <20221123131630.52020-1-sgarzare@redhat.com> +Signed-off-by: Alex Bennée +Reviewed-by: Michael S. Tsirkin +Message-Id: <20221130112439.2527228-3-alex.bennee@linaro.org> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + backends/cryptodev-vhost.c | 4 ++-- + backends/vhost-user.c | 4 ++-- + hw/block/vhost-user-blk.c | 4 ++-- + hw/net/vhost_net.c | 6 ++--- + hw/scsi/vhost-scsi-common.c | 4 ++-- + hw/virtio/trace-events | 4 ++-- + hw/virtio/vdpa-dev.c | 4 ++-- + hw/virtio/vhost-user-fs.c | 4 ++-- + hw/virtio/vhost-user-i2c.c | 4 ++-- + hw/virtio/vhost-user-rng.c | 4 ++-- + hw/virtio/vhost-vsock-common.c | 4 ++-- + hw/virtio/vhost.c | 44 ++++++++++++++++++++++++++++++---- + include/hw/virtio/vhost.h | 9 +++++-- + 13 files changed, 69 insertions(+), 30 deletions(-) + +diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c +index bc13e466b4..572f87b3be 100644 +--- a/backends/cryptodev-vhost.c ++++ b/backends/cryptodev-vhost.c +@@ -94,7 +94,7 @@ cryptodev_vhost_start_one(CryptoDevBackendVhost *crypto, + goto fail_notifiers; + } + +- r = vhost_dev_start(&crypto->dev, dev); ++ r = vhost_dev_start(&crypto->dev, dev, false); + if (r < 0) { + goto fail_start; + } +@@ -111,7 +111,7 @@ static void + cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto, + VirtIODevice *dev) + { +- vhost_dev_stop(&crypto->dev, dev); ++ vhost_dev_stop(&crypto->dev, dev, false); + vhost_dev_disable_notifiers(&crypto->dev, dev); + } + +diff --git a/backends/vhost-user.c b/backends/vhost-user.c +index 10b39992d2..6632e2fe6f 100644 +--- a/backends/vhost-user.c ++++ b/backends/vhost-user.c +@@ -85,7 +85,7 @@ vhost_user_backend_start(VhostUserBackend *b) + } + + b->dev.acked_features = b->vdev->guest_features; +- ret = vhost_dev_start(&b->dev, b->vdev); ++ ret = vhost_dev_start(&b->dev, b->vdev, true); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; +@@ -120,7 +120,7 @@ vhost_user_backend_stop(VhostUserBackend *b) + return; + } + +- vhost_dev_stop(&b->dev, b->vdev); ++ vhost_dev_stop(&b->dev, b->vdev, true); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index 9bf18434c2..eddc5588fa 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -167,7 +167,7 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp) + goto err_guest_notifiers; + } + +- ret = vhost_dev_start(&s->dev, vdev); ++ ret = vhost_dev_start(&s->dev, vdev, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; +@@ -207,7 +207,7 @@ static void vhost_user_blk_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&s->dev, vdev); ++ vhost_dev_stop(&s->dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index f709c060b6..c950d7e2e8 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -319,7 +319,7 @@ static int vhost_net_start_one(struct vhost_net *net, + goto fail_notifiers; + } + +- r = vhost_dev_start(&net->dev, dev); ++ r = vhost_dev_start(&net->dev, dev, false); + if (r < 0) { + goto fail_start; + } +@@ -368,7 +368,7 @@ fail: + if (net->nc->info->poll) { + net->nc->info->poll(net->nc, true); + } +- vhost_dev_stop(&net->dev, dev); ++ vhost_dev_stop(&net->dev, dev, false); + fail_start: + vhost_dev_disable_notifiers(&net->dev, dev); + fail_notifiers: +@@ -389,7 +389,7 @@ static void vhost_net_stop_one(struct vhost_net *net, + if (net->nc->info->poll) { + net->nc->info->poll(net->nc, true); + } +- vhost_dev_stop(&net->dev, dev); ++ vhost_dev_stop(&net->dev, dev, false); + if (net->nc->info->stop) { + net->nc->info->stop(net->nc); + } +diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c +index 767f827e55..18ea5dcfa1 100644 +--- a/hw/scsi/vhost-scsi-common.c ++++ b/hw/scsi/vhost-scsi-common.c +@@ -68,7 +68,7 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) + goto err_guest_notifiers; + } + +- ret = vhost_dev_start(&vsc->dev, vdev); ++ ret = vhost_dev_start(&vsc->dev, vdev, true); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; +@@ -101,7 +101,7 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret = 0; + +- vhost_dev_stop(&vsc->dev, vdev); ++ vhost_dev_stop(&vsc->dev, vdev, true); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index b8a33b2a83..35d4c00e59 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -9,8 +9,8 @@ vhost_section(const char *name) "%s" + vhost_reject_section(const char *name, int d) "%s:%d" + vhost_iotlb_miss(void *dev, int step) "%p step %d" + vhost_dev_cleanup(void *dev) "%p" +-vhost_dev_start(void *dev, const char *name) "%p:%s" +-vhost_dev_stop(void *dev, const char *name) "%p:%s" ++vhost_dev_start(void *dev, const char *name, bool vrings) "%p:%s vrings:%d" ++vhost_dev_stop(void *dev, const char *name, bool vrings) "%p:%s vrings:%d" + + + # vhost-user.c +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 1840f0e450..465b08c0e3 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -242,7 +242,7 @@ static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) + + s->dev.acked_features = vdev->guest_features; + +- ret = vhost_dev_start(&s->dev, vdev); ++ ret = vhost_dev_start(&s->dev, vdev, false); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; +@@ -283,7 +283,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&s->dev, vdev); ++ vhost_dev_stop(&s->dev, vdev, false); + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 392b7d3aa1..c2739557f2 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -74,7 +74,7 @@ static void vuf_start(VirtIODevice *vdev) + } + + fs->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&fs->vhost_dev, vdev); ++ ret = vhost_dev_start(&fs->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost: %d", -ret); + goto err_guest_notifiers; +@@ -108,7 +108,7 @@ static void vuf_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&fs->vhost_dev, vdev); ++ vhost_dev_stop(&fs->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c +index d172632bb0..dcaf471115 100644 +--- a/hw/virtio/vhost-user-i2c.c ++++ b/hw/virtio/vhost-user-i2c.c +@@ -45,7 +45,7 @@ static void vu_i2c_start(VirtIODevice *vdev) + + i2c->vhost_dev.acked_features = vdev->guest_features; + +- ret = vhost_dev_start(&i2c->vhost_dev, vdev); ++ ret = vhost_dev_start(&i2c->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-i2c: %d", -ret); + goto err_guest_notifiers; +@@ -79,7 +79,7 @@ static void vu_i2c_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&i2c->vhost_dev, vdev); ++ vhost_dev_stop(&i2c->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c +index 543f3e3cef..f25b7cf624 100644 +--- a/hw/virtio/vhost-user-rng.c ++++ b/hw/virtio/vhost-user-rng.c +@@ -42,7 +42,7 @@ static void vu_rng_start(VirtIODevice *vdev) + } + + rng->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&rng->vhost_dev, vdev); ++ ret = vhost_dev_start(&rng->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-rng: %d", -ret); + goto err_guest_notifiers; +@@ -76,7 +76,7 @@ static void vu_rng_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&rng->vhost_dev, vdev); ++ vhost_dev_stop(&rng->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index cd45aaf28e..42e4db4712 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -68,7 +68,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev) + } + + vvc->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&vvc->vhost_dev, vdev); ++ ret = vhost_dev_start(&vvc->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost: %d", -ret); + goto err_guest_notifiers; +@@ -103,7 +103,7 @@ void vhost_vsock_common_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&vvc->vhost_dev, vdev); ++ vhost_dev_stop(&vvc->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 86c727d2ab..22ec9e1ef7 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1760,15 +1760,36 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + return 0; + } + ++static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable) ++{ ++ if (!hdev->vhost_ops->vhost_set_vring_enable) { ++ return 0; ++ } ++ ++ /* ++ * For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not ++ * been negotiated, the rings start directly in the enabled state, and ++ * .vhost_set_vring_enable callback will fail since ++ * VHOST_USER_SET_VRING_ENABLE is not supported. ++ */ ++ if (hdev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER && ++ !virtio_has_feature(hdev->backend_features, ++ VHOST_USER_F_PROTOCOL_FEATURES)) { ++ return 0; ++ } ++ ++ return hdev->vhost_ops->vhost_set_vring_enable(hdev, enable); ++} ++ + /* Host notifiers must be enabled at this point. */ +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + { + int i, r; + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + +- trace_vhost_dev_start(hdev, vdev->name); ++ trace_vhost_dev_start(hdev, vdev->name, vrings); + + vdev->vhost_started = true; + hdev->started = true; +@@ -1813,10 +1834,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + goto fail_log; + } + } ++ if (vrings) { ++ r = vhost_dev_set_vring_enable(hdev, true); ++ if (r) { ++ goto fail_log; ++ } ++ } + if (hdev->vhost_ops->vhost_dev_start) { + r = hdev->vhost_ops->vhost_dev_start(hdev, true); + if (r) { +- goto fail_log; ++ goto fail_start; + } + } + if (vhost_dev_has_iommu(hdev) && +@@ -1831,6 +1858,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + return 0; ++fail_start: ++ if (vrings) { ++ vhost_dev_set_vring_enable(hdev, false); ++ } + fail_log: + vhost_log_put(hdev, false); + fail_vq: +@@ -1849,18 +1880,21 @@ fail_features: + } + + /* Host notifiers must be enabled at this point. */ +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + { + int i; + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + +- trace_vhost_dev_stop(hdev, vdev->name); ++ trace_vhost_dev_stop(hdev, vdev->name, vrings); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } ++ if (vrings) { ++ vhost_dev_set_vring_enable(hdev, false); ++ } + for (i = 0; i < hdev->nvqs; ++i) { + vhost_virtqueue_stop(hdev, + vdev, +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index d7ab2579ff..662e0f4370 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -5,6 +5,9 @@ + #include "hw/virtio/virtio.h" + #include "exec/memory.h" + ++#define VHOST_F_DEVICE_IOTLB 63 ++#define VHOST_USER_F_PROTOCOL_FEATURES 30 ++ + /* Generic structures common for any vhost based device. */ + + struct vhost_inflight { +@@ -165,24 +168,26 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + * vhost_dev_start() - start the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure ++ * @vrings: true to have vrings enabled in this call + * + * Starts the vhost device. From this point VirtIO feature negotiation + * can start and the device can start processing VirtIO transactions. + * + * Return: 0 on success, < 0 on error. + */ +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + + /** + * vhost_dev_stop() - stop the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure ++ * @vrings: true to have vrings disabled in this call + * + * Stop the vhost device. After the device is stopped the notifiers + * can be disabled (@vhost_dev_disable_notifiers) and the device can + * be torn down (@vhost_dev_cleanup). + */ +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + + /** + * DOC: vhost device configuration handling +-- +2.27.0 + diff --git a/vhost-fix-null-pointer-access.patch b/vhost-fix-null-pointer-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..432e8a78babd183447b47c676fbfcc3988ae26b2 --- /dev/null +++ b/vhost-fix-null-pointer-access.patch @@ -0,0 +1,74 @@ +From e2db610c0b0cb9130ba1ce2668a57318a416fdc4 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 14:48:18 +0800 +Subject: [PATCH] vhost: fix null pointer access + +Check vhost_get/set_used_memslots function before calling it. + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 59a12735f9..7930b37499 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -58,6 +58,10 @@ bool vhost_has_free_slot(void) + struct vhost_dev *hdev; + + QLIST_FOREACH(hdev, &vhost_devices, entry) { ++ if (!hdev->vhost_ops->vhost_get_used_memslots || ++ !hdev->vhost_ops->vhost_backend_memslots_limit) { ++ continue; ++ } + if (hdev->vhost_ops->vhost_get_used_memslots() >= + hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { + return false; +@@ -748,7 +752,9 @@ static void vhost_region_add_section(struct vhost_dev *dev, + dev->tmp_sections[dev->n_tmp_sections - 1].fv = NULL; + memory_region_ref(section->mr); + } +- dev->vhost_ops->vhost_set_used_memslots(dev); ++ if (dev->vhost_ops->vhost_set_used_memslots) { ++ dev->vhost_ops->vhost_set_used_memslots(dev); ++ } + } + + /* Used for both add and nop callbacks */ +@@ -772,7 +778,9 @@ static void vhost_region_del(MemoryListener *listener, + if (!vhost_section(dev, section)) { + return; + } +- dev->vhost_ops->vhost_set_used_memslots(dev); ++ if (dev->vhost_ops->vhost_set_used_memslots) { ++ dev->vhost_ops->vhost_set_used_memslots(dev); ++ } + } + + static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +@@ -1367,6 +1375,11 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) + + static bool vhost_dev_used_memslots_is_exceeded(struct vhost_dev *hdev) + { ++ if (!hdev->vhost_ops->vhost_get_used_memslots || ++ !hdev->vhost_ops->vhost_backend_memslots_limit) { ++ goto out; ++ } ++ + if (hdev->vhost_ops->vhost_get_used_memslots() > + hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { + error_report("vhost backend memory slots limit is less" +@@ -1375,6 +1388,7 @@ static bool vhost_dev_used_memslots_is_exceeded(struct vhost_dev *hdev) + return true; + } + ++out: + used_memslots_exceeded = false; + return false; + } +-- +2.27.0 + diff --git a/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch b/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch new file mode 100644 index 0000000000000000000000000000000000000000..a21d4be091bce3daa0fca77fdb2561bca92f0ac4 --- /dev/null +++ b/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch @@ -0,0 +1,108 @@ +From fdc4e7386f7fa5f0d47d6d7b582a01854073206e Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 9 May 2023 16:48:17 +0800 +Subject: [PATCH] vhost: fix possible wrap in SVQ descriptor ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU invokes vhost_svq_add() when adding a guest's element +into SVQ. In vhost_svq_add(), it uses vhost_svq_available_slots() +to check whether QEMU can add the element into SVQ. If there is +enough space, then QEMU combines some out descriptors and some +in descriptors into one descriptor chain, and adds it into +`svq->vring.desc` by vhost_svq_vring_write_descs(). + +Yet the problem is that, `svq->shadow_avail_idx - svq->shadow_used_idx` +in vhost_svq_available_slots() returns the number of occupied elements, +or the number of descriptor chains, instead of the number of occupied +descriptors, which may cause wrapping in SVQ descriptor ring. + +Here is an example. In vhost_handle_guest_kick(), QEMU forwards +as many available buffers to device by virtqueue_pop() and +vhost_svq_add_element(). virtqueue_pop() returns a guest's element, +and then this element is added into SVQ by vhost_svq_add_element(), +a wrapper to vhost_svq_add(). If QEMU invokes virtqueue_pop() and +vhost_svq_add_element() `svq->vring.num` times, +vhost_svq_available_slots() thinks QEMU just ran out of slots and +everything should work fine. But in fact, virtqueue_pop() returns +`svq->vring.num` elements or descriptor chains, more than +`svq->vring.num` descriptors due to guest memory fragmentation, +and this causes wrapping in SVQ descriptor ring. + +This bug is valid even before marking the descriptors used. +If the guest memory is fragmented, SVQ must add chains +so it can try to add more descriptors than possible. + +This patch solves it by adding `num_free` field in +VhostShadowVirtqueue structure and updating this field +in vhost_svq_add() and vhost_svq_get_buf(), to record +the number of free descriptors. + +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") +Signed-off-by: Hawkins Jiawei +Acked-by: Eugenio Pérez +Message-Id: <20230509084817.3973-1-yin31149@gmail.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 5 ++++- + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 7d6afcb528..8d99edb196 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -66,7 +66,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) + */ + static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) + { +- return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); ++ return svq->num_free; + } + + /** +@@ -255,6 +255,7 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + return -EINVAL; + } + ++ svq->num_free -= ndescs; + svq->desc_state[qemu_head].elem = elem; + svq->desc_state[qemu_head].ndescs = ndescs; + vhost_svq_kick(svq); +@@ -426,6 +427,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; ++ svq->num_free += num; + + *len = used_elem.len; + return g_steal_pointer(&svq->desc_state[used_elem.id].elem); +@@ -636,6 +638,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->iova_tree = iova_tree; + + svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); ++ svq->num_free = svq->vring.num; + driver_size = vhost_svq_driver_area_size(svq); + device_size = vhost_svq_device_area_size(svq); + svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 926a4897b1..6efe051a70 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -107,6 +107,9 @@ typedef struct VhostShadowVirtqueue { + + /* Next head to consume from the device */ + uint16_t last_used_idx; ++ ++ /* Size of SVQ vring free descriptors */ ++ uint16_t num_free; + } VhostShadowVirtqueue; + + bool vhost_svq_valid_features(uint64_t features, Error **errp); +-- +2.27.0 + diff --git a/vhost-fix-the-fd-leak.patch b/vhost-fix-the-fd-leak.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ccc1833d9488fc8a86a301efa79fa79cae4e355 --- /dev/null +++ b/vhost-fix-the-fd-leak.patch @@ -0,0 +1,37 @@ +From 2fb147eb0189ee24a74ebf784b9a682667288d3d Mon Sep 17 00:00:00 2001 +From: Li Feng +Date: Mon, 31 Jul 2023 20:10:06 +0800 +Subject: [PATCH] vhost: fix the fd leak + +When the vhost-user reconnect to the backend, the notifer should be +cleanup. Otherwise, the fd resource will be exhausted. + +Fixes: f9a09ca3ea ("vhost: add support for configure interrupt") + +Signed-off-by: Li Feng +Reviewed-by: Raphael Norwitz +Message-Id: <20230731121018.2856310-2-fengli@smartx.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Fiona Ebner +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 490c97424b..63ddcb3e6d 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -2009,6 +2009,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + event_notifier_test_and_clear(&vdev->config_notifier); ++ event_notifier_cleanup( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + + trace_vhost_dev_stop(hdev, vdev->name, vrings); + +-- +2.27.0 + diff --git a/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch b/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch new file mode 100644 index 0000000000000000000000000000000000000000..9854a13c6a4c46a5c9f61daea7f0ee6be3ecc097 --- /dev/null +++ b/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch @@ -0,0 +1,143 @@ +From 1f8330f9b4cba6ce8d88d227aeae4849c0062cf0 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 16 Dec 2022 11:35:52 +0800 +Subject: [PATCH] vhost: fix vq dirty bitmap syncing when vIOMMU is enabled + +When vIOMMU is enabled, the vq->used_phys is actually the IOVA not +GPA. So we need to translate it to GPA before the syncing otherwise we +may hit the following crash since IOVA could be out of the scope of +the GPA log size. This could be noted when using virtio-IOMMU with +vhost using 1G memory. + +Fixes: c471ad0e9bd46 ("vhost_net: device IOTLB support") +Cc: qemu-stable@nongnu.org +Tested-by: Lei Yang +Reported-by: Yalan Zhang +Signed-off-by: Jason Wang +Message-Id: <20221216033552.77087-1-jasowang@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 84 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 64 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 8e8657fb0d..19ea9aef69 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -20,6 +20,7 @@ + #include "qemu/range.h" + #include "qemu/error-report.h" + #include "qemu/memfd.h" ++#include "qemu/log.h" + #include "standard-headers/linux/vhost_types.h" + #include "hw/virtio/virtio-bus.h" + #include "hw/virtio/virtio-access.h" +@@ -110,6 +111,24 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, + } + } + ++static bool vhost_dev_has_iommu(struct vhost_dev *dev) ++{ ++ VirtIODevice *vdev = dev->vdev; ++ ++ /* ++ * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support ++ * incremental memory mapping API via IOTLB API. For platform that ++ * does not have IOMMU, there's no need to enable this feature ++ * which may cause unnecessary IOTLB miss/update transactions. ++ */ ++ if (vdev) { ++ return virtio_bus_device_iommu_enabled(vdev) && ++ virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ } else { ++ return false; ++ } ++} ++ + static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + MemoryRegionSection *section, + hwaddr first, +@@ -141,8 +160,51 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + continue; + } + +- vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys, +- range_get_last(vq->used_phys, vq->used_size)); ++ if (vhost_dev_has_iommu(dev)) { ++ IOMMUTLBEntry iotlb; ++ hwaddr used_phys = vq->used_phys, used_size = vq->used_size; ++ hwaddr phys, s, offset; ++ ++ while (used_size) { ++ rcu_read_lock(); ++ iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as, ++ used_phys, ++ true, ++ MEMTXATTRS_UNSPECIFIED); ++ rcu_read_unlock(); ++ ++ if (!iotlb.target_as) { ++ qemu_log_mask(LOG_GUEST_ERROR, "translation " ++ "failure for used_iova %"PRIx64"\n", ++ used_phys); ++ return -EINVAL; ++ } ++ ++ offset = used_phys & iotlb.addr_mask; ++ phys = iotlb.translated_addr + offset; ++ ++ /* ++ * Distance from start of used ring until last byte of ++ * IOMMU page. ++ */ ++ s = iotlb.addr_mask - offset; ++ /* ++ * Size of used ring, or of the part of it until end ++ * of IOMMU page. To avoid zero result, do the adding ++ * outside of MIN(). ++ */ ++ s = MIN(s, used_size - 1) + 1; ++ ++ vhost_dev_sync_region(dev, section, start_addr, end_addr, phys, ++ range_get_last(phys, s)); ++ used_size -= s; ++ used_phys += s; ++ } ++ } else { ++ vhost_dev_sync_region(dev, section, start_addr, ++ end_addr, vq->used_phys, ++ range_get_last(vq->used_phys, vq->used_size)); ++ } + } + return 0; + } +@@ -310,24 +372,6 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + dev->log_size = size; + } + +-static bool vhost_dev_has_iommu(struct vhost_dev *dev) +-{ +- VirtIODevice *vdev = dev->vdev; +- +- /* +- * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support +- * incremental memory mapping API via IOTLB API. For platform that +- * does not have IOMMU, there's no need to enable this feature +- * which may cause unnecessary IOTLB miss/update transactions. +- */ +- if (vdev) { +- return virtio_bus_device_iommu_enabled(vdev) && +- virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); +- } else { +- return false; +- } +-} +- + static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, + hwaddr *plen, bool is_write) + { +-- +2.27.0 + diff --git a/vhost-implement-migration-state-notifier-for-vdpa-de.patch b/vhost-implement-migration-state-notifier-for-vdpa-de.patch new file mode 100644 index 0000000000000000000000000000000000000000..246961427a2f65208c2bd25d1b3531f226484c65 --- /dev/null +++ b/vhost-implement-migration-state-notifier-for-vdpa-de.patch @@ -0,0 +1,78 @@ +From ce5fa02db01263ef5188b3bb3a1367c806ddb7ce Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:55:53 +0800 +Subject: [PATCH] vhost: implement migration state notifier for vdpa device + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev-mig.c | 28 ++++++++++++++++++++++++++++ + include/hw/virtio/vdpa-dev.h | 1 + + 2 files changed, 29 insertions(+) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index c0bcbda7d4..a36517b147 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -344,6 +344,31 @@ static SaveVMHandlers savevm_vdpa_handlers = { + .load_setup = vdpa_load_setup, + }; + ++static void vdpa_migration_state_notifier(Notifier *notifier, void *data) ++{ ++ MigrationState *s = data; ++ VhostVdpaDevice *vdev = container_of(notifier, ++ VhostVdpaDevice, ++ migration_state); ++ struct vhost_dev *hdev = &vdev->dev; ++ int ret; ++ ++ switch (s->state) { ++ case MIGRATION_STATUS_CANCELLING: ++ case MIGRATION_STATUS_CANCELLED: ++ case MIGRATION_STATUS_FAILED: ++ ret = vhost_vdpa_set_mig_state(hdev, VDPA_DEVICE_CANCEL); ++ if (ret) { ++ error_report("Failed to set state CANCEL\n"); ++ } ++ ++ break; ++ case MIGRATION_STATUS_COMPLETED: ++ default: ++ break; ++ } ++} ++ + void vdpa_migration_register(VhostVdpaDevice *vdev) + { + vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), +@@ -351,10 +376,13 @@ void vdpa_migration_register(VhostVdpaDevice *vdev) + DEVICE(vdev)); + register_savevm_live("vdpa", -1, 1, + &savevm_vdpa_handlers, DEVICE(vdev)); ++ vdev->migration_state.notify = vdpa_migration_state_notifier; ++ add_migration_state_change_notifier(&vdev->migration_state); + } + + void vdpa_migration_unregister(VhostVdpaDevice *vdev) + { ++ remove_migration_state_change_notifier(&vdev->migration_state); + unregister_savevm(VMSTATE_IF(&vdev->parent_obj.parent_obj), "vdpa", DEVICE(vdev)); + qemu_del_vm_change_state_handler(vdev->vmstate); + } +diff --git a/include/hw/virtio/vdpa-dev.h b/include/hw/virtio/vdpa-dev.h +index 43cbcef81b..20f50c76c6 100644 +--- a/include/hw/virtio/vdpa-dev.h ++++ b/include/hw/virtio/vdpa-dev.h +@@ -39,6 +39,7 @@ struct VhostVdpaDevice { + bool started; + int (*post_init)(VhostVdpaDevice *v, Error **errp); + VMChangeStateEntry *vmstate; ++ Notifier migration_state; + }; + + #endif +-- +2.27.0 + diff --git a/vhost-implement-post-resume-bh.patch b/vhost-implement-post-resume-bh.patch new file mode 100644 index 0000000000000000000000000000000000000000..b16606d7c30046a97dddba1bd47c86bf04bfcfbd --- /dev/null +++ b/vhost-implement-post-resume-bh.patch @@ -0,0 +1,56 @@ +From 07fc3e07d6160508f7e6543e2fc49668607f79ad Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:57:35 +0800 +Subject: [PATCH] vhost: implement post resume bh + +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev-mig.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index a36517b147..ee3e27f2bb 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -33,6 +33,7 @@ + #include "qemu/error-report.h" + #include "hw/virtio/vdpa-dev-mig.h" + #include "migration/qemu-file-types.h" ++#include "qemu/main-loop.h" + + /* + * Flags used as delimiter: +@@ -225,6 +226,18 @@ err_host_notifiers: + return ret; + } + ++static void vdpa_dev_migration_handle_incoming_bh(void *opaque) ++{ ++ struct vhost_dev *hdev = opaque; ++ int ret; ++ ++ /* Post start device, unsupport rollback if failed! */ ++ ret = vhost_vdpa_set_mig_state(hdev, VDPA_DEVICE_POST_START); ++ if (ret) { ++ error_report("Failed to set state: POST_START\n"); ++ } ++} ++ + static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) + { + VhostVdpaDevice *vdpa = VHOST_VDPA_DEVICE(opaque); +@@ -254,6 +267,10 @@ static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) + + if (mis->state == RUN_STATE_RESTORE_VM) { + vhost_vdpa_call(hdev, VHOST_VDPA_RESUME, NULL); ++ /* post resume */ ++ mis->bh = qemu_bh_new(vdpa_dev_migration_handle_incoming_bh, ++ hdev); ++ qemu_bh_schedule(mis->bh); + } + } + } +-- +2.27.0 + diff --git a/vhost-implement-savevm_hanlder-for-vdpa-device.patch b/vhost-implement-savevm_hanlder-for-vdpa-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..16cacc110077ed3c5c5652dd313f953d19875de7 --- /dev/null +++ b/vhost-implement-savevm_hanlder-for-vdpa-device.patch @@ -0,0 +1,265 @@ +From 9cd596fd081bdb88b03b5e969631d8d08797c14d Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:53:28 +0800 +Subject: [PATCH] vhost: implement savevm_hanlder for vdpa device + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev-mig.c | 174 +++++++++++++++++++++++++++++++ + include/hw/virtio/vdpa-dev-mig.h | 13 +++ + linux-headers/linux/vhost.h | 8 ++ + 3 files changed, 195 insertions(+) + +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +index 64c9e245d1..c0bcbda7d4 100644 +--- a/hw/virtio/vdpa-dev-mig.c ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -32,6 +32,17 @@ + #include "sysemu/runstate.h" + #include "qemu/error-report.h" + #include "hw/virtio/vdpa-dev-mig.h" ++#include "migration/qemu-file-types.h" ++ ++/* ++ * Flags used as delimiter: ++ * 0xffffffff => MSB 32-bit all 1s ++ * 0xef10 => emulated (virtual) function IO ++ * 0x0000 => 16-bits reserved for flags ++ */ ++#define VDPA_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL) ++#define VDPA_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL) ++#define VDPA_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) + + static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, + void *arg) +@@ -47,6 +58,80 @@ static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, + return ioctl(fd, request, arg); + } + ++static int vhost_vdpa_set_mig_state(struct vhost_dev *dev, uint8_t state) ++{ ++ return vhost_vdpa_call(dev, VHOST_VDPA_SET_MIG_STATE, &state); ++} ++ ++static int vhost_vdpa_dev_buffer_size(struct vhost_dev *dev, uint32_t *size) ++{ ++ return vhost_vdpa_call(dev, VHOST_GET_DEV_BUFFER_SIZE, size); ++} ++ ++static int vhost_vdpa_dev_buffer_save(struct vhost_dev *dev, QEMUFile *f) ++{ ++ struct vhost_vdpa_config *config; ++ unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); ++ uint32_t buffer_size = 0; ++ int ret; ++ ++ ret = vhost_vdpa_dev_buffer_size(dev, &buffer_size); ++ if (ret) { ++ error_report("get dev buffer size failed: %d\n", ret); ++ return ret; ++ } ++ ++ qemu_put_be32(f, buffer_size); ++ ++ config = g_malloc(buffer_size + config_size); ++ config->off = 0; ++ config->len = buffer_size; ++ ++ ret = vhost_vdpa_call(dev, VHOST_GET_DEV_BUFFER, config); ++ if (ret) { ++ error_report("get dev buffer failed: %d\n", ret); ++ goto free; ++ } ++ ++ qemu_put_buffer(f, config->buf, buffer_size); ++free: ++ g_free(config); ++ ++ return ret; ++} ++ ++static int vhost_vdpa_dev_buffer_load(struct vhost_dev *dev, QEMUFile *f) ++{ ++ struct vhost_vdpa_config *config; ++ unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); ++ uint32_t buffer_size, recv_size; ++ int ret; ++ ++ buffer_size = qemu_get_be32(f); ++ ++ config = g_malloc(buffer_size + config_size); ++ config->off = 0; ++ config->len = buffer_size; ++ ++ recv_size = qemu_get_buffer(f, config->buf, buffer_size); ++ if (recv_size != buffer_size) { ++ error_report("read dev mig buffer failed, buffer_size: %u, " ++ "recv_size: %u\n", buffer_size, recv_size); ++ ret = -EINVAL; ++ goto free; ++ } ++ ++ ret = vhost_vdpa_call(dev, VHOST_SET_DEV_BUFFER, config); ++ if (ret) { ++ error_report("set dev buffer failed: %d\n", ret); ++ } ++ ++free: ++ g_free(config); ++ ++ return ret; ++} ++ + static int vhost_vdpa_device_suspend(VhostVdpaDevice *vdpa) + { + VirtIODevice *vdev = VIRTIO_DEVICE(vdpa); +@@ -173,14 +258,103 @@ static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) + } + } + ++static int vdpa_save_setup(QEMUFile *f, void *opaque) ++{ ++ qemu_put_be64(f, VDPA_MIG_FLAG_DEV_SETUP_STATE); ++ qemu_put_be64(f, VDPA_MIG_FLAG_END_OF_STATE); ++ ++ return qemu_file_get_error(f); ++} ++ ++static int vdpa_save_complete_precopy(QEMUFile *f, void *opaque) ++{ ++ VhostVdpaDevice *vdev = VHOST_VDPA_DEVICE(opaque); ++ struct vhost_dev *hdev = &vdev->dev; ++ int ret; ++ ++ qemu_put_be64(f, VDPA_MIG_FLAG_DEV_CONFIG_STATE); ++ ret = vhost_vdpa_dev_buffer_save(hdev, f); ++ if (ret) { ++ error_report("Save vdpa device buffer failed: %d\n", ret); ++ return ret; ++ } ++ qemu_put_be64(f, VDPA_MIG_FLAG_END_OF_STATE); ++ ++ return qemu_file_get_error(f); ++} ++ ++static int vdpa_load_state(QEMUFile *f, void *opaque, int version_id) ++{ ++ VhostVdpaDevice *vdev = VHOST_VDPA_DEVICE(opaque); ++ struct vhost_dev *hdev = &vdev->dev; ++ ++ int ret; ++ uint64_t data; ++ ++ data = qemu_get_be64(f); ++ while (data != VDPA_MIG_FLAG_END_OF_STATE) { ++ if (data == VDPA_MIG_FLAG_DEV_SETUP_STATE) { ++ data = qemu_get_be64(f); ++ if (data == VDPA_MIG_FLAG_END_OF_STATE) { ++ return 0; ++ } else { ++ error_report("SETUP STATE: EOS not found 0x%lx\n", data); ++ return -EINVAL; ++ } ++ } else if (data == VDPA_MIG_FLAG_DEV_CONFIG_STATE) { ++ ret = vhost_vdpa_dev_buffer_load(hdev, f); ++ if (ret) { ++ error_report("fail to restore device buffer.\n"); ++ return ret; ++ } ++ } ++ ++ ret = qemu_file_get_error(f); ++ if (ret) { ++ error_report("qemu file error: %d\n", ret); ++ return ret; ++ } ++ data = qemu_get_be64(f); ++ } ++ ++ return 0; ++} ++ ++static int vdpa_load_setup(QEMUFile *f, void *opaque) ++{ ++ VhostVdpaDevice *v = VHOST_VDPA_DEVICE(opaque); ++ struct vhost_dev *hdev = &v->dev; ++ int ret = 0; ++ ++ ret = vhost_vdpa_set_mig_state(hdev, VDPA_DEVICE_PRE_START); ++ if (ret) { ++ error_report("pre start device failed: %d\n", ret); ++ goto out; ++ } ++ ++ return qemu_file_get_error(f); ++out: ++ return ret; ++} ++ ++static SaveVMHandlers savevm_vdpa_handlers = { ++ .save_setup = vdpa_save_setup, ++ .save_live_complete_precopy = vdpa_save_complete_precopy, ++ .load_state = vdpa_load_state, ++ .load_setup = vdpa_load_setup, ++}; ++ + void vdpa_migration_register(VhostVdpaDevice *vdev) + { + vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), + vdpa_dev_vmstate_change, + DEVICE(vdev)); ++ register_savevm_live("vdpa", -1, 1, ++ &savevm_vdpa_handlers, DEVICE(vdev)); + } + + void vdpa_migration_unregister(VhostVdpaDevice *vdev) + { ++ unregister_savevm(VMSTATE_IF(&vdev->parent_obj.parent_obj), "vdpa", DEVICE(vdev)); + qemu_del_vm_change_state_handler(vdev->vmstate); + } +diff --git a/include/hw/virtio/vdpa-dev-mig.h b/include/hw/virtio/vdpa-dev-mig.h +index 89665ca747..adc1d657f7 100644 +--- a/include/hw/virtio/vdpa-dev-mig.h ++++ b/include/hw/virtio/vdpa-dev-mig.h +@@ -9,6 +9,19 @@ + + #include "hw/virtio/vdpa-dev.h" + ++enum { ++ VDPA_DEVICE_START, ++ VDPA_DEVICE_STOP, ++ VDPA_DEVICE_PRE_START, ++ VDPA_DEVICE_PRE_STOP, ++ VDPA_DEVICE_CANCEL, ++ VDPA_DEVICE_POST_START, ++ VDPA_DEVICE_START_ASYNC, ++ VDPA_DEVICE_STOP_ASYNC, ++ VDPA_DEVICE_PRE_START_ASYNC, ++ VDPA_DEVICE_QUERY_OP_STATE, ++}; ++ + void vdpa_migration_register(VhostVdpaDevice *vdev); + + void vdpa_migration_unregister(VhostVdpaDevice *vdev); +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index 9b3f71b20f..457923974c 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -192,4 +192,12 @@ + */ + #define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) + ++/* set and get device buffer */ ++#define VHOST_GET_DEV_BUFFER _IOR(VHOST_VIRTIO, 0xb0, struct vhost_vdpa_config) ++#define VHOST_SET_DEV_BUFFER _IOW(VHOST_VIRTIO, 0xb1, struct vhost_vdpa_config) ++#define VHOST_GET_DEV_BUFFER_SIZE _IOR(VHOST_VIRTIO, 0xb3, __u32) ++ ++/* set device migtration state */ ++#define VHOST_VDPA_SET_MIG_STATE _IOW(VHOST_VIRTIO, 0xb2, __u8) ++ + #endif +-- +2.27.0 + diff --git a/vhost-implement-vhost-vdpa-suspend-resume.patch b/vhost-implement-vhost-vdpa-suspend-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a499e6cee0c8aae98d989aa1cff4ef88cafd6b9 --- /dev/null +++ b/vhost-implement-vhost-vdpa-suspend-resume.patch @@ -0,0 +1,85 @@ +From 98c74a827b742807f979fc36bca99ba0db38d295 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:22:20 +0800 +Subject: [PATCH] vhost: implement vhost-vdpa suspend/resume + +vhost-vdpa implements the vhost_dev_suspend interface, +which will be called during the shutdown phase of the +live migration source virtual machine to suspend the +device but not reset the device information. + +vhost-vdpa implements the vhost_dev_resume interface. +If the live migration fails, it will be called during +the startup phase of the source virtual machine. +Enable the device but set the status, etc. + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 44 ++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 42 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 7663d78b43..7688dc0eba 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1318,6 +1318,43 @@ static unsigned int vhost_vdpa_get_used_memslots(void) + return vhost_vdpa_used_memslots; + } + ++static int vhost_vdpa_suspend_device(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ int ret; ++ ++ vhost_vdpa_svqs_stop(dev); ++ vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); ++ ++ if (dev->vq_index + dev->nvqs != dev->vq_index_end) { ++ return 0; ++ } ++ ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_SUSPEND, NULL); ++ memory_listener_unregister(&v->listener); ++ return ret; ++} ++ ++static int vhost_vdpa_resume_device(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ bool ok; ++ ++ vhost_vdpa_host_notifiers_init(dev); ++ ok = vhost_vdpa_svqs_start(dev); ++ if (unlikely(!ok)) { ++ return -1; ++ } ++ vhost_vdpa_set_vring_ready(dev); ++ ++ if (dev->vq_index + dev->nvqs != dev->vq_index_end) { ++ return 0; ++ } ++ ++ memory_listener_register(&v->listener, &address_space_memory); ++ return vhost_vdpa_call(dev, VHOST_VDPA_RESUME, NULL); ++} ++ + static int vhost_vdpa_log_sync(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; +@@ -1364,6 +1401,9 @@ const VhostOps vdpa_ops = { + .vhost_force_iommu = vhost_vdpa_force_iommu, + .vhost_log_sync = vhost_vdpa_log_sync, + .vhost_set_config_call = vhost_vdpa_set_config_call, +- .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, +- .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, ++ .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, ++ .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, ++ .vhost_dev_suspend = vhost_vdpa_suspend_device, ++ .vhost_dev_resume = vhost_vdpa_resume_device, ++ + }; +-- +2.27.0 + diff --git a/vhost-implement-vhost_vdpa_device_suspend-resume.patch b/vhost-implement-vhost_vdpa_device_suspend-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..9345bd282e10ec6383af29d23e4a78807e86fcd4 --- /dev/null +++ b/vhost-implement-vhost_vdpa_device_suspend-resume.patch @@ -0,0 +1,453 @@ +From a21603f7ecfaa2fb53b2037f46ee3fb868d8c9cb Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:27:34 +0800 +Subject: [PATCH] vhost: implement vhost_vdpa_device_suspend/resume + +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 2 +- + hw/virtio/vdpa-dev-mig.c | 186 +++++++++++++++++++++++++++++++ + hw/virtio/vhost.c | 138 +++++++++++++++++++++++ + include/hw/virtio/vdpa-dev-mig.h | 16 +++ + include/hw/virtio/vdpa-dev.h | 1 + + include/hw/virtio/vhost.h | 4 + + migration/migration.c | 3 +- + migration/migration.h | 2 + + 8 files changed, 349 insertions(+), 3 deletions(-) + create mode 100644 hw/virtio/vdpa-dev-mig.c + create mode 100644 include/hw/virtio/vdpa-dev-mig.h + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index c2da69616f..94a030f329 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -29,7 +29,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) + virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) + virtio_ss.add(when: ['CONFIG_VHOST_USER_RNG', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-rng-pci.c')) +-virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) ++virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c', 'vdpa-dev-mig.c')) + + virtio_pci_ss = ss.source_set() + virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) +diff --git a/hw/virtio/vdpa-dev-mig.c b/hw/virtio/vdpa-dev-mig.c +new file mode 100644 +index 0000000000..64c9e245d1 +--- /dev/null ++++ b/hw/virtio/vdpa-dev-mig.c +@@ -0,0 +1,186 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ */ ++ ++#include ++#include ++#include "qemu/osdep.h" ++#include "migration/misc.h" ++#include "hw/qdev-core.h" ++#include "hw/qdev-properties.h" ++#include "hw/virtio/vhost.h" ++#include "hw/virtio/vdpa-dev.h" ++#include "hw/virtio/virtio.h" ++#include "hw/virtio/virtio-bus.h" ++#include "hw/virtio/virtio-access.h" ++#include "migration/register.h" ++#include "migration/migration.h" ++#include "qemu-common.h" ++#include "sysemu/runstate.h" ++#include "qemu/error-report.h" ++#include "hw/virtio/vdpa-dev-mig.h" ++ ++static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, ++ void *arg) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ int fd = v->device_fd; ++ ++ if (dev->vhost_ops->backend_type != VHOST_BACKEND_TYPE_VDPA) { ++ error_report("backend type isn't VDPA. Operation not permitted!\n"); ++ return -EPERM; ++ } ++ ++ return ioctl(fd, request, arg); ++} ++ ++static int vhost_vdpa_device_suspend(VhostVdpaDevice *vdpa) ++{ ++ VirtIODevice *vdev = VIRTIO_DEVICE(vdpa); ++ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); ++ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); ++ int ret; ++ ++ if (!vdpa->started) { ++ return -EFAULT; ++ } ++ ++ if (!k->set_guest_notifiers) { ++ return -EFAULT; ++ } ++ ++ vdpa->started = false; ++ ++ ret = vhost_dev_suspend(&vdpa->dev, vdev, false); ++ if (ret) { ++ goto suspend_fail; ++ } ++ ++ ret = k->set_guest_notifiers(qbus->parent, vdpa->dev.nvqs, false); ++ if (ret < 0) { ++ error_report("vhost guest notifier cleanup failed: %d\n", ret); ++ goto set_guest_notifiers_fail; ++ } ++ ++ vhost_dev_disable_notifiers(&vdpa->dev, vdev); ++ return ret; ++ ++set_guest_notifiers_fail: ++ ret = k->set_guest_notifiers(qbus->parent, vdpa->dev.nvqs, true); ++ if (ret) { ++ error_report("vhost guest notifier restore failed: %d\n", ret); ++ } ++ ++suspend_fail: ++ vdpa->started = true; ++ return ret; ++} ++ ++static int vhost_vdpa_device_resume(VhostVdpaDevice *vdpa) ++{ ++ VirtIODevice *vdev = VIRTIO_DEVICE(vdpa); ++ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); ++ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); ++ int i, ret; ++ ++ if (!k->set_guest_notifiers) { ++ error_report("binding does not support guest notifiers\n"); ++ return -ENOSYS; ++ } ++ ++ ret = vhost_dev_enable_notifiers(&vdpa->dev, vdev); ++ if (ret < 0) { ++ error_report("Error enabling host notifiers: %d\n", ret); ++ return ret; ++ } ++ ++ ret = k->set_guest_notifiers(qbus->parent, vdpa->dev.nvqs, true); ++ if (ret < 0) { ++ error_report("Error binding guest notifier: %d\n", ret); ++ goto err_host_notifiers; ++ } ++ ++ vdpa->dev.acked_features = vdev->guest_features; ++ ++ ret = vhost_dev_resume(&vdpa->dev, vdev, false); ++ if (ret < 0) { ++ error_report("Error starting vhost: %d\n", ret); ++ goto err_guest_notifiers; ++ } ++ vdpa->started = true; ++ ++ /* ++ * guest_notifier_mask/pending not used yet, so just unmask ++ * everything here. virtio-pci will do the right thing by ++ * enabling/disabling irqfd. ++ */ ++ for (i = 0; i < vdpa->dev.nvqs; i++) { ++ vhost_virtqueue_mask(&vdpa->dev, vdev, i, false); ++ } ++ ++ return ret; ++ ++err_guest_notifiers: ++ k->set_guest_notifiers(qbus->parent, vdpa->dev.nvqs, false); ++err_host_notifiers: ++ vhost_dev_disable_notifiers(&vdpa->dev, vdev); ++ return ret; ++} ++ ++static void vdpa_dev_vmstate_change(void *opaque, bool running, RunState state) ++{ ++ VhostVdpaDevice *vdpa = VHOST_VDPA_DEVICE(opaque); ++ struct vhost_dev *hdev = &vdpa->dev; ++ int ret; ++ MigrationState *ms = migrate_get_current(); ++ MigrationIncomingState *mis = migration_incoming_get_current(); ++ ++ if (!running) { ++ if (ms->state == RUN_STATE_PAUSED) { ++ ret = vhost_vdpa_device_suspend(vdpa); ++ if (ret) { ++ error_report("suspend vdpa device failed: %d\n", ret); ++ if (ms->migration_thread_running) { ++ migrate_fd_cancel(ms); ++ } ++ } ++ } ++ } else { ++ if (ms->state == RUN_STATE_RESTORE_VM) { ++ ret = vhost_vdpa_device_resume(vdpa); ++ if (ret) { ++ error_report("migration dest resume device failed, abort!\n"); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ if (mis->state == RUN_STATE_RESTORE_VM) { ++ vhost_vdpa_call(hdev, VHOST_VDPA_RESUME, NULL); ++ } ++ } ++} ++ ++void vdpa_migration_register(VhostVdpaDevice *vdev) ++{ ++ vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), ++ vdpa_dev_vmstate_change, ++ DEVICE(vdev)); ++} ++ ++void vdpa_migration_unregister(VhostVdpaDevice *vdev) ++{ ++ qemu_del_vm_change_state_handler(vdev->vmstate); ++} +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index d2b9278474..ed1506d3e0 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -2201,3 +2201,141 @@ bool used_memslots_is_exceeded(void) + { + return used_memslots_exceeded; + } ++ ++int vhost_dev_resume(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) ++{ ++ int i, r; ++ EventNotifier *e = &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ ++ /* should only be called after backend is connected */ ++ if (!hdev->vhost_ops) { ++ error_report("Missing vhost_ops! Operation not permitted!\n"); ++ return -EPERM; ++ } ++ ++ vdev->vhost_started = true; ++ hdev->started = true; ++ hdev->vdev = vdev; ++ ++ if (vhost_dev_has_iommu(hdev)) { ++ memory_listener_register(&hdev->iommu_listener, vdev->dma_as); ++ } ++ ++ r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); ++ if (r < 0) { ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); ++ goto fail_mem; ++ } ++ for (i = 0; i < hdev->nvqs; ++i) { ++ r = vhost_virtqueue_start(hdev, ++ vdev, ++ hdev->vqs + i, ++ hdev->vq_index + i); ++ if (r < 0) { ++ goto fail_vq; ++ } ++ } ++ ++ r = event_notifier_init(e, 0); ++ if (r < 0) { ++ return r; ++ } ++ event_notifier_test_and_clear(e); ++ if (!vdev->use_guest_notifier_mask) { ++ vhost_config_mask(hdev, vdev, true); ++ } ++ if (vrings) { ++ r = vhost_dev_set_vring_enable(hdev, true); ++ if (r) { ++ goto fail_vq; ++ } ++ } ++ if (hdev->vhost_ops->vhost_dev_resume) { ++ r = hdev->vhost_ops->vhost_dev_resume(hdev); ++ if (r) { ++ goto fail_start; ++ } ++ } ++ if (vhost_dev_has_iommu(hdev)) { ++ hdev->vhost_ops->vhost_set_iotlb_callback(hdev, true); ++ ++ /* ++ * Update used ring information for IOTLB to work correctly, ++ * vhost-kernel code requires for this. ++ */ ++ for (i = 0; i < hdev->nvqs; ++i) { ++ struct vhost_virtqueue *vq = hdev->vqs + i; ++ vhost_device_iotlb_miss(hdev, vq->used_phys, true); ++ } ++ } ++ vhost_start_config_intr(hdev); ++ return 0; ++fail_start: ++ if (vrings) { ++ vhost_dev_set_vring_enable(hdev, false); ++ } ++fail_vq: ++ while (--i >= 0) { ++ vhost_virtqueue_stop(hdev, ++ vdev, ++ hdev->vqs + i, ++ hdev->vq_index + i); ++ } ++ ++fail_mem: ++ vdev->vhost_started = false; ++ hdev->started = false; ++ return r; ++} ++ ++int vhost_dev_suspend(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) ++{ ++ int i; ++ int ret = 0; ++ EventNotifier *e = &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ ++ /* should only be called after backend is connected */ ++ if (!hdev->vhost_ops) { ++ error_report("Missing vhost_ops! Operation not permitted!\n"); ++ return -EPERM; ++ } ++ ++ event_notifier_test_and_clear(e); ++ event_notifier_test_and_clear(&vdev->config_notifier); ++ ++ if (hdev->vhost_ops->vhost_dev_suspend) { ++ ret = hdev->vhost_ops->vhost_dev_suspend(hdev); ++ if (ret) { ++ goto fail_suspend; ++ } ++ } ++ if (vrings) { ++ ret = vhost_dev_set_vring_enable(hdev, false); ++ if (ret) { ++ goto fail_suspend; ++ } ++ } ++ for (i = 0; i < hdev->nvqs; ++i) { ++ vhost_virtqueue_stop(hdev, ++ vdev, ++ hdev->vqs + i, ++ hdev->vq_index + i); ++ } ++ ++ if (vhost_dev_has_iommu(hdev)) { ++ hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false); ++ memory_listener_unregister(&hdev->iommu_listener); ++ } ++ vhost_stop_config_intr(hdev); ++ vhost_log_put(hdev, true); ++ hdev->started = false; ++ vdev->vhost_started = false; ++ hdev->vdev = NULL; ++ ++ return ret; ++ ++fail_suspend: ++ event_notifier_test_and_clear(e); ++ ++ return ret; ++} +diff --git a/include/hw/virtio/vdpa-dev-mig.h b/include/hw/virtio/vdpa-dev-mig.h +new file mode 100644 +index 0000000000..89665ca747 +--- /dev/null ++++ b/include/hw/virtio/vdpa-dev-mig.h +@@ -0,0 +1,16 @@ ++/* ++ * Vhost Vdpa Device Migration Header ++ * ++ * Copyright (c) Huawei Technologies Co., Ltd. 2023. All Rights Reserved. ++ */ ++ ++#ifndef _VHOST_VDPA_MIGRATION_H ++#define _VHOST_VDPA_MIGRATION_H ++ ++#include "hw/virtio/vdpa-dev.h" ++ ++void vdpa_migration_register(VhostVdpaDevice *vdev); ++ ++void vdpa_migration_unregister(VhostVdpaDevice *vdev); ++ ++#endif /* _VHOST_VDPA_MIGRATION_H */ +diff --git a/include/hw/virtio/vdpa-dev.h b/include/hw/virtio/vdpa-dev.h +index 4dbf98195c..43cbcef81b 100644 +--- a/include/hw/virtio/vdpa-dev.h ++++ b/include/hw/virtio/vdpa-dev.h +@@ -38,6 +38,7 @@ struct VhostVdpaDevice { + uint16_t queue_size; + bool started; + int (*post_init)(VhostVdpaDevice *v, Error **errp); ++ VMChangeStateEntry *vmstate; + }; + + #endif +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 0491fe1ed7..9441b4c50e 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -277,4 +277,8 @@ int vhost_dev_set_inflight(struct vhost_dev *dev, + int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + struct vhost_inflight *inflight); + bool used_memslots_is_exceeded(void); ++ ++int vhost_dev_resume(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); ++int vhost_dev_suspend(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); ++ + #endif +diff --git a/migration/migration.c b/migration/migration.c +index 2ec116f901..40e743b4e9 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -178,7 +178,6 @@ static bool migration_object_check(MigrationState *ms, Error **errp); + static int migration_maybe_pause(MigrationState *s, + int *current_active_state, + int new_state); +-static void migrate_fd_cancel(MigrationState *s); + + static gint page_request_addr_cmp(gconstpointer ap, gconstpointer bp) + { +@@ -1914,7 +1913,7 @@ void migrate_fd_error(MigrationState *s, const Error *error) + migrate_set_error(s, error); + } + +-static void migrate_fd_cancel(MigrationState *s) ++void migrate_fd_cancel(MigrationState *s) + { + int old_state ; + QEMUFile *f = migrate_get_current()->to_dst_file; +diff --git a/migration/migration.h b/migration/migration.h +index 4ed4f555da..a87fd54d10 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -393,4 +393,6 @@ void migration_cancel(const Error *error); + + void populate_vfio_info(MigrationInfo *info); + ++void migrate_fd_cancel(MigrationState *s); ++ + #endif +-- +2.27.0 + diff --git a/vhost-introduce-bytemap-for-vhost-backend-logging.patch b/vhost-introduce-bytemap-for-vhost-backend-logging.patch new file mode 100644 index 0000000000000000000000000000000000000000..afa3d4d1adef19e67d80318cdf628773cb0ea66d --- /dev/null +++ b/vhost-introduce-bytemap-for-vhost-backend-logging.patch @@ -0,0 +1,271 @@ +From e2f1953ad26a61e59f1d45892c6937d7454e65b5 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:09:26 +0800 +Subject: [PATCH] vhost: introduce bytemap for vhost backend logging + +As vhost backend may use bytemap for logging, when get log_size +of vhost device, check whether vhost device support VHOST_BACKEND_F_BYTEMAPLOG. +If vhost device support, use bytemap for logging. + +By the way, add log_resize func pointer check and vhost_log_sync return +value check. + +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 144 ++++++++++++++++++++++++++++++++++++-- + include/hw/virtio/vhost.h | 1 + + 2 files changed, 139 insertions(+), 6 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 7930b37499..d2b9278474 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -19,9 +19,11 @@ + #include "qemu/atomic.h" + #include "qemu/range.h" + #include "qemu/error-report.h" ++#include "cpu.h" + #include "qemu/memfd.h" + #include "qemu/log.h" + #include "standard-headers/linux/vhost_types.h" ++#include "exec/ram_addr.h" + #include "hw/virtio/virtio-bus.h" + #include "hw/virtio/virtio-access.h" + #include "migration/blocker.h" +@@ -30,6 +32,7 @@ + #include "sysemu/dma.h" + #include "sysemu/tcg.h" + #include "trace.h" ++#include "qapi/qapi-commands-migration.h" + + /* enabled until disconnected backend stabilizes */ + #define _VHOST_DEBUG 1 +@@ -45,6 +48,11 @@ + do { } while (0) + #endif + ++static inline bool vhost_bytemap_log_support(struct vhost_dev *dev) ++{ ++ return (dev->backend_cap & BIT_ULL(VHOST_BACKEND_F_BYTEMAPLOG)); ++} ++ + static struct vhost_log *vhost_log; + static struct vhost_log *vhost_log_shm; + +@@ -213,12 +221,93 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + return 0; + } + ++#define BYTES_PER_LONG (sizeof(unsigned long)) ++#define BYTE_WORD(nr) ((nr) / BYTES_PER_LONG) ++#define BYTES_TO_LONGS(nr) DIV_ROUND_UP(nr, BYTES_PER_LONG) ++ ++static inline int64_t _set_dirty_bytemap_atomic(unsigned long *bytemap, unsigned long cur_pfn) ++{ ++ char *byte_of_long = (char *)bytemap; ++ int i; ++ int64_t dirty_num = 0; ++ ++ for (i = 0; i < BYTES_PER_LONG; i++) { ++ if (byte_of_long[i]) { ++ cpu_physical_memory_set_dirty_range((cur_pfn + i) << TARGET_PAGE_BITS, ++ TARGET_PAGE_SIZE, ++ 1 << DIRTY_MEMORY_MIGRATION); ++ /* Per byte ops, no need to atomic_xchg */ ++ byte_of_long[i] = 0; ++ dirty_num++; ++ } ++ } ++ ++ return dirty_num; ++} ++ ++static inline int64_t cpu_physical_memory_set_dirty_bytemap(unsigned long *bytemap, ++ ram_addr_t start, ++ ram_addr_t pages) ++{ ++ unsigned long i; ++ unsigned long len = BYTES_TO_LONGS(pages); ++ unsigned long pfn = (start >> TARGET_PAGE_BITS) / ++ BYTES_PER_LONG * BYTES_PER_LONG; ++ int64_t dirty_mig_bits = 0; ++ ++ for (i = 0; i < len; i++) { ++ if (bytemap[i]) { ++ dirty_mig_bits += _set_dirty_bytemap_atomic(&bytemap[i], ++ pfn + BYTES_PER_LONG * i); ++ } ++ } ++ ++ return dirty_mig_bits; ++} ++ ++static int vhost_sync_dirty_bytemap(struct vhost_dev *dev, ++ MemoryRegionSection *section) ++{ ++ struct vhost_log *log = dev->log; ++ ++ ram_addr_t start = section->offset_within_region + ++ memory_region_get_ram_addr(section->mr); ++ ram_addr_t pages = int128_get64(section->size) >> TARGET_PAGE_BITS; ++ ++ hwaddr idx = BYTE_WORD( ++ section->offset_within_address_space >> TARGET_PAGE_BITS); ++ ++ return cpu_physical_memory_set_dirty_bytemap((unsigned long *)log->log + idx, ++ start, pages); ++} ++ + static void vhost_log_sync(MemoryListener *listener, + MemoryRegionSection *section) + { + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); +- vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL); ++ MigrationState *ms = migrate_get_current(); ++ ++ if (!dev->log_enabled || !dev->started) { ++ return; ++ } ++ ++ if (dev->vhost_ops->vhost_log_sync) { ++ int r = dev->vhost_ops->vhost_log_sync(dev); ++ if (r < 0) { ++ error_report("Failed to sync dirty log: 0x%x\n", r); ++ if (migration_is_running(ms->state)) { ++ qmp_migrate_cancel(NULL); ++ } ++ return; ++ } ++ } ++ ++ if (vhost_bytemap_log_support(dev)) { ++ vhost_sync_dirty_bytemap(dev, section); ++ } else { ++ vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL); ++ } + } + + static void vhost_log_sync_range(struct vhost_dev *dev, +@@ -228,7 +317,11 @@ static void vhost_log_sync_range(struct vhost_dev *dev, + /* FIXME: this is N^2 in number of sections */ + for (i = 0; i < dev->n_mem_sections; ++i) { + MemoryRegionSection *section = &dev->mem_sections[i]; +- vhost_sync_dirty_bitmap(dev, section, first, last); ++ if (vhost_bytemap_log_support(dev)) { ++ vhost_sync_dirty_bytemap(dev, section); ++ } else { ++ vhost_sync_dirty_bitmap(dev, section, first, last); ++ } + } + } + +@@ -236,11 +329,19 @@ static uint64_t vhost_get_log_size(struct vhost_dev *dev) + { + uint64_t log_size = 0; + int i; ++ uint64_t vhost_log_chunk_size; ++ ++ if (vhost_bytemap_log_support(dev)) { ++ vhost_log_chunk_size = VHOST_LOG_CHUNK_BYTES; ++ } else { ++ vhost_log_chunk_size = VHOST_LOG_CHUNK; ++ } ++ + for (i = 0; i < dev->mem->nregions; ++i) { + struct vhost_memory_region *reg = dev->mem->regions + i; + uint64_t last = range_get_last(reg->guest_phys_addr, + reg->memory_size); +- log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1); ++ log_size = MAX(log_size, last / vhost_log_chunk_size + 1); + } + return log_size; + } +@@ -358,12 +459,21 @@ static bool vhost_dev_log_is_shared(struct vhost_dev *dev) + dev->vhost_ops->vhost_requires_shm_log(dev); + } + +-static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) ++static inline int vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + { + struct vhost_log *log = vhost_log_get(size, vhost_dev_log_is_shared(dev)); +- uint64_t log_base = (uintptr_t)log->log; ++ uint64_t log_base; ++ int log_fd; + int r; + ++ if (!log) { ++ r = -ENOMEM; ++ goto out; ++ } ++ ++ log_base = (uint64_t)log->log; ++ log_fd = log_fd; ++ + /* inform backend of log switching, this must be done before + releasing the current log, to ensure no logging is lost */ + r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); +@@ -371,9 +481,19 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + } + ++ if (dev->vhost_ops->vhost_set_log_size) { ++ r = dev->vhost_ops->vhost_set_log_size(dev, size, dev->log); ++ if (r < 0) { ++ VHOST_OPS_DEBUG(r, "vhost_set_log_size failed"); ++ } ++ } ++ + vhost_log_put(dev, true); + dev->log = log; + dev->log_size = size; ++ ++out: ++ return r; + } + + static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, +@@ -990,7 +1110,11 @@ static int vhost_migration_log(MemoryListener *listener, bool enable) + } + vhost_log_put(dev, false); + } else { +- vhost_dev_log_resize(dev, vhost_get_log_size(dev)); ++ r = vhost_dev_log_resize(dev, vhost_get_log_size(dev)); ++ if ( r < 0 ) { ++ return r; ++ } ++ + r = vhost_dev_set_log(dev, true); + if (r < 0) { + goto check_dev_state; +@@ -1967,6 +2091,14 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + goto fail_log; + } ++ ++ if (hdev->vhost_ops->vhost_set_log_size) { ++ r = hdev->vhost_ops->vhost_set_log_size(hdev, hdev->log_size, hdev->log); ++ if (r < 0) { ++ VHOST_OPS_DEBUG(r, "vhost_set_log_size failed"); ++ goto fail_log; ++ } ++ } + } + if (vrings) { + r = vhost_dev_set_vring_enable(hdev, true); +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 420f93e5cd..0491fe1ed7 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -40,6 +40,7 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_PAGE 0x1000 + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) ++#define VHOST_LOG_CHUNK_BYTES (VHOST_LOG_PAGE * sizeof(vhost_log_chunk_t)) + #define VHOST_INVALID_FEATURE_BIT (0xff) + #define VHOST_QUEUE_NUM_CONFIG_INR 0 + +-- +2.27.0 + diff --git a/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch b/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1e7a94074bf8f60bba3e83339e8f541d495f74a --- /dev/null +++ b/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch @@ -0,0 +1,42 @@ +From 0e8cd86ad1cc2c67fb3bd31493b534d740c9ac28 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:45 +0800 +Subject: [PATCH] vhost: introduce new VhostOps vhost_set_config_call + +This patch introduces new VhostOps vhost_set_config_call. +This function allows the qemu to set the config +event fd to kernel driver. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-5-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + include/hw/virtio/vhost-backend.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index a64708f456..bd1c7dfe4f 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,6 +125,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); ++typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, ++ int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -173,6 +175,7 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; ++ vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/vhost-introduce-new-VhostOps-vhost_set_config_call.patch b/vhost-introduce-new-VhostOps-vhost_set_config_call.patch new file mode 100644 index 0000000000000000000000000000000000000000..92b4c263fa9d297c411fae0f2ddfb1569ba141b1 --- /dev/null +++ b/vhost-introduce-new-VhostOps-vhost_set_config_call.patch @@ -0,0 +1,41 @@ +From af8377d0e9437401ad30d80a27ab1fcf8252fad1 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:57 +0800 +Subject: [PATCH] vhost: introduce new VhostOps vhost_set_config_call + +This patch introduces new VhostOps vhost_set_config_call. This function allows the +vhost to set the event fd to kernel + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-5-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + include/hw/virtio/vhost-backend.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index a64708f456..bd1c7dfe4f 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,6 +125,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); ++typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, ++ int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -173,6 +175,7 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; ++ vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/vhost-move-descriptor-translation-to-vhost_svq_vring.patch b/vhost-move-descriptor-translation-to-vhost_svq_vring.patch new file mode 100644 index 0000000000000000000000000000000000000000..a45e88f8e505c993072011089f1c6902e3e49f99 --- /dev/null +++ b/vhost-move-descriptor-translation-to-vhost_svq_vring.patch @@ -0,0 +1,101 @@ +From 16fdc235caece008e3802934250f434e9ca03dd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:26 +0200 +Subject: [PATCH] vhost: move descriptor translation to + vhost_svq_vring_write_descs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's done for both in and out descriptors so it's better placed here. + +Acked-by: Jason Wang +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 38 +++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index cea2c3f8dd..da1e1ce3c7 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -121,17 +121,35 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, + return true; + } + +-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, +- const struct iovec *iovec, size_t num, +- bool more_descs, bool write) ++/** ++ * Write descriptors to SVQ vring ++ * ++ * @svq: The shadow virtqueue ++ * @sg: Cache for hwaddr ++ * @iovec: The iovec from the guest ++ * @num: iovec length ++ * @more_descs: True if more descriptors come in the chain ++ * @write: True if they are writeable descriptors ++ * ++ * Return true if success, false otherwise and print error. ++ */ ++static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, ++ const struct iovec *iovec, size_t num, ++ bool more_descs, bool write) + { + uint16_t i = svq->free_head, last = svq->free_head; + unsigned n; + uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0; + vring_desc_t *descs = svq->vring.desc; ++ bool ok; + + if (num == 0) { +- return; ++ return true; ++ } ++ ++ ok = vhost_svq_translate_addr(svq, sg, iovec, num); ++ if (unlikely(!ok)) { ++ return false; + } + + for (n = 0; n < num; n++) { +@@ -149,6 +167,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + } + + svq->free_head = le16_to_cpu(svq->desc_next[last]); ++ return true; + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +@@ -168,21 +187,18 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return false; + } + +- ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num); ++ ok = vhost_svq_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, ++ elem->in_num > 0, false); + if (unlikely(!ok)) { + return false; + } +- vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, +- elem->in_num > 0, false); +- + +- ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num); ++ ok = vhost_svq_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, ++ true); + if (unlikely(!ok)) { + return false; + } + +- vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true); +- + /* + * Put the entry in the available array (but don't update avail->idx until + * they do sync). +-- +2.27.0 + diff --git a/vhost-move-iova_tree-set-to-vhost_svq_start.patch b/vhost-move-iova_tree-set-to-vhost_svq_start.patch new file mode 100644 index 0000000000000000000000000000000000000000..93cccc1ad9bc1bdfaf857f92f4a5ca3a705f1a78 --- /dev/null +++ b/vhost-move-iova_tree-set-to-vhost_svq_start.patch @@ -0,0 +1,114 @@ +From 7c93447234412390e6cd3bae1d5001426287a362 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:36 +0100 +Subject: [PATCH] vhost: move iova_tree set to vhost_svq_start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since we don't know if we will use SVQ at qemu initialization, let's +allocate iova_tree only if needed. To do so, accept it at SVQ start, not +at initialization. + +This will avoid to create it if the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 9 ++++----- + hw/virtio/vhost-shadow-virtqueue.h | 5 ++--- + hw/virtio/vhost-vdpa.c | 5 ++--- + 3 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 1ea7b5cf59..7d6afcb528 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -619,9 +619,10 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + * @svq: Shadow Virtqueue + * @vdev: VirtIO device + * @vq: Virtqueue to shadow ++ * @iova_tree: Tree to perform descriptors translations + */ + void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, +- VirtQueue *vq) ++ VirtQueue *vq, VhostIOVATree *iova_tree) + { + size_t desc_size, driver_size, device_size; + +@@ -632,6 +633,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->last_used_idx = 0; + svq->vdev = vdev; + svq->vq = vq; ++ svq->iova_tree = iova_tree; + + svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); + driver_size = vhost_svq_driver_area_size(svq); +@@ -689,18 +691,15 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * Creates vhost shadow virtqueue, and instructs the vhost device to use the + * shadow methods and file descriptors. + * +- * @iova_tree: Tree to perform descriptors translations + * @ops: SVQ owner callbacks + * @ops_opaque: ops opaque pointer + */ +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, +- const VhostShadowVirtqueueOps *ops, ++VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque) + { + VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); +- svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; + return svq; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d04c34a589..926a4897b1 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -126,11 +126,10 @@ size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); + size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + + void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, +- VirtQueue *vq); ++ VirtQueue *vq, VhostIOVATree *iova_tree); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, +- const VhostShadowVirtqueueOps *ops, ++VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque); + + void vhost_svq_free(gpointer vq); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 2fd7af1c6b..f5d816f5ec 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -419,8 +419,7 @@ static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) + for (unsigned n = 0; n < hdev->nvqs; ++n) { + VhostShadowVirtqueue *svq; + +- svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, +- v->shadow_vq_ops_opaque); ++ svq = vhost_svq_new(v->shadow_vq_ops, v->shadow_vq_ops_opaque); + g_ptr_array_add(shadow_vqs, svq); + } + +@@ -1060,7 +1059,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + goto err; + } + +- vhost_svq_start(svq, dev->vdev, vq); ++ vhost_svq_start(svq, dev->vdev, vq, v->iova_tree); + ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err); + if (unlikely(!ok)) { + goto err_map; +-- +2.27.0 + diff --git a/vhost-net-fix-improper-cleanup-in-vhost_net_start.patch b/vhost-net-fix-improper-cleanup-in-vhost_net_start.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2db14cec61a7b061a0027612b5d00fdbc9af420 --- /dev/null +++ b/vhost-net-fix-improper-cleanup-in-vhost_net_start.patch @@ -0,0 +1,44 @@ +From 4670dbaa57d7f034c2b5720d2a4c141a82f73025 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:15 -0700 +Subject: [PATCH 4/5] vhost-net: fix improper cleanup in vhost_net_start + +vhost_net_start() missed a corresponding stop_one() upon error from +vhost_set_vring_enable(). While at it, make the error handling for +err_start more robust. No real issue was found due to this though. + +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-5-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: zhangxinhao +--- + hw/net/vhost_net.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index e8a79db94d..1911ffd7ed 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -439,6 +439,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + r = vhost_set_vring_enable(peer, peer->vring_enable); + + if (r < 0) { ++ vhost_net_stop_one(get_vhost_net(peer), dev); + goto err_start; + } + } +@@ -448,7 +449,8 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + + err_start: + while (--i >= 0) { +- peer = qemu_get_peer(ncs , i); ++ peer = qemu_get_peer(ncs, i < data_queue_pairs ? ++ i : n->max_queue_pairs); + vhost_net_stop_one(get_vhost_net(peer), dev); + } + e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); +-- +2.27.0 + diff --git a/vhost-release-virtqueue-objects-in-error-path.patch b/vhost-release-virtqueue-objects-in-error-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..895d2b2b70ed145bd58d195a307f2d7e28438bc2 --- /dev/null +++ b/vhost-release-virtqueue-objects-in-error-path.patch @@ -0,0 +1,39 @@ +From ec9c8583bee8ba140274abd3f5e8366442ceaa8e Mon Sep 17 00:00:00 2001 +From: Prasad Pandit +Date: Mon, 29 May 2023 17:13:33 +0530 +Subject: [PATCH] vhost: release virtqueue objects in error path + +vhost_dev_start function does not release virtqueue objects when +event_notifier_init() function fails. Release virtqueue objects +and log a message about function failure. + +Signed-off-by: Prasad Pandit +Message-Id: <20230529114333.31686-3-ppandit@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Fixes: f9a09ca3ea ("vhost: add support for configure interrupt") +Reviewed-by: Peter Xu +Cc: qemu-stable@nongnu.org +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 63ddcb3e6d..59a12735f9 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1931,7 +1931,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + r = event_notifier_init( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); + if (r < 0) { +- return r; ++ VHOST_OPS_DEBUG(r, "event_notifier_init failed"); ++ goto fail_vq; + } + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +-- +2.27.0 + diff --git a/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch b/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d95b5ce14b4849df4aea3402defa73a3107c8e3 --- /dev/null +++ b/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch @@ -0,0 +1,65 @@ +From 462ece480c425ef9de419f5454ec2b7293c35e16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:34 +0100 +Subject: [PATCH] vhost: set SVQ device call handler at SVQ start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By the end of this series CVQ is shadowed as long as the features +support it. + +Since we don't know at the beginning of qemu running if this is +supported, move the event notifier handler setting to the start of the +SVQ, instead of the start of qemu run. This will avoid to create them if +the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-3-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index ae443f54fe..bc12bb42f3 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -625,6 +625,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + { + size_t desc_size, driver_size, device_size; + ++ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->next_guest_avail_elem = NULL; + svq->shadow_avail_idx = 0; + svq->shadow_used_idx = 0; +@@ -681,6 +682,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + g_free(svq->desc_state); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); ++ event_notifier_set_handler(&svq->hdev_call, NULL); + } + + /** +@@ -717,7 +719,6 @@ VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, + } + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); +- event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; +@@ -740,7 +741,6 @@ void vhost_svq_free(gpointer pvq) + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); +- event_notifier_set_handler(&vq->hdev_call, NULL); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +-- +2.27.0 + diff --git a/vhost-stick-to-errno-error-return-convention.patch b/vhost-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000000000000000000000000000000000000..2607c44617db1ebeec0f47ed42afb5948a0b54a4 --- /dev/null +++ b/vhost-stick-to-errno-error-return-convention.patch @@ -0,0 +1,349 @@ +From a5d0727f516b27e39b1f223e8dcf57b4c1bf95ea Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:56 +0800 +Subject: [PATCH] vhost: stick to -errno error return convention + +The generic vhost code expects that many of the VhostOps methods in the +respective backends set errno on errors. However, none of the existing +backends actually bothers to do so. In a number of those methods errno +from the failed call is clobbered by successful later calls to some +library functions; on a few code paths the generic vhost code then +negates and returns that errno, thus making failures look as successes +to the caller. + +As a result, in certain scenarios (e.g. live migration) the device +doesn't notice the first failure and goes on through its state +transitions as if everything is ok, instead of taking recovery actions +(break and reestablish the vhost-user connection, cancel migration, etc) +before it's too late. + +To fix this, consolidate on the convention to return negated errno on +failures throughout generic vhost, and use it for error propagation. + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-10-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 100 +++++++++++++++++++++------------------------- + 1 file changed, 46 insertions(+), 54 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index c3f375f276..caa53443ab 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -34,11 +34,13 @@ + #define _VHOST_DEBUG 1 + + #ifdef _VHOST_DEBUG +-#define VHOST_OPS_DEBUG(fmt, ...) \ +- do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ +- strerror(errno), errno); } while (0) ++#define VHOST_OPS_DEBUG(retval, fmt, ...) \ ++ do { \ ++ error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ ++ strerror(-retval), -retval); \ ++ } while (0) + #else +-#define VHOST_OPS_DEBUG(fmt, ...) \ ++#define VHOST_OPS_DEBUG(retval, fmt, ...) \ + do { } while (0) + #endif + +@@ -300,7 +302,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + releasing the current log, to ensure no logging is lost */ + r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_log_base failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + } + + vhost_log_put(dev, true); +@@ -552,7 +554,7 @@ static void vhost_commit(MemoryListener *listener) + if (!dev->log_enabled) { + r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + } + goto out; + } +@@ -566,7 +568,7 @@ static void vhost_commit(MemoryListener *listener) + } + r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + } + /* To log less, can only decrease log size after table update. */ + if (dev->log_size > log_size + VHOST_LOG_BUFFER) { +@@ -817,8 +819,8 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, + if (dev->vhost_ops->vhost_vq_get_addr) { + r = dev->vhost_ops->vhost_vq_get_addr(dev, &addr, vq); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_vq_get_addr failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_vq_get_addr failed"); ++ return r; + } + } else { + addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc; +@@ -830,10 +832,9 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, + addr.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0; + r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_vring_addr failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_addr failed"); + } +- return 0; ++ return r; + } + + static int vhost_dev_set_features(struct vhost_dev *dev, +@@ -854,19 +855,19 @@ static int vhost_dev_set_features(struct vhost_dev *dev, + } + r = dev->vhost_ops->vhost_set_features(dev, features); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_features failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_features failed"); + goto out; + } + if (dev->vhost_ops->vhost_set_backend_cap) { + r = dev->vhost_ops->vhost_set_backend_cap(dev); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_backend_cap failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_backend_cap failed"); + goto out; + } + } + + out: +- return r < 0 ? -errno : 0; ++ return r; + } + + static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) +@@ -1021,22 +1022,17 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, + bool is_big_endian, + int vhost_vq_index) + { ++ int r; + struct vhost_vring_state s = { + .index = vhost_vq_index, + .num = is_big_endian + }; + +- if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) { +- return 0; +- } +- +- VHOST_OPS_DEBUG("vhost_set_vring_endian failed"); +- if (errno == ENOTTY) { +- error_report("vhost does not support cross-endian"); +- return -ENOSYS; ++ r = dev->vhost_ops->vhost_set_vring_endian(dev, &s); ++ if (r < 0) { ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_endian failed"); + } +- +- return -errno; ++ return r; + } + + static int vhost_memory_region_lookup(struct vhost_dev *hdev, +@@ -1128,15 +1124,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + vq->num = state.num = virtio_queue_get_num(vdev, idx); + r = dev->vhost_ops->vhost_set_vring_num(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_num failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_num failed"); ++ return r; + } + + state.num = virtio_queue_get_last_avail_idx(vdev, idx); + r = dev->vhost_ops->vhost_set_vring_base(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_base failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_base failed"); ++ return r; + } + + if (vhost_needs_vring_endian(vdev)) { +@@ -1144,7 +1140,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + virtio_is_big_endian(vdev), + vhost_vq_index); + if (r) { +- return -errno; ++ return r; + } + } + +@@ -1172,15 +1168,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + + r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); + if (r < 0) { +- r = -errno; + goto fail_alloc; + } + + file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); + r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_kick failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_kick failed"); + goto fail_kick; + } + +@@ -1240,7 +1234,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, + + r = dev->vhost_ops->vhost_get_vring_base(dev, &state); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost VQ %u ring restore failed: %d", idx, r); ++ VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r); + /* Connection to the backend is broken, so let's sync internal + * last avail idx to the device used idx. + */ +@@ -1284,7 +1278,7 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, + + r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_busyloop_timeout failed"); + return r; + } + +@@ -1306,8 +1300,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, + file.fd = event_notifier_get_fd(&vq->masked_notifier); + r = dev->vhost_ops->vhost_set_vring_call(dev, &file); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_call failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); + goto fail_call; + } + +@@ -1584,7 +1577,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); + r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_vring_call failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); + } + } + +@@ -1622,7 +1615,7 @@ void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) + } + r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_config_call failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_config_call failed"); + } + } + +@@ -1687,7 +1680,7 @@ int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, + } + + error_setg(errp, "vhost_get_config not implemented"); +- return -ENOTSUP; ++ return -ENOSYS; + } + + int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, +@@ -1700,7 +1693,7 @@ int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, + size, flags); + } + +- return -1; ++ return -ENOSYS; + } + + void vhost_dev_set_config_notifier(struct vhost_dev *hdev, +@@ -1729,7 +1722,7 @@ static int vhost_dev_resize_inflight(struct vhost_inflight *inflight, + + if (err) { + error_report_err(err); +- return -1; ++ return -ENOMEM; + } + + vhost_dev_free_inflight(inflight); +@@ -1762,8 +1755,9 @@ int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f) + } + + if (inflight->size != size) { +- if (vhost_dev_resize_inflight(inflight, size)) { +- return -1; ++ int ret = vhost_dev_resize_inflight(inflight, size); ++ if (ret < 0) { ++ return ret; + } + } + inflight->queue_size = qemu_get_be16(f); +@@ -1786,7 +1780,7 @@ int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev) + + r = vhost_dev_set_features(hdev, hdev->log_enabled); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_dev_prepare_inflight failed"); ++ VHOST_OPS_DEBUG(r, "vhost_dev_prepare_inflight failed"); + return r; + } + +@@ -1801,8 +1795,8 @@ int vhost_dev_set_inflight(struct vhost_dev *dev, + if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) { + r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_inflight_fd failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_inflight_fd failed"); ++ return r; + } + } + +@@ -1817,8 +1811,8 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + if (dev->vhost_ops->vhost_get_inflight_fd) { + r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight); + if (r) { +- VHOST_OPS_DEBUG("vhost_get_inflight_fd failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_get_inflight_fd failed"); ++ return r; + } + } + +@@ -1847,8 +1841,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + + r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + goto fail_mem; + } + for (i = 0; i < hdev->nvqs; ++i) { +@@ -1882,8 +1875,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + hdev->log_size ? log_base : 0, + hdev->log); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_log_base failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + goto fail_log; + } + } +@@ -1963,7 +1955,7 @@ int vhost_net_set_backend(struct vhost_dev *hdev, + return hdev->vhost_ops->vhost_net_set_backend(hdev, file); + } + +- return -1; ++ return -ENOSYS; + } + + bool used_memslots_is_exceeded(void) +-- +2.27.0 + diff --git a/vhost-user-Add-support-reconnect-vhost-user-socket.patch b/vhost-user-Add-support-reconnect-vhost-user-socket.patch new file mode 100644 index 0000000000000000000000000000000000000000..cbe49c282b7ba86473e412201d613b6c01040f96 --- /dev/null +++ b/vhost-user-Add-support-reconnect-vhost-user-socket.patch @@ -0,0 +1,168 @@ +From 3a223111d71307eb4fdc18f5ee46ce3d6cb57660 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 18:05:47 +0800 +Subject: [PATCH] vhost-user: Add support reconnect vhost-user socket + +Add support reconnect vhost-user socket, the reconnect time +is set to be 3 seconds. + +Signed-off-by: Jinhua Cao +--- + chardev/char-socket.c | 19 ++++++++++++++++++- + hw/net/vhost_net.c | 4 +++- + hw/virtio/vhost-user.c | 6 ++++++ + include/chardev/char.h | 16 ++++++++++++++++ + net/vhost-user.c | 3 +++ + 5 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 836cfa0bc2..b1e9f43ec6 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -393,6 +393,22 @@ static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond) + return qio_channel_create_watch(s->ioc, cond); + } + ++static void tcp_chr_set_reconnect_time(Chardev *chr, ++ int64_t reconnect_time) ++{ ++ SocketChardev *s = SOCKET_CHARDEV(chr); ++ s->reconnect_time = reconnect_time; ++} ++ ++void qemu_chr_set_reconnect_time(Chardev *chr, int64_t reconnect_time) ++{ ++ ChardevClass *cc = CHARDEV_GET_CLASS(chr); ++ ++ if (cc->chr_set_reconnect_time) { ++ cc->chr_set_reconnect_time(chr, reconnect_time); ++ } ++} ++ + static void remove_hup_source(SocketChardev *s) + { + if (s->hup_source != NULL) { +@@ -591,7 +607,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len) + if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) { + qio_channel_set_blocking(s->ioc, false, NULL); + } +- if (size == 0) { ++ if (size == 0 && chr->chr_for_flag != CHR_FOR_VHOST_USER) { + /* connection closed */ + tcp_chr_disconnect(chr); + } +@@ -1585,6 +1601,7 @@ static void char_socket_class_init(ObjectClass *oc, void *data) + cc->set_msgfds = tcp_set_msgfds; + cc->chr_add_client = tcp_chr_add_client; + cc->chr_add_watch = tcp_chr_add_watch; ++ cc->chr_set_reconnect_time = tcp_chr_set_reconnect_time; + cc->chr_update_read_handler = tcp_chr_update_read_handler; + + object_class_property_add(oc, "addr", "SocketAddress", +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index 30379d2ca4..a60f7cef9a 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -376,7 +376,9 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + goto err_start; + } + +- if (peer->vring_enable) { ++ /* ovs needs to restore all states of vring */ ++ if (peer->vring_enable || ++ ncs[i].peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { + /* restore vring enable state */ + r = vhost_set_vring_enable(peer, peer->vring_enable); + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index c265e9e92c..fc2b1b81c9 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -1926,9 +1926,15 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, + uint64_t features, protocol_features, ram_slots; + struct vhost_user *u; + int err; ++ Chardev *chr; + + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); + ++ chr = qemu_chr_fe_get_driver(((VhostUserState *)opaque)->chr); ++ if (chr) { ++ chr->chr_for_flag = CHR_FOR_VHOST_USER; ++ } ++ + u = g_new0(struct vhost_user, 1); + u->user = opaque; + u->dev = dev; +diff --git a/include/chardev/char.h b/include/chardev/char.h +index a319b5fdff..f388d4b109 100644 +--- a/include/chardev/char.h ++++ b/include/chardev/char.h +@@ -14,6 +14,8 @@ + #define IAC_SB 250 + #define IAC 255 + ++#define CHR_FOR_VHOST_USER 0x32a1 ++ + /* character device */ + typedef struct CharBackend CharBackend; + +@@ -70,6 +72,7 @@ struct Chardev { + GSource *gsource; + GMainContext *gcontext; + DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST); ++ int chr_for_flag; + }; + + /** +@@ -227,6 +230,16 @@ int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all); + #define qemu_chr_write_all(s, buf, len) qemu_chr_write(s, buf, len, true) + int qemu_chr_wait_connected(Chardev *chr, Error **errp); + ++/** ++ * @qemu_chr_set_reconnect_time: ++ * ++ * Set reconnect time for char disconnect. ++ * Currently, only vhost user will call it. ++ * ++ * @reconnect_time the reconnect_time to be set ++ */ ++void qemu_chr_set_reconnect_time(Chardev *chr, int64_t reconnect_time); ++ + #define TYPE_CHARDEV "chardev" + OBJECT_DECLARE_TYPE(Chardev, ChardevClass, CHARDEV) + +@@ -306,6 +319,9 @@ struct ChardevClass { + + /* handle various events */ + void (*chr_be_event)(Chardev *s, QEMUChrEvent event); ++ ++ /* set reconnect time */ ++ void (*chr_set_reconnect_time)(Chardev *chr, int64_t reconnect_time); + }; + + Chardev *qemu_chardev_new(const char *id, const char *typename, +diff --git a/net/vhost-user.c b/net/vhost-user.c +index b1a0247b59..d1aefcb9aa 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -21,6 +21,8 @@ + #include "qemu/option.h" + #include "trace.h" + ++#define VHOST_USER_RECONNECT_TIME (3) ++ + typedef struct NetVhostUserState { + NetClientState nc; + CharBackend chr; /* only queue index 0 */ +@@ -287,6 +289,7 @@ static void net_vhost_user_event(void *opaque, QEMUChrEvent event) + trace_vhost_user_event(chr->label, event); + switch (event) { + case CHR_EVENT_OPENED: ++ qemu_chr_set_reconnect_time(chr, VHOST_USER_RECONNECT_TIME); + if (vhost_user_start(queues, ncs, s->vhost_user) < 0) { + qemu_chr_fe_disconnect(&s->chr); + return; +-- +2.27.0 + diff --git a/vhost-user-Fix-the-virtio-features-negotiation-flaw.patch b/vhost-user-Fix-the-virtio-features-negotiation-flaw.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d45f1810c80f9d28316c7a2189f3bad4f2f90fa --- /dev/null +++ b/vhost-user-Fix-the-virtio-features-negotiation-flaw.patch @@ -0,0 +1,92 @@ +From d29a94eff93b12790fe96c40412854c4cff843d2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Fri, 11 Nov 2022 19:33:26 +0800 +Subject: [PATCH 11/17] vhost-user: Fix the virtio features negotiation flaw +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch aims to fix unexpected negotiation features for +vhost-user netdev interface. + +When openvswitch reconnect Qemu after an unexpected disconnection +and Qemu therefore start the vhost_dev, acked_features field in +vhost_dev is initialized with value fetched from acked_features +field in NetVhostUserState, which should be up-to-date at that +moment but Qemu could not make it actually during the time window +of virtio features negotiation. + +So we save the acked_features right after being configured by +guest virtio driver so it can be used to restore acked_features +field in vhost_dev correctly. + +Signed-off-by: Hyman Huang(黄勇) +Signed-off-by: Guoyi Tu +--- + hw/net/vhost_net-stub.c | 5 +++++ + hw/net/vhost_net.c | 6 ++++++ + hw/net/virtio-net.c | 6 ++++++ + include/net/vhost_net.h | 1 + + 4 files changed, 18 insertions(+) + +diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c +index 89d71cfb8e..199b09952a 100644 +--- a/hw/net/vhost_net-stub.c ++++ b/hw/net/vhost_net-stub.c +@@ -101,3 +101,8 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) + { + return 0; + } ++ ++void vhost_net_save_acked_features(NetClientState *nc) ++{ ++ ++} +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index 1911ffd7ed..a98575ffbc 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -141,6 +141,12 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net) + return net->dev.acked_features; + } + ++void vhost_net_save_acked_features(NetClientState *nc) ++{ ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); ++ vhost_user_save_acked_features(nc); ++} ++ + static int vhost_net_get_fd(NetClientState *backend) + { + switch (backend->info->type) { +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 918a7aba89..4946b65e22 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -935,6 +935,12 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) + continue; + } + vhost_net_ack_features(get_vhost_net(nc->peer), features); ++ ++ /* ++ * keep acked_features in NetVhostUserState up-to-date so it ++ * can't miss any features configured by guest virtio driver. ++ */ ++ vhost_net_save_acked_features(nc->peer); + } + + if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 387e913e4e..7bdbf484e4 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -48,4 +48,5 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net); + + int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu); + ++void vhost_net_save_acked_features(NetClientState *nc); + #endif +-- +2.27.0 + diff --git a/vhost-user-Print-unexpected-slave-message-types.patch b/vhost-user-Print-unexpected-slave-message-types.patch deleted file mode 100644 index 4287428e059d06ffaac516ed2c2aa83b4f5d4e98..0000000000000000000000000000000000000000 --- a/vhost-user-Print-unexpected-slave-message-types.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 6e084ff24ad73eb4f7541573c6097013f5b94959 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 7 Feb 2019 18:22:40 +0000 -Subject: [PATCH] vhost-user: Print unexpected slave message types -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When we receive an unexpected message type on the slave fd, print -the type. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Daniel P. Berrangé -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Dr. David Alan Gilbert ---- - hw/virtio/vhost-user.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c -index 4ca5b2551e..f012774210 100644 ---- a/hw/virtio/vhost-user.c -+++ b/hw/virtio/vhost-user.c -@@ -1054,7 +1054,7 @@ static void slave_read(void *opaque) - fd[0]); - break; - default: -- error_report("Received unexpected msg type."); -+ error_report("Received unexpected msg type: %d.", hdr.request); - ret = -EINVAL; - } - --- -2.27.0 - diff --git a/vhost-user-Refactor-the-chr_closed_bh.patch b/vhost-user-Refactor-the-chr_closed_bh.patch new file mode 100644 index 0000000000000000000000000000000000000000..52289c54b81a605ff6778e1460dcfbcfd75ad89c --- /dev/null +++ b/vhost-user-Refactor-the-chr_closed_bh.patch @@ -0,0 +1,38 @@ +From b8c6b11e9651c5c94d3a66c64a9d54becb625a8e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Fri, 11 Nov 2022 20:03:56 +0800 +Subject: [PATCH 10/17] vhost-user: Refactor the chr_closed_bh +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use vhost_user_save_acked_features to implemente acked features +saving. + +Signed-off-by: Hyman Huang(黄勇) +Signed-off-by: Guoyi Tu +--- + net/vhost-user.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/vhost-user.c b/net/vhost-user.c +index dca277db8c..e3680b769f 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -263,11 +263,7 @@ static void chr_closed_bh(void *opaque) + s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); + + for (i = queues -1; i >= 0; i--) { +- s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); +- +- if (s->vhost_net) { +- s->acked_features = vhost_net_get_acked_features(s->vhost_net); +- } ++ vhost_user_save_acked_features(ncs[i]); + } + + qmp_set_link(name, false, &err); +-- +2.27.0 + diff --git a/vhost-user-Refactor-vhost-acked-features-saving.patch b/vhost-user-Refactor-vhost-acked-features-saving.patch new file mode 100644 index 0000000000000000000000000000000000000000..da7e913638e6169309061ec0959f4a1768a9387a --- /dev/null +++ b/vhost-user-Refactor-vhost-acked-features-saving.patch @@ -0,0 +1,75 @@ +From b51c193973c5bf80f08da173dcc8eb859f0f4049 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Mon, 26 Sep 2022 05:32:46 +0800 +Subject: [PATCH 09/17] vhost-user: Refactor vhost acked features saving +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Abstract vhost acked features saving into +vhost_user_save_acked_features, export it as util function. + +Signed-off-by: Hyman Huang(黄勇) +Signed-off-by: Guoyi Tu +--- + include/net/vhost-user.h | 1 + + net/vhost-user.c | 21 +++++++++++++++------ + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h +index 5bcd8a6285..35bf619709 100644 +--- a/include/net/vhost-user.h ++++ b/include/net/vhost-user.h +@@ -14,5 +14,6 @@ + struct vhost_net; + struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc); + uint64_t vhost_user_get_acked_features(NetClientState *nc); ++void vhost_user_save_acked_features(NetClientState *nc); + + #endif /* VHOST_USER_H */ +diff --git a/net/vhost-user.c b/net/vhost-user.c +index f910a286e4..dca277db8c 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -48,10 +48,23 @@ uint64_t vhost_user_get_acked_features(NetClientState *nc) + return s->acked_features; + } + +-static void vhost_user_stop(int queues, NetClientState *ncs[]) ++void vhost_user_save_acked_features(NetClientState *nc) + { + NetVhostUserState *s; ++ ++ s = DO_UPCAST(NetVhostUserState, nc, nc); ++ if (s->vhost_net) { ++ uint64_t features = vhost_net_get_acked_features(s->vhost_net); ++ if (features) { ++ s->acked_features = features; ++ } ++ } ++} ++ ++static void vhost_user_stop(int queues, NetClientState *ncs[]) ++{ + int i; ++ NetVhostUserState *s; + + for (i = 0; i < queues; i++) { + assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); +@@ -59,11 +72,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) + s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); + + if (s->vhost_net) { +- /* save acked features */ +- uint64_t features = vhost_net_get_acked_features(s->vhost_net); +- if (features) { +- s->acked_features = features; +- } ++ vhost_user_save_acked_features(ncs[i]); + vhost_net_cleanup(s->vhost_net); + } + } +-- +2.27.0 + diff --git a/vhost-user-Set-the-acked_features-to-vm-s-featrue.patch b/vhost-user-Set-the-acked_features-to-vm-s-featrue.patch new file mode 100644 index 0000000000000000000000000000000000000000..63c03535bc4e3e4e8886981205f79aff8b40f145 --- /dev/null +++ b/vhost-user-Set-the-acked_features-to-vm-s-featrue.patch @@ -0,0 +1,96 @@ +From 12af29806ba8ede96567e4df9223f0c02669727c Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 18:49:21 +0800 +Subject: [PATCH] vhost-user: Set the acked_features to vm's featrue + +Fix the problem when vm restart, the ovs restart and lead to the net +unreachable. The soluation is set the acked_features to vm's featrue +just the same as guest virtio-net mod load. + +Signed-off-by: Jinhua Cao +--- + hw/net/vhost_net.c | 58 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 57 insertions(+), 1 deletion(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index a60f7cef9a..e8a79db94d 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -152,9 +152,26 @@ static int vhost_net_get_fd(NetClientState *backend) + } + } + ++static uint64_t vhost_get_mask_features(const int *feature_bits, uint64_t features) ++{ ++ const int *bit = feature_bits; ++ uint64_t out_features = 0; ++ ++ while (*bit != VHOST_INVALID_FEATURE_BIT) { ++ uint64_t bit_mask = (1ULL << *bit); ++ if (features & bit_mask) { ++ out_features |= bit_mask; ++ } ++ bit++; ++ } ++ return out_features; ++} ++ + struct vhost_net *vhost_net_init(VhostNetOptions *options) + { + int r; ++ VirtIONet *n; ++ VirtIODevice *vdev; + bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL; + struct vhost_net *net = g_new0(struct vhost_net, 1); + uint64_t features = 0; +@@ -180,7 +197,46 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) + net->backend = r; + net->dev.protocol_features = 0; + } else { +- net->dev.backend_features = 0; ++ /* for ovs restart when vm start. ++ * Normal situation: ++ * 1.vm start. ++ * 2.vhost_net_init init ok, then dev.acked_features is 0x40000000. ++ * 3.guest virtio-net mod load. qemu will call virtio_net_set_features set ++ * dev.acked_features to 0x40408000. ++ * 4.feature set to ovs's vhostuser(0x40408000). ++ * 5.ovs restart. ++ * 6.vhost_user_stop will save net->dev.acked_features(0x40408000) to ++ * VhostUserState's acked_features(0x40408000). ++ * 7.restart ok. ++ * 8.vhost_net_init fun call vhost_user_get_acked_features get the save ++ * features, and set to net->dev.acked_features. ++ * Abnormal situation: ++ * 1.vm start. ++ * 2.vhost_net_init init ok, then dev.acked_features is 0x40000000. ++ * 3.ovs restart. ++ * 4.vhost_user_stop will save net->dev.acked_features(0x40000000) to ++ * VhostUserState's acked_features(0x40000000). ++ * 5.guest virtio-net mod load. qemu will call virtio_net_set_features set ++ * dev.acked_features to 0x40408000. ++ * 6.restart ok. ++ * 7.vhost_net_init fun call vhost_user_get_acked_features get the save ++ * features(0x40000000), and set to net->dev.acked_features(0x40000000). ++ * 8.feature set to ovs's vhostuser(0x40000000). ++ * ++ * in abnormal situation, qemu set the wrong features to ovs's vhostuser, ++ * then the vm's network will be down. ++ * in abnormal situation, we found it just lost the guest feartures in ++ * acked_features, so hear we set the acked_features to vm's featrue ++ * just the same as guest virtio-net mod load. ++ */ ++ if (options->net_backend->peer) { ++ n = qemu_get_nic_opaque(options->net_backend->peer); ++ vdev = VIRTIO_DEVICE(n); ++ net->dev.backend_features = vhost_get_mask_features(vhost_net_get_feature_bits(net), ++ vdev->guest_features); ++ } else { ++ net->dev.backend_features = 0; ++ } + net->dev.protocol_features = 0; + net->backend = -1; + +-- +2.27.0 + diff --git a/vhost-user-Use-correct-macro-name-TARGET_PPC64.patch b/vhost-user-Use-correct-macro-name-TARGET_PPC64.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d469cb1fcf3b75ce98ae13836fb0b6a2780563c --- /dev/null +++ b/vhost-user-Use-correct-macro-name-TARGET_PPC64.patch @@ -0,0 +1,42 @@ +From f985f564a64e122e55a02f7a22e877f0de2de464 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 21 Aug 2023 06:55:57 +0000 +Subject: [PATCH] vhost-user: Use correct macro name TARGET_PPC64 mainline + inclusion commit 97252353c1f6ecbb54385c9272378b5788749a16 category: bugfix + +--------------------------------------------------------------- + +The correct name of the macro is TARGET_PPC64. + +Fixes: 27598393a232 ("Lift max memory slots limit imposed by vhost-user") +Reported-by: Fabiano Rosas +Signed-off-by: Murilo Opsfelder Araujo +Cc: Raphael Norwitz +Cc: Peter Turschmid +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Raphael Norwitz +Message-Id: <20220503180108.34506-1-muriloo@linux.ibm.com> +Signed-off-by: Daniel Henrique Barboza + +Signed-off-by: tangbinzy +--- + hw/virtio/vhost-user.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 42a9e16cd9..24f80d5d18 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -52,7 +52,7 @@ + #include "hw/acpi/acpi.h" + #define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS + +-#elif defined(TARGET_PPC) || defined(TARGET_PPC_64) ++#elif defined(TARGET_PPC) || defined(TARGET_PPC64) + #include "hw/ppc/spapr.h" + #define VHOST_USER_MAX_RAM_SLOTS SPAPR_MAX_RAM_SLOTS + +-- +2.41.0.windows.1 + diff --git a/vhost-user-add-separate-memslot-counter-for-vhost-us.patch b/vhost-user-add-separate-memslot-counter-for-vhost-us.patch new file mode 100644 index 0000000000000000000000000000000000000000..d84f83043c6570edeb16df68fbf0572906ed7c7d --- /dev/null +++ b/vhost-user-add-separate-memslot-counter-for-vhost-us.patch @@ -0,0 +1,244 @@ +From 185d7efe768229b43911504f64fccd33ad3650ef Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 19:17:59 +0800 +Subject: [PATCH] vhost-user: add separate memslot counter for vhost-user + +Used_memslots is equal to dev->mem->nregions now, it is true for +vhost kernel, but not for vhost user, which uses the memory regions +that have file descriptor. In fact, not all of the memory regions +have file descriptor. +It is usefully in some scenarios, e.g. used_memslots is 8, and only +5 memory slots can be used by vhost user, it is failed to hot plug +a new memory RAM because vhost_has_free_slot just returned false, +but we can hot plug it safely in fact. + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost-backend.c | 14 ++++++++++ + hw/virtio/vhost-user.c | 27 ++++++++++++++++++ + hw/virtio/vhost.c | 46 +++++++++++++++++++++++++------ + include/hw/virtio/vhost-backend.h | 4 +++ + 4 files changed, 82 insertions(+), 9 deletions(-) + +diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c +index b65f8f7e97..2acfb750fd 100644 +--- a/hw/virtio/vhost-backend.c ++++ b/hw/virtio/vhost-backend.c +@@ -20,6 +20,8 @@ + #include + #include + ++static unsigned int vhost_kernel_used_memslots; ++ + static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, + void *arg) + { +@@ -293,6 +295,16 @@ static void vhost_kernel_set_iotlb_callback(struct vhost_dev *dev, + qemu_set_fd_handler((uintptr_t)dev->opaque, NULL, NULL, NULL); + } + ++static void vhost_kernel_set_used_memslots(struct vhost_dev *dev) ++{ ++ vhost_kernel_used_memslots = dev->mem->nregions; ++} ++ ++static unsigned int vhost_kernel_get_used_memslots(void) ++{ ++ return vhost_kernel_used_memslots; ++} ++ + const VhostOps kernel_ops = { + .backend_type = VHOST_BACKEND_TYPE_KERNEL, + .vhost_backend_init = vhost_kernel_init, +@@ -325,6 +337,8 @@ const VhostOps kernel_ops = { + #endif /* CONFIG_VHOST_VSOCK */ + .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback, + .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg, ++ .vhost_set_used_memslots = vhost_kernel_set_used_memslots, ++ .vhost_get_used_memslots = vhost_kernel_get_used_memslots, + }; + #endif + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index a8feea489b..176cae9244 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -234,6 +234,7 @@ static VhostUserMsg m __attribute__ ((unused)); + + /* The version of the protocol we support */ + #define VHOST_USER_VERSION (0x1) ++static unsigned int vhost_user_used_memslots; + + struct vhost_user { + struct vhost_dev *dev; +@@ -2524,6 +2525,30 @@ void vhost_user_cleanup(VhostUserState *user) + user->chr = NULL; + } + ++static void vhost_user_set_used_memslots(struct vhost_dev *dev) ++{ ++ unsigned int counter = 0; ++ int i; ++ ++ for (i = 0; i < dev->mem->nregions; ++i) { ++ struct vhost_memory_region *reg = dev->mem->regions + i; ++ ram_addr_t offset; ++ MemoryRegion *mr; ++ ++ mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, ++ &offset); ++ if (mr && memory_region_get_fd(mr) > 0) { ++ counter++; ++ } ++ } ++ vhost_user_used_memslots = counter; ++} ++ ++static unsigned int vhost_user_get_used_memslots(void) ++{ ++ return vhost_user_used_memslots; ++} ++ + const VhostOps user_ops = { + .backend_type = VHOST_BACKEND_TYPE_USER, + .vhost_backend_init = vhost_user_backend_init, +@@ -2557,4 +2582,6 @@ const VhostOps user_ops = { + .vhost_backend_mem_section_filter = vhost_user_mem_section_filter, + .vhost_get_inflight_fd = vhost_user_get_inflight_fd, + .vhost_set_inflight_fd = vhost_user_set_inflight_fd, ++ .vhost_set_used_memslots = vhost_user_set_used_memslots, ++ .vhost_get_used_memslots = vhost_user_get_used_memslots, + }; +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index dafb23c481..e4809777bc 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -45,20 +45,20 @@ + static struct vhost_log *vhost_log; + static struct vhost_log *vhost_log_shm; + +-static unsigned int used_memslots; + static QLIST_HEAD(, vhost_dev) vhost_devices = + QLIST_HEAD_INITIALIZER(vhost_devices); + + bool vhost_has_free_slot(void) + { +- unsigned int slots_limit = ~0U; + struct vhost_dev *hdev; + + QLIST_FOREACH(hdev, &vhost_devices, entry) { +- unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); +- slots_limit = MIN(slots_limit, r); ++ if (hdev->vhost_ops->vhost_get_used_memslots() >= ++ hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { ++ return false; ++ } + } +- return slots_limit > used_memslots; ++ return true; + } + + static void vhost_dev_sync_region(struct vhost_dev *dev, +@@ -521,7 +521,6 @@ static void vhost_commit(MemoryListener *listener) + dev->n_mem_sections * sizeof dev->mem->regions[0]; + dev->mem = g_realloc(dev->mem, regions_size); + dev->mem->nregions = dev->n_mem_sections; +- used_memslots = dev->mem->nregions; + for (i = 0; i < dev->n_mem_sections; i++) { + struct vhost_memory_region *cur_vmr = dev->mem->regions + i; + struct MemoryRegionSection *mrs = dev->mem_sections + i; +@@ -697,6 +696,7 @@ static void vhost_region_add_section(struct vhost_dev *dev, + dev->tmp_sections[dev->n_tmp_sections - 1].fv = NULL; + memory_region_ref(section->mr); + } ++ dev->vhost_ops->vhost_set_used_memslots(dev); + } + + /* Used for both add and nop callbacks */ +@@ -712,6 +712,17 @@ static void vhost_region_addnop(MemoryListener *listener, + vhost_region_add_section(dev, section); + } + ++static void vhost_region_del(MemoryListener *listener, ++ MemoryRegionSection *section) ++{ ++ struct vhost_dev *dev = container_of(listener, struct vhost_dev, ++ memory_listener); ++ if (!vhost_section(dev, section)) { ++ return; ++ } ++ dev->vhost_ops->vhost_set_used_memslots(dev); ++} ++ + static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) + { + struct vhost_iommu *iommu = container_of(n, struct vhost_iommu, n); +@@ -1319,6 +1330,18 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) + event_notifier_cleanup(&vq->masked_notifier); + } + ++static bool vhost_dev_used_memslots_is_exceeded(struct vhost_dev *hdev) ++{ ++ if (hdev->vhost_ops->vhost_get_used_memslots() > ++ hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { ++ error_report("vhost backend memory slots limit is less" ++ " than current number of present memory slots"); ++ return true; ++ } ++ ++ return false; ++} ++ + int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + VhostBackendType backend_type, uint32_t busyloop_timeout, + Error **errp) +@@ -1374,6 +1397,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + .name = "vhost", + .begin = vhost_begin, + .commit = vhost_commit, ++ .region_del = vhost_region_del, + .region_add = vhost_region_addnop, + .region_nop = vhost_region_addnop, + .log_start = vhost_log_start, +@@ -1420,9 +1444,13 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + memory_listener_register(&hdev->memory_listener, &address_space_memory); + QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); + +- if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { +- error_setg(errp, "vhost backend memory slots limit is less" +- " than current number of present memory slots"); ++ /* ++ * If we started a VM without any vhost device, ++ * vhost_dev_used_memslots_is_exceeded will always return false for the ++ * first time vhost device hot-plug(vhost_get_used_memslots is always 0), ++ * so it needs to double check here ++ */ ++ if (vhost_dev_used_memslots_is_exceeded(hdev)) { + r = -EINVAL; + goto fail_busyloop; + } +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index 81bf3109f8..a64708f456 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,6 +125,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); ++typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); ++typedef unsigned int (*vhost_get_used_memslots_op)(void); + + typedef struct VhostOps { + VhostBackendType backend_type; +@@ -171,6 +173,8 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; ++ vhost_set_used_memslots_op vhost_set_used_memslots; ++ vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; + + int vhost_backend_update_device_iotlb(struct vhost_dev *dev, +-- +2.27.0 + diff --git a/vhost-user-add-unregister_savevm-when-vhost-user-cle.patch b/vhost-user-add-unregister_savevm-when-vhost-user-cle.patch new file mode 100644 index 0000000000000000000000000000000000000000..95488a220c8d37b4fae6d3ebfc2cc016ea45f364 --- /dev/null +++ b/vhost-user-add-unregister_savevm-when-vhost-user-cle.patch @@ -0,0 +1,33 @@ +From a9459c849c5484a022f67a317b72de764c84c845 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 20:21:33 +0800 +Subject: [PATCH] vhost-user: add unregister_savevm when vhost-user cleanup + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost-user.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index bf6e50223c..c265e9e92c 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -24,6 +24,7 @@ + #include "sysemu/cryptodev.h" + #include "migration/migration.h" + #include "migration/postcopy-ram.h" ++#include "migration/register.h" + #include "trace.h" + + #include +@@ -2068,6 +2069,7 @@ static int vhost_user_backend_cleanup(struct vhost_dev *dev) + u->region_rb_len = 0; + g_free(u); + dev->opaque = 0; ++ unregister_savevm(NULL, "vhost-user", dev); + + return 0; + } +-- +2.27.0 + diff --git a/vhost-user-add-vhost_set_mem_table-when-vm-load_setu.patch b/vhost-user-add-vhost_set_mem_table-when-vm-load_setu.patch new file mode 100644 index 0000000000000000000000000000000000000000..fcd6bbf930f6496eee95cee86459f83b979ab507 --- /dev/null +++ b/vhost-user-add-vhost_set_mem_table-when-vm-load_setu.patch @@ -0,0 +1,61 @@ +From 5c753d539a968f2127ff6e5b916cd4b38a08b40c Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 18:59:34 +0800 +Subject: [PATCH] vhost-user: add vhost_set_mem_table when vm load_setup at + destination + +When migrate huge vm, packages lost are 90+. + +During the load_setup of the destination vm, pass the +vm mem structure to ovs, the netcard could be enabled +when the migration finish state shifting. + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost-user.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index fc2b1b81c9..a8feea489b 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -1920,6 +1920,28 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, + return 0; + } + ++static int vhost_user_load_setup(QEMUFile *f, void *opaque) ++{ ++ struct vhost_dev *hdev = opaque; ++ int r; ++ ++ if (hdev->vhost_ops && hdev->vhost_ops->vhost_set_mem_table) { ++ r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); ++ if (r < 0) { ++ qemu_log("error: vhost_set_mem_table failed: %s(%d)\n", ++ strerror(errno), errno); ++ return r; ++ } else { ++ qemu_log("info: vhost_set_mem_table OK\n"); ++ } ++ } ++ return 0; ++} ++ ++SaveVMHandlers savevm_vhost_user_handlers = { ++ .load_setup = vhost_user_load_setup, ++}; ++ + static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, + Error **errp) + { +@@ -2044,6 +2066,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, + + u->postcopy_notifier.notify = vhost_user_postcopy_notifier; + postcopy_add_notifier(&u->postcopy_notifier); ++ register_savevm_live("vhost-user", -1, 1, &savevm_vhost_user_handlers, dev); + + return 0; + } +-- +2.27.0 + diff --git a/vhost-user-blk-convert-to-new-virtio_delete_queue.patch b/vhost-user-blk-convert-to-new-virtio_delete_queue.patch deleted file mode 100644 index 3f419966ec034fe4eecd8e6606b6e7dc611517e1..0000000000000000000000000000000000000000 --- a/vhost-user-blk-convert-to-new-virtio_delete_queue.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 30d20e1258722431198cd2a8298c85b7af2a0c1b Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Mon, 24 Feb 2020 12:13:36 +0800 -Subject: [PATCH 5/9] vhost-user-blk: convert to new virtio_delete_queue - -use the new virtio_delete_queue function to cleanup. - -Signed-off-by: Pan Nengyuan -Message-Id: <20200224041336.30790-3-pannengyuan@huawei.com> -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/block/vhost-user-blk.c | 20 ++++++++++++-------- - include/hw/virtio/vhost-user-blk.h | 4 +++- - 2 files changed, 15 insertions(+), 9 deletions(-) - -diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c -index dbc0a2e..146b927 100644 ---- a/hw/block/vhost-user-blk.c -+++ b/hw/block/vhost-user-blk.c -@@ -303,7 +303,7 @@ static int vhost_user_blk_connect(DeviceState *dev) - s->connected = true; - - s->dev.nvqs = s->num_queues; -- s->dev.vqs = s->vqs; -+ s->dev.vqs = s->vhost_vqs; - s->dev.vq_index = 0; - s->dev.backend_features = 0; - -@@ -430,13 +430,15 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, - sizeof(struct virtio_blk_config)); - -+ s->virtqs = g_new(VirtQueue *, s->num_queues); - for (i = 0; i < s->num_queues; i++) { -- virtio_add_queue(vdev, s->queue_size, -- vhost_user_blk_handle_output); -+ s->virtqs[i] = virtio_add_queue(vdev, s->queue_size, -+ vhost_user_blk_handle_output); - } - - s->inflight = g_new0(struct vhost_inflight, 1); -- s->vqs = g_new(struct vhost_virtqueue, s->num_queues); -+ s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); -+ s->watch = 0; - s->connected = false; - - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, -@@ -467,11 +469,12 @@ reconnect: - return; - - virtio_err: -- g_free(s->vqs); -+ g_free(s->vhost_vqs); - g_free(s->inflight); - for (i = 0; i < s->num_queues; i++) { -- virtio_del_queue(vdev, i); -+ virtio_delete_queue(s->virtqs[i]); - } -+ g_free(s->virtqs); - virtio_cleanup(vdev); - vhost_user_cleanup(&s->vhost_user); - } -@@ -487,12 +490,13 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) - NULL, NULL, NULL, false); - vhost_dev_cleanup(&s->dev); - vhost_dev_free_inflight(s->inflight); -- g_free(s->vqs); -+ g_free(s->vhost_vqs); - g_free(s->inflight); - - for (i = 0; i < s->num_queues; i++) { -- virtio_del_queue(vdev, i); -+ virtio_delete_queue(s->virtqs[i]); - } -+ g_free(s->virtqs); - virtio_cleanup(vdev); - vhost_user_cleanup(&s->vhost_user); - } -diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h -index ad9b742..29375dd 100644 ---- a/include/hw/virtio/vhost-user-blk.h -+++ b/include/hw/virtio/vhost-user-blk.h -@@ -37,7 +37,9 @@ typedef struct VHostUserBlk { - struct vhost_dev dev; - struct vhost_inflight *inflight; - VhostUserState vhost_user; -- struct vhost_virtqueue *vqs; -+ struct vhost_virtqueue *vhost_vqs; -+ VirtQueue **virtqs; -+ guint watch; - bool connected; - } VHostUserBlk; - --- -1.8.3.1 - diff --git a/vhost-user-blk-delay-vhost_user_blk_disconnect.patch b/vhost-user-blk-delay-vhost_user_blk_disconnect.patch deleted file mode 100644 index 422e2a17b028d83690cc620a57829260c76aab52..0000000000000000000000000000000000000000 --- a/vhost-user-blk-delay-vhost_user_blk_disconnect.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 632a841b6ba547906b475250f5c2cb46774ab4af Mon Sep 17 00:00:00 2001 -From: Dima Stepanov -Date: Thu, 28 May 2020 12:11:19 +0300 -Subject: [PATCH 14/14] vhost-user-blk: delay vhost_user_blk_disconnect - -A socket write during vhost-user communication may trigger a disconnect -event, calling vhost_user_blk_disconnect() and clearing all the -vhost_dev structures holding data that vhost-user functions expect to -remain valid to roll back initialization correctly. Delay the cleanup to -keep vhost_dev structure valid. -There are two possible states to handle: -1. RUN_STATE_PRELAUNCH: skip bh oneshot call and perform disconnect in -the caller routine. -2. RUN_STATE_RUNNING: delay by using bh - -BH changes are based on the similar changes for the vhost-user-net -device: - commit e7c83a885f865128ae3cf1946f8cb538b63cbfba - "vhost-user: delay vhost_user_stop" - -Signed-off-by: Dima Stepanov -Message-Id: <69b73b94dcd066065595266c852810e0863a0895.1590396396.git.dimastep@yandex-team.ru> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Li Feng -Reviewed-by: Raphael Norwitz -Signed-off-by: Peng Liang ---- - hw/block/vhost-user-blk.c | 38 +++++++++++++++++++++++++++++++++++++- - 1 file changed, 37 insertions(+), 1 deletion(-) - -diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c -index dc66f8a5febd..6b719d1d80e1 100644 ---- a/hw/block/vhost-user-blk.c -+++ b/hw/block/vhost-user-blk.c -@@ -346,6 +346,19 @@ static void vhost_user_blk_disconnect(DeviceState *dev) - vhost_dev_cleanup(&s->dev); - } - -+static void vhost_user_blk_event(void *opaque, int event); -+ -+static void vhost_user_blk_chr_closed_bh(void *opaque) -+{ -+ DeviceState *dev = opaque; -+ VirtIODevice *vdev = VIRTIO_DEVICE(dev); -+ VHostUserBlk *s = VHOST_USER_BLK(vdev); -+ -+ vhost_user_blk_disconnect(dev); -+ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, -+ NULL, opaque, NULL, true); -+} -+ - static void vhost_user_blk_event(void *opaque, int event) - { - DeviceState *dev = opaque; -@@ -360,7 +373,30 @@ static void vhost_user_blk_event(void *opaque, int event) - } - break; - case CHR_EVENT_CLOSED: -- vhost_user_blk_disconnect(dev); -+ /* -+ * A close event may happen during a read/write, but vhost -+ * code assumes the vhost_dev remains setup, so delay the -+ * stop & clear. There are two possible paths to hit this -+ * disconnect event: -+ * 1. When VM is in the RUN_STATE_PRELAUNCH state. The -+ * vhost_user_blk_device_realize() is a caller. -+ * 2. In tha main loop phase after VM start. -+ * -+ * For p2 the disconnect event will be delayed. We can't -+ * do the same for p1, because we are not running the loop -+ * at this moment. So just skip this step and perform -+ * disconnect in the caller function. -+ * -+ * TODO: maybe it is a good idea to make the same fix -+ * for other vhost-user devices. -+ */ -+ if (runstate_is_running()) { -+ AioContext *ctx = qemu_get_current_aio_context(); -+ -+ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, -+ NULL, NULL, false); -+ aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); -+ } - break; - } - } --- -2.26.2 - diff --git a/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch b/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch deleted file mode 100644 index e57f5b59c972cf4c769d7b87cc2a654b72eb3b64..0000000000000000000000000000000000000000 --- a/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch +++ /dev/null @@ -1,69 +0,0 @@ -From d8febdc4940d719dba77a17a10a8d36ad08305ab Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Mon, 24 Feb 2020 12:13:35 +0800 -Subject: [PATCH 4/9] vhost-user-blk: delete virtioqueues in unrealize to fix - memleaks - -virtio queues forgot to delete in unrealize, and aslo error path in -realize, this patch fix these memleaks, the leak stack is as follow: - -Direct leak of 114688 byte(s) in 16 object(s) allocated from: - #0 0x7f24024fdbf0 in calloc (/lib64/libasan.so.3+0xcabf0) - #1 0x7f2401642015 in g_malloc0 (/lib64/libglib-2.0.so.0+0x50015) - #2 0x55ad175a6447 in virtio_add_queue /mnt/sdb/qemu/hw/virtio/virtio.c:2327 - #3 0x55ad17570cf9 in vhost_user_blk_device_realize /mnt/sdb/qemu/hw/block/vhost-user-blk.c:419 - #4 0x55ad175a3707 in virtio_device_realize /mnt/sdb/qemu/hw/virtio/virtio.c:3509 - #5 0x55ad176ad0d1 in device_set_realized /mnt/sdb/qemu/hw/core/qdev.c:876 - #6 0x55ad1781ff9d in property_set_bool /mnt/sdb/qemu/qom/object.c:2080 - #7 0x55ad178245ae in object_property_set_qobject /mnt/sdb/qemu/qom/qom-qobject.c:26 - #8 0x55ad17821eb4 in object_property_set_bool /mnt/sdb/qemu/qom/object.c:1338 - #9 0x55ad177aeed7 in virtio_pci_realize /mnt/sdb/qemu/hw/virtio/virtio-pci.c:1801 - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Reviewed-by: Stefan Hajnoczi -Message-Id: <20200224041336.30790-2-pannengyuan@huawei.com> -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/block/vhost-user-blk.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c -index 6b719d1..dbc0a2e 100644 ---- a/hw/block/vhost-user-blk.c -+++ b/hw/block/vhost-user-blk.c -@@ -469,6 +469,9 @@ reconnect: - virtio_err: - g_free(s->vqs); - g_free(s->inflight); -+ for (i = 0; i < s->num_queues; i++) { -+ virtio_del_queue(vdev, i); -+ } - virtio_cleanup(vdev); - vhost_user_cleanup(&s->vhost_user); - } -@@ -477,6 +480,7 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) - { - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VHostUserBlk *s = VHOST_USER_BLK(dev); -+ int i; - - virtio_set_status(vdev, 0); - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, -@@ -485,6 +489,10 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) - vhost_dev_free_inflight(s->inflight); - g_free(s->vqs); - g_free(s->inflight); -+ -+ for (i = 0; i < s->num_queues; i++) { -+ virtio_del_queue(vdev, i); -+ } - virtio_cleanup(vdev); - vhost_user_cleanup(&s->vhost_user); - } --- -1.8.3.1 - diff --git a/vhost-user-blk-fix-the-resize-crash.patch b/vhost-user-blk-fix-the-resize-crash.patch new file mode 100644 index 0000000000000000000000000000000000000000..83c6cea4ed8459c0a48963f144351f5502a3d8ad --- /dev/null +++ b/vhost-user-blk-fix-the-resize-crash.patch @@ -0,0 +1,41 @@ +From 17e6be412054ae22027a339614fca82d55e64973 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Thu, 30 Mar 2023 17:45:11 +0800 +Subject: [PATCH] vhost-user-blk: fix the resize crash + +cheery-pick from ab6075d849f4285fc730d3ae6e17418d65d09998 + +If the os is not installed and doesn't have the virtio guest driver, +the vhost dev isn't started, so the dev->vdev is NULL. + +Reproduce: mount a Win 2019 iso, go into the install ui, then resize +the virtio-blk device, qemu crash. + +Signed-off-by: qihao_yewu +Signed-off-by: Li Feng +Message-Id: <20220919121816.3252223-1-fengli@smartx.com> +Reviewed-by: Raphael Norwitz +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +--- + hw/block/vhost-user-blk.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index eb1264afc7..bcc3f83c4b 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -95,6 +95,10 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) + VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); + Error *local_err = NULL; + ++ if (!dev->started) { ++ return 0; ++ } ++ + ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, + sizeof(struct virtio_blk_config), + &local_err); +-- +2.27.0 + diff --git a/vhost-user-blk-propagate-error-return-from-generic-v.patch b/vhost-user-blk-propagate-error-return-from-generic-v.patch new file mode 100644 index 0000000000000000000000000000000000000000..7894db573723a59ed7e8ee70af058b0bf48eddb1 --- /dev/null +++ b/vhost-user-blk-propagate-error-return-from-generic-v.patch @@ -0,0 +1,36 @@ +From 2a4dcc55ce71f1251d0dc0ccd293866bfe4dc071 Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 11:15:58 +0800 +Subject: [PATCH] vhost-user-blk: propagate error return from generic vhost + +cherry picked from commit fb767859345506d747876c23d181155b183f8e94 + +Fix the only callsite that doesn't propagate the error code from the +generic vhost code. + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-11-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Raphael Norwitz +Signed-off-by: Luo Yifan +--- + hw/block/vhost-user-blk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index eddc5588fa..f1a281a965 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -104,7 +104,7 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) + &local_err); + if (ret < 0) { + error_report_err(local_err); +- return -1; ++ return ret; + } + + /* valid for resize only */ +-- +2.27.0 + diff --git a/vhost-user-blk-reconnect-on-any-error-during-realize.patch b/vhost-user-blk-reconnect-on-any-error-during-realize.patch new file mode 100644 index 0000000000000000000000000000000000000000..25eaab24a154eb9e72caa7a38137c74b6b98fbdb --- /dev/null +++ b/vhost-user-blk-reconnect-on-any-error-during-realize.patch @@ -0,0 +1,51 @@ +From a64c32378bd5a1119ea69d8c29f93b6365d3346b Mon Sep 17 00:00:00 2001 +From: Luo Yifan +Date: Mon, 4 Dec 2023 11:11:29 +0800 +Subject: [PATCH] vhost-user-blk: reconnect on any error during realize + +cherry picked from commit b7107e758f4ecdd8f07ede3f093cbbfdb623e865 + +vhost-user-blk realize only attempts to reconnect if the previous +connection attempt failed on "a problem with the connection and not an +error related to the content (which would fail again the same way in the +next attempt)". + +However this distinction is very subtle, and may be inadvertently broken +if the code changes somewhere deep down the stack and a new error gets +propagated up to here. + +OTOH now that the number of reconnection attempts is limited it seems +harmless to try reconnecting on any error. + +So relax the condition of whether to retry connecting to check for any +error. + +This patch amends a527e312b5 "vhost-user-blk: Implement reconnection +during realize". + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-2-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Raphael Norwitz +Signed-off-by: Luo Yifan +--- + hw/block/vhost-user-blk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index eddc5588fa..a2236c5239 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -516,7 +516,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + *errp = NULL; + } + ret = vhost_user_blk_realize_connect(s, errp); +- } while (ret == -EPROTO && retries--); ++ } while (ret < 0 && retries--); + + if (ret < 0) { + goto virtio_err; +-- +2.27.0 + diff --git a/vhost-user-fix-VirtQ-notifier-cleanup.patch b/vhost-user-fix-VirtQ-notifier-cleanup.patch new file mode 100644 index 0000000000000000000000000000000000000000..96bba60295d7dd010f5c4085abc87b9436d6c126 --- /dev/null +++ b/vhost-user-fix-VirtQ-notifier-cleanup.patch @@ -0,0 +1,151 @@ +From 0d022f741ab510b52453bb9e9e07b968e7d5e0df Mon Sep 17 00:00:00 2001 +From: Xueming Li +Date: Mon, 7 Feb 2022 15:19:29 +0800 +Subject: [PATCH 2/2] vhost-user: fix VirtQ notifier cleanup + +When vhost-user device cleanup, remove notifier MR and munmaps notifier +address in the event-handling thread, VM CPU thread writing the notifier +in concurrent fails with an error of accessing invalid address. It +happens because MR is still being referenced and accessed in another +thread while the underlying notifier mmap address is being freed and +becomes invalid. + +This patch calls RCU and munmap notifiers in the callback after the +memory flatview update finish. + +Fixes: 44866521bd6e ("vhost-user: support registering external host notifiers") +Cc: qemu-stable@nongnu.org +Signed-off-by: Xueming Li +Message-Id: <20220207071929.527149-3-xuemingl@nvidia.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 0b0af4d62f7002b31cd7b2762b26d2fcb76bb2ba) +--- + hw/virtio/vhost-user.c | 48 ++++++++++++++++++++-------------- + include/hw/virtio/vhost-user.h | 2 ++ + 2 files changed, 31 insertions(+), 19 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 7b21e09723..42a9e16cd9 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -26,6 +26,7 @@ + #include "migration/postcopy-ram.h" + #include "migration/register.h" + #include "trace.h" ++#include "exec/ramblock.h" + + #include + #include +@@ -1145,15 +1146,26 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, + return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); + } + +-static void vhost_user_host_notifier_remove(struct vhost_dev *dev, +- int queue_idx) ++static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) + { +- struct vhost_user *u = dev->opaque; +- VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; +- VirtIODevice *vdev = dev->vdev; ++ assert(n && n->unmap_addr); ++ munmap(n->unmap_addr, qemu_real_host_page_size); ++ n->unmap_addr = NULL; ++} ++ ++static void vhost_user_host_notifier_remove(VhostUserState *user, ++ VirtIODevice *vdev, int queue_idx) ++{ ++ VhostUserHostNotifier *n = &user->notifier[queue_idx]; + + if (n->addr) { +- virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); ++ if (vdev) { ++ virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); ++ } ++ assert(!n->unmap_addr); ++ n->unmap_addr = n->addr; ++ n->addr = NULL; ++ call_rcu(n, vhost_user_host_notifier_free, rcu); + } + } + +@@ -1192,8 +1204,9 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, + .payload.state = *ring, + .hdr.size = sizeof(msg.payload.state), + }; ++ struct vhost_user *u = dev->opaque; + +- vhost_user_host_notifier_remove(dev, ring->index); ++ vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); + + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + return -1; +@@ -1488,12 +1501,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + + n = &user->notifier[queue_idx]; + +- if (n->addr) { +- virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); +- object_unparent(OBJECT(&n->mr)); +- munmap(n->addr, page_size); +- n->addr = NULL; +- } ++ vhost_user_host_notifier_remove(user, vdev, queue_idx); + + if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { + return 0; +@@ -1512,9 +1520,12 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + + name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", + user, queue_idx); +- if (!n->mr.ram) /* Don't init again after suspend. */ ++ if (!n->mr.ram) { /* Don't init again after suspend. */ + memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name, + page_size, addr); ++ } else { ++ n->mr.ram_block->host = addr; ++ } + g_free(name); + + if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { +@@ -2492,17 +2503,16 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) + void vhost_user_cleanup(VhostUserState *user) + { + int i; ++ VhostUserHostNotifier *n; + + if (!user->chr) { + return; + } + memory_region_transaction_begin(); + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { +- if (user->notifier[i].addr) { +- object_unparent(OBJECT(&user->notifier[i].mr)); +- munmap(user->notifier[i].addr, qemu_real_host_page_size); +- user->notifier[i].addr = NULL; +- } ++ n = &user->notifier[i]; ++ vhost_user_host_notifier_remove(user, NULL, i); ++ object_unparent(OBJECT(&n->mr)); + } + memory_region_transaction_commit(); + user->chr = NULL; +diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h +index f6012b2078..e44a41bb70 100644 +--- a/include/hw/virtio/vhost-user.h ++++ b/include/hw/virtio/vhost-user.h +@@ -12,8 +12,10 @@ + #include "hw/virtio/virtio.h" + + typedef struct VhostUserHostNotifier { ++ struct rcu_head rcu; + MemoryRegion mr; + void *addr; ++ void *unmap_addr; + } VhostUserHostNotifier; + + typedef struct VhostUserState { +-- +2.27.0 + diff --git a/vhost-user-fs-Back-up-vqs-before-cleaning-up-vhost_d.patch b/vhost-user-fs-Back-up-vqs-before-cleaning-up-vhost_d.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d9f4c575026e47dc712786fbb069fccea62c36c --- /dev/null +++ b/vhost-user-fs-Back-up-vqs-before-cleaning-up-vhost_d.patch @@ -0,0 +1,43 @@ +From d48beee81ba11b6bc5151f4f882a9fe2ff9b1d2c Mon Sep 17 00:00:00 2001 +From: dinglimin_yewu +Date: Thu, 28 Sep 2023 16:07:30 +0800 +Subject: [PATCH] vhost-user-fs: Back up vqs before cleaning up vhost_dev + +cheery-pick from 331acddc87b739c64b936ba4e58518f8491f1c6b + +vhost_dev_cleanup() clears vhost_dev so back up its vqs member to free the memory pointed by the member. + +Fixes: 98fc1ada4c ("virtio: add vhost-user-fs base device") +Signed-off-by: Akihiko Odaki +Signed-off-by: Stefan Hajnoczi +Message-Id: <20230130140225.77964-1-akihiko.odaki at daynix.com> +Signed-off-by: dinglimin_yewu +--- + hw/virtio/vhost-user-fs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index c595957983..fc7dcc96ef 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -258,6 +258,7 @@ static void vuf_device_unrealize(DeviceState *dev) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserFS *fs = VHOST_USER_FS(dev); ++ struct vhost_virtqueue *vhost_vqs = fs->vhost_dev.vqs; + int i; + + /* This will stop vhost backend if appropriate. */ +@@ -273,8 +274,7 @@ static void vuf_device_unrealize(DeviceState *dev) + } + g_free(fs->req_vqs); + virtio_cleanup(vdev); +- g_free(fs->vhost_dev.vqs); +- fs->vhost_dev.vqs = NULL; ++ g_free(vhost_vqs); + } + + static const VMStateDescription vuf_vmstate = { +-- +2.41.0.windows.1 + diff --git a/vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch b/vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch deleted file mode 100644 index 11f9ce807bca6c991b77e007d078a73289d27e2e..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch +++ /dev/null @@ -1,51 +0,0 @@ -From acb9f3aadde7222eacf95b2d70204dd6f8351ed7 Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 10:14:06 +0800 -Subject: [PATCH] vhost-user-gpu: fix OOB write in 'virgl_cmd_get_capset' - (CVE-2021-3546) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -If 'virgl_cmd_get_capset' set 'max_size' to 0, -the 'virgl_renderer_fill_caps' will write the data after the 'resp'. -This patch avoid this by checking the returned 'max_size'. - -virtio-gpu fix: abd7f08b - - ("display: virtio-gpu-3d: check -virgl capabilities max_size") - -Fixes: CVE-2021-3546 -Reported-by: default avatarLi Qiang -Reviewed-by: default avatarPrasad J Pandit -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-8-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/virgl.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c -index 44e79ab82a..ad2834902b 100644 ---- a/contrib/vhost-user-gpu/virgl.c -+++ b/contrib/vhost-user-gpu/virgl.c -@@ -173,6 +173,10 @@ virgl_cmd_get_capset(VuGpu *g, - - virgl_renderer_get_cap_set(gc.capset_id, &max_ver, - &max_size); -+ if (!max_size) { -+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; -+ return; -+ } - resp = g_malloc0(sizeof(*resp) + max_size); - - resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; --- -2.27.0 - diff --git a/vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch b/vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch deleted file mode 100644 index 46353183baae4d3465048614bb198988597901a7..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 511cac8cbc60fafdae2589d674b7aeab15388eef Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 10:11:17 +0800 -Subject: [PATCH] vhost-user-gpu: fix memory disclosure in - virgl_cmd_get_capset_info (CVE-2021-3545) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -Otherwise some of the 'resp' will be leaked to guest. - -Fixes: CVE-2021-3545 -Reported-by: default avatarLi Qiang -virtio-gpu fix: 42a8dadc - - ("virtio-gpu: fix information leak -in getting capset info dispatch") -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-2-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/virgl.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c -index 79556df094..44e79ab82a 100644 ---- a/contrib/vhost-user-gpu/virgl.c -+++ b/contrib/vhost-user-gpu/virgl.c -@@ -131,6 +131,7 @@ virgl_cmd_get_capset_info(VuGpu *g, - - VUGPU_FILL_CMD(info); - -+ memset(&resp, 0, sizeof(resp)); - if (info.capset_index == 0) { - resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; - virgl_renderer_get_cap_set(resp.capset_id, --- -2.27.0 - diff --git a/vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch b/vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch deleted file mode 100644 index 7c44ec4578db09283d0a6fa67c85298679472f4d..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch +++ /dev/null @@ -1,49 +0,0 @@ -From b9f6004899adb8e501e1b9ce1cb0976a2268ad60 Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 09:56:42 +0800 -Subject: [PATCH] vhost-user-gpu: fix memory leak in vg_resource_attach_backing - (CVE-2021-3544) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -Check whether the 'res' has already been attach_backing to avoid -memory leak. - -Fixes: CVE-2021-3544 -Reported-by: default avatarLi Qiang -virtio-gpu fix: 204f01b3 - - ("virtio-gpu: fix memory leak -in resource attach backing") -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-4-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/main.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/contrib/vhost-user-gpu/main.c b/contrib/vhost-user-gpu/main.c -index f69af7d17f..4f087d6000 100644 ---- a/contrib/vhost-user-gpu/main.c -+++ b/contrib/vhost-user-gpu/main.c -@@ -468,6 +468,11 @@ vg_resource_attach_backing(VuGpu *g, - return; - } - -+ if (res->iov) { -+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; -+ return; -+ } -+ - ret = vg_create_mapping_iov(g, &ab, cmd, &res->iov); - if (ret != 0) { - cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; --- -2.27.0 - diff --git a/vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch b/vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch deleted file mode 100644 index c0dccd7a33a11fbcc7e14ed605f8eeff080e3c9a..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 5bdbe19681e151318b749cb6b2443626bf54b82e Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 10:05:40 +0800 -Subject: [PATCH] vhost-user-gpu: fix memory leak in 'virgl_cmd_resource_unref' - (CVE-2021-3544) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -The 'res->iov' will be leaked if the guest trigger following sequences: - - virgl_cmd_create_resource_2d - virgl_resource_attach_backing - virgl_cmd_resource_unref - -This patch fixes this. - -Fixes: CVE-2021-3544 -Reported-by: default avatarLi Qiang -virtio-gpu fix: 5e8e3c4c - - ("virtio-gpu: fix resource leak -in virgl_cmd_resource_unref" -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-6-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/virgl.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c -index 43413e29df..4b8b536edf 100644 ---- a/contrib/vhost-user-gpu/virgl.c -+++ b/contrib/vhost-user-gpu/virgl.c -@@ -105,8 +105,14 @@ virgl_cmd_resource_unref(VuGpu *g, - struct virtio_gpu_ctrl_command *cmd) - { - struct virtio_gpu_resource_unref unref; -+ struct iovec *res_iovs = NULL; -+ int num_iovs = 0; - - VUGPU_FILL_CMD(unref); -+ virgl_renderer_resource_detach_iov(unref.resource_id, -+ &res_iovs, -+ &num_iovs); -+ g_free(res_iovs); - - virgl_renderer_resource_unref(unref.resource_id); - } --- -2.27.0 - diff --git a/vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch b/vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch deleted file mode 100644 index 986a49f81fa988ed176c541265571ca01d5c5c85..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 6348348ee6a76c28159c64d6392fb6ba5a0b4374 Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 10:09:13 +0800 -Subject: [PATCH] vhost-user-gpu: fix memory leak in - 'virgl_resource_attach_backing' (CVE-2021-3544) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -If 'virgl_renderer_resource_attach_iov' failed, the 'res_iovs' will -be leaked. - -Fixes: CVE-2021-3544 -Reported-by: default avatarLi Qiang -virtio-gpu fix: 33243031 - - ("virtio-gpu-3d: fix memory leak -in resource attach backing") -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-7-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/virgl.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c -index 4b8b536edf..79556df094 100644 ---- a/contrib/vhost-user-gpu/virgl.c -+++ b/contrib/vhost-user-gpu/virgl.c -@@ -282,8 +282,11 @@ virgl_resource_attach_backing(VuGpu *g, - return; - } - -- virgl_renderer_resource_attach_iov(att_rb.resource_id, -+ ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, - res_iovs, att_rb.nr_entries); -+ if (ret != 0) { -+ g_free(res_iovs); -+ } - } - - static void --- -2.27.0 - diff --git a/vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch b/vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch deleted file mode 100644 index e67cd9a6f4220e628237a6cee4eeb5f755c67196..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch +++ /dev/null @@ -1,51 +0,0 @@ -From c276538416e9238e352d0f720db57ea1020e555f Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 10:02:08 +0800 -Subject: [PATCH] vhost-user-gpu: fix memory leak while calling - 'vg_resource_unref' (CVE-2021-3544) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -If the guest trigger following sequences, the attach_backing will be leaked: - - vg_resource_create_2d - vg_resource_attach_backing - vg_resource_unref - -This patch fix this by freeing 'res->iov' in vg_resource_destroy. - -Fixes: CVE-2021-3544 -Reported-by: default avatarLi Qiang -virtio-gpu fix: 5e8e3c4c - - ("virtio-gpu: fix resource leak -in virgl_cmd_resource_unref") -Reviewed-by: default avatarPrasad J Pandit -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-5-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/main.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/contrib/vhost-user-gpu/main.c b/contrib/vhost-user-gpu/main.c -index 4f087d6000..43d9851800 100644 ---- a/contrib/vhost-user-gpu/main.c -+++ b/contrib/vhost-user-gpu/main.c -@@ -379,6 +379,7 @@ vg_resource_destroy(VuGpu *g, - } - - vugbm_buffer_destroy(&res->buffer); -+ g_free(res->iov); - pixman_image_unref(res->image); - QTAILQ_REMOVE(&g->reslist, res, next); - g_free(res); --- -2.27.0 - diff --git a/vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch b/vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch deleted file mode 100644 index 8d565004e122e2c0308162fafb5ce3294a69f873..0000000000000000000000000000000000000000 --- a/vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 58e7327879e89700630ca766974a18f9ac55897c Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 15 Jun 2021 09:53:22 +0800 -Subject: [PATCH] vhost-user-gpu: fix resource leak in 'vg_resource_create_2d' - (CVE-2021-3544) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix CVE-2021-3544 - -Call 'vugbm_buffer_destroy' in error path to avoid resource leak. - -Fixes: CVE-2021-3544 -Reported-by: default avatarLi Qiang -Reviewed-by: default avatarPrasad J Pandit -Signed-off-by: default avatarLi Qiang -Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau -Message-Id: <20210516030403.107723-3-liq3ea@163.com> -Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann - -Signed-off-by: Jiajie Li ---- - contrib/vhost-user-gpu/main.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/contrib/vhost-user-gpu/main.c b/contrib/vhost-user-gpu/main.c -index b45d2019b4..f69af7d17f 100644 ---- a/contrib/vhost-user-gpu/main.c -+++ b/contrib/vhost-user-gpu/main.c -@@ -328,6 +328,7 @@ vg_resource_create_2d(VuGpu *g, - g_critical("%s: resource creation failed %d %d %d", - __func__, c2d.resource_id, c2d.width, c2d.height); - g_free(res); -+ vugbm_buffer_destroy(&res->buffer); - cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; - return; - } --- -2.27.0 - diff --git a/vhost-user-quit-infinite-loop-while-used-memslots-is.patch b/vhost-user-quit-infinite-loop-while-used-memslots-is.patch new file mode 100644 index 0000000000000000000000000000000000000000..e6990e38165989e32f2c9b443187e805edcbb23b --- /dev/null +++ b/vhost-user-quit-infinite-loop-while-used-memslots-is.patch @@ -0,0 +1,88 @@ +From f46191f24706a6200cfe607a902b3da45f57c9ad Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 19:24:30 +0800 +Subject: [PATCH] vhost-user: quit infinite loop while used memslots is more + than the backend limit + +When used memslots is more than the backend limit, +the vhost-user netcard would attach fail and quit +infinite loop. + +Signed-off-by: Jinhua Cao +--- + hw/virtio/vhost.c | 9 +++++++++ + include/hw/virtio/vhost.h | 1 + + net/vhost-user.c | 6 ++++++ + 3 files changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index e4809777bc..4c4072951c 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -48,6 +48,8 @@ static struct vhost_log *vhost_log_shm; + static QLIST_HEAD(, vhost_dev) vhost_devices = + QLIST_HEAD_INITIALIZER(vhost_devices); + ++bool used_memslots_exceeded; ++ + bool vhost_has_free_slot(void) + { + struct vhost_dev *hdev; +@@ -1336,9 +1338,11 @@ static bool vhost_dev_used_memslots_is_exceeded(struct vhost_dev *hdev) + hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { + error_report("vhost backend memory slots limit is less" + " than current number of present memory slots"); ++ used_memslots_exceeded = true; + return true; + } + ++ used_memslots_exceeded = false; + return false; + } + +@@ -1895,3 +1899,8 @@ int vhost_net_set_backend(struct vhost_dev *hdev, + + return -1; + } ++ ++bool used_memslots_is_exceeded(void) ++{ ++ return used_memslots_exceeded; ++} +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 58a73e7b7a..86f36f0106 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -154,4 +154,5 @@ int vhost_dev_set_inflight(struct vhost_dev *dev, + struct vhost_inflight *inflight); + int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + struct vhost_inflight *inflight); ++bool used_memslots_is_exceeded(void); + #endif +diff --git a/net/vhost-user.c b/net/vhost-user.c +index d1aefcb9aa..f910a286e4 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -20,6 +20,7 @@ + #include "qemu/error-report.h" + #include "qemu/option.h" + #include "trace.h" ++#include "include/hw/virtio/vhost.h" + + #define VHOST_USER_RECONNECT_TIME (3) + +@@ -369,6 +370,11 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, + net_vhost_user_event, NULL, nc0->name, NULL, + true); ++ if (used_memslots_is_exceeded()) { ++ error_report("used memslots exceeded the backend limit, quit " ++ "loop"); ++ goto err; ++ } + } while (!s->started); + + assert(s->vhost_net); +-- +2.27.0 + diff --git a/vhost-user-remove-VirtQ-notifier-restore.patch b/vhost-user-remove-VirtQ-notifier-restore.patch new file mode 100644 index 0000000000000000000000000000000000000000..fae278a626c64d38606d692ad9febf2c2866ab36 --- /dev/null +++ b/vhost-user-remove-VirtQ-notifier-restore.patch @@ -0,0 +1,100 @@ +From f06e65cb747cbd32f4d12f1d880625c14a8bd9da Mon Sep 17 00:00:00 2001 +From: Xueming Li +Date: Mon, 7 Feb 2022 15:19:28 +0800 +Subject: [PATCH 1/2] vhost-user: remove VirtQ notifier restore + +Notifier set when vhost-user backend asks qemu to mmap an FD and +offset. When vhost-user backend restart or getting killed, VQ notifier +FD and mmap addresses become invalid. After backend restart, MR contains +the invalid address will be restored and fail on notifier access. + +On the other hand, qemu should munmap the notifier, release underlying +hardware resources to enable backend restart and allocate hardware +notifier resources correctly. + +Qemu shouldn't reference and use resources of disconnected backend. + +This patch removes VQ notifier restore, uses the default vhost-user +notifier to avoid invalid address access. + +After backend restart, the backend should ask qemu to install a hardware +notifier if needed. + +Fixes: 44866521bd6e ("vhost-user: support registering external host notifiers") +Cc: qemu-stable@nongnu.org +Signed-off-by: Xueming Li +Message-Id: <20220207071929.527149-2-xuemingl@nvidia.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit e867144b73b3c5009266b6df07d5ff44acfb82c3) +--- + hw/virtio/vhost-user.c | 19 +------------------ + include/hw/virtio/vhost-user.h | 1 - + 2 files changed, 1 insertion(+), 19 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 176cae9244..7b21e09723 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -1145,19 +1145,6 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, + return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); + } + +-static void vhost_user_host_notifier_restore(struct vhost_dev *dev, +- int queue_idx) +-{ +- struct vhost_user *u = dev->opaque; +- VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; +- VirtIODevice *vdev = dev->vdev; +- +- if (n->addr && !n->set) { +- virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true); +- n->set = true; +- } +-} +- + static void vhost_user_host_notifier_remove(struct vhost_dev *dev, + int queue_idx) + { +@@ -1165,17 +1152,14 @@ static void vhost_user_host_notifier_remove(struct vhost_dev *dev, + VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; + VirtIODevice *vdev = dev->vdev; + +- if (n->addr && n->set) { ++ if (n->addr) { + virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); +- n->set = false; + } + } + + static int vhost_user_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { +- vhost_user_host_notifier_restore(dev, ring->index); +- + return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); + } + +@@ -1540,7 +1524,6 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + } + + n->addr = addr; +- n->set = true; + + return 0; + } +diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h +index a9abca3288..f6012b2078 100644 +--- a/include/hw/virtio/vhost-user.h ++++ b/include/hw/virtio/vhost-user.h +@@ -14,7 +14,6 @@ + typedef struct VhostUserHostNotifier { + MemoryRegion mr; + void *addr; +- bool set; + } VhostUserHostNotifier; + + typedef struct VhostUserState { +-- +2.27.0 + diff --git a/vhost-user-save-features-if-the-char-dev-is-closed.patch b/vhost-user-save-features-if-the-char-dev-is-closed.patch deleted file mode 100644 index 9a0d04f4d7d98fd97e84bfba35f99d4871605b37..0000000000000000000000000000000000000000 --- a/vhost-user-save-features-if-the-char-dev-is-closed.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 7b404cae7fa2850d476c29258f03b8e77a5b4bd0 Mon Sep 17 00:00:00 2001 -From: Adrian Moreno -Date: Tue, 24 Sep 2019 18:20:44 +0200 -Subject: [PATCH] vhost-user: save features if the char dev is closed - -That way the state can be correctly restored when the device is opened -again. This might happen if the backend is restarted. - -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1738768 -Reported-by: Pei Zhang -Fixes: 6ab79a20af3a ("do not call vhost_net_cleanup() on running net from char user event") -Cc: ddstreet@canonical.com -Cc: Michael S. Tsirkin -Cc: qemu-stable@nongnu.org -Signed-off-by: Adrian Moreno -Message-Id: <20190924162044.11414-1-amorenoz@redhat.com> -Acked-by: Jason Wang -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit c6beefd674fff8d41b90365dfccad32e53a5abcb) -Signed-off-by: Michael Roth ---- - net/vhost-user.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/net/vhost-user.c b/net/vhost-user.c -index 51921de443..014199d600 100644 ---- a/net/vhost-user.c -+++ b/net/vhost-user.c -@@ -235,6 +235,10 @@ static void chr_closed_bh(void *opaque) - - s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); - -+ if (s->vhost_net) { -+ s->acked_features = vhost_net_get_acked_features(s->vhost_net); -+ } -+ - qmp_set_link(name, false, &err); - - qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, --- -2.23.0 diff --git a/vhost-user-scsi-add-support-for-SPDK-hot-upgrade.patch b/vhost-user-scsi-add-support-for-SPDK-hot-upgrade.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d54935e19501bf8eda7b896bf937cd68f0b161d --- /dev/null +++ b/vhost-user-scsi-add-support-for-SPDK-hot-upgrade.patch @@ -0,0 +1,94 @@ +From 8c52233c08fe66b2e5c79fd514d4f804aa6fe427 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Fri, 11 Feb 2022 20:13:50 +0800 +Subject: [PATCH] vhost-user-scsi: add support for SPDK hot upgrade + +In the hot upgrade scenario, the reconnection mechanism of qemu and SPDK after upgrade + +Signed-off-by: Jinhua Cao +--- + hw/scsi/vhost-user-scsi.c | 42 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c +index 1b2f7eed98..052740a76e 100644 +--- a/hw/scsi/vhost-user-scsi.c ++++ b/hw/scsi/vhost-user-scsi.c +@@ -29,6 +29,9 @@ + #include "hw/virtio/virtio-access.h" + #include "chardev/char-fe.h" + #include "sysemu/sysemu.h" ++#include "qemu/log.h" ++ ++#define VHOST_USER_SCSI_RECONNECT_TIME 3 + + /* Features supported by the host application */ + static const int user_feature_bits[] = { +@@ -59,7 +62,7 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) + ret = vhost_scsi_common_start(vsc); + if (ret < 0) { + error_report("unable to start vhost-user-scsi: %s", strerror(-ret)); +- exit(1); ++ return; + } + } else { + vhost_scsi_common_stop(vsc); +@@ -89,11 +92,43 @@ static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) + { + } + ++static void vhost_user_scsi_event(void *opaque, QEMUChrEvent event) ++{ ++ int ret; ++ VHostUserSCSI *s = (VHostUserSCSI *)opaque; ++ VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); ++ VirtIODevice *vdev = VIRTIO_DEVICE(s); ++ ++ qemu_log("event:%d, vdev status:%d\n", event, vdev->status); ++ ++ /* if CHR_EVENT_CLOSED, do nothing */ ++ if (event != CHR_EVENT_OPENED) { ++ return; ++ }; ++ ++ /* if status of vdev is not DRIVER_OK, just waiting. ++ * vsc should start when status change to DRIVER_OK */ ++ if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { ++ return; ++ } ++ ++ /* vsc may not fully start because of vhost app stopping */ ++ if (vsc->dev.started) { ++ vhost_scsi_common_stop(vsc); ++ } ++ ++ ret = vhost_scsi_common_start(vsc); ++ if (ret < 0) { ++ qemu_log("unable to start vhost-user-scsi: %s\n", strerror(-ret)); ++ } ++} ++ + static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) + { + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + VHostUserSCSI *s = VHOST_USER_SCSI(dev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); ++ Chardev *chr; + struct vhost_virtqueue *vqs = NULL; + Error *err = NULL; + int ret; +@@ -132,6 +167,11 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) + vsc->lun = 0; + vsc->target = vs->conf.boot_tpgt; + ++ chr = qemu_chr_fe_get_driver(&vs->conf.chardev); ++ qemu_chr_set_reconnect_time(chr, VHOST_USER_SCSI_RECONNECT_TIME); ++ qemu_chr_fe_set_handlers(&vs->conf.chardev, NULL, NULL, ++ vhost_user_scsi_event, NULL, s, NULL, true); ++ + return; + + free_vhost: +-- +2.27.0 + diff --git a/vhost-user-scsi-prevent-using-uninitialized-vqs.patch b/vhost-user-scsi-prevent-using-uninitialized-vqs.patch deleted file mode 100644 index d1bf2a087bf4fcbedf2a8c0fbb8b62188737d1e7..0000000000000000000000000000000000000000 --- a/vhost-user-scsi-prevent-using-uninitialized-vqs.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 4d8f2885b3f1219c3df2cf1a00dc0c55b23ee715 Mon Sep 17 00:00:00 2001 -From: Raphael Norwitz -Date: Tue, 14 Apr 2020 21:39:05 +0800 -Subject: [PATCH] vhost-user-scsi: prevent using uninitialized vqs - -Of the 3 virtqueues, seabios only sets cmd, leaving ctrl -and event without a physical address. This can cause -vhost_verify_ring_part_mapping to return ENOMEM, causing -the following logs: - -qemu-system-x86_64: Unable to map available ring for ring 0 -qemu-system-x86_64: Verify ring failure on region 0 - -The qemu commit e6cc11d64fc998c11a4dfcde8fda3fc33a74d844 -has already resolved the issue for vhost scsi devices but -the fix was never applied to vhost-user scsi devices. - -Signed-off-by: Raphael Norwitz -Reviewed-by: Stefan Hajnoczi -Message-id: 1560299717-177734-1-git-send-email-raphael.norwitz@nutanix.com -Message-Id: <1560299717-177734-1-git-send-email-raphael.norwitz@nutanix.com> -Signed-off-by: Stefan Hajnoczi -(cherry-picked from commit 5d4c1ed3d46d7e2010b389fe5f3376f605182ab0) ---- - hw/scsi/vhost-user-scsi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c -index fcee67d5..affc2431 100644 ---- a/hw/scsi/vhost-user-scsi.c -+++ b/hw/scsi/vhost-user-scsi.c -@@ -91,7 +91,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) - } - - vsc->dev.nvqs = 2 + vs->conf.num_queues; -- vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); -+ vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); - vsc->dev.vq_index = 0; - vsc->dev.backend_features = 0; - vqs = vsc->dev.vqs; --- -2.23.0 diff --git a/vhost-user-stick-to-errno-error-return-convention.patch b/vhost-user-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000000000000000000000000000000000000..037c3a28415b4685ee875906dfa72d85e3c79c3b --- /dev/null +++ b/vhost-user-stick-to-errno-error-return-convention.patch @@ -0,0 +1,1100 @@ +From f6c384a73aaaa7dfc52ed3ceb8ec135f33551629 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:55 +0800 +Subject: [PATCH] vhost-user: stick to -errno error return convention + +VhostOps methods in user_ops are not very consistent in their error +returns: some return negated errno while others just -1. + +Make sure all of them consistently return negated errno. This also +helps error propagation from the functions being called inside. +Besides, this synchronizes the error return convention with the other +two vhost backends, kernel and vdpa, and will therefore allow for +consistent error propagation in the generic vhost code (in a followup +patch). + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-9-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user.c | 401 +++++++++++++++++++++++------------------ + 1 file changed, 223 insertions(+), 178 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 24f80d5d18..358dc82010 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -283,9 +283,10 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + + r = qemu_chr_fe_read_all(chr, p, size); + if (r != size) { ++ int saved_errno = errno; + error_report("Failed to read msg header. Read %d instead of %d." + " Original request %d.", r, size, msg->hdr.request); +- return -1; ++ return r < 0 ? -saved_errno : -EIO; + } + + /* validate received flags */ +@@ -293,7 +294,7 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + error_report("Failed to read msg header." + " Flags 0x%x instead of 0x%x.", msg->hdr.flags, + VHOST_USER_REPLY_MASK | VHOST_USER_VERSION); +- return -1; ++ return -EPROTO; + } + + return 0; +@@ -317,8 +318,9 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + uint8_t *p = (uint8_t *) msg; + int r, size; + +- if (vhost_user_read_header(dev, msg) < 0) { +- data->ret = -1; ++ r = vhost_user_read_header(dev, msg); ++ if (r < 0) { ++ data->ret = r; + goto end; + } + +@@ -327,7 +329,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + error_report("Failed to read msg header." + " Size %d exceeds the maximum %zu.", msg->hdr.size, + VHOST_USER_PAYLOAD_SIZE); +- data->ret = -1; ++ data->ret = -EPROTO; + goto end; + } + +@@ -336,9 +338,10 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + size = msg->hdr.size; + r = qemu_chr_fe_read_all(chr, p, size); + if (r != size) { ++ int saved_errno = errno; + error_report("Failed to read msg payload." + " Read %d instead of %d.", r, msg->hdr.size); +- data->ret = -1; ++ data->ret = r < 0 ? -saved_errno : -EIO; + goto end; + } + } +@@ -421,24 +424,26 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + static int process_message_reply(struct vhost_dev *dev, + const VhostUserMsg *msg) + { ++ int ret; + VhostUserMsg msg_reply; + + if ((msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) == 0) { + return 0; + } + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + if (msg_reply.hdr.request != msg->hdr.request) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + msg->hdr.request, msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + +- return msg_reply.payload.u64 ? -1 : 0; ++ return msg_reply.payload.u64 ? -EIO : 0; + } + + static bool vhost_user_one_time_request(VhostUserRequest request) +@@ -475,14 +480,15 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, + + if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) { + error_report("Failed to set msg fds."); +- return -1; ++ return -EINVAL; + } + + ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size); + if (ret != size) { ++ int saved_errno = errno; + error_report("Failed to write msg." + " Wrote %d instead of %d.", ret, size); +- return -1; ++ return ret < 0 ? -saved_errno : -EIO; + } + + return 0; +@@ -505,6 +511,7 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + size_t fd_num = 0; + bool shmfd = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_LOG_SHMFD); ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_SET_LOG_BASE, + .hdr.flags = VHOST_USER_VERSION, +@@ -517,21 +524,23 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + fds[fd_num++] = log->fd; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + + if (shmfd) { + msg.hdr.size = 0; +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_SET_LOG_BASE) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_SET_LOG_BASE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + } + +@@ -591,7 +600,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, + u->region_rb[i] = mr->ram_block; + } else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) { + error_report("Failed preparing vhost-user memory table msg"); +- return -1; ++ return -ENOBUFS; + } + vhost_user_fill_msg_region(®ion_buffer, reg, offset); + msg->payload.memory.regions[*fd_num] = region_buffer; +@@ -607,14 +616,14 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, + if (!*fd_num) { + error_report("Failed initializing vhost-user memory map, " + "consider using -object memory-backend-file share=on"); +- return -1; ++ return -EINVAL; + } + + msg->hdr.size = sizeof(msg->payload.memory.nregions); + msg->hdr.size += sizeof(msg->payload.memory.padding); + msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion); + +- return 1; ++ return 0; + } + + static inline bool reg_equal(struct vhost_memory_region *shadow_reg, +@@ -744,8 +753,9 @@ static int send_remove_regions(struct vhost_dev *dev, + vhost_user_fill_msg_region(®ion_buffer, shadow_reg, 0); + msg->payload.mem_reg.region = region_buffer; + +- if (vhost_user_write(dev, msg, &fd, 1) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, &fd, 1); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -804,15 +814,17 @@ static int send_add_regions(struct vhost_dev *dev, + vhost_user_fill_msg_region(®ion_buffer, reg, offset); + msg->payload.mem_reg.region = region_buffer; + +- if (vhost_user_write(dev, msg, &fd, 1) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, &fd, 1); ++ if (ret < 0) { ++ return ret; + } + + if (track_ramblocks) { + uint64_t reply_gpa; + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + reply_gpa = msg_reply.payload.mem_reg.region.guest_phys_addr; +@@ -822,7 +834,7 @@ static int send_add_regions(struct vhost_dev *dev, + "Expected %d received %d", __func__, + VHOST_USER_ADD_MEM_REG, + msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + + /* +@@ -833,7 +845,7 @@ static int send_add_regions(struct vhost_dev *dev, + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg->hdr.size); +- return -1; ++ return -EPROTO; + } + + /* Get the postcopy client base from the backend's reply. */ +@@ -849,7 +861,7 @@ static int send_add_regions(struct vhost_dev *dev, + "Got guest physical address %" PRIX64 ", expected " + "%" PRIX64, __func__, reply_gpa, + dev->mem->regions[reg_idx].guest_phys_addr); +- return -1; ++ return -EPROTO; + } + } else if (reply_supported) { + ret = process_message_reply(dev, msg); +@@ -890,6 +902,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS]; + uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {}; + int nr_add_reg, nr_rem_reg; ++ int ret; + + msg->hdr.size = sizeof(msg->payload.mem_reg); + +@@ -897,16 +910,20 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg, + shadow_pcb, track_ramblocks); + +- if (nr_rem_reg && send_remove_regions(dev, rem_reg, nr_rem_reg, msg, +- reply_supported) < 0) +- { +- goto err; ++ if (nr_rem_reg) { ++ ret = send_remove_regions(dev, rem_reg, nr_rem_reg, msg, ++ reply_supported); ++ if (ret < 0) { ++ goto err; ++ } + } + +- if (nr_add_reg && send_add_regions(dev, add_reg, nr_add_reg, msg, +- shadow_pcb, reply_supported, track_ramblocks) < 0) +- { +- goto err; ++ if (nr_add_reg) { ++ ret = send_add_regions(dev, add_reg, nr_add_reg, msg, shadow_pcb, ++ reply_supported, track_ramblocks); ++ if (ret < 0) { ++ goto err; ++ } + } + + if (track_ramblocks) { +@@ -921,8 +938,9 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + msg->hdr.size = sizeof(msg->payload.u64); + msg->payload.u64 = 0; /* OK */ + +- if (vhost_user_write(dev, msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + } + +@@ -934,7 +952,7 @@ err: + sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); + } + +- return -1; ++ return ret; + } + + static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, +@@ -947,6 +965,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + size_t fd_num = 0; + VhostUserMsg msg_reply; + int region_i, msg_i; ++ int ret; + + VhostUserMsg msg = { + .hdr.flags = VHOST_USER_VERSION, +@@ -964,29 +983,32 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + } + + if (config_mem_slots) { +- if (vhost_user_add_remove_regions(dev, &msg, reply_supported, +- true) < 0) { +- return -1; ++ ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, true); ++ if (ret < 0) { ++ return ret; + } + } else { +- if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, +- true) < 0) { +- return -1; ++ ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ++ true); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) { + error_report("%s: Received unexpected msg type." + "Expected %d received %d", __func__, + VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + + /* +@@ -997,7 +1019,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg.hdr.size); +- return -1; ++ return -EPROTO; + } + + memset(u->postcopy_client_bases, 0, +@@ -1027,7 +1049,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + error_report("%s: postcopy reply not fully consumed " + "%d vs %zd", + __func__, msg_i, fd_num); +- return -1; ++ return -EIO; + } + + /* +@@ -1038,8 +1060,9 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + /* TODO: Use this for failure cases as well with a bad value. */ + msg.hdr.size = sizeof(msg.payload.u64); + msg.payload.u64 = 0; /* OK */ +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + } + +@@ -1058,6 +1081,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, + bool config_mem_slots = + virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS); ++ int ret; + + if (do_postcopy) { + /* +@@ -1077,17 +1101,20 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, + } + + if (config_mem_slots) { +- if (vhost_user_add_remove_regions(dev, &msg, reply_supported, +- false) < 0) { +- return -1; ++ ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, false); ++ if (ret < 0) { ++ return ret; + } + } else { +- if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, +- false) < 0) { +- return -1; ++ ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ++ false); ++ if (ret < 0) { ++ return ret; + } +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -1112,14 +1139,10 @@ static int vhost_user_set_vring_endian(struct vhost_dev *dev, + + if (!cross_endian) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_set_vring(struct vhost_dev *dev, +@@ -1133,11 +1156,7 @@ static int vhost_set_vring(struct vhost_dev *dev, + .hdr.size = sizeof(msg.payload.state), + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_set_vring_num(struct vhost_dev *dev, +@@ -1180,16 +1199,25 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) + int i; + + if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) { +- return -1; ++ return -EINVAL; + } + + for (i = 0; i < dev->nvqs; ++i) { ++ int ret; + struct vhost_vring_state state = { + .index = dev->vq_index + i, + .num = enable, + }; + +- vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); ++ ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); ++ if (ret < 0) { ++ /* ++ * Restoring the previous state is likely infeasible, as well as ++ * proceeding regardless the error, so just bail out and hope for ++ * the device-level recovery. ++ */ ++ return ret; ++ } + } + + return 0; +@@ -1198,6 +1226,7 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) + static int vhost_user_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_VRING_BASE, + .hdr.flags = VHOST_USER_VERSION, +@@ -1208,23 +1237,25 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, + + vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_VRING_BASE) { + error_report("Received unexpected msg type. Expected %d received %d", + VHOST_USER_GET_VRING_BASE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.state)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + *ring = msg.payload.state; +@@ -1251,11 +1282,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev, + msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, fds, fd_num); + } + + static int vhost_user_set_vring_kick(struct vhost_dev *dev, +@@ -1273,6 +1300,7 @@ static int vhost_user_set_vring_call(struct vhost_dev *dev, + + static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = request, + .hdr.flags = VHOST_USER_VERSION, +@@ -1282,23 +1310,25 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) + return 0; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != request) { + error_report("Received unexpected msg type. Expected %d received %d", + request, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.u64)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + *u64 = msg.payload.u64; +@@ -1336,6 +1366,7 @@ static int enforce_reply(struct vhost_dev *dev, + static int vhost_user_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_SET_VRING_ADDR, + .hdr.flags = VHOST_USER_VERSION, +@@ -1356,8 +1387,9 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (wait_for_reply) { +@@ -1376,6 +1408,7 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, + .payload.u64 = u64, + .hdr.size = sizeof(msg.payload.u64), + }; ++ int ret; + + if (wait_for_reply) { + bool reply_supported = virtio_has_feature(dev->protocol_features, +@@ -1385,8 +1418,9 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, + } + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (wait_for_reply) { +@@ -1423,11 +1457,7 @@ static int vhost_user_set_owner(struct vhost_dev *dev) + .hdr.flags = VHOST_USER_VERSION, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -EPROTO; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_get_max_memslots(struct vhost_dev *dev, +@@ -1458,26 +1488,16 @@ static int vhost_user_reset_device(struct vhost_dev *dev) + ? VHOST_USER_RESET_DEVICE + : VHOST_USER_RESET_OWNER; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) + { +- int ret = -1; +- +- if (!dev->config_ops) { +- return -1; ++ if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { ++ return -ENOSYS; + } + +- if (dev->config_ops->vhost_dev_config_notifier) { +- ret = dev->config_ops->vhost_dev_config_notifier(dev); +- } +- +- return ret; ++ return dev->config_ops->vhost_dev_config_notifier(dev); + } + + static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, +@@ -1496,7 +1516,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) || + vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) { +- return -1; ++ return -EINVAL; + } + + n = &user->notifier[queue_idx]; +@@ -1509,13 +1529,13 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + + /* Sanity check. */ + if (area->size != page_size) { +- return -1; ++ return -EINVAL; + } + + addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, area->offset); + if (addr == MAP_FAILED) { +- return -1; ++ return -EFAULT; + } + + name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", +@@ -1531,7 +1551,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { + object_unparent(OBJECT(&n->mr)); + munmap(addr, page_size); +- return -1; ++ return -ENXIO; + } + + n->addr = addr; +@@ -1660,14 +1680,15 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { ++ int saved_errno = errno; + error_report("socketpair() failed"); +- return -1; ++ return -saved_errno; + } + + ioc = QIO_CHANNEL(qio_channel_socket_new_fd(sv[0], &local_err)); + if (!ioc) { + error_report_err(local_err); +- return -1; ++ return -ECONNREFUSED; + } + u->slave_ioc = ioc; + slave_update_read_handler(dev, NULL); +@@ -1774,35 +1795,38 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + int ufd; ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_POSTCOPY_ADVISE, + .hdr.flags = VHOST_USER_VERSION, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_advise to vhost"); +- return -1; ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { + error_setg(errp, "Failed to get postcopy_advise reply from vhost"); +- return -1; ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_POSTCOPY_ADVISE) { + error_setg(errp, "Unexpected msg type. Expected %d received %d", + VHOST_USER_POSTCOPY_ADVISE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size) { + error_setg(errp, "Received bad msg size."); +- return -1; ++ return -EPROTO; + } + ufd = qemu_chr_fe_get_msgfd(chr); + if (ufd < 0) { + error_setg(errp, "%s: Failed to get ufd", __func__); +- return -1; ++ return -EIO; + } + qemu_set_nonblock(ufd); + +@@ -1816,7 +1840,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) + return 0; + #else + error_setg(errp, "Postcopy not supported on non-Linux systems"); +- return -1; ++ return -ENOSYS; + #endif + } + +@@ -1832,10 +1856,13 @@ static int vhost_user_postcopy_listen(struct vhost_dev *dev, Error **errp) + .hdr.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, + }; + u->postcopy_listen = true; ++ + trace_vhost_user_postcopy_listen(); +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_listen to vhost"); +- return -1; ++ return ret; + } + + ret = process_message_reply(dev, &msg); +@@ -1860,9 +1887,11 @@ static int vhost_user_postcopy_end(struct vhost_dev *dev, Error **errp) + struct vhost_user *u = dev->opaque; + + trace_vhost_user_postcopy_end_entry(); +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_end to vhost"); +- return -1; ++ return ret; + } + + ret = process_message_reply(dev, &msg); +@@ -2141,7 +2170,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) + + return vhost_user_write(dev, &msg, NULL, 0); + } +- return -1; ++ return -ENOTSUP; + } + + static bool vhost_user_can_merge(struct vhost_dev *dev, +@@ -2162,6 +2191,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + VhostUserMsg msg; + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); ++ int ret; + + if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) { + return 0; +@@ -2175,8 +2205,9 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + /* If reply_ack supported, slave has to ack specified MTU is valid */ +@@ -2190,6 +2221,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev, + struct vhost_iotlb_msg *imsg) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_IOTLB_MSG, + .hdr.size = sizeof(msg.payload.iotlb), +@@ -2197,8 +2229,9 @@ static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev, + .payload.iotlb = *imsg, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -EFAULT; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + return process_message_reply(dev, &msg); +@@ -2213,6 +2246,7 @@ static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled) + static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + uint32_t config_len, Error **errp) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_CONFIG, + .hdr.flags = VHOST_USER_VERSION, +@@ -2229,26 +2263,28 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + + msg.payload.config.offset = 0; + msg.payload.config.size = config_len; +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_setg_errno(errp, EPROTO, "vhost_get_config failed"); +- return -EPROTO; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "vhost_get_config failed"); ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- error_setg_errno(errp, EPROTO, "vhost_get_config failed"); +- return -EPROTO; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "vhost_get_config failed"); ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_CONFIG) { + error_setg(errp, + "Received unexpected msg type. Expected %d received %d", + VHOST_USER_GET_CONFIG, msg.hdr.request); +- return -EINVAL; ++ return -EPROTO; + } + + if (msg.hdr.size != VHOST_USER_CONFIG_HDR_SIZE + config_len) { + error_setg(errp, "Received bad msg size."); +- return -EINVAL; ++ return -EPROTO; + } + + memcpy(config, msg.payload.config.region, config_len); +@@ -2259,6 +2295,7 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags) + { ++ int ret; + uint8_t *p; + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); +@@ -2271,7 +2308,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { +- return -1; ++ return -ENOTSUP; + } + + if (reply_supported) { +@@ -2279,7 +2316,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + } + + if (size > VHOST_USER_MAX_CONFIG_SIZE) { +- return -1; ++ return -EINVAL; + } + + msg.payload.config.offset = offset, +@@ -2288,8 +2325,9 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + p = msg.payload.config.region; + memcpy(p, data, size); + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -2303,6 +2341,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + void *session_info, + uint64_t *session_id) + { ++ int ret; + bool crypto_session = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); + CryptoDevBackendSymSessionInfo *sess_info = session_info; +@@ -2316,7 +2355,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + + if (!crypto_session) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + + memcpy(&msg.payload.session.session_setup_data, sess_info, +@@ -2329,31 +2368,35 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + memcpy(&msg.payload.session.auth_key, sess_info->auth_key, + sess_info->auth_key_len); + } +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_report("vhost_user_write() return -1, create session failed"); +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_report("vhost_user_write() return %d, create session failed", ++ ret); ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- error_report("vhost_user_read() return -1, create session failed"); +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ error_report("vhost_user_read() return %d, create session failed", ++ ret); ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) { + error_report("Received unexpected msg type. Expected %d received %d", + VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.session)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + if (msg.payload.session.session_id < 0) { + error_report("Bad session id: %" PRId64 "", + msg.payload.session.session_id); +- return -1; ++ return -EINVAL; + } + *session_id = msg.payload.session.session_id; + +@@ -2363,6 +2406,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + static int + vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) + { ++ int ret; + bool crypto_session = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); + VhostUserMsg msg = { +@@ -2374,12 +2418,14 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) + + if (!crypto_session) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_report("vhost_user_write() return -1, close session failed"); +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_report("vhost_user_write() return %d, close session failed", ++ ret); ++ return ret; + } + + return 0; +@@ -2401,6 +2447,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + { + void *addr; + int fd; ++ int ret; + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + VhostUserMsg msg = { +@@ -2416,24 +2463,26 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + return 0; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.inflight)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + if (!msg.payload.inflight.mmap_size) { +@@ -2443,7 +2492,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + fd = qemu_chr_fe_get_msgfd(chr); + if (fd < 0) { + error_report("Failed to get mem fd"); +- return -1; ++ return -EIO; + } + + addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE, +@@ -2452,7 +2501,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + if (addr == MAP_FAILED) { + error_report("Failed to mmap mem fd"); + close(fd); +- return -1; ++ return -EFAULT; + } + + inflight->addr = addr; +@@ -2482,11 +2531,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev, + return 0; + } + +- if (vhost_user_write(dev, &msg, &inflight->fd, 1) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, &inflight->fd, 1); + } + + bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) +-- +2.27.0 + diff --git a/vhost-vdpa-add-VHOST_BACKEND_F_BYTEMAPLOG.patch b/vhost-vdpa-add-VHOST_BACKEND_F_BYTEMAPLOG.patch new file mode 100644 index 0000000000000000000000000000000000000000..d40dd186cc2313bcf9321399b8d12f916066b473 --- /dev/null +++ b/vhost-vdpa-add-VHOST_BACKEND_F_BYTEMAPLOG.patch @@ -0,0 +1,49 @@ +From b0c67874628455a869ca1afde0de44572c70d5b9 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 14:49:53 +0800 +Subject: [PATCH] vhost-vdpa: add VHOST_BACKEND_F_BYTEMAPLOG + +support VHOST_BACKEND_F_BYTEMAPLOG to support vhost +device bytemap logging. + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 7 ++++--- + include/standard-headers/linux/vhost_types.h | 2 ++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 986fc795bf..e1c90cf6c2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -660,9 +660,10 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + { + uint64_t features; +- uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | +- 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | +- 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID; ++ uint64_t f = BIT_ULL(VHOST_BACKEND_F_IOTLB_MSG_V2) | ++ BIT_ULL(VHOST_BACKEND_F_IOTLB_BATCH) | ++ BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID) | ++ BIT_ULL(VHOST_BACKEND_F_BYTEMAPLOG); + int r; + + if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { +diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h +index 17833e320e..3801d95182 100644 +--- a/include/standard-headers/linux/vhost_types.h ++++ b/include/standard-headers/linux/vhost_types.h +@@ -157,5 +157,7 @@ struct vhost_vdpa_iova_range { + * message + */ + #define VHOST_BACKEND_F_IOTLB_ASID 0x3 ++/* device can use bytemap log */ ++#define VHOST_BACKEND_F_BYTEMAPLOG 0x3f + + #endif +-- +2.27.0 + diff --git a/vhost-vdpa-add-memslot-getter-setter-for-vhost-vdpa.patch b/vhost-vdpa-add-memslot-getter-setter-for-vhost-vdpa.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a35b3d496a14d0b69c2077d851de4fd04b247b4 --- /dev/null +++ b/vhost-vdpa-add-memslot-getter-setter-for-vhost-vdpa.patch @@ -0,0 +1,70 @@ +From f32dbb81662b5c74d1a929ff8a58fec6a920a34a Mon Sep 17 00:00:00 2001 +From: Pengyuan +Date: Mon, 7 Nov 2022 10:11:06 +0800 +Subject: [PATCH 7/7] vhost-vdpa: add memslot getter/setter for vhost-vdpa + +When vhost-vdpa is used as the virtio-net-pci backend on +the ARM64 platform, a null pointer access is triggered. + +#0 0x0000000000000000 in () +#1 0x0000aaaaab63bdcc in vhost_dev_used_memslots_is_exceeded (hdev=0xaaaaac632420) at ../hw/virtio/vhost.c:1341 +#2 0x0000aaaaab63c420 in vhost_dev_init (hdev=0xaaaaac632420, opaque=0xfffff4321190, backend_type=VHOST_BACKEND_TYPE_VDPA, busyloop_timeout=0, errp=0xfffffffff210) at ../hw/virtio/vhost.c:1461 +#3 0x0000aaaaab0d6ad8 in vhost_net_init (options=0xfffffffff290) at ../hw/net/vhost_net.c:247 +#4 0x0000aaaaaaf05f40 in vhost_vdpa_add (ncs=0xfffff4321010, be=0xfffff4321190, queue_pair_index=0, nvqs=2) at ../net/vhost-vdpa.c:109 +#5 0x0000aaaaaaf06358 in net_vhost_vdpa_init (peer=0x0, device=0xaaaaaba47140 "vhost-vdpa", name=0xaaaaac63a640 "vhost-vdpa0", vdpa_device_fd=12, queue_pair_index=0, nvqs=2, is_datapath=true) at ../net/vhost-vdpa.c:214 +#6 0x0000aaaaaaf066ac in net_init_vhost_vdpa (netdev=0xaaaaac6322a0, name=0xaaaaac63a640 "vhost-vdpa0", peer=0x0, errp=0xaaaaac26ea20 ) at ../net/vhost-vdpa.c:291 +#7 0x0000aaaaaaef7f94 in net_client_init1 (netdev=0xaaaaac6322a0, is_netdev=true, errp=0xaaaaac26ea20 ) at ../net/net.c:1064 +#8 0x0000aaaaaaef8334 in net_client_init (opts=0xaaaaac32bf80, is_netdev=true, errp=0xaaaaac26ea20 ) at ../net/net.c:1162 +#9 0x0000aaaaaaef90a4 in net_init_netdev (dummy=0x0, opts=0xaaaaac32bf80, errp=0xaaaaac26ea20 ) at ../net/net.c:1494 +#10 0x0000aaaaab97aee0 in qemu_opts_foreach (list=0xaaaaac1038c0 , func=0xaaaaaaef9040 , opaque=0x0, errp=0xaaaaac26ea20 ) at ../util/qemu-option.c:1135 +#11 0x0000aaaaaaef93a4 in net_init_clients (errp=0xaaaaac26ea20 ) at ../net/net.c:1567 +#12 0x0000aaaaab586f8c in qemu_create_late_backends () at ../softmmu/vl.c:2000 +#13 0x0000aaaaab58b234 in qemu_init (argc=37, argv=0xfffffffff848, envp=0xfffffffff978) at ../softmmu/vl.c:3763 +#14 0x0000aaaaaae1f7f8 in main (argc=37, argv=0xfffffffff848, envp=0xfffffffff978) at ../softmmu/main.c:50 + +Fixes: 185d7efe768 ("vhost-user: add separate memslot counter for vhost-user") +Signed-off-by:Pengyuan Zhao +--- + hw/virtio/vhost-vdpa.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index bcaf00e09f..f285edb786 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -24,6 +24,8 @@ + #include "trace.h" + #include "qemu-common.h" + ++static unsigned int vhost_vdpa_used_memslots; ++ + /* + * Return one past the end of the end of section. Be careful with uint64_t + * conversions! +@@ -763,6 +765,16 @@ static bool vhost_vdpa_force_iommu(struct vhost_dev *dev) + return true; + } + ++static void vhost_vdpa_set_used_memslots(struct vhost_dev *dev) ++{ ++ vhost_vdpa_used_memslots = dev->mem->nregions; ++} ++ ++static unsigned int vhost_vdpa_get_used_memslots(void) ++{ ++ return vhost_vdpa_used_memslots; ++} ++ + const VhostOps vdpa_ops = { + .backend_type = VHOST_BACKEND_TYPE_VDPA, + .vhost_backend_init = vhost_vdpa_init, +@@ -795,4 +807,6 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, ++ .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/vhost-vdpa-add-migration-log-ops-for-VhostOps.patch b/vhost-vdpa-add-migration-log-ops-for-VhostOps.patch new file mode 100644 index 0000000000000000000000000000000000000000..9de17d74f0dd9ef3cdd260e53f994272fff96c35 --- /dev/null +++ b/vhost-vdpa-add-migration-log-ops-for-VhostOps.patch @@ -0,0 +1,129 @@ +From 51c8cb0fa2481be78282e7ea8f24a3f97083e2fd Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Mon, 4 Dec 2023 15:04:25 +0800 +Subject: [PATCH] vhost-vdpa: add migration log ops for VhostOps + +Implement vhost_set_log_size for setting buffer size for logging. +Implement vhost_set_log_fd to specify an eventfd to signal on log write. +Implement vhost_log_sync for getting dirtymap logged by vhost backend. + +Signed-off-by: libai +Signed-off-by: jiangdongxu +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 37 +++++++++++++++++++++++++++++++ + include/hw/virtio/vhost-backend.h | 8 +++++++ + linux-headers/linux/vhost.h | 4 ++++ + 3 files changed, 49 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index e1c90cf6c2..7663d78b43 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1146,6 +1146,30 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + return vhost_vdpa_call(dev, VHOST_SET_LOG_BASE, &base); + } + ++static int vhost_vdpa_set_log_fd(struct vhost_dev *dev, int fd, ++ struct vhost_log *log) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { ++ return 0; ++ } ++ ++ return vhost_vdpa_call(dev, VHOST_SET_LOG_FD, &fd); ++} ++ ++static int vhost_vdpa_set_log_size(struct vhost_dev *dev, uint64_t size, ++ struct vhost_log *log) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ uint64_t logsize = size * sizeof(*(log->log)); ++ ++ if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { ++ return 0; ++ } ++ ++ return vhost_vdpa_call(dev, VHOST_SET_LOG_SIZE, &logsize); ++} ++ + static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) + { +@@ -1294,11 +1318,23 @@ static unsigned int vhost_vdpa_get_used_memslots(void) + return vhost_vdpa_used_memslots; + } + ++static int vhost_vdpa_log_sync(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { ++ return 0; ++ } ++ ++ return vhost_vdpa_call(dev, VHOST_LOG_SYNC, NULL); ++} ++ + const VhostOps vdpa_ops = { + .backend_type = VHOST_BACKEND_TYPE_VDPA, + .vhost_backend_init = vhost_vdpa_init, + .vhost_backend_cleanup = vhost_vdpa_cleanup, + .vhost_set_log_base = vhost_vdpa_set_log_base, ++ .vhost_set_log_size = vhost_vdpa_set_log_size, ++ .vhost_set_log_fd = vhost_vdpa_set_log_fd, + .vhost_set_vring_addr = vhost_vdpa_set_vring_addr, + .vhost_set_vring_num = vhost_vdpa_set_vring_num, + .vhost_set_vring_base = vhost_vdpa_set_vring_base, +@@ -1326,6 +1362,7 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_log_sync = vhost_vdpa_log_sync, + .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index bd1c7dfe4f..86154dd0b2 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -53,6 +53,11 @@ typedef int (*vhost_scsi_get_abi_version_op)(struct vhost_dev *dev, + int *version); + typedef int (*vhost_set_log_base_op)(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log); ++typedef int (*vhost_set_log_size_op)(struct vhost_dev *dev, uint64_t size, ++ struct vhost_log *log); ++typedef int (*vhost_set_log_fd_op)(struct vhost_dev *dev, int fd, ++ struct vhost_log *log); ++typedef int (*vhost_log_sync_op)(struct vhost_dev *dev); + typedef int (*vhost_set_mem_table_op)(struct vhost_dev *dev, + struct vhost_memory *mem); + typedef int (*vhost_set_vring_addr_op)(struct vhost_dev *dev, +@@ -141,6 +146,9 @@ typedef struct VhostOps { + vhost_scsi_clear_endpoint_op vhost_scsi_clear_endpoint; + vhost_scsi_get_abi_version_op vhost_scsi_get_abi_version; + vhost_set_log_base_op vhost_set_log_base; ++ vhost_set_log_size_op vhost_set_log_size; ++ vhost_set_log_fd_op vhost_set_log_fd; ++ vhost_log_sync_op vhost_log_sync; + vhost_set_mem_table_op vhost_set_mem_table; + vhost_set_vring_addr_op vhost_set_vring_addr; + vhost_set_vring_endian_op vhost_set_vring_endian; +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index b6ded7f831..65c6b49788 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -43,6 +43,10 @@ + * The bit is set using an atomic 32 bit operation. */ + /* Set base address for logging. */ + #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) ++/* Set buffer size for logging */ ++#define VHOST_SET_LOG_SIZE _IOW(VHOST_VIRTIO, 0x05, __u64) ++/* Logging sync */ ++#define VHOST_LOG_SYNC _IO(VHOST_VIRTIO, 0x06) + /* Specify an eventfd file descriptor to signal on log write. */ + #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) + +-- +2.27.0 + diff --git a/vhost-vdpa-add-support-for-config-interrupt-new.patch b/vhost-vdpa-add-support-for-config-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d6739558daacf62d115e06c041c2a45d4fa45dd --- /dev/null +++ b/vhost-vdpa-add-support-for-config-interrupt-new.patch @@ -0,0 +1,62 @@ +From 1a5b6648f563f7991fba0c4cb07a3a4d05834c83 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:46 +0800 +Subject: [PATCH] vhost-vdpa: add support for config interrupt + +Add new call back function in vhost-vdpa, The function +vhost_set_config_call can set the event fd to kernel. +This function will be called in the vhost_dev_start +and vhost_dev_stop + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-6-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 + + hw/virtio/vhost-vdpa.c | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index edbbbeb621..0396518241 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -61,6 +61,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 ++vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8b44f5a7b8..c9289e2c01 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -719,6 +719,13 @@ static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) + return 0; + } + ++static int vhost_vdpa_set_config_call(struct vhost_dev *dev, ++ int fd) ++{ ++ trace_vhost_vdpa_set_config_call(dev, fd); ++ return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); ++} ++ + static void vhost_vdpa_dump_config(struct vhost_dev *dev, const uint8_t *config, + uint32_t config_len) + { +@@ -1311,6 +1318,7 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/vhost-vdpa-add-support-for-config-interrupt.patch b/vhost-vdpa-add-support-for-config-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..f154b19ab4a31ce7f47dda01f5b2405ac3402d42 --- /dev/null +++ b/vhost-vdpa-add-support-for-config-interrupt.patch @@ -0,0 +1,59 @@ +From cc9df379f703274eb600dd6af7dbacae4d457d5f Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:51 +0800 +Subject: [PATCH] vhost-vdpa: add support for config interrupt + +Add new call back function in vhost-vdpa, this function will +set the event fd to kernel. This function will be called +in the vhost_dev_start and vhost_dev_stop + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-6-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 + + hw/virtio/vhost-vdpa.c | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 650e521e35..39c36ff7a6 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -53,6 +53,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 ++vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 287025ef93..b7bbd65cdd 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -728,6 +728,12 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } ++static int vhost_vdpa_set_config_call(struct vhost_dev *dev, ++ int fd) ++{ ++ trace_vhost_vdpa_set_config_call(dev, fd); ++ return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); ++} + + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) +@@ -808,6 +814,7 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch b/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch new file mode 100644 index 0000000000000000000000000000000000000000..c17fb9d8b40cbe3034062f1a17808de59f21a76c --- /dev/null +++ b/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch @@ -0,0 +1,114 @@ +From 2feaf4260eae797c518c86d181f24eca5948b8b0 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Sat, 8 Oct 2022 00:58:58 -0700 +Subject: [PATCH] vhost-vdpa: allow passing opened vhostfd to vhost-vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar to other vhost backends, vhostfd can be passed to vhost-vdpa +backend as another parameter to instantiate vhost-vdpa net client. +This would benefit the use case where only open file descriptors, as +opposed to raw vhost-vdpa device paths, are accessible from the QEMU +process. + +(qemu) netdev_add type=vhost-vdpa,vhostfd=61,id=vhost-vdpa1 + +Signed-off-by: Si-Wei Liu +Acked-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 25 ++++++++++++++++++++----- + qapi/net.json | 3 +++ + qemu-options.hx | 6 ++++-- + 3 files changed, 27 insertions(+), 7 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index c8c433002d..58225649f9 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -642,14 +642,29 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +- if (!opts->vhostdev) { +- error_setg(errp, "vdpa character device not specified with vhostdev"); ++ if (!opts->has_vhostdev && !opts->has_vhostfd) { ++ error_setg(errp, ++ "vhost-vdpa: neither vhostdev= nor vhostfd= was specified"); + return -1; + } + +- vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); +- if (vdpa_device_fd == -1) { +- return -errno; ++ if (opts->has_vhostdev && opts->has_vhostfd) { ++ error_setg(errp, ++ "vhost-vdpa: vhostdev= and vhostfd= are mutually exclusive"); ++ return -1; ++ } ++ ++ if (opts->has_vhostdev) { ++ vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); ++ if (vdpa_device_fd == -1) { ++ return -errno; ++ } ++ } else if (opts->has_vhostfd) { ++ vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp); ++ if (vdpa_device_fd == -1) { ++ error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: "); ++ return -1; ++ } + } + + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); +diff --git a/qapi/net.json b/qapi/net.json +index 6a5460ce56..a38a7b611b 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -442,6 +442,8 @@ + # @vhostdev: path of vhost-vdpa device + # (default:'/dev/vhost-vdpa-0') + # ++# @vhostfd: file descriptor of an already opened vhost vdpa device ++# + # @queues: number of queues to be created for multiqueue vhost-vdpa + # (default: 1) + # +@@ -456,6 +458,7 @@ + { 'struct': 'NetdevVhostVDPAOptions', + 'data': { + '*vhostdev': 'str', ++ '*vhostfd': 'str', + '*queues': 'int', + '*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } } + +diff --git a/qemu-options.hx b/qemu-options.hx +index e329ec58ca..e25b76771d 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -2739,8 +2739,10 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, + " configure a vhost-user network, backed by a chardev 'dev'\n" + #endif + #ifdef __linux__ +- "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" ++ "-netdev vhost-vdpa,id=str[,vhostdev=/path/to/dev][,vhostfd=h]\n" + " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" ++ " use 'vhostdev=/path/to/dev' to open a vhost vdpa device\n" ++ " use 'vhostfd=h' to connect to an already opened vhost vdpa device\n" + #endif + "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" + " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) +@@ -3220,7 +3222,7 @@ SRST + -netdev type=vhost-user,id=net0,chardev=chr0 \ + -device virtio-net-pci,netdev=net0 + +-``-netdev vhost-vdpa,vhostdev=/path/to/dev`` ++``-netdev vhost-vdpa[,vhostdev=/path/to/dev][,vhostfd=h]`` + Establish a vhost-vdpa netdev. + + vDPA device is a device that uses a datapath which complies with +-- +2.27.0 + diff --git a/vhost-vdpa-backend-feature-should-set-only-once.patch b/vhost-vdpa-backend-feature-should-set-only-once.patch new file mode 100644 index 0000000000000000000000000000000000000000..b14e65f830247bae9abd095101515192fe70b613 --- /dev/null +++ b/vhost-vdpa-backend-feature-should-set-only-once.patch @@ -0,0 +1,49 @@ +From a089328f183371ec7f7cd641f46beeeea2c9decc Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:16 -0700 +Subject: [PATCH] vhost-vdpa: backend feature should set only once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The vhost_vdpa_one_time_request() branch in +vhost_vdpa_set_backend_cap() incorrectly sends down +ioctls on vhost_dev with non-zero index. This may +end up with multiple VHOST_SET_BACKEND_FEATURES +ioctl calls sent down on the vhost-vdpa fd that is +shared between all these vhost_dev's. + +To fix it, send down ioctl only once via the first +vhost_dev with index 0. Toggle the polarity of the +vhost_vdpa_one_time_request() test should do the +trick. + +Fixes: 4d191cfdc7de ("vhost-vdpa: classify one time request") +Signed-off-by: Si-Wei Liu +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: <1651890498-24478-6-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 1360f2eaf7..cb74d71b80 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -669,7 +669,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_one_time_request(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +-- +2.27.0 + diff --git a/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch b/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c67ccd022dca2b1c4cea6874cdaf3d44ad69dc9 --- /dev/null +++ b/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch @@ -0,0 +1,111 @@ +From fdf8d168adeac8e91bb61d4940756af0df3b8d2c Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:17 -0700 +Subject: [PATCH] vhost-vdpa: change name and polarity for + vhost_vdpa_one_time_request() + +The name vhost_vdpa_one_time_request() was confusing. No +matter whatever it returns, its typical occurrence had +always been at requests that only need to be applied once. +And the name didn't suggest what it actually checks for. +Change it to vhost_vdpa_first_dev() with polarity flipped +for better readibility of code. That way it is able to +reflect what the check is really about. + +This call is applicable to request which performs operation +only once, before queues are set up, and usually at the beginning +of the caller function. Document the requirement for it in place. + +Signed-off-by: Si-Wei Liu +Message-Id: <1651890498-24478-7-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index cb74d71b80..73ff599f2b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -370,11 +370,18 @@ static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) + v->iova_range.last); + } + +-static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) ++/* ++ * The use of this function is for requests that only need to be ++ * applied once. Typically such request occurs at the beginning ++ * of operation, and before setting up queues. It should not be ++ * used for request that performs operation until all queues are ++ * set, which would need to check dev->vq_index_end instead. ++ */ ++static bool vhost_vdpa_first_dev(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + +- return v->index != 0; ++ return v->index == 0; + } + + static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, +@@ -455,7 +462,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + + vhost_vdpa_get_iova_range(v); + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -598,7 +605,7 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) + static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + struct vhost_memory *mem) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -627,7 +634,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + struct vhost_vdpa *v = dev->opaque; + int ret; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -669,7 +676,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (!vhost_vdpa_one_time_request(dev)) { ++ if (vhost_vdpa_first_dev(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +@@ -1122,7 +1129,7 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) + { + struct vhost_vdpa *v = dev->opaque; +- if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { ++ if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -1244,7 +1251,7 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, + + static int vhost_vdpa_set_owner(struct vhost_dev *dev) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +-- +2.27.0 + diff --git a/vhost-vdpa-do-not-cleanup-the-vdpa-vhost-net-structu.patch b/vhost-vdpa-do-not-cleanup-the-vdpa-vhost-net-structu.patch new file mode 100644 index 0000000000000000000000000000000000000000..d74d15c97f0db3359159bd532f1155d44ab025a1 --- /dev/null +++ b/vhost-vdpa-do-not-cleanup-the-vdpa-vhost-net-structu.patch @@ -0,0 +1,59 @@ +From b6e32ca6cb92d6b1c5414206a262fd72cedd56bc Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Mon, 19 Jun 2023 12:22:09 +0530 +Subject: [PATCH] vhost-vdpa: do not cleanup the vdpa/vhost-net structures if + peer nic is present + +When a peer nic is still attached to the vdpa backend, it is too early to free +up the vhost-net and vdpa structures. If these structures are freed here, then +QEMU crashes when the guest is being shut down. The following call chain +would result in an assertion failure since the pointer returned from +vhost_vdpa_get_vhost_net() would be NULL: + +do_vm_stop() -> vm_state_notify() -> virtio_set_status() -> +virtio_net_vhost_status() -> get_vhost_net(). + +Therefore, we defer freeing up the structures until at guest shutdown +time when qemu_cleanup() calls net_cleanup() which then calls +qemu_del_net_client() which would eventually call vhost_vdpa_cleanup() +again to free up the structures. This time, the loop in net_cleanup() +ensures that vhost_vdpa_cleanup() will be called one last time when +all the peer nics are detached and freed. + +All unit tests pass with this change. + +CC: imammedo@redhat.com +CC: jusual@redhat.com +CC: mst@redhat.com +Fixes: CVE-2023-3301 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2128929 +Signed-off-by: Ani Sinha +Message-Id: <20230619065209.442185-1-anisinha@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + net/vhost-vdpa.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 25dd6dd975..60b715aef1 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -128,6 +128,14 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + ++ /* ++ * If a peer NIC is attached, do not cleanup anything. ++ * Cleanup will happen as a part of qemu_cleanup() -> net_cleanup() ++ * when the guest is shutting down. ++ */ ++ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { ++ return; ++ } + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); +-- +2.41.0.windows.1 + diff --git a/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch b/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch new file mode 100644 index 0000000000000000000000000000000000000000..b49311e91e0858283caec25d57ea59f91c0e48a3 --- /dev/null +++ b/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch @@ -0,0 +1,75 @@ +From 0462d79e6b607799538ac96b9486b60ee6819e9f Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Tue, 8 Nov 2022 12:19:28 +0800 +Subject: [PATCH] vhost-vdpa: fix assert + !virtio_net_get_subqueue(nc)->async_tx.elem in virtio_net_reset + +The citing commit has incorrect code in vhost_vdpa_receive() that returns +zero instead of full packet size to the caller. This renders pending packets +unable to be freed so then get clogged in the tx queue forever. When device +is being reset later on, below assertion failure ensues: + +0 0x00007f86d53bb387 in raise () from /lib64/libc.so.6 +1 0x00007f86d53bca78 in abort () from /lib64/libc.so.6 +2 0x00007f86d53b41a6 in __assert_fail_base () from /lib64/libc.so.6 +3 0x00007f86d53b4252 in __assert_fail () from /lib64/libc.so.6 +4 0x000055b8f6ff6fcc in virtio_net_reset (vdev=) at /usr/src/debug/qemu/hw/net/virtio-net.c:563 +5 0x000055b8f7012fcf in virtio_reset (opaque=0x55b8faf881f0) at /usr/src/debug/qemu/hw/virtio/virtio.c:1993 +6 0x000055b8f71f0086 in virtio_bus_reset (bus=bus@entry=0x55b8faf88178) at /usr/src/debug/qemu/hw/virtio/virtio-bus.c:102 +7 0x000055b8f71f1620 in virtio_pci_reset (qdev=) at /usr/src/debug/qemu/hw/virtio/virtio-pci.c:1845 +8 0x000055b8f6fafc6c in memory_region_write_accessor (mr=, addr=, value=, + size=, shift=, mask=, attrs=...) at /usr/src/debug/qemu/memory.c:483 +9 0x000055b8f6fadce9 in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f867e7fb7e8, size=size@entry=1, + access_size_min=, access_size_max=, access_fn=0x55b8f6fafc20 , + mr=0x55b8faf80a50, attrs=...) at /usr/src/debug/qemu/memory.c:544 +10 0x000055b8f6fb1d0b in memory_region_dispatch_write (mr=mr@entry=0x55b8faf80a50, addr=addr@entry=20, data=0, op=, + attrs=attrs@entry=...) at /usr/src/debug/qemu/memory.c:1470 +11 0x000055b8f6f62ada in flatview_write_continue (fv=fv@entry=0x7f86ac04cd20, addr=addr@entry=549755813908, attrs=..., + attrs@entry=..., buf=buf@entry=0x7f86d0223028
, len=len@entry=1, addr1=20, l=1, + mr=0x55b8faf80a50) at /usr/src/debug/qemu/exec.c:3266 +12 0x000055b8f6f62c8f in flatview_write (fv=0x7f86ac04cd20, addr=549755813908, attrs=..., + buf=0x7f86d0223028
, len=1) at /usr/src/debug/qemu/exec.c:3306 +13 0x000055b8f6f674cb in address_space_write (as=, addr=, attrs=..., buf=, + len=) at /usr/src/debug/qemu/exec.c:3396 +14 0x000055b8f6f67575 in address_space_rw (as=, addr=, attrs=..., attrs@entry=..., + buf=buf@entry=0x7f86d0223028
, len=, is_write=) + at /usr/src/debug/qemu/exec.c:3406 +15 0x000055b8f6fc1cc8 in kvm_cpu_exec (cpu=cpu@entry=0x55b8f9aa0e10) at /usr/src/debug/qemu/accel/kvm/kvm-all.c:2410 +16 0x000055b8f6fa5f5e in qemu_kvm_cpu_thread_fn (arg=0x55b8f9aa0e10) at /usr/src/debug/qemu/cpus.c:1318 +17 0x000055b8f7336e16 in qemu_thread_start (args=0x55b8f9ac8480) at /usr/src/debug/qemu/util/qemu-thread-posix.c:519 +18 0x00007f86d575aea5 in start_thread () from /lib64/libpthread.so.0 +19 0x00007f86d5483b2d in clone () from /lib64/libc.so.6 + +Make vhost_vdpa_receive() return the size passed in as is, so that the +caller qemu_deliver_packet_iov() would eventually propagate it back to +virtio_net_flush_tx() to release pending packets from the async_tx queue. +Which corresponds to the drop path where qemu_sendv_packet_async() returns +non-zero in virtio_net_flush_tx(). + +Fixes: 846a1e85da64 ("vdpa: Add dummy receive callback") +Cc: Eugenio Perez Martin +Signed-off-by: Si-Wei Liu +Signed-off-by: Jason Wang +Signed-off-by: Stefan Hajnoczi +Message-Id: <20221108041929.18417-2-jasowang@redhat.com> +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index c89f9d1243..eae2ed364f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -218,7 +218,7 @@ static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc, + static ssize_t vhost_vdpa_receive(NetClientState *nc, const uint8_t *buf, + size_t size) + { +- return 0; ++ return size; + } + + static NetClientInfo net_vhost_vdpa_info = { +-- +2.27.0 + diff --git a/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch b/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch new file mode 100644 index 0000000000000000000000000000000000000000..ecb45191573bc973eee4e3d32d9c826153f8f617 --- /dev/null +++ b/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch @@ -0,0 +1,36 @@ +From ddd117ccb7dfc57dcd45d52d35cd71f746d81c3a Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:14 -0700 +Subject: [PATCH] vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa + +... such that no memory leaks on dangling net clients in case of +error. + +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-4-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 9ba0f7bfca..7201c79116 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -314,7 +314,9 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + err: + if (i) { +- qemu_del_net_client(ncs[0]); ++ for (i--; i >= 0; i--) { ++ qemu_del_net_client(ncs[i]); ++ } + } + qemu_close(vdpa_device_fd); + +-- +2.27.0 + diff --git a/vhost-vdpa-fix-typo-in-a-comment.patch b/vhost-vdpa-fix-typo-in-a-comment.patch new file mode 100644 index 0000000000000000000000000000000000000000..b55cff07d2d541dfadb4a338780ba6fcfec96fdf --- /dev/null +++ b/vhost-vdpa-fix-typo-in-a-comment.patch @@ -0,0 +1,35 @@ +From 208e92b8d029d8483f994858304d49af5b6d875a Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Mon, 28 Mar 2022 17:20:22 +0200 +Subject: [PATCH] vhost-vdpa: fix typo in a comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Replace vpda with vdpa. + +Signed-off-by: Stefano Garzarella +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220328152022.73245-1-sgarzare@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3b5456cc0e..b66697da6e 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -301,7 +301,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + memory_region_unref(section->mr); + } + /* +- * IOTLB API is used by vhost-vpda which requires incremental updating ++ * IOTLB API is used by vhost-vdpa which requires incremental updating + * of the mapping. So we can not use generic vhost memory listener which + * depends on the addnop(). + */ +-- +2.27.0 + diff --git a/vhost-vdpa-stick-to-errno-error-return-convention.patch b/vhost-vdpa-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ef8091e130d3ce4dd1c3b4c925980ef810c8fa5 --- /dev/null +++ b/vhost-vdpa-stick-to-errno-error-return-convention.patch @@ -0,0 +1,107 @@ +From 69fdbac8d37a02cfc91e6c849a768e58e57dd15f Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:55 +0800 +Subject: [PATCH] vhost-vdpa: stick to -errno error return convention + +Almost all VhostOps methods in vdpa_ops follow the convention of +returning negated errno on error. + +Adjust the few that don't. To that end, rework vhost_vdpa_add_status to +check if setting of the requested status bits has succeeded and return +the respective error code it hasn't, and propagate the error codes +wherever it's appropriate. + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-8-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 37 +++++++++++++++++++++++-------------- + 1 file changed, 23 insertions(+), 14 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index b7bbd65cdd..d8fba0b714 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -294,18 +294,34 @@ static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, + return ret < 0 ? -errno : ret; + } + +-static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) ++static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + { + uint8_t s; ++ int ret; + + trace_vhost_vdpa_add_status(dev, status); +- if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) { +- return; ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s); ++ if (ret < 0) { ++ return ret; + } + + s |= status; + +- vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (!(s & status)) { ++ return -EIO; ++ } ++ ++ return 0; + } + + static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) +@@ -487,7 +503,7 @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + } + } + if (mem->padding) { +- return -1; ++ return -EINVAL; + } + + return 0; +@@ -504,14 +520,11 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + + trace_vhost_vdpa_set_features(dev, features); + ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); +- uint8_t status = 0; + if (ret) { + return ret; + } +- vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); +- vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); + +- return !(status & VIRTIO_CONFIG_S_FEATURES_OK); ++ return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); + } + + static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) +@@ -653,12 +666,8 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + + if (started) { +- uint8_t status = 0; + memory_listener_register(&v->listener, &address_space_memory); +- vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); +- vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); +- +- return !(status & VIRTIO_CONFIG_S_DRIVER_OK); ++ return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + } else { + vhost_vdpa_reset_device(dev); + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | +-- +2.27.0 + diff --git a/vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch b/vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch new file mode 100644 index 0000000000000000000000000000000000000000..019f41be808442382fe083d8bfb712e46826422a --- /dev/null +++ b/vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch @@ -0,0 +1,56 @@ +From 1362d692f9fac12d5ee37a44163c652bb58075eb Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Mon, 28 Feb 2022 10:50:58 +0100 +Subject: [PATCH 1/2] vhost-vsock: detach the virqueue element in case of error + +In vhost_vsock_common_send_transport_reset(), if an element popped from +the virtqueue is invalid, we should call virtqueue_detach_element() to +detach it from the virtqueue before freeing its memory. + +Fixes: fc0b9b0e1c ("vhost-vsock: add virtio sockets device") +Fixes: CVE-2022-26354 +Cc: qemu-stable@nongnu.org +Reported-by: VictorV +Signed-off-by: Stefano Garzarella +Message-Id: <20220228095058.27899-1-sgarzare@redhat.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/vhost-vsock-common.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index 3f3771274e..ed706681ac 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -153,19 +153,23 @@ static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc) + if (elem->out_num) { + error_report("invalid vhost-vsock event virtqueue element with " + "out buffers"); +- goto out; ++ goto err; + } + + if (iov_from_buf(elem->in_sg, elem->in_num, 0, + &event, sizeof(event)) != sizeof(event)) { + error_report("vhost-vsock event virtqueue element is too short"); +- goto out; ++ goto err; + } + + virtqueue_push(vq, elem, sizeof(event)); + virtio_notify(VIRTIO_DEVICE(vvc), vq); + +-out: ++ g_free(elem); ++ return; ++ ++err: ++ virtqueue_detach_element(vq, elem, 0); + g_free(elem); + } + +-- +2.27.0 + diff --git a/vhost_net-Add-NetClientInfo-start-callback.patch b/vhost_net-Add-NetClientInfo-start-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..546c4ef93974c34f24a2de1efb5732eb6e82c8fc --- /dev/null +++ b/vhost_net-Add-NetClientInfo-start-callback.patch @@ -0,0 +1,64 @@ +From 533bcae898152213703a1f15b3d4a938292fd23f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:30 +0200 +Subject: [PATCH] vhost_net: Add NetClientInfo start callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is used by the backend to perform actions before the device is +started. + +In particular, vdpa net use it to map CVQ buffers to the device, so it +can send control commands using them. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 7 +++++++ + include/net/net.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index bea053a742..92df7558bf 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -307,6 +307,13 @@ static int vhost_net_start_one(struct vhost_net *net, + struct vhost_vring_file file = { }; + int r; + ++ if (net->nc->info->start) { ++ r = net->nc->info->start(net->nc); ++ if (r < 0) { ++ return r; ++ } ++ } ++ + r = vhost_dev_enable_notifiers(&net->dev, dev); + if (r < 0) { + goto fail_notifiers; +diff --git a/include/net/net.h b/include/net/net.h +index 523136c7ac..ad9e80083a 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -44,6 +44,7 @@ typedef struct NICConf { + + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); ++typedef int (NetStart)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); + typedef void (NetCleanup) (NetClientState *); +@@ -71,6 +72,7 @@ typedef struct NetClientInfo { + NetReceive *receive_raw; + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; ++ NetStart *start; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; + QueryRxFilter *query_rx_filter; +-- +2.27.0 + diff --git a/vhost_net-Add-NetClientInfo-stop-callback.patch b/vhost_net-Add-NetClientInfo-stop-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..80cbd5266a278c2dc50bdcdd740f2a166b04bba2 --- /dev/null +++ b/vhost_net-Add-NetClientInfo-stop-callback.patch @@ -0,0 +1,59 @@ +From d25c4237821c994e36b7a23e0a0c609993707d47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:31 +0200 +Subject: [PATCH] vhost_net: Add NetClientInfo stop callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Used by the backend to perform actions after the device is stopped. + +In particular, vdpa net use it to unmap CVQ buffers to the device, +cleaning the actions performed in prepare(). + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 3 +++ + include/net/net.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index 92df7558bf..fe6932171b 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -383,6 +383,9 @@ static void vhost_net_stop_one(struct vhost_net *net, + net->nc->info->poll(net->nc, true); + } + vhost_dev_stop(&net->dev, dev); ++ if (net->nc->info->stop) { ++ net->nc->info->stop(net->nc); ++ } + vhost_dev_disable_notifiers(&net->dev, dev); + } + +diff --git a/include/net/net.h b/include/net/net.h +index ad9e80083a..476ad45b9a 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -45,6 +45,7 @@ typedef struct NICConf { + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); + typedef int (NetStart)(NetClientState *); ++typedef void (NetStop)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); + typedef void (NetCleanup) (NetClientState *); +@@ -73,6 +74,7 @@ typedef struct NetClientInfo { + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; + NetStart *start; ++ NetStop *stop; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; + QueryRxFilter *query_rx_filter; +-- +2.27.0 + diff --git a/vhost_net-add-NetClientState-load-callback.patch b/vhost_net-add-NetClientState-load-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..39d93523ab27c05d093406a27c181177b4e4015d --- /dev/null +++ b/vhost_net-add-NetClientState-load-callback.patch @@ -0,0 +1,64 @@ +From 4b0c6e40f26af49416d00b186840344b424b48ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:35 +0200 +Subject: [PATCH] vhost_net: add NetClientState->load() callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It allows per-net client operations right after device's successful +start. In particular, to load the device status. + +Vhost-vdpa net will use it to add the CVQ buffers to restore the device +status. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 7 +++++++ + include/net/net.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index fe6932171b..f709c060b6 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -344,6 +344,13 @@ static int vhost_net_start_one(struct vhost_net *net, + } + } + } ++ ++ if (net->nc->info->load) { ++ r = net->nc->info->load(net->nc); ++ if (r < 0) { ++ goto fail; ++ } ++ } + return 0; + fail: + file.fd = -1; +diff --git a/include/net/net.h b/include/net/net.h +index 476ad45b9a..81d0b21def 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -45,6 +45,7 @@ typedef struct NICConf { + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); + typedef int (NetStart)(NetClientState *); ++typedef int (NetLoad)(NetClientState *); + typedef void (NetStop)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); +@@ -74,6 +75,7 @@ typedef struct NetClientInfo { + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; + NetStart *start; ++ NetLoad *load; + NetStop *stop; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; +-- +2.27.0 + diff --git a/vhost_net-keep-acked_feature-only-for-NET_CLIENT_DRI.patch b/vhost_net-keep-acked_feature-only-for-NET_CLIENT_DRI.patch new file mode 100644 index 0000000000000000000000000000000000000000..762aad2c4e8ff6e4cdad84c11b276d1e36e747e0 --- /dev/null +++ b/vhost_net-keep-acked_feature-only-for-NET_CLIENT_DRI.patch @@ -0,0 +1,38 @@ +From fece8b3e700c30be2b6bb1239041333b3c1fc17b Mon Sep 17 00:00:00 2001 +From: liuxiangdong +Date: Mon, 5 Dec 2022 07:11:28 +0800 +Subject: [PATCH] vhost_net: keep acked_feature only for + NET_CLIENT_DRIVER_VHOST_USER + +Keep acked_features in NetVhostUserState up-to-date by function vhost_net_save_acked_features +in function virtio_net_set_features. But nc->peer->info->type maybe NET_CLIENT_DRIVER_TAP or +NET_CLIENT_DRIVER_VHOST_VDPA besides NET_CLIENT_DRIVER_VHOST_USER. + +Don't keep acked_features in other type now except NET_CLIENT_DRIVER_VHOST_USER + +Fix d29a94eff(vhost-user: Fix the virtio features negotiation flaw) + +Signed-off-by: liuxiangdong +--- + hw/net/vhost_net.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index a98575ffbc..bea053a742 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -143,8 +143,9 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net) + + void vhost_net_save_acked_features(NetClientState *nc) + { +- assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); +- vhost_user_save_acked_features(nc); ++ if (nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { ++ vhost_user_save_acked_features(nc); ++ } + } + + static int vhost_net_get_fd(NetClientState *backend) +-- +2.27.0 + diff --git a/vhost_vdpa-fix-the-input-in-trace_vhost_vdpa_listene.patch b/vhost_vdpa-fix-the-input-in-trace_vhost_vdpa_listene.patch new file mode 100644 index 0000000000000000000000000000000000000000..b842678e13d3f4f61117be82c61a324e9cae78d0 --- /dev/null +++ b/vhost_vdpa-fix-the-input-in-trace_vhost_vdpa_listene.patch @@ -0,0 +1,37 @@ +From 48b7b68cab05b9c614163935d0b42bb684e56ca9 Mon Sep 17 00:00:00 2001 +From: jipengfei_yewu +Date: Mon, 18 Dec 2023 11:58:32 +0000 +Subject: [PATCH] vhost_vdpa: fix the input in + trace_vhost_vdpa_listener_region_del() + +In trace_vhost_vdpa_listener_region_del, the value for llend +should change to int128_get64(int128_sub(llend, int128_one())) + +cheery-pick from 3d1e4d34a81a212e234f674e57e73c824d4b131a + +Signed-off-by:jipengfei_yewu +Signed-off-by: Cindy Lu +Message-Id: <20230510054631.2951812-3-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/vhost-vdpa.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c7aaff7f20..22fd1b1e2f 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -290,7 +290,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + llend = vhost_vdpa_section_end(section); + +- trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(llend)); ++ trace_vhost_vdpa_listener_region_del(v, iova, ++ int128_get64(int128_sub(llend, int128_one()))); + + if (int128_ge(int128_make64(iova), llend)) { + return; +-- +2.27.0 + diff --git a/virtio-Add-vhost_svq_get_vring_addr.patch b/virtio-Add-vhost_svq_get_vring_addr.patch new file mode 100644 index 0000000000000000000000000000000000000000..67f864e8cc09f12a1258bc8a3f9c31824cb6ee80 --- /dev/null +++ b/virtio-Add-vhost_svq_get_vring_addr.patch @@ -0,0 +1,96 @@ +From c9b863e96be5277e775cb424cf8ea34f8f921776 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:45 +0100 +Subject: [PATCH] virtio: Add vhost_svq_get_vring_addr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It reports the shadow virtqueue address from qemu virtual address space. + +Since this will be different from the guest's vaddr, but the device can +access it, SVQ takes special care about its alignment & lack of garbage +data. It assumes that IOMMU will work in host_page_size ranges for that. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 29 +++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 9 +++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 519328445c..573ac0d9cf 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -106,6 +106,35 @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) + } + } + ++/** ++ * Get the shadow vq vring address. ++ * @svq: Shadow virtqueue ++ * @addr: Destination to store address ++ */ ++void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr) ++{ ++ addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc; ++ addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail; ++ addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used; ++} ++ ++size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq) ++{ ++ size_t desc_size = sizeof(vring_desc_t) * svq->vring.num; ++ size_t avail_size = offsetof(vring_avail_t, ring) + ++ sizeof(uint16_t) * svq->vring.num; ++ ++ return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size); ++} ++ ++size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq) ++{ ++ size_t used_size = offsetof(vring_used_t, ring) + ++ sizeof(vring_used_elem_t) * svq->vring.num; ++ return ROUND_UP(used_size, qemu_real_host_page_size); ++} ++ + /** + * Set a new file descriptor for the guest to kick the SVQ and notify for avail + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 9e12f77201..82cea1c3fa 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -11,9 +11,14 @@ + #define VHOST_SHADOW_VIRTQUEUE_H + + #include "qemu/event_notifier.h" ++#include "hw/virtio/virtio.h" ++#include "standard-headers/linux/vhost_types.h" + + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { ++ /* Shadow vring */ ++ struct vring vring; ++ + /* Shadow kick notifier, sent to vhost */ + EventNotifier hdev_kick; + /* Shadow call notifier, sent to vhost */ +@@ -37,6 +42,10 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); ++void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr); ++size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); ++size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-- +2.27.0 + diff --git a/virtio-add-ability-to-delete-vq-through-a-pointer.patch b/virtio-add-ability-to-delete-vq-through-a-pointer.patch deleted file mode 100644 index e0989895e40fe4e0d3816966a24075d74b8797a0..0000000000000000000000000000000000000000 --- a/virtio-add-ability-to-delete-vq-through-a-pointer.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 98ae454efe48b2a465dfe9bc3c412b6375f1fbfc Mon Sep 17 00:00:00 2001 -From: "Michael S. Tsirkin" -Date: Mon, 9 Dec 2019 11:46:13 -0500 -Subject: [PATCH 1/9] virtio: add ability to delete vq through a pointer - -Devices tend to maintain vq pointers, allow deleting them trough a vq pointer. - -Signed-off-by: Michael S. Tsirkin -Reviewed-by: David Hildenbrand -Signed-off-by: AlexChen ---- - hw/virtio/virtio.c | 13 +++++++++---- - include/hw/virtio/virtio.h | 2 ++ - 2 files changed, 11 insertions(+), 4 deletions(-) - -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index 79c2dcf..3d027d3 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -1636,16 +1636,21 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, - return &vdev->vq[i]; - } - -+void virtio_delete_queue(VirtQueue *vq) -+{ -+ vq->vring.num = 0; -+ vq->vring.num_default = 0; -+ vq->handle_output = NULL; -+ vq->handle_aio_output = NULL; -+} -+ - void virtio_del_queue(VirtIODevice *vdev, int n) - { - if (n < 0 || n >= VIRTIO_QUEUE_MAX) { - abort(); - } - -- vdev->vq[n].vring.num = 0; -- vdev->vq[n].vring.num_default = 0; -- vdev->vq[n].handle_output = NULL; -- vdev->vq[n].handle_aio_output = NULL; -+ virtio_delete_queue(&vdev->vq[n]); - } - - static void virtio_set_isr(VirtIODevice *vdev, int value) -diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h -index f9f6237..ca2fbae 100644 ---- a/include/hw/virtio/virtio.h -+++ b/include/hw/virtio/virtio.h -@@ -187,6 +187,8 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, - - void virtio_del_queue(VirtIODevice *vdev, int n); - -+void virtio_delete_queue(VirtQueue *vq); -+ - void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, - unsigned int len); - void virtqueue_flush(VirtQueue *vq, unsigned int count); --- -1.8.3.1 - diff --git a/virtio-add-support-for-configure-interrupt-new.patch b/virtio-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..72a134791f3be49c3dda5ab63536f170626805c2 --- /dev/null +++ b/virtio-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,102 @@ +From 90152f58401b828febbb060cff86330827e6befe Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:47 +0800 +Subject: [PATCH] virtio: add support for configure interrupt + +Add the functions to support the configure interrupt in virtio +The function virtio_config_guest_notifier_read will notify the +guest if there is an configure interrupt. +The function virtio_config_set_guest_notifier_fd_handler is +to set the fd hander for the notifier + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-7-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 +++++++++++++++++++++++++++++ + include/hw/virtio/virtio.h | 4 ++++ + 2 files changed, 33 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 12f4a8ab3d..e3f392fc59 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3548,7 +3548,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } ++static void virtio_config_guest_notifier_read(EventNotifier *n) ++{ ++ VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + ++ if (event_notifier_test_and_clear(n)) { ++ virtio_notify_config(vdev); ++ } ++} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3565,6 +3572,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd) ++{ ++ EventNotifier *n; ++ n = &vdev->config_notifier; ++ if (assign && !with_irqfd) { ++ event_notifier_set_handler(n, virtio_config_guest_notifier_read); ++ } else { ++ event_notifier_set_handler(n, NULL); ++ } ++ if (!assign) { ++ /* Test and clear notifier before closing it,*/ ++ /* in case poll callback didn't have time to run. */ ++ virtio_config_guest_notifier_read(n); ++ } ++} ++ + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3638,6 +3662,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) ++{ ++ return &vdev->config_notifier; ++} ++ + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 91d1c3433a..43509b33ff 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -114,6 +114,7 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; ++ EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -329,6 +330,9 @@ void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, + VirtIOHandleAIOOutput handle_output); + VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); + VirtQueue *virtio_vector_next_queue(VirtQueue *vq); ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd); + + static inline void virtio_add_feature(uint64_t *features, unsigned int fbit) + { +-- +2.27.0 + diff --git a/virtio-add-support-for-configure-interrupt.patch b/virtio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..b5bc73ab8480c461ba17ba7c37155d6150d4bae9 --- /dev/null +++ b/virtio-add-support-for-configure-interrupt.patch @@ -0,0 +1,106 @@ +From 3ada114454dba1f4b8c6c30e64dfeedd41a6efc8 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:52 +0800 +Subject: [PATCH] virtio: add support for configure interrupt + +Add the functions to support the configure interrupt in virtio +The function virtio_config_guest_notifier_read will notify the +guest if there is an configure interrupt. +The function virtio_config_set_guest_notifier_fd_handler is +to set the fd hander for the notifier + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-7-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 +++++++++++++++++++++++++++++ + include/hw/virtio/virtio.h | 4 ++++ + 2 files changed, 33 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 071668e3e0..d90cabe868 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3546,7 +3546,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } ++static void virtio_config_guest_notifier_read(EventNotifier *n) ++{ ++ VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + ++ if (event_notifier_test_and_clear(n)) { ++ virtio_notify_config(vdev); ++ } ++} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3563,6 +3570,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd) ++{ ++ EventNotifier *n; ++ n = &vdev->config_notifier; ++ if (assign && !with_irqfd) { ++ event_notifier_set_handler(n, virtio_config_guest_notifier_read); ++ } else { ++ event_notifier_set_handler(n, NULL); ++ } ++ if (!assign) { ++ /* Test and clear notifier before closing it,*/ ++ /* in case poll callback didn't have time to run. */ ++ virtio_config_guest_notifier_read(n); ++ } ++} ++ + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3636,6 +3660,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) ++{ ++ return &vdev->config_notifier; ++} ++ + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index c113a5b864..8788ccd1f3 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -112,6 +112,7 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; ++ EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -315,11 +316,14 @@ uint16_t virtio_get_queue_index(VirtQueue *vq); + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd); ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd); + int virtio_device_start_ioeventfd(VirtIODevice *vdev); + int virtio_device_grab_ioeventfd(VirtIODevice *vdev); + void virtio_device_release_ioeventfd(VirtIODevice *vdev); + bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); + EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); + void virtio_queue_host_notifier_read(EventNotifier *n); + void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, +-- +2.27.0 + diff --git a/virtio-add-vhost-support-for-virtio-devices.patch b/virtio-add-vhost-support-for-virtio-devices.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d9448014ff279e0442c45fcad56ea60b6ac7937 --- /dev/null +++ b/virtio-add-vhost-support-for-virtio-devices.patch @@ -0,0 +1,336 @@ +From b51d5c0def1e902a716bd3896d2f1868c635c554 Mon Sep 17 00:00:00 2001 +From: Jonah Palmer +Date: Fri, 1 Apr 2022 09:23:19 -0400 +Subject: [PATCH] virtio: add vhost support for virtio devices + +This patch adds a get_vhost() callback function for VirtIODevices that +returns the device's corresponding vhost_dev structure, if the vhost +device is running. This patch also adds a vhost_started flag for +VirtIODevices. + +Previously, a VirtIODevice wouldn't be able to tell if its corresponding +vhost device was active or not. + +Signed-off-by: Jonah Palmer +Message-Id: <1648819405-25696-3-git-send-email-jonah.palmer@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/block/vhost-user-blk.c | 7 +++++++ + hw/display/vhost-user-gpu.c | 7 +++++++ + hw/input/vhost-user-input.c | 7 +++++++ + hw/net/virtio-net.c | 9 +++++++++ + hw/scsi/vhost-scsi.c | 8 ++++++++ + hw/virtio/vhost-user-fs.c | 7 +++++++ + hw/virtio/vhost-user-rng.c | 7 +++++++ + hw/virtio/vhost-vsock-common.c | 7 +++++++ + hw/virtio/vhost.c | 4 +++- + hw/virtio/virtio-crypto.c | 10 ++++++++++ + hw/virtio/virtio.c | 1 + + include/hw/virtio/virtio.h | 3 +++ + 12 files changed, 76 insertions(+), 1 deletion(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index bcc3f83c4b..9bf18434c2 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -573,6 +573,12 @@ static void vhost_user_blk_instance_init(Object *obj) + "/disk@0,0", DEVICE(obj)); + } + ++static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserBlk *s = VHOST_USER_BLK(vdev); ++ return &s->dev; ++} ++ + static const VMStateDescription vmstate_vhost_user_blk = { + .name = "vhost-user-blk", + .minimum_version_id = 1, +@@ -607,6 +613,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data) + vdc->get_features = vhost_user_blk_get_features; + vdc->set_status = vhost_user_blk_set_status; + vdc->reset = vhost_user_blk_reset; ++ vdc->get_vhost = vhost_user_blk_get_vhost; + } + + static const TypeInfo vhost_user_blk_info = { +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 49df56cd14..6e93b463d6 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -565,6 +565,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) + g->vhost_gpu_fd = -1; + } + ++static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev) ++{ ++ VhostUserGPU *g = VHOST_USER_GPU(vdev); ++ return &g->vhost->dev; ++} ++ + static Property vhost_user_gpu_properties[] = { + VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf), + DEFINE_PROP_END_OF_LIST(), +@@ -586,6 +592,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data) + vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending; + vdc->get_config = vhost_user_gpu_get_config; + vdc->set_config = vhost_user_gpu_set_config; ++ vdc->get_vhost = vhost_user_gpu_get_vhost; + + device_class_set_props(dc, vhost_user_gpu_properties); + } +diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c +index 273e96a7b1..43d2ff3816 100644 +--- a/hw/input/vhost-user-input.c ++++ b/hw/input/vhost-user-input.c +@@ -79,6 +79,12 @@ static void vhost_input_set_config(VirtIODevice *vdev, + virtio_notify_config(vdev); + } + ++static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserInput *vhi = VHOST_USER_INPUT(vdev); ++ return &vhi->vhost->dev; ++} ++ + static const VMStateDescription vmstate_vhost_input = { + .name = "vhost-user-input", + .unmigratable = 1, +@@ -93,6 +99,7 @@ static void vhost_input_class_init(ObjectClass *klass, void *data) + dc->vmsd = &vmstate_vhost_input; + vdc->get_config = vhost_input_get_config; + vdc->set_config = vhost_input_set_config; ++ vdc->get_vhost = vhost_input_get_vhost; + vic->realize = vhost_input_realize; + vic->change_active = vhost_input_change_active; + } +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 3bd786cc22..41bb4010b0 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3644,6 +3644,14 @@ static bool dev_unplug_pending(void *opaque) + return vdc->primary_unplug_pending(dev); + } + ++static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) ++{ ++ VirtIONet *n = VIRTIO_NET(vdev); ++ NetClientState *nc = qemu_get_queue(n->nic); ++ struct vhost_net *net = get_vhost_net(nc->peer); ++ return &net->dev; ++} ++ + static const VMStateDescription vmstate_virtio_net = { + .name = "virtio-net", + .minimum_version_id = VIRTIO_NET_VM_VERSION, +@@ -3785,6 +3793,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) + vdc->post_load = virtio_net_post_load_virtio; + vdc->vmsd = &vmstate_virtio_net_device; + vdc->primary_unplug_pending = primary_unplug_pending; ++ vdc->get_vhost = virtio_net_get_vhost; + } + + static const TypeInfo virtio_net_info = { +diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c +index 039caf2614..b0a9c45e43 100644 +--- a/hw/scsi/vhost-scsi.c ++++ b/hw/scsi/vhost-scsi.c +@@ -264,6 +264,13 @@ static void vhost_scsi_unrealize(DeviceState *dev) + virtio_scsi_common_unrealize(dev); + } + ++static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev) ++{ ++ VHostSCSI *s = VHOST_SCSI(vdev); ++ VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); ++ return &vsc->dev; ++} ++ + static Property vhost_scsi_properties[] = { + DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd), + DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn), +@@ -298,6 +305,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) + vdc->get_features = vhost_scsi_common_get_features; + vdc->set_config = vhost_scsi_common_set_config; + vdc->set_status = vhost_scsi_set_status; ++ vdc->get_vhost = vhost_scsi_get_vhost; + fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; + } + +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index fc7dcc96ef..392b7d3aa1 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -277,6 +277,12 @@ static void vuf_device_unrealize(DeviceState *dev) + g_free(vhost_vqs); + } + ++static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserFS *fs = VHOST_USER_FS(vdev); ++ return &fs->vhost_dev; ++} ++ + static const VMStateDescription vuf_vmstate = { + .name = "vhost-user-fs", + .unmigratable = 1, +@@ -314,6 +320,7 @@ static void vuf_class_init(ObjectClass *klass, void *data) + vdc->set_status = vuf_set_status; + vdc->guest_notifier_mask = vuf_guest_notifier_mask; + vdc->guest_notifier_pending = vuf_guest_notifier_pending; ++ vdc->get_vhost = vuf_get_vhost; + } + + static const TypeInfo vuf_info = { +diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c +index 209ee5bf9a..543f3e3cef 100644 +--- a/hw/virtio/vhost-user-rng.c ++++ b/hw/virtio/vhost-user-rng.c +@@ -247,6 +247,12 @@ static void vu_rng_device_unrealize(DeviceState *dev) + vhost_user_cleanup(&rng->vhost_user); + } + ++static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserRNG *rng = VHOST_USER_RNG(vdev); ++ return &rng->vhost_dev; ++} ++ + static const VMStateDescription vu_rng_vmstate = { + .name = "vhost-user-rng", + .unmigratable = 1, +@@ -272,6 +278,7 @@ static void vu_rng_class_init(ObjectClass *klass, void *data) + vdc->set_status = vu_rng_set_status; + vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; + vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; ++ vdc->get_vhost = vu_rng_get_vhost; + } + + static const TypeInfo vu_rng_info = { +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index ed706681ac..cd45aaf28e 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -259,6 +259,12 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev) + virtio_cleanup(vdev); + } + ++static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev) ++{ ++ VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); ++ return &vvc->vhost_dev; ++} ++ + static Property vhost_vsock_common_properties[] = { + DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, + ON_OFF_AUTO_AUTO), +@@ -274,6 +280,7 @@ static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; + vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; ++ vdc->get_vhost = vhost_vsock_common_get_vhost; + } + + static const TypeInfo vhost_vsock_common_info = { +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2f9bb96d63..c1f5cb5b91 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1766,6 +1766,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ vdev->vhost_started = true; + hdev->started = true; + hdev->vdev = vdev; + +@@ -1838,7 +1839,7 @@ fail_vq: + + fail_mem: + fail_features: +- ++ vdev->vhost_started = false; + hdev->started = false; + return r; + } +@@ -1869,6 +1870,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + vhost_log_put(hdev, true); + hdev->started = false; ++ vdev->vhost_started = false; + hdev->vdev = NULL; + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 274c7b4dea..f9d849fa43 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -966,6 +966,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + ++static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) ++{ ++ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); ++ CryptoDevBackend *b = vcrypto->cryptodev; ++ CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; ++ CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); ++ return &vhost_crypto->dev; ++} ++ + static void virtio_crypto_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); +@@ -982,6 +991,7 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data) + vdc->set_status = virtio_crypto_set_status; + vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; + vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; ++ vdc->get_vhost = virtio_crypto_get_vhost; + } + + static void virtio_crypto_instance_init(Object *obj) +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index c1497f59aa..12f4a8ab3d 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3298,6 +3298,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, + + vdev->start_on_kick = false; + vdev->started = false; ++ vdev->vhost_started = false; + vdev->device_id = device_id; + vdev->status = 0; + qatomic_set(&vdev->isr, 0); +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 7472145821..223e82436f 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -22,6 +22,7 @@ + #include "standard-headers/linux/virtio_config.h" + #include "standard-headers/linux/virtio_ring.h" + #include "qom/object.h" ++#include "hw/virtio/vhost.h" + + /* A guest should never accept this. It implies negotiation is broken. */ + #define VIRTIO_F_BAD_FEATURE 30 +@@ -103,6 +104,7 @@ struct VirtIODevice + bool started; + bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */ + bool disable_legacy_check; ++ bool vhost_started; + VMChangeStateEntry *vmstate; + char *bus_name; + uint8_t device_endian; +@@ -162,6 +164,7 @@ struct VirtioDeviceClass { + int (*post_load)(VirtIODevice *vdev); + const VMStateDescription *vmsd; + bool (*primary_unplug_pending)(void *opaque); ++ struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); + }; + + void virtio_instance_init_common(Object *proxy_obj, void *data, +-- +2.27.0 + diff --git a/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch b/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch deleted file mode 100644 index 3c2a3f2a424bd30ff95b8fcb53ae23c324d43153..0000000000000000000000000000000000000000 --- a/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 01be50603be4f17af4318a7a3fe58dcc6dab1b31 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Fri, 16 Aug 2019 19:15:03 +0200 -Subject: [PATCH] virtio-blk: Cancel the pending BH when the dataplane is reset -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When 'system_reset' is called, the main loop clear the memory -region cache before the BH has a chance to execute. Later when -the deferred function is called, some assumptions that were -made when scheduling them are no longer true when they actually -execute. - -This is what happens using a virtio-blk device (fresh RHEL7.8 install): - - $ (sleep 12.3; echo system_reset; sleep 12.3; echo system_reset; sleep 1; echo q) \ - | qemu-system-x86_64 -m 4G -smp 8 -boot menu=on \ - -device virtio-blk-pci,id=image1,drive=drive_image1 \ - -drive file=/var/lib/libvirt/images/rhel78.qcow2,if=none,id=drive_image1,format=qcow2,cache=none \ - -device virtio-net-pci,netdev=net0,id=nic0,mac=52:54:00:c4:e7:84 \ - -netdev tap,id=net0,script=/bin/true,downscript=/bin/true,vhost=on \ - -monitor stdio -serial null -nographic - (qemu) system_reset - (qemu) system_reset - (qemu) qemu-system-x86_64: hw/virtio/virtio.c:225: vring_get_region_caches: Assertion `caches != NULL' failed. - Aborted - - (gdb) bt - Thread 1 (Thread 0x7f109c17b680 (LWP 10939)): - #0 0x00005604083296d1 in vring_get_region_caches (vq=0x56040a24bdd0) at hw/virtio/virtio.c:227 - #1 0x000056040832972b in vring_avail_flags (vq=0x56040a24bdd0) at hw/virtio/virtio.c:235 - #2 0x000056040832d13d in virtio_should_notify (vdev=0x56040a240630, vq=0x56040a24bdd0) at hw/virtio/virtio.c:1648 - #3 0x000056040832d1f8 in virtio_notify_irqfd (vdev=0x56040a240630, vq=0x56040a24bdd0) at hw/virtio/virtio.c:1662 - #4 0x00005604082d213d in notify_guest_bh (opaque=0x56040a243ec0) at hw/block/dataplane/virtio-blk.c:75 - #5 0x000056040883dc35 in aio_bh_call (bh=0x56040a243f10) at util/async.c:90 - #6 0x000056040883dccd in aio_bh_poll (ctx=0x560409161980) at util/async.c:118 - #7 0x0000560408842af7 in aio_dispatch (ctx=0x560409161980) at util/aio-posix.c:460 - #8 0x000056040883e068 in aio_ctx_dispatch (source=0x560409161980, callback=0x0, user_data=0x0) at util/async.c:261 - #9 0x00007f10a8fca06d in g_main_context_dispatch () at /lib64/libglib-2.0.so.0 - #10 0x0000560408841445 in glib_pollfds_poll () at util/main-loop.c:215 - #11 0x00005604088414bf in os_host_main_loop_wait (timeout=0) at util/main-loop.c:238 - #12 0x00005604088415c4 in main_loop_wait (nonblocking=0) at util/main-loop.c:514 - #13 0x0000560408416b1e in main_loop () at vl.c:1923 - #14 0x000056040841e0e8 in main (argc=20, argv=0x7ffc2c3f9c58, envp=0x7ffc2c3f9d00) at vl.c:4578 - -Fix this by cancelling the BH when the virtio dataplane is stopped. - -[This is version of the patch was modified as discussed with Philippe on -the mailing list thread. ---Stefan] - -Reported-by: Yihuang Yu -Suggested-by: Stefan Hajnoczi -Fixes: https://bugs.launchpad.net/qemu/+bug/1839428 -Signed-off-by: Philippe Mathieu-Daudé -Message-Id: <20190816171503.24761-1-philmd@redhat.com> -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit ebb6ff25cd888a52a64a9adc3692541c6d1d9a42) -Signed-off-by: Michael Roth ---- - hw/block/dataplane/virtio-blk.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c -index 158c78f852..5fea76df85 100644 ---- a/hw/block/dataplane/virtio-blk.c -+++ b/hw/block/dataplane/virtio-blk.c -@@ -297,6 +297,9 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) - virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); - } - -+ qemu_bh_cancel(s->bh); -+ notify_guest_bh(s); /* final chance to notify guest */ -+ - /* Clean up guest notifier (irq) */ - k->set_guest_notifiers(qbus->parent, nvqs, false); - --- -2.23.0 diff --git a/virtio-blk-On-restart-process-queued-requests-in-the.patch b/virtio-blk-On-restart-process-queued-requests-in-the.patch deleted file mode 100644 index 5edb6fd96f56ff66757af73d40bb90db142bbdc9..0000000000000000000000000000000000000000 --- a/virtio-blk-On-restart-process-queued-requests-in-the.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 882897127955fbede44c73703ec297c8ae89775d Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Thu, 21 Jan 2021 15:46:52 +0800 -Subject: [PATCH] virtio-blk: On restart, process queued requests in the proper - context - -On restart, we were scheduling a BH to process queued requests, which -would run before starting up the data plane, leading to those requests -being assigned and started on coroutines on the main context. - -This could cause requests to be wrongly processed in parallel from -different threads (the main thread and the iothread managing the data -plane), potentially leading to multiple issues. - -For example, stopping and resuming a VM multiple times while the guest -is generating I/O on a virtio_blk device can trigger a crash with a -stack tracing looking like this one: - -<------> - Thread 2 (Thread 0x7ff736765700 (LWP 1062503)): - #0 0x00005567a13b99d6 in iov_memset - (iov=0x6563617073206f4e, iov_cnt=1717922848, offset=516096, fillc=0, bytes=7018105756081554803) - at util/iov.c:69 - #1 0x00005567a13bab73 in qemu_iovec_memset - (qiov=0x7ff73ec99748, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:530 - #2 0x00005567a12f411c in qemu_laio_process_completion (laiocb=0x7ff6512ee6c0) at block/linux-aio.c:86 - #3 0x00005567a12f42ff in qemu_laio_process_completions (s=0x7ff7182e8420) at block/linux-aio.c:217 - #4 0x00005567a12f480d in ioq_submit (s=0x7ff7182e8420) at block/linux-aio.c:323 - #5 0x00005567a12f43d9 in qemu_laio_process_completions_and_submit (s=0x7ff7182e8420) - at block/linux-aio.c:236 - #6 0x00005567a12f44c2 in qemu_laio_poll_cb (opaque=0x7ff7182e8430) at block/linux-aio.c:267 - #7 0x00005567a13aed83 in run_poll_handlers_once (ctx=0x5567a2b58c70, timeout=0x7ff7367645f8) - at util/aio-posix.c:520 - #8 0x00005567a13aee9f in run_poll_handlers (ctx=0x5567a2b58c70, max_ns=16000, timeout=0x7ff7367645f8) - at util/aio-posix.c:562 - #9 0x00005567a13aefde in try_poll_mode (ctx=0x5567a2b58c70, timeout=0x7ff7367645f8) - at util/aio-posix.c:597 - #10 0x00005567a13af115 in aio_poll (ctx=0x5567a2b58c70, blocking=true) at util/aio-posix.c:639 - #11 0x00005567a109acca in iothread_run (opaque=0x5567a2b29760) at iothread.c:75 - #12 0x00005567a13b2790 in qemu_thread_start (args=0x5567a2b694c0) at util/qemu-thread-posix.c:519 - #13 0x00007ff73eedf2de in start_thread () at /lib64/libpthread.so.0 - #14 0x00007ff73ec10e83 in clone () at /lib64/libc.so.6 - - Thread 1 (Thread 0x7ff743986f00 (LWP 1062500)): - #0 0x00005567a13b99d6 in iov_memset - (iov=0x6563617073206f4e, iov_cnt=1717922848, offset=516096, fillc=0, bytes=7018105756081554803) - at util/iov.c:69 - #1 0x00005567a13bab73 in qemu_iovec_memset - (qiov=0x7ff73ec99748, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:530 - #2 0x00005567a12f411c in qemu_laio_process_completion (laiocb=0x7ff6512ee6c0) at block/linux-aio.c:86 - #3 0x00005567a12f42ff in qemu_laio_process_completions (s=0x7ff7182e8420) at block/linux-aio.c:217 - #4 0x00005567a12f480d in ioq_submit (s=0x7ff7182e8420) at block/linux-aio.c:323 - #5 0x00005567a12f4a2f in laio_do_submit (fd=19, laiocb=0x7ff5f4ff9ae0, offset=472363008, type=2) - at block/linux-aio.c:375 - #6 0x00005567a12f4af2 in laio_co_submit - (bs=0x5567a2b8c460, s=0x7ff7182e8420, fd=19, offset=472363008, qiov=0x7ff5f4ff9ca0, type=2) - at block/linux-aio.c:394 - #7 0x00005567a12f1803 in raw_co_prw - (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, type=2) - at block/file-posix.c:1892 - #8 0x00005567a12f1941 in raw_co_pwritev - (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, flags=0) - at block/file-posix.c:1925 - #9 0x00005567a12fe3e1 in bdrv_driver_pwritev - (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, qiov_offset=0, flags=0) - at block/io.c:1183 - #10 0x00005567a1300340 in bdrv_aligned_pwritev - (child=0x5567a2b5b070, req=0x7ff5f4ff9db0, offset=472363008, bytes=20480, align=512, qiov=0x7ff72c0425b8, qiov_offset=0, flags=0) at block/io.c:1980 - #11 0x00005567a1300b29 in bdrv_co_pwritev_part - (child=0x5567a2b5b070, offset=472363008, bytes=20480, qiov=0x7ff72c0425b8, qiov_offset=0, flags=0) - at block/io.c:2137 - #12 0x00005567a12baba1 in qcow2_co_pwritev_task - (bs=0x5567a2b92740, file_cluster_offset=472317952, offset=487305216, bytes=20480, qiov=0x7ff72c0425b8, qiov_offset=0, l2meta=0x0) at block/qcow2.c:2444 - #13 0x00005567a12bacdb in qcow2_co_pwritev_task_entry (task=0x5567a2b48540) at block/qcow2.c:2475 - #14 0x00005567a13167d8 in aio_task_co (opaque=0x5567a2b48540) at block/aio_task.c:45 - #15 0x00005567a13cf00c in coroutine_trampoline (i0=738245600, i1=32759) at util/coroutine-ucontext.c:115 - #16 0x00007ff73eb622e0 in __start_context () at /lib64/libc.so.6 - #17 0x00007ff6626f1350 in () - #18 0x0000000000000000 in () -<------> - -This is also known to cause crashes with this message (assertion -failed): - - aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule' - -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1812765 -Signed-off-by: Sergio Lopez -Message-Id: <20200603093240.40489-3-slp(a)redhat.com> -Signed-off-by: Kevin Wolf ---- - hw/block/dataplane/virtio-blk.c | 8 ++++++++ - hw/block/virtio-blk.c | 18 ++++++++++++------ - include/hw/virtio/virtio-blk.h | 2 +- - 3 files changed, 21 insertions(+), 7 deletions(-) - -diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c -index 5fea76df85..4476f97960 100644 ---- a/hw/block/dataplane/virtio-blk.c -+++ b/hw/block/dataplane/virtio-blk.c -@@ -219,6 +219,9 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) - goto fail_guest_notifiers; - } - -+ /* Process queued requests before the ones in vring */ -+ virtio_blk_process_queued_requests(vblk, false); -+ - /* Kick right away to begin processing requests already in vring */ - for (i = 0; i < nvqs; i++) { - VirtQueue *vq = virtio_get_queue(s->vdev, i); -@@ -238,6 +241,11 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) - return 0; - - fail_guest_notifiers: -+ /* -+ * If we failed to set up the guest notifiers queued requests will be -+ * processed on the main context. -+ */ -+ virtio_blk_process_queued_requests(vblk, false); - vblk->dataplane_disabled = true; - s->starting = false; - vblk->dataplane_started = true; -diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index cee2c673a5..ddf525b9d7 100644 ---- a/hw/block/virtio-blk.c -+++ b/hw/block/virtio-blk.c -@@ -809,7 +809,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) - virtio_blk_handle_output_do(s, vq); - } - --void virtio_blk_process_queued_requests(VirtIOBlock *s) -+void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) - { - VirtIOBlockReq *req = s->rq; - MultiReqBuffer mrb = {}; -@@ -837,7 +837,9 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s) - if (mrb.num_reqs) { - virtio_blk_submit_multireq(s->blk, &mrb); - } -- blk_dec_in_flight(s->conf.conf.blk); -+ if (is_bh) { -+ blk_dec_in_flight(s->conf.conf.blk); -+ } - aio_context_release(blk_get_aio_context(s->conf.conf.blk)); - } - -@@ -848,21 +850,25 @@ static void virtio_blk_dma_restart_bh(void *opaque) - qemu_bh_delete(s->bh); - s->bh = NULL; - -- virtio_blk_process_queued_requests(s); -+ virtio_blk_process_queued_requests(s, true); - } - - static void virtio_blk_dma_restart_cb(void *opaque, int running, - RunState state) - { - VirtIOBlock *s = opaque; -+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); -+ VirtioBusState *bus = VIRTIO_BUS(qbus); - - if (!running) { - return; - } - -- if (!s->bh) { -- /* FIXME The data plane is not started yet, so these requests are -- * processed in the main thread. */ -+ /* -+ * If ioeventfd is enabled, don't schedule the BH here as queued -+ * requests will be processed while starting the data plane. -+ */ -+ if (!s->bh && !virtio_bus_ioeventfd_enabled(bus)) { - s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), - virtio_blk_dma_restart_bh, s); - blk_inc_in_flight(s->conf.conf.blk); -diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h -index cf8eea2f58..e77f0db3b0 100644 ---- a/include/hw/virtio/virtio-blk.h -+++ b/include/hw/virtio/virtio-blk.h -@@ -84,6 +84,6 @@ typedef struct MultiReqBuffer { - } MultiReqBuffer; - - bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); --void virtio_blk_process_queued_requests(VirtIOBlock *s); -+void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); - - #endif --- -2.27.0 - diff --git a/virtio-blk-Refactor-the-code-that-processes-queued-r.patch b/virtio-blk-Refactor-the-code-that-processes-queued-r.patch deleted file mode 100644 index 2848fbd0aae20aceae61a1ad4b07a47d147659b4..0000000000000000000000000000000000000000 --- a/virtio-blk-Refactor-the-code-that-processes-queued-r.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 21c5ffb363930dfe6213bb677c5811fede3bcee2 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez -Date: Thu, 21 Jan 2021 15:46:51 +0800 -Subject: [PATCH] virtio-blk: Refactor the code that processes queued requests - -Move the code that processes queued requests from -virtio_blk_dma_restart_bh() to its own, non-static, function. This -will allow us to call it from the virtio_blk_data_plane_start() in a -future patch. - -Signed-off-by: Sergio Lopez -Message-Id: <20200603093240.40489-2-slp(a)redhat.com> -Signed-off-by: Kevin Wolf ---- - hw/block/virtio-blk.c | 16 +++++++++++----- - include/hw/virtio/virtio-blk.h | 1 + - 2 files changed, 12 insertions(+), 5 deletions(-) - -diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index 703ed4c93b..cee2c673a5 100644 ---- a/hw/block/virtio-blk.c -+++ b/hw/block/virtio-blk.c -@@ -809,15 +809,11 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) - virtio_blk_handle_output_do(s, vq); - } - --static void virtio_blk_dma_restart_bh(void *opaque) -+void virtio_blk_process_queued_requests(VirtIOBlock *s) - { -- VirtIOBlock *s = opaque; - VirtIOBlockReq *req = s->rq; - MultiReqBuffer mrb = {}; - -- qemu_bh_delete(s->bh); -- s->bh = NULL; -- - s->rq = NULL; - - aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); -@@ -845,6 +841,16 @@ static void virtio_blk_dma_restart_bh(void *opaque) - aio_context_release(blk_get_aio_context(s->conf.conf.blk)); - } - -+static void virtio_blk_dma_restart_bh(void *opaque) -+{ -+ VirtIOBlock *s = opaque; -+ -+ qemu_bh_delete(s->bh); -+ s->bh = NULL; -+ -+ virtio_blk_process_queued_requests(s); -+} -+ - static void virtio_blk_dma_restart_cb(void *opaque, int running, - RunState state) - { -diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h -index cddcfbebe9..cf8eea2f58 100644 ---- a/include/hw/virtio/virtio-blk.h -+++ b/include/hw/virtio/virtio-blk.h -@@ -84,5 +84,6 @@ typedef struct MultiReqBuffer { - } MultiReqBuffer; - - bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); -+void virtio_blk_process_queued_requests(VirtIOBlock *s); - - #endif --- -2.27.0 - diff --git a/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch b/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch deleted file mode 100644 index 205f663470d3aa594910bd19e2be8547d226e1a8..0000000000000000000000000000000000000000 --- a/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch +++ /dev/null @@ -1,45 +0,0 @@ -From ec8a25fec9898f46a6a94aa4f328fe02948b3d59 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Sat, 28 Mar 2020 08:57:04 +0800 -Subject: [PATCH 12/14] virtio-blk: delete vqs on the error path in realize() - -virtio_vqs forgot to free on the error path in realize(). Fix that. - -The asan stack: -Direct leak of 14336 byte(s) in 1 object(s) allocated from: - #0 0x7f58b93fd970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) - #1 0x7f58b858249d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) - #2 0x5562cc627f49 in virtio_add_queue /mnt/sdb/qemu/hw/virtio/virtio.c:2413 - #3 0x5562cc4b524a in virtio_blk_device_realize /mnt/sdb/qemu/hw/block/virtio-blk.c:1202 - #4 0x5562cc613050 in virtio_device_realize /mnt/sdb/qemu/hw/virtio/virtio.c:3615 - #5 0x5562ccb7a568 in device_set_realized /mnt/sdb/qemu/hw/core/qdev.c:891 - #6 0x5562cd39cd45 in property_set_bool /mnt/sdb/qemu/qom/object.c:2238 - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Reviewed-by: Stefano Garzarella -Message-Id: <20200328005705.29898-2-pannengyuan@huawei.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Peng Liang ---- - hw/block/virtio-blk.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index cbb3729158fe..703ed4c93bff 100644 ---- a/hw/block/virtio-blk.c -+++ b/hw/block/virtio-blk.c -@@ -1173,6 +1173,9 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) - virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); - if (err != NULL) { - error_propagate(errp, err); -+ for (i = 0; i < conf->num_queues; i++) { -+ virtio_del_queue(vdev, i); -+ } - virtio_cleanup(vdev); - return; - } --- -2.26.2 - diff --git a/virtio-bugfix-add-rcu_read_lock-when-vring_avail_idx.patch b/virtio-bugfix-add-rcu_read_lock-when-vring_avail_idx.patch new file mode 100644 index 0000000000000000000000000000000000000000..39551a752e5ae493872be352cb39191a026420ad --- /dev/null +++ b/virtio-bugfix-add-rcu_read_lock-when-vring_avail_idx.patch @@ -0,0 +1,38 @@ +From 41aa66e37d04246d48b5417c57967425ecc466a0 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 11:16:26 +0800 +Subject: [PATCH] virtio: bugfix: add rcu_read_lock when vring_avail_idx is + called + +viring_avail_idx should be called within rcu_read_lock(), +or may get NULL caches in vring_get_region_caches() and +trigger assert(). + +Signed-off-by: Jinhua Cao +--- + hw/virtio/virtio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 007f4c9e26..0af9684881 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2864,6 +2864,7 @@ static void check_vring_avail_num(VirtIODevice *vdev, int index) + { + uint16_t nheads; + ++ rcu_read_lock(); + /* Check it isn't doing strange things with descriptor numbers. */ + nheads = vring_avail_idx(&vdev->vq[index]) - vdev->vq[index].last_avail_idx; + if (nheads > vdev->vq[index].vring.num) { +@@ -2874,6 +2875,7 @@ static void check_vring_avail_num(VirtIODevice *vdev, int index) + vring_avail_idx(&vdev->vq[index]), + vdev->vq[index].last_avail_idx, nheads); + } ++ rcu_read_unlock(); + } + + int virtio_save(VirtIODevice *vdev, QEMUFile *f) +-- +2.27.0 + diff --git a/virtio-bugfix-check-the-value-of-caches-before-acces.patch b/virtio-bugfix-check-the-value-of-caches-before-acces.patch new file mode 100644 index 0000000000000000000000000000000000000000..8cead345733d1b88a88b21c45c71948e38b147b6 --- /dev/null +++ b/virtio-bugfix-check-the-value-of-caches-before-acces.patch @@ -0,0 +1,42 @@ +From 74ab61b4317f12b231fb2cbcd54a333a07efd678 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 14:37:52 +0800 +Subject: [PATCH] virtio: bugfix: check the value of caches before accessing it + +Vring caches may be NULL in check_vring_avail_num() if +virtio_reset() is called at the same time, such as when +the virtual machine starts. +So check it before accessing it in vring_avail_idx(). + +Signed-off-by: Jinhua Cao +--- + hw/virtio/virtio.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 9a2a83d507..b08fff9419 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2863,8 +2863,19 @@ static const VMStateDescription vmstate_virtio = { + static void check_vring_avail_num(VirtIODevice *vdev, int index) + { + uint16_t nheads; ++ VRingMemoryRegionCaches *caches; + + rcu_read_lock(); ++ caches = qatomic_rcu_read(&vdev->vq[index].vring.caches); ++ if (caches == NULL) { ++ /* ++ * caches may be NULL if virtio_reset is called at the same time, ++ * such as when the virtual machine starts. ++ */ ++ rcu_read_unlock(); ++ return; ++ } ++ + /* Check it isn't doing strange things with descriptor numbers. */ + nheads = vring_avail_idx(&vdev->vq[index]) - vdev->vq[index].last_avail_idx; + if (nheads > vdev->vq[index].vring.num) { +-- +2.27.0 + diff --git a/virtio-bugfix-clean-up-callback-when-del-virtqueue.patch b/virtio-bugfix-clean-up-callback-when-del-virtqueue.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0e259b19742a5aef0b42e3d8cb16100e6449ae5 --- /dev/null +++ b/virtio-bugfix-clean-up-callback-when-del-virtqueue.patch @@ -0,0 +1,52 @@ +From 95d334a905e8ddaac4a8cec908dcdb03b2e5993f Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 10:17:20 +0800 +Subject: [PATCH] virtio: bugfix: clean up callback when del virtqueue + +We will access NULL pointer as follow: +1. Start a vm with multiqueue vhost-net +2. then we write VIRTIO_PCI_GUEST_FEATURES in PCI configuration to + trigger multiqueue disable in this vm which will delete the virtqueue. + In this step, the tx_bh is deleted but the callback virtio_net_handle_tx_bh + still exist. +3. Finally, we write VIRTIO_PCI_QUEUE_NOTIFY in PCI configuration to + notify the deleted virtqueue. In this way, virtio_net_handle_tx_bh + will be called and qemu will be crashed. + +Signed-off-by: Jinhua Cao +--- + hw/net/virtio-net.c | 5 ++++- + hw/virtio/virtio.c | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index f2014d5ea0..b3a5d0b19e 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -2644,7 +2644,10 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) + return; + } + virtio_queue_set_notification(vq, 0); +- qemu_bh_schedule(q->tx_bh); ++ ++ if (q->tx_bh) { ++ qemu_bh_schedule(q->tx_bh); ++ } + } + + static void virtio_net_tx_timer(void *opaque) +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 9b4ac58a16..ec3e96af3b 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2417,6 +2417,7 @@ void virtio_delete_queue(VirtQueue *vq) + { + vq->vring.num = 0; + vq->vring.num_default = 0; ++ vq->vring.align = 0; + vq->handle_output = NULL; + vq->handle_aio_output = NULL; + g_free(vq->used_elems); +-- +2.27.0 + diff --git a/virtio-check-descriptor-numbers.patch b/virtio-check-descriptor-numbers.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea38103f2e17a2657060d9b72edf6470c8b0041c --- /dev/null +++ b/virtio-check-descriptor-numbers.patch @@ -0,0 +1,52 @@ +From 9e04e1c6a7a12e3e1d0a8a7cf07f441597a1dbb7 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 11:09:36 +0800 +Subject: [PATCH] virtio: check descriptor numbers + +Check if the vring num is normal in virtio_save(), and add LOG +the vm push the wrong viring num down through writing IO Port. + +Signed-off-by: Jinhua Cao +--- + hw/virtio/virtio.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 03afa36e99..007f4c9e26 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2860,6 +2860,22 @@ static const VMStateDescription vmstate_virtio = { + } + }; + ++static void check_vring_avail_num(VirtIODevice *vdev, int index) ++{ ++ uint16_t nheads; ++ ++ /* Check it isn't doing strange things with descriptor numbers. */ ++ nheads = vring_avail_idx(&vdev->vq[index]) - vdev->vq[index].last_avail_idx; ++ if (nheads > vdev->vq[index].vring.num) { ++ qemu_log("VQ %d size 0x%x Guest index 0x%x " ++ "inconsistent with Host index 0x%x: " ++ "delta 0x%x\n", ++ index, vdev->vq[index].vring.num, ++ vring_avail_idx(&vdev->vq[index]), ++ vdev->vq[index].last_avail_idx, nheads); ++ } ++} ++ + int virtio_save(VirtIODevice *vdev, QEMUFile *f) + { + BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); +@@ -2890,6 +2906,8 @@ int virtio_save(VirtIODevice *vdev, QEMUFile *f) + if (vdev->vq[i].vring.num == 0) + break; + ++ check_vring_avail_num(vdev, i); ++ + qemu_put_be32(f, vdev->vq[i].vring.num); + if (k->has_variable_vring_alignment) { + qemu_put_be32(f, vdev->vq[i].vring.align); +-- +2.27.0 + diff --git a/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch b/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch deleted file mode 100644 index aab3e86663021d2576763fff2a4f9c5985a2fb32..0000000000000000000000000000000000000000 --- a/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 62ded4fc6b38e2642ea4d95a93d70d0f608bee65 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Tue, 25 Feb 2020 15:55:54 +0800 -Subject: [PATCH 3/9] virtio-crypto: do delete ctrl_vq in - virtio_crypto_device_unrealize - -Similar to other virtio-deivces, ctrl_vq forgot to delete in virtio_crypto_device_unrealize, this patch fix it. -This device has aleardy maintained vq pointers. Thus, we use the new virtio_delete_queue function directly to do the cleanup. - -The leak stack: -Direct leak of 10752 byte(s) in 3 object(s) allocated from: - #0 0x7f4c024b1970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) - #1 0x7f4c018be49d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) - #2 0x55a2f8017279 in virtio_add_queue /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio.c:2333 - #3 0x55a2f8057035 in virtio_crypto_device_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio-crypto.c:814 - #4 0x55a2f8005d80 in virtio_device_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio.c:3531 - #5 0x55a2f8497d1b in device_set_realized /mnt/sdb/qemu-new/qemu_test/qemu/hw/core/qdev.c:891 - #6 0x55a2f8b48595 in property_set_bool /mnt/sdb/qemu-new/qemu_test/qemu/qom/object.c:2238 - #7 0x55a2f8b54fad in object_property_set_qobject /mnt/sdb/qemu-new/qemu_test/qemu/qom/qom-qobject.c:26 - #8 0x55a2f8b4de2c in object_property_set_bool /mnt/sdb/qemu-new/qemu_test/qemu/qom/object.c:1390 - #9 0x55a2f80609c9 in virtio_crypto_pci_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio-crypto-pci.c:58 - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Cc: "Gonglei (Arei)" -Message-Id: <20200225075554.10835-5-pannengyuan@huawei.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/virtio/virtio-crypto.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c -index 45187d3..0076b4b 100644 ---- a/hw/virtio/virtio-crypto.c -+++ b/hw/virtio/virtio-crypto.c -@@ -830,12 +830,13 @@ static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp) - - max_queues = vcrypto->multiqueue ? vcrypto->max_queues : 1; - for (i = 0; i < max_queues; i++) { -- virtio_del_queue(vdev, i); -+ virtio_delete_queue(vcrypto->vqs[i].dataq); - q = &vcrypto->vqs[i]; - qemu_bh_delete(q->dataq_bh); - } - - g_free(vcrypto->vqs); -+ virtio_delete_queue(vcrypto->ctrl_vq); - - virtio_cleanup(vdev); - cryptodev_backend_set_used(vcrypto->cryptodev, false); --- -1.8.3.1 - diff --git a/virtio-crypto-verify-src-dst-buffer-length-for-sym-r.patch b/virtio-crypto-verify-src-dst-buffer-length-for-sym-r.patch new file mode 100644 index 0000000000000000000000000000000000000000..a449c2df4fed8f4f990ea4a3a9095c46d416f5c3 --- /dev/null +++ b/virtio-crypto-verify-src-dst-buffer-length-for-sym-r.patch @@ -0,0 +1,47 @@ +From 017c7af0d5b928c6af60f8262c62d4c570b2e55e Mon Sep 17 00:00:00 2001 +From: zhenwei pi +Date: Thu, 3 Aug 2023 10:43:13 +0800 +Subject: [PATCH] virtio-crypto: verify src&dst buffer length for sym request + +For symmetric algorithms, the length of ciphertext must be as same +as the plaintext. +The missing verification of the src_len and the dst_len in +virtio_crypto_sym_op_helper() may lead buffer overflow/divulged. + +This patch is originally written by Yiming Tao for QEMU-SECURITY, +resend it(a few changes of error message) in qemu-devel. + +Fixes: CVE-2023-3180 +Fixes: 04b9b37edda("virtio-crypto: add data queue processing handler") +Cc: Gonglei +Cc: Mauro Matteo Cascella +Cc: Yiming Tao +Signed-off-by: zhenwei pi +Message-Id: <20230803024314.29962-2-pizhenwei@bytedance.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 9d38a8434721a6479fe03fb5afb150ca793d3980) +Signed-off-by: Michael Tokarev +--- + hw/virtio/virtio-crypto.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 54f9bbb789..274c7b4dea 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -461,6 +461,11 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, + return NULL; + } + ++ if (unlikely(src_len != dst_len)) { ++ virtio_error(vdev, "sym request src len is different from dst len"); ++ return NULL; ++ } ++ + max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; + if (unlikely(max_len > vcrypto->conf.max_size)) { + virtio_error(vdev, "virtio-crypto too big length"); +-- +2.41.0.windows.1 + diff --git a/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch b/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch new file mode 100644 index 0000000000000000000000000000000000000000..76ce5d75e24557b07aba59af4f7becd36d407a26 --- /dev/null +++ b/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch @@ -0,0 +1,46 @@ +From 9110c9bf711a39b3c9a1bdbe2fc84f38930d3094 Mon Sep 17 00:00:00 2001 +From: zhenwei pi +Date: Thu, 3 Aug 2023 10:43:13 +0800 +Subject: [PATCH] virtio-crypto: verify src&dst buffer length for sym request + +For symmetric algorithms, the length of ciphertext must be as same +as the plaintext. +The missing verification of the src_len and the dst_len in +virtio_crypto_sym_op_helper() may lead buffer overflow/divulged. + +This patch is originally written by Yiming Tao for QEMU-SECURITY, +resend it(a few changes of error message) in qemu-devel. + +Fixes: CVE-2023-3180 +Fixes: 04b9b37edda("virtio-crypto: add data queue processing handler") +Cc: Gonglei +Cc: Mauro Matteo Cascella +Cc: Yiming Tao +Signed-off-by: zhenwei pi +Message-Id: <20230803024314.29962-2-pizhenwei@bytedance.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-crypto.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 98304184cd..9f7dcc88ba 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -466,6 +466,11 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, + return NULL; + } + ++ if (unlikely(src_len != dst_len)) { ++ virtio_error(vdev, "sym request src len is different from dst len"); ++ return NULL; ++ } ++ + max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; + if (unlikely(max_len > vcrypto->conf.max_size)) { + virtio_error(vdev, "virtio-crypto too big length"); +-- +2.27.0 + diff --git a/virtio-don-t-enable-notifications-during-polling.patch b/virtio-don-t-enable-notifications-during-polling.patch deleted file mode 100644 index cb77429e9e2fa70688ed245f7cf440fb61cd38ad..0000000000000000000000000000000000000000 --- a/virtio-don-t-enable-notifications-during-polling.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 0592b1e444e8ef7f00fb04a637dba72b732b70e4 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 9 Dec 2019 21:09:57 +0000 -Subject: [PATCH] virtio: don't enable notifications during polling - -Virtqueue notifications are not necessary during polling, so we disable -them. This allows the guest driver to avoid MMIO vmexits. -Unfortunately the virtio-blk and virtio-scsi handler functions re-enable -notifications, defeating this optimization. - -Fix virtio-blk and virtio-scsi emulation so they leave notifications -disabled. The key thing to remember for correctness is that polling -always checks one last time after ending its loop, therefore it's safe -to lose the race when re-enabling notifications at the end of polling. - -There is a measurable performance improvement of 5-10% with the null-co -block driver. Real-life storage configurations will see a smaller -improvement because the MMIO vmexit overhead contributes less to -latency. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20191209210957.65087-1-stefanha@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin ---- - hw/block/virtio-blk.c | 9 +++++++-- - hw/scsi/virtio-scsi.c | 9 +++++++-- - hw/virtio/virtio.c | 12 ++++++------ - include/hw/virtio/virtio.h | 1 + - 4 files changed, 21 insertions(+), 10 deletions(-) - -diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index 2db9804cfe..fbe2ed6779 100644 ---- a/hw/block/virtio-blk.c -+++ b/hw/block/virtio-blk.c -@@ -766,13 +766,16 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) - { - VirtIOBlockReq *req; - MultiReqBuffer mrb = {}; -+ bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; - - aio_context_acquire(blk_get_aio_context(s->blk)); - blk_io_plug(s->blk); - - do { -- virtio_queue_set_notification(vq, 0); -+ if (suppress_notifications) { -+ virtio_queue_set_notification(vq, 0); -+ } - - while ((req = virtio_blk_get_request(s, vq))) { - progress = true; -@@ -783,7 +786,9 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) - } - } - -- virtio_queue_set_notification(vq, 1); -+ if (suppress_notifications) { -+ virtio_queue_set_notification(vq, 1); -+ } - } while (!virtio_queue_empty(vq)); - - if (mrb.num_reqs) { -diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c -index 8b9e5e2b49..eddb13e7c6 100644 ---- a/hw/scsi/virtio-scsi.c -+++ b/hw/scsi/virtio-scsi.c -@@ -594,12 +594,15 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) - { - VirtIOSCSIReq *req, *next; - int ret = 0; -+ bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; - - QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - - do { -- virtio_queue_set_notification(vq, 0); -+ if (suppress_notifications) { -+ virtio_queue_set_notification(vq, 0); -+ } - - while ((req = virtio_scsi_pop_req(s, vq))) { - progress = true; -@@ -619,7 +622,9 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) - } - } - -- virtio_queue_set_notification(vq, 1); -+ if (suppress_notifications) { -+ virtio_queue_set_notification(vq, 1); -+ } - } while (ret != -EINVAL && !virtio_queue_empty(vq)); - - QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index 90971f4afa..daa8250332 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -390,6 +390,11 @@ void virtio_queue_set_notification(VirtQueue *vq, int enable) - rcu_read_unlock(); - } - -+bool virtio_queue_get_notification(VirtQueue *vq) -+{ -+ return vq->notification; -+} -+ - int virtio_queue_ready(VirtQueue *vq) - { - return vq->vring.avail != 0; -@@ -2572,17 +2577,12 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque) - { - EventNotifier *n = opaque; - VirtQueue *vq = container_of(n, VirtQueue, host_notifier); -- bool progress; - - if (!vq->vring.desc || virtio_queue_empty(vq)) { - return false; - } - -- progress = virtio_queue_notify_aio_vq(vq); -- -- /* In case the handler function re-enabled notifications */ -- virtio_queue_set_notification(vq, 0); -- return progress; -+ return virtio_queue_notify_aio_vq(vq); - } - - static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) -diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h -index ca2fbaeb35..7394715407 100644 ---- a/include/hw/virtio/virtio.h -+++ b/include/hw/virtio/virtio.h -@@ -229,6 +229,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); - - void virtio_notify_config(VirtIODevice *vdev); - -+bool virtio_queue_get_notification(VirtQueue *vq); - void virtio_queue_set_notification(VirtQueue *vq, int enable); - - int virtio_queue_ready(VirtQueue *vq); --- -2.27.0 - diff --git a/virtio-fix-enable-vhost-user-build-on-non-Linux.patch b/virtio-fix-enable-vhost-user-build-on-non-Linux.patch new file mode 100644 index 0000000000000000000000000000000000000000..c124baf67a3615f63340642476aeeecdc9f326b6 --- /dev/null +++ b/virtio-fix-enable-vhost-user-build-on-non-Linux.patch @@ -0,0 +1,39 @@ +From 558472cd6040b5515baaf860b5bba0c1c511d18b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 28 Mar 2022 17:58:27 +0200 +Subject: [PATCH] virtio: fix --enable-vhost-user build on non-Linux +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The vhost-shadow-virtqueue.c build requires include files from +linux-headers/, so it cannot be built on non-Linux systems. +Fortunately it is only needed by vhost-vdpa, so move it there. + +Acked-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Paolo Bonzini +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index c2e193f56d..c2da69616f 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,9 +11,9 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) +-virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) ++virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-shadow-virtqueue.c', 'vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) + virtio_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-crypto-pci.c')) +-- +2.27.0 + diff --git a/virtio-fix-reachable-assertion-due-to-stale-value-of.patch b/virtio-fix-reachable-assertion-due-to-stale-value-of.patch new file mode 100644 index 0000000000000000000000000000000000000000..e070054f871114dd33a301f61d365f8a7e77d4b5 --- /dev/null +++ b/virtio-fix-reachable-assertion-due-to-stale-value-of.patch @@ -0,0 +1,110 @@ +From fc3c5fc2f3ccc236a6bcb670043912ab31e99772 Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 26 May 2023 11:09:19 +0800 +Subject: [PATCH] virtio: fix reachable assertion due to stale value of cached + region size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In virtqueue_{split,packed}_get_avail_bytes() descriptors are read +in a loop via MemoryRegionCache regions and calls to +vring_{split,packed}_desc_read() - these take a region cache and the +index of the descriptor to be read. + +For direct descriptors we use a cache provided by the caller, whose +size matches that of the virtqueue vring. We limit the number of +descriptors we can read by the size of that vring: + max = vq->vring.num; + ... + MemoryRegionCache *desc_cache = &caches->desc; + +For indirect descriptors, we initialize a new cache and limit the +number of descriptors by the size of the intermediate descriptor: + + len = address_space_cache_init(&indirect_desc_cache, + vdev->dma_as, + desc.addr, desc.len, false); + desc_cache = &indirect_desc_cache; + ... + max = desc.len / sizeof(VRingDesc); + +However, the first initialization of `max` is done outside the loop +where we process guest descriptors, while the second one is done +inside. This means that a sequence of an indirect descriptor followed +by a direct one will leave a stale value in `max`. If the second +descriptor's `next` field is smaller than the stale value, but +greater than the size of the virtqueue ring (and thus the cached +region), a failed assertion will be triggered in +address_space_read_cached() down the call chain. + +Fix this by initializing `max` inside the loop in both functions. + +origin commit: https://gitlab.com/qemu-project/qemu/-/commit/bbc1c327d7974261c61566cdb950cc5fa0196b41 +Signed-off-by: Meiyang Wang +Fixes: 9796d0ac8fb0 ("virtio: use address_space_map/unmap to access descriptors") +Signed-off-by: Carlos López +Message-Id: <20230302100358.3613-1-clopez@suse.de> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/virtio.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index f8ab48e6bd..071668e3e0 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -983,7 +983,7 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq, + VRingMemoryRegionCaches *caches) + { + VirtIODevice *vdev = vq->vdev; +- unsigned int max, idx; ++ unsigned int idx; + unsigned int total_bufs, in_total, out_total; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + int64_t len = 0; +@@ -992,13 +992,12 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq, + idx = vq->last_avail_idx; + total_bufs = in_total = out_total = 0; + +- max = vq->vring.num; +- + while ((rc = virtqueue_num_heads(vq, idx)) > 0) { + MemoryRegionCache *desc_cache = &caches->desc; + unsigned int num_bufs; + VRingDesc desc; + unsigned int i; ++ unsigned int max = vq->vring.num; + + num_bufs = total_bufs; + +@@ -1120,7 +1119,7 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq, + VRingMemoryRegionCaches *caches) + { + VirtIODevice *vdev = vq->vdev; +- unsigned int max, idx; ++ unsigned int idx; + unsigned int total_bufs, in_total, out_total; + MemoryRegionCache *desc_cache; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; +@@ -1132,14 +1131,14 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq, + wrap_counter = vq->last_avail_wrap_counter; + total_bufs = in_total = out_total = 0; + +- max = vq->vring.num; +- + for (;;) { + unsigned int num_bufs = total_bufs; + unsigned int i = idx; + int rc; ++ unsigned int max = vq->vring.num; + + desc_cache = &caches->desc; ++ + vring_packed_desc_read(vdev, &desc, desc_cache, idx, true); + if (!is_desc_avail(desc.flags, wrap_counter)) { + break; +-- +2.41.0.windows.1 + diff --git a/virtio-get-class_id-and-pci-device-id-by-the-virtio-.patch b/virtio-get-class_id-and-pci-device-id-by-the-virtio-.patch new file mode 100644 index 0000000000000000000000000000000000000000..28d19266c62fca46e8e60bdb6314856e21f49ff4 --- /dev/null +++ b/virtio-get-class_id-and-pci-device-id-by-the-virtio-.patch @@ -0,0 +1,156 @@ +From 78f66113a2c3a01f0290a982f6901ba57516f47f Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 12 Nov 2022 22:40:09 +0800 +Subject: [PATCH 2/7] virtio: get class_id and pci device id by the virtio id + +Add helpers to get the "Transitional PCI Device ID" and "class_id" +of the device specified by the "Virtio Device ID". + +These helpers will be used to build the generic vDPA device later. + +Acked-by: Jason Wang +Signed-off-by: Longpeng +--- + hw/virtio/virtio-pci.c | 88 ++++++++++++++++++++++++++++++++++++++++++ + hw/virtio/virtio-pci.h | 5 +++ + 2 files changed, 93 insertions(+) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 38a5dc1ba8..21c0ec3b1b 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -19,6 +19,7 @@ + + #include "exec/memop.h" + #include "standard-headers/linux/virtio_pci.h" ++#include "standard-headers/linux/virtio_ids.h" + #include "hw/boards.h" + #include "hw/virtio/virtio.h" + #include "migration/qemu-file-types.h" +@@ -213,6 +214,90 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) + return 0; + } + ++typedef struct VirtIOPCIIDInfo { ++ /* virtio id */ ++ uint16_t vdev_id; ++ /* pci device id for the transitional device */ ++ uint16_t trans_devid; ++ uint16_t class_id; ++} VirtIOPCIIDInfo; ++ ++static const VirtIOPCIIDInfo virtio_pci_id_info[] = { ++ { ++ .vdev_id = VIRTIO_ID_CRYPTO, ++ .class_id = PCI_CLASS_OTHERS, ++ }, { ++ .vdev_id = VIRTIO_ID_FS, ++ .class_id = PCI_CLASS_STORAGE_OTHER, ++ }, { ++ .vdev_id = VIRTIO_ID_NET, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_NET, ++ .class_id = PCI_CLASS_NETWORK_ETHERNET, ++ }, { ++ .vdev_id = VIRTIO_ID_BLOCK, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_BLOCK, ++ .class_id = PCI_CLASS_STORAGE_SCSI, ++ }, { ++ .vdev_id = VIRTIO_ID_CONSOLE, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_CONSOLE, ++ .class_id = PCI_CLASS_COMMUNICATION_OTHER, ++ }, { ++ .vdev_id = VIRTIO_ID_SCSI, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_SCSI, ++ .class_id = PCI_CLASS_STORAGE_SCSI ++ }, { ++ .vdev_id = VIRTIO_ID_9P, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_9P, ++ .class_id = PCI_BASE_CLASS_NETWORK, ++ }, { ++ .vdev_id = VIRTIO_ID_BALLOON, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_BALLOON, ++ .class_id = PCI_CLASS_OTHERS, ++ }, { ++ .vdev_id = VIRTIO_ID_RNG, ++ .trans_devid = PCI_DEVICE_ID_VIRTIO_RNG, ++ .class_id = PCI_CLASS_OTHERS, ++ }, ++}; ++ ++static const VirtIOPCIIDInfo *virtio_pci_get_id_info(uint16_t vdev_id) ++{ ++ const VirtIOPCIIDInfo *info = NULL; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(virtio_pci_id_info); i++) { ++ if (virtio_pci_id_info[i].vdev_id == vdev_id) { ++ info = &virtio_pci_id_info[i]; ++ break; ++ } ++ } ++ ++ if (!info) { ++ /* The device id is invalid or not added to the id_info yet. */ ++ error_report("Invalid virtio device(id %u)", vdev_id); ++ abort(); ++ } ++ ++ return info; ++} ++ ++/* ++ * Get the Transitional Device ID for the specific device, return ++ * zero if the device is non-transitional. ++ */ ++uint16_t virtio_pci_get_trans_devid(uint16_t device_id) ++{ ++ return virtio_pci_get_id_info(device_id)->trans_devid; ++} ++ ++/* ++ * Get the Class ID for the specific device. ++ */ ++uint16_t virtio_pci_get_class_id(uint16_t device_id) ++{ ++ return virtio_pci_get_id_info(device_id)->class_id; ++} ++ + static bool virtio_pci_ioeventfd_enabled(DeviceState *d) + { + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); +@@ -1674,6 +1759,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) + * is set to PCI_SUBVENDOR_ID_REDHAT_QUMRANET by default. + */ + pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); ++ if (proxy->trans_devid) { ++ pci_config_set_device_id(config, proxy->trans_devid); ++ } + } else { + /* pure virtio-1.0 */ + pci_set_word(config + PCI_VENDOR_ID, +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index 2446dcd9ae..d95b1a13a5 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -146,6 +146,8 @@ struct VirtIOPCIProxy { + bool disable_modern; + bool ignore_backend_features; + OnOffAuto disable_legacy; ++ /* Transitional device id */ ++ uint16_t trans_devid; + uint32_t class_code; + uint32_t nvectors; + uint32_t dfselect; +@@ -179,6 +181,9 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) + proxy->disable_modern = true; + } + ++uint16_t virtio_pci_get_trans_devid(uint16_t device_id); ++uint16_t virtio_pci_get_class_id(uint16_t device_id); ++ + /* + * virtio-input-pci: This extends VirtioPCIProxy. + */ +-- +2.27.0 + diff --git a/virtio-gpu-add-a-FIXME-for-virtio_gpu_load.patch b/virtio-gpu-add-a-FIXME-for-virtio_gpu_load.patch new file mode 100644 index 0000000000000000000000000000000000000000..04f60db3dc7dbb4ec256a32bd2561f82e3078bf7 --- /dev/null +++ b/virtio-gpu-add-a-FIXME-for-virtio_gpu_load.patch @@ -0,0 +1,37 @@ +From 5a69ce95a920377f1c4f0c34c6cb8073dc5dbf8d Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 26 Jun 2023 14:29:40 +0800 +Subject: [PATCH] virtio-gpu: add a FIXME for virtio_gpu_load() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 529969b8d03970bae5feef8c69ebf5e0f521131c + +It looks like the virtio_gpu_load() does not compute and set the offset, +the same way virtio_gpu_set_scanout() does. This probably results in +incorrect display until the scanout/framebuffer is updated again, I +guess we should fix it, although I haven't checked this yet. + +Signed-off-by: Marc-André Lureau +Message-Id: <20230515132518.1025853-1-marcandre.lureau@redhat.com> +Signed-off-by: qihao_yewu +--- + hw/display/virtio-gpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index c6dc818988..9ccc0575e3 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -1284,6 +1284,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, + /* load & apply scanout state */ + vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { ++ /* FIXME: should take scanout.r.{x,y} into account */ + scanout = &g->parent_obj.scanout[i]; + if (!scanout->resource_id) { + continue; +-- +2.41.0.windows.1 + diff --git a/virtio-gracefully-handle-invalid-region-caches.patch b/virtio-gracefully-handle-invalid-region-caches.patch deleted file mode 100644 index 2793f21b0d988625b4f53624c471c403937fcedc..0000000000000000000000000000000000000000 --- a/virtio-gracefully-handle-invalid-region-caches.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 63a3c25baa9c7372b80df80be4447552af6d6ba0 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 7 Feb 2020 10:46:19 +0000 -Subject: [PATCH 7/9] virtio: gracefully handle invalid region caches - -The virtqueue code sets up MemoryRegionCaches to access the virtqueue -guest RAM data structures. The code currently assumes that -VRingMemoryRegionCaches is initialized before device emulation code -accesses the virtqueue. An assertion will fail in -vring_get_region_caches() when this is not true. Device fuzzing found a -case where this assumption is false (see below). - -Virtqueue guest RAM addresses can also be changed from a vCPU thread -while an IOThread is accessing the virtqueue. This breaks the same -assumption but this time the caches could become invalid partway through -the virtqueue code. The code fetches the caches RCU pointer multiple -times so we will need to validate the pointer every time it is fetched. - -Add checks each time we call vring_get_region_caches() and treat invalid -caches as a nop: memory stores are ignored and memory reads return 0. - -The fuzz test failure is as follows: - - $ qemu -M pc -device virtio-blk-pci,id=drv0,drive=drive0,addr=4.0 \ - -drive if=none,id=drive0,file=null-co://,format=raw,auto-read-only=off \ - -drive if=none,id=drive1,file=null-co://,file.read-zeroes=on,format=raw \ - -display none \ - -qtest stdio - endianness - outl 0xcf8 0x80002020 - outl 0xcfc 0xe0000000 - outl 0xcf8 0x80002004 - outw 0xcfc 0x7 - write 0xe0000000 0x24 0x00ffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffab5cffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffab0000000001 - inb 0x4 - writew 0xe000001c 0x1 - write 0xe0000014 0x1 0x0d - -The following error message is produced: - - qemu-system-x86_64: /home/stefanha/qemu/hw/virtio/virtio.c:286: vring_get_region_caches: Assertion `caches != NULL' failed. - -The backtrace looks like this: - - #0 0x00007ffff5520625 in raise () at /lib64/libc.so.6 - #1 0x00007ffff55098d9 in abort () at /lib64/libc.so.6 - #2 0x00007ffff55097a9 in _nl_load_domain.cold () at /lib64/libc.so.6 - #3 0x00007ffff5518a66 in annobin_assert.c_end () at /lib64/libc.so.6 - #4 0x00005555559073da in vring_get_region_caches (vq=) at qemu/hw/virtio/virtio.c:286 - #5 vring_get_region_caches (vq=) at qemu/hw/virtio/virtio.c:283 - #6 0x000055555590818d in vring_used_flags_set_bit (mask=1, vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:398 - #7 virtio_queue_split_set_notification (enable=0, vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:398 - #8 virtio_queue_set_notification (vq=vq@entry=0x5555575ceea0, enable=enable@entry=0) at qemu/hw/virtio/virtio.c:451 - #9 0x0000555555908512 in virtio_queue_set_notification (vq=vq@entry=0x5555575ceea0, enable=enable@entry=0) at qemu/hw/virtio/virtio.c:444 - #10 0x00005555558c697a in virtio_blk_handle_vq (s=0x5555575c57e0, vq=0x5555575ceea0) at qemu/hw/block/virtio-blk.c:775 - #11 0x0000555555907836 in virtio_queue_notify_aio_vq (vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:2244 - #12 0x0000555555cb5dd7 in aio_dispatch_handlers (ctx=ctx@entry=0x55555671a420) at util/aio-posix.c:429 - #13 0x0000555555cb67a8 in aio_dispatch (ctx=0x55555671a420) at util/aio-posix.c:460 - #14 0x0000555555cb307e in aio_ctx_dispatch (source=, callback=, user_data=) at util/async.c:260 - #15 0x00007ffff7bbc510 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0 - #16 0x0000555555cb5848 in glib_pollfds_poll () at util/main-loop.c:219 - #17 os_host_main_loop_wait (timeout=) at util/main-loop.c:242 - #18 main_loop_wait (nonblocking=) at util/main-loop.c:518 - #19 0x00005555559b20c9 in main_loop () at vl.c:1683 - #20 0x0000555555838115 in main (argc=, argv=, envp=) at vl.c:4441 - -Reported-by: Alexander Bulekov -Cc: Michael Tsirkin -Cc: Cornelia Huck -Cc: Paolo Bonzini -Cc: qemu-stable@nongnu.org -Signed-off-by: Stefan Hajnoczi -Message-Id: <20200207104619.164892-1-stefanha@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/virtio/virtio.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 59 insertions(+), 7 deletions(-) - -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index 3d027d3..90971f4 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -221,15 +221,19 @@ static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, - - static VRingMemoryRegionCaches *vring_get_region_caches(struct VirtQueue *vq) - { -- VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); -- assert(caches != NULL); -- return caches; -+ return atomic_rcu_read(&vq->vring.caches); - } -+ - /* Called within rcu_read_lock(). */ - static inline uint16_t vring_avail_flags(VirtQueue *vq) - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingAvail, flags); -+ -+ if (!caches) { -+ return 0; -+ } -+ - return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); - } - -@@ -238,6 +242,11 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq) - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingAvail, idx); -+ -+ if (!caches) { -+ return 0; -+ } -+ - vq->shadow_avail_idx = virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); - return vq->shadow_avail_idx; - } -@@ -247,6 +256,11 @@ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingAvail, ring[i]); -+ -+ if (!caches) { -+ return 0; -+ } -+ - return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); - } - -@@ -262,6 +276,11 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingUsed, ring[i]); -+ -+ if (!caches) { -+ return; -+ } -+ - virtio_tswap32s(vq->vdev, &uelem->id); - virtio_tswap32s(vq->vdev, &uelem->len); - address_space_write_cached(&caches->used, pa, uelem, sizeof(VRingUsedElem)); -@@ -273,6 +292,11 @@ static uint16_t vring_used_idx(VirtQueue *vq) - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingUsed, idx); -+ -+ if (!caches) { -+ return 0; -+ } -+ - return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); - } - -@@ -281,8 +305,12 @@ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) - { - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - hwaddr pa = offsetof(VRingUsed, idx); -- virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); -- address_space_cache_invalidate(&caches->used, pa, sizeof(val)); -+ -+ if (caches) { -+ virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); -+ address_space_cache_invalidate(&caches->used, pa, sizeof(val)); -+ } -+ - vq->used_idx = val; - } - -@@ -292,8 +320,13 @@ static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - VirtIODevice *vdev = vq->vdev; - hwaddr pa = offsetof(VRingUsed, flags); -- uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); -+ uint16_t flags; -+ -+ if (!caches) { -+ return; -+ } - -+ flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); - virtio_stw_phys_cached(vdev, &caches->used, pa, flags | mask); - address_space_cache_invalidate(&caches->used, pa, sizeof(flags)); - } -@@ -304,8 +337,13 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) - VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); - VirtIODevice *vdev = vq->vdev; - hwaddr pa = offsetof(VRingUsed, flags); -- uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); -+ uint16_t flags; - -+ if (!caches) { -+ return; -+ } -+ -+ flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); - virtio_stw_phys_cached(vdev, &caches->used, pa, flags & ~mask); - address_space_cache_invalidate(&caches->used, pa, sizeof(flags)); - } -@@ -320,6 +358,10 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) - } - - caches = vring_get_region_caches(vq); -+ if (!caches) { -+ return; -+ } -+ - pa = offsetof(VRingUsed, ring[vq->vring.num]); - virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); - address_space_cache_invalidate(&caches->used, pa, sizeof(val)); -@@ -626,6 +668,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, - - max = vq->vring.num; - caches = vring_get_region_caches(vq); -+ if (!caches) { -+ virtio_error(vdev, "Region cached not initialized"); -+ goto err; -+ } -+ - if (caches->desc.len < max * sizeof(VRingDesc)) { - virtio_error(vdev, "Cannot map descriptor ring"); - goto err; -@@ -894,6 +941,11 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) - i = head; - - caches = vring_get_region_caches(vq); -+ if (!caches) { -+ virtio_error(vdev, "Region caches not initialized"); -+ goto done; -+ } -+ - if (caches->desc.len < max * sizeof(VRingDesc)) { - virtio_error(vdev, "Cannot map descriptor ring"); - goto done; --- -1.8.3.1 - diff --git a/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch b/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch new file mode 100644 index 0000000000000000000000000000000000000000..79c916cd088ad0d6dd31a1899e56af486fa22b20 --- /dev/null +++ b/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch @@ -0,0 +1,55 @@ +From 7f25adf1fd99b5b8f9455537d0c6108837ee25de Mon Sep 17 00:00:00 2001 +From: Viresh Kumar +Date: Tue, 18 Apr 2023 09:24:54 +0530 +Subject: [PATCH] virtio: i2c: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX + +Since the driver doesn't support interrupts, we must return early when +index is set to VIRTIO_CONFIG_IRQ_IDX. + +Fixes: 544f0278afca ("virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX") +Signed-off-by: Viresh Kumar +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user-i2c.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c +index dcaf471115..19add4a707 100644 +--- a/hw/virtio/vhost-user-i2c.c ++++ b/hw/virtio/vhost-user-i2c.c +@@ -129,6 +129,14 @@ static void vu_i2c_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ + vhost_virtqueue_mask(&i2c->vhost_dev, vdev, idx, mask); + } + +@@ -136,6 +144,14 @@ static bool vu_i2c_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } ++ + return vhost_virtqueue_pending(&i2c->vhost_dev, idx); + } + +-- +2.27.0 + diff --git a/virtio-input-fix-memory-leak-on-unrealize.patch b/virtio-input-fix-memory-leak-on-unrealize.patch deleted file mode 100644 index df83453f04525eb4b9fa29ba3d03dc6fa8b31fc5..0000000000000000000000000000000000000000 --- a/virtio-input-fix-memory-leak-on-unrealize.patch +++ /dev/null @@ -1,45 +0,0 @@ -From e29f08036ff11bf220463b4327b315505e760a44 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Thu, 21 Nov 2019 13:56:49 +0400 -Subject: [PATCH 9/9] virtio-input: fix memory leak on unrealize -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Spotted by ASAN + minor stylistic change. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Message-Id: <20191121095649.25453-1-marcandre.lureau@redhat.com> -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/input/virtio-input.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c -index 9946394..401c1de 100644 ---- a/hw/input/virtio-input.c -+++ b/hw/input/virtio-input.c -@@ -275,6 +275,7 @@ static void virtio_input_finalize(Object *obj) - - g_free(vinput->queue); - } -+ - static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) - { - VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); -@@ -288,6 +289,8 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) - return; - } - } -+ virtio_del_queue(vdev, 0); -+ virtio_del_queue(vdev, 1); - virtio_cleanup(vdev); - } - --- -1.8.3.1 - diff --git a/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch b/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000000000000000000000000000000000000..c46da01cb045b956501d2b571769badd1ba97452 --- /dev/null +++ b/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,166 @@ +From 438e224baf7c2debab5ac109739316d9db562e2c Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:50 +0800 +Subject: [PATCH] virtio: introduce macro IRTIO_CONFIG_IRQ_IDX + +To support configure interrupt for vhost-vdpa +Introduce VIRTIO_CONFIG_IRQ_IDX -1 as configure interrupt's queue index, +Then we can reuse the functions guest_notifier_mask and guest_notifier_pending. +Add the check of queue index in these drivers, if the driver does not support +configure interrupt, the function will just return + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-2-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 6 ++++++ + hw/net/virtio-net.c | 10 ++++++++-- + hw/virtio/vhost-user-fs.c | 6 ++++++ + hw/virtio/vhost-vsock-common.c | 6 ++++++ + hw/virtio/virtio-crypto.c | 6 ++++++ + include/hw/virtio/virtio.h | 3 +++ + 6 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 49df56cd14..73ad3d84c9 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,6 +485,9 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -493,6 +496,9 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 3bd786cc22..7537f44d10 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3195,6 +3195,9 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3204,8 +3207,11 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), +- vdev, idx, mask); ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index fc7dcc96ef..90c2bc9c5d 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,6 +161,9 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -168,6 +171,9 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index ed706681ac..b1f0d46209 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,6 +125,9 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -133,6 +136,9 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 274c7b4dea..52ba34ef1e 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,6 +953,9 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -963,6 +966,9 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 7472145821..c113a5b864 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -68,6 +68,9 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + ++/* special index value used internally for config irqs */ ++#define VIRTIO_CONFIG_IRQ_IDX -1 ++ + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch b/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000000000000000000000000000000000000..67c848beb5cc3451c9b423a06cc98d05b41987ff --- /dev/null +++ b/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,227 @@ +From 61630772adbe254719e312fb7704a8edd00cc72b Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:42 +0800 +Subject: [PATCH] virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX + +To support configure interrupt for vhost-vdpa +Introduce VIRTIO_CONFIG_IRQ_IDX -1 as configure interrupt's queue index, +Then we can reuse the functions guest_notifier_mask and guest_notifier_pending. +Add the check of queue index in these drivers, if the driver does not support +configure interrupt, the function will just return + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-2-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 18 ++++++++++++++++++ + hw/net/virtio-net.c | 22 ++++++++++++++++++++-- + hw/virtio/vhost-user-fs.c | 18 ++++++++++++++++++ + hw/virtio/vhost-vsock-common.c | 18 ++++++++++++++++++ + hw/virtio/virtio-crypto.c | 18 ++++++++++++++++++ + include/hw/virtio/virtio.h | 3 +++ + 6 files changed, 95 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 6e93b463d6..1c78272a83 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,6 +485,15 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -493,6 +502,15 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 867a1e77dc..304f501da5 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3232,6 +3232,15 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return false ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3255,8 +3264,17 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), +- vdev, idx, mask); ++ /* ++ *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index c2739557f2..0c6ecd3b4f 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,6 +161,15 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -168,6 +177,15 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index 42e4db4712..e4a8d90f4c 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,6 +125,15 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -133,6 +142,15 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index f9d849fa43..98304184cd 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,6 +953,15 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -963,6 +972,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 223e82436f..91d1c3433a 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -69,6 +69,9 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + ++/* special index value used internally for config irqs */ ++#define VIRTIO_CONFIG_IRQ_IDX -1 ++ + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch b/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ae4766bbdb40027f7ea52064293b043dc2afdd9 --- /dev/null +++ b/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch @@ -0,0 +1,60 @@ +From 1e73eaa18c753157046d22e43333fd9bc711eaa9 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:55:19 +0000 +Subject: [PATCH] virtio-iommu: Fix the partial copy of probe request mainline + inclusion commit 45461aace83d961e933b27519b81d17b4c690514 category: bugfix + +--------------------------------------------------------------- + +The structure of probe request doesn't include the tail, this leads +to a few field missed to be copied. Currently this isn't an issue as +those missed field belong to reserved field, just in case reserved +field will be used in the future. + +Changed 4th parameter of virtio_iommu_iov_to_req() to receive size +of device-readable part. + +Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request") +Signed-off-by: Zhenzhong Duan +Message-Id: <20220623023152.3473231-1-zhenzhong.duan@intel.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Jean-Philippe Brucker +Reviewed-by: Eric Auger + +Signed-off-by: tangbinzy +--- + hw/virtio/virtio-iommu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index ed47d4cb64..ae33d93b11 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -547,11 +547,10 @@ static int virtio_iommu_probe(VirtIOIOMMU *s, + + static int virtio_iommu_iov_to_req(struct iovec *iov, + unsigned int iov_cnt, +- void *req, size_t req_sz) ++ void *req, size_t payload_sz) + { +- size_t sz, payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail); ++ size_t sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); + +- sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); + if (unlikely(sz != payload_sz)) { + return VIRTIO_IOMMU_S_INVAL; + } +@@ -564,7 +563,8 @@ static int virtio_iommu_handle_ ## __req(VirtIOIOMMU *s, \ + unsigned int iov_cnt) \ + { \ + struct virtio_iommu_req_ ## __req req; \ +- int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req)); \ ++ int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, \ ++ sizeof(req) - sizeof(struct virtio_iommu_req_tail));\ + \ + return ret ? ret : virtio_iommu_ ## __req(s, &req); \ + } +-- +2.27.0 + diff --git a/virtio-iommu-use-after-free-fix.patch b/virtio-iommu-use-after-free-fix.patch new file mode 100644 index 0000000000000000000000000000000000000000..23b4e7a93a2179046e5f624af77eaa7fa4eb5cbf --- /dev/null +++ b/virtio-iommu-use-after-free-fix.patch @@ -0,0 +1,82 @@ +From ab4228f1a5b45450490077a06094670f364b4efc Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 21 Aug 2023 06:02:21 +0000 +Subject: [PATCH] virtio-iommu: use-after-free fix mainline inclusion commit + 4bf58c7213b0ab03209a53731c71f0861c35ef91 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +A potential Use-after-free was reported in virtio_iommu_handle_command +when using virtio-iommu: + +> I find a potential Use-after-free in QEMU 6.2.0, which is in +> virtio_iommu_handle_command() (./hw/virtio/virtio-iommu.c). +> +> +> Specifically, in the loop body, the variable 'buf' allocated at line 639 can be +> freed by g_free() at line 659. However, if the execution path enters the loop +> body again and the if branch takes true at line 616, the control will directly +> jump to 'out' at line 651. At this time, 'buf' is a freed pointer, which is not +> assigned with an allocated memory but used at line 653. As a result, a UAF bug +> is triggered. +> +> +> +> 599 for (;;) { +> ... +> 615 sz = iov_to_buf(iov, iov_cnt, 0, &head, sizeof(head)); +> 616 if (unlikely(sz != sizeof(head))) { +> 617 tail.status = VIRTIO_IOMMU_S_DEVERR; +> 618 goto out; +> 619 } +> ... +> 639 buf = g_malloc0(output_size); +> ... +> 651 out: +> 652 sz = iov_from_buf(elem->in_sg, elem->in_num, 0, +> 653 buf ? buf : &tail, output_size); +> ... +> 659 g_free(buf); +> +> We can fix it by set ‘buf‘ to NULL after freeing it: +> +> +> 651 out: +> 652 sz = iov_from_buf(elem->in_sg, elem->in_num, 0, +> 653 buf ? buf : &tail, output_size); +> ... +> 659 g_free(buf); +> +++ buf = NULL; +> 660 } + +Fix as suggested by the reporter. + +Signed-off-by: Wentao Liang +Signed-off-by: Michael S. Tsirkin +Message-id: 20220407095047.50371-1-mst@redhat.com +Message-ID: <20220406040445-mutt-send-email-mst@kernel.org> +Signed-off-by: Peter Maydell + +Signed-off-by: tangbinzy +--- + hw/virtio/virtio-iommu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index 1b23e8e18c..ed47d4cb64 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -657,6 +657,7 @@ out: + virtio_notify(vdev, vq); + g_free(elem); + g_free(buf); ++ buf = NULL; + } + } + +-- +2.41.0.windows.1 + diff --git a/virtio-mem-Don-t-skip-alignment-checks-when-warning-.patch b/virtio-mem-Don-t-skip-alignment-checks-when-warning-.patch new file mode 100644 index 0000000000000000000000000000000000000000..39bcaf94576f5f598a8416f036c7ea1845184915 --- /dev/null +++ b/virtio-mem-Don-t-skip-alignment-checks-when-warning-.patch @@ -0,0 +1,45 @@ +From d319f43f223df53ed5c9c13c5b60caaa1b952c35 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Wed, 23 Nov 2022 06:26:18 +0000 +Subject: [PATCH 08/29] virtio-mem: Don't skip alignment checks when warning + about block size mainline inclusion commit + 7656d9ce09cb1d6d76eeb2081f164a920361d1d3 category: bugfix + +--------------------------------------------------------------- + +If we warn about the block size being smaller than the default, we skip +some alignment checks. + +This can currently only fail on x86-64, when specifying a block size of +1 MiB, however, we detect the THP size of 2 MiB. + +Fixes: 228957fea3a9 ("virtio-mem: Probe THP size to determine default block size") +Cc: "Michael S. Tsirkin" +Signed-off-by: David Hildenbrand +Message-Id: <20211011173305.13778-1-david@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + + +Signed-off-by: tangbinzy +--- + hw/virtio/virtio-mem.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index d5a578142b..341c3fa2c1 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -733,7 +733,8 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + warn_report("'%s' property is smaller than the default block size (%" + PRIx64 " MiB)", VIRTIO_MEM_BLOCK_SIZE_PROP, + virtio_mem_default_block_size(rb) / MiB); +- } else if (!QEMU_IS_ALIGNED(vmem->requested_size, vmem->block_size)) { ++ } ++ if (!QEMU_IS_ALIGNED(vmem->requested_size, vmem->block_size)) { + error_setg(errp, "'%s' property has to be multiples of '%s' (0x%" PRIx64 + ")", VIRTIO_MEM_REQUESTED_SIZE_PROP, + VIRTIO_MEM_BLOCK_SIZE_PROP, vmem->block_size); +-- +2.27.0 + diff --git a/virtio-mmio-add-support-for-configure-interrupt-new.patch b/virtio-mmio-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0900ca310338b13ba2c383abc3a66e7073838dd --- /dev/null +++ b/virtio-mmio-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,67 @@ +From 3f5311e1a80539a9cc21905fd3134709417e3747 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:50 +0800 +Subject: [PATCH] virtio-mmio: add support for configure interrupt + +Add configure interrupt support in virtio-mmio bus. +add function to set configure guest notifier. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-10-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 72da12fea5..508dd4cdb7 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,7 +673,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } ++static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign, ++ bool with_irqfd) ++{ ++ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); ++ EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); ++ int r = 0; + ++ if (assign) { ++ r = event_notifier_init(notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ event_notifier_cleanup(notifier); ++ } ++ if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { ++ vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); ++ } ++ return r; ++} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -695,6 +718,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } ++ r = virtio_mmio_set_config_guest_notifier(d, assign, with_irqfd); ++ if (r < 0) { ++ goto assign_error; ++ } + + return 0; + +-- +2.27.0 + diff --git a/virtio-mmio-add-support-for-configure-interrupt.patch b/virtio-mmio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b4d42599563676d9fc6f170c359f99bb1747928 --- /dev/null +++ b/virtio-mmio-add-support-for-configure-interrupt.patch @@ -0,0 +1,66 @@ +From 89b329c73a84ca3f1376f8d8533154306bc50187 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:54 +0800 +Subject: [PATCH] virtio-mmio: add support for configure interrupt + +Add configure interrupt support for virtio-mmio bus. This +interrupt will be working while the backend is vhost-vdpa + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-10-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 72da12fea5..809132018b 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,7 +673,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } ++static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign) ++{ ++ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); ++ bool with_irqfd = false; ++ EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); ++ int r = 0; + ++ if (assign) { ++ r = event_notifier_init(notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ event_notifier_cleanup(notifier); ++ } ++ if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { ++ vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); ++ } ++ return r; ++} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -695,6 +718,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } ++ r = virtio_mmio_set_config_guest_notifier(d, assign); ++ if (r < 0) { ++ goto assign_error; ++ } + + return 0; + +-- +2.27.0 + diff --git a/virtio-net-Expose-MAC_TABLE_ENTRIES.patch b/virtio-net-Expose-MAC_TABLE_ENTRIES.patch new file mode 100644 index 0000000000000000000000000000000000000000..15e740579fecc5bc32e1012d7a2f15b56cb72562 --- /dev/null +++ b/virtio-net-Expose-MAC_TABLE_ENTRIES.patch @@ -0,0 +1,50 @@ +From c8ee92256e06a7fec7cfff3bf18e21ec03016613 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:27 +0200 +Subject: [PATCH] virtio-net: Expose MAC_TABLE_ENTRIES +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +vhost-vdpa control virtqueue needs to know the maximum entries supported +by the virtio-net device, so we know if it is possible to apply the +filter. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 1 - + include/hw/virtio/virtio-net.h | 3 +++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 512b37eb76..36d24b47bb 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -48,7 +48,6 @@ + + #define VIRTIO_NET_VM_VERSION 11 + +-#define MAC_TABLE_ENTRIES 64 + #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ + + /* previously fixed value */ +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index eb87032627..cce1c554f7 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -35,6 +35,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET) + * and latency. */ + #define TX_BURST 256 + ++/* Maximum VIRTIO_NET_CTRL_MAC_TABLE_SET unicast + multicast entries. */ ++#define MAC_TABLE_ENTRIES 64 ++ + typedef struct virtio_net_conf + { + uint32_t txtimer; +-- +2.27.0 + diff --git a/virtio-net-Expose-ctrl-virtqueue-logic.patch b/virtio-net-Expose-ctrl-virtqueue-logic.patch new file mode 100644 index 0000000000000000000000000000000000000000..fc50d2007e0a1eaa868bd59515f62f20c1a4b0e6 --- /dev/null +++ b/virtio-net-Expose-ctrl-virtqueue-logic.patch @@ -0,0 +1,149 @@ +From 4987c967fb3b9b403bde7a1103f5ea1bf20445c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:28 +0200 +Subject: [PATCH] virtio-net: Expose ctrl virtqueue logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external vhost-net devices to modify the state of the +VirtIO device model once the vhost-vdpa device has acknowledged the +control commands. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 83 ++++++++++++++++++++-------------- + include/hw/virtio/virtio-net.h | 4 ++ + 2 files changed, 53 insertions(+), 34 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 36d24b47bb..999072921d 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1452,56 +1452,71 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_OK; + } + +-static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ++size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, ++ const struct iovec *in_sg, unsigned in_num, ++ const struct iovec *out_sg, ++ unsigned out_num) + { + VirtIONet *n = VIRTIO_NET(vdev); + struct virtio_net_ctrl_hdr ctrl; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- VirtQueueElement *elem; + size_t s; + struct iovec *iov, *iov2; +- unsigned int iov_cnt; ++ ++ if (iov_size(in_sg, in_num) < sizeof(status) || ++ iov_size(out_sg, out_num) < sizeof(ctrl)) { ++ virtio_error(vdev, "virtio-net ctrl missing headers"); ++ return 0; ++ } ++ ++ iov2 = iov = g_memdup(out_sg, sizeof(struct iovec) * out_num); ++ s = iov_to_buf(iov, out_num, 0, &ctrl, sizeof(ctrl)); ++ iov_discard_front(&iov, &out_num, sizeof(ctrl)); ++ if (s != sizeof(ctrl)) { ++ status = VIRTIO_NET_ERR; ++ } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { ++ status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { ++ status = virtio_net_handle_mac(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { ++ status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { ++ status = virtio_net_handle_announce(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { ++ status = virtio_net_handle_mq(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { ++ status = virtio_net_handle_offloads(n, ctrl.cmd, iov, out_num); ++ } ++ ++ s = iov_from_buf(in_sg, in_num, 0, &status, sizeof(status)); ++ assert(s == sizeof(status)); ++ ++ g_free(iov2); ++ return sizeof(status); ++} ++ ++static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ++{ ++ VirtQueueElement *elem; + + for (;;) { ++ size_t written; + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } +- if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || +- iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { +- virtio_error(vdev, "virtio-net ctrl missing headers"); ++ ++ written = virtio_net_handle_ctrl_iov(vdev, elem->in_sg, elem->in_num, ++ elem->out_sg, elem->out_num); ++ if (written > 0) { ++ virtqueue_push(vq, elem, written); ++ virtio_notify(vdev, vq); ++ g_free(elem); ++ } else { + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; + } +- +- iov_cnt = elem->out_num; +- iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); +- s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); +- iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); +- if (s != sizeof(ctrl)) { +- status = VIRTIO_NET_ERR; +- } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { +- status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { +- status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { +- status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { +- status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { +- status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { +- status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); +- } +- +- s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); +- assert(s == sizeof(status)); +- +- virtqueue_push(vq, elem, sizeof(status)); +- virtio_notify(vdev, vq); +- g_free(iov2); +- g_free(elem); + } + } + +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index cce1c554f7..ef234ffe7e 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -221,6 +221,10 @@ struct VirtIONet { + struct EBPFRSSContext ebpf_rss; + }; + ++size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, ++ const struct iovec *in_sg, unsigned in_num, ++ const struct iovec *out_sg, ++ unsigned out_num); + void virtio_net_set_netclient_name(VirtIONet *n, const char *name, + const char *type); + +-- +2.27.0 + diff --git a/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch b/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb9f7adb5a87d2ccefcd644292ee5656da523c27 --- /dev/null +++ b/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch @@ -0,0 +1,53 @@ +From 49c90114e00fb1cbbe25eeaee825981210c24f41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:18 +0200 +Subject: [PATCH] virtio-net: Update virtio-net curr_queue_pairs in vdpa + backends +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was returned as error before. Instead of it, simply update the +corresponding field so qemu can send it in the migration data. + +Signed-off-by: Eugenio Pérez +Acked-by: Si-Wei Liu +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 999072921d..867a1e77dc 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1431,19 +1431,14 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_ERR; + } + +- /* Avoid changing the number of queue_pairs for vdpa device in +- * userspace handler. A future fix is needed to handle the mq +- * change in userspace handler with vhost-vdpa. Let's disable +- * the mq handling from userspace for now and only allow get +- * done through the kernel. Ripples may be seen when falling +- * back to userspace, but without doing it qemu process would +- * crash on a recursive entry to virtio_net_set_status(). +- */ ++ n->curr_queue_pairs = queue_pairs; + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { +- return VIRTIO_NET_ERR; ++ /* ++ * Avoid updating the backend for a vdpa device: We're only interested ++ * in updating the device model queues. ++ */ ++ return VIRTIO_NET_OK; + } +- +- n->curr_queue_pairs = queue_pairs; + /* stop the backend before changing the number of queue_pairs to avoid handling a + * disabled queue */ + virtio_net_set_status(vdev, vdev->status); +-- +2.27.0 + diff --git a/virtio-net-add-support-for-configure-interrupt-new.patch b/virtio-net-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..006222ded936cbfe789b1f914046111cf40afcb6 --- /dev/null +++ b/virtio-net-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,102 @@ +From e55e9f52865565415000834b4cacb741b0abb2d8 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:49 +0800 +Subject: [PATCH] virtio-net: add support for configure interrupt + +Add functions to support configure interrupt in virtio_net +Add the functions to support vhost_net_config_pending +and vhost_net_config_mask. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-9-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net-stub.c | 9 +++++++++ + hw/net/vhost_net.c | 9 +++++++++ + hw/net/virtio-net.c | 4 ++-- + include/net/vhost_net.h | 2 ++ + 4 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c +index 199b09952a..db171829b4 100644 +--- a/hw/net/vhost_net-stub.c ++++ b/hw/net/vhost_net-stub.c +@@ -82,6 +82,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + { + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return false; ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++} ++ + int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) + { + return -1; +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index c950d7e2e8..d226dba83c 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -541,6 +541,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return vhost_config_pending(&net->dev); ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++ vhost_config_mask(&net->dev, dev, mask); ++} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 304f501da5..bc26f5347a 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3239,7 +3239,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; ++ return vhost_net_config_pending(get_vhost_net(nc->peer)); + } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } +@@ -3271,9 +3271,9 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ vhost_net_config_mask(get_vhost_net(nc->peer), vdev, mask); + return; + } +- + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 7bdbf484e4..1844f0ed46 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); ++bool vhost_net_config_pending(VHostNetState *net); ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/virtio-net-add-support-for-configure-interrupt.patch b/virtio-net-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..98ac5d22ed702ac7d00e9aacb1d6bed3a186c0c2 --- /dev/null +++ b/virtio-net-add-support-for-configure-interrupt.patch @@ -0,0 +1,56 @@ +From 0ae5aeef8aa5bf2d32fdf393cf66c36172c3e974 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:53 +0800 +Subject: [PATCH] virtio-net: add support for configure interrupt + +Add functions to support configure interrupt in virtio_net +The functions are config_pending and config_mask, while +this input idx is VIRTIO_CONFIG_IRQ_IDX will check the +function of configure interrupt. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-9-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 9 +++++++++ + include/net/vhost_net.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index bea053a742..d5a92144bb 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -524,6 +524,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return vhost_config_pending(&net->dev); ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++ vhost_config_mask(&net->dev, dev, mask); ++} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 7bdbf484e4..1844f0ed46 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); ++bool vhost_net_config_pending(VHostNetState *net); ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch b/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c86d6473433eab6c32a0bb6a07ca509c31729a5 --- /dev/null +++ b/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch @@ -0,0 +1,131 @@ +From 9bfeaccd2adb6bc4d4e7efacc508324112e5651f Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:13 -0700 +Subject: [PATCH] virtio-net: align ctrl_vq index for non-mq guest for + vhost_vdpa + +With MQ enabled vdpa device and non-MQ supporting guest e.g. +booting vdpa with mq=on over OVMF of single vqp, below assert +failure is seen: + +../hw/virtio/vhost-vdpa.c:560: vhost_vdpa_get_vq_index: Assertion `idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs' failed. + +0 0x00007f8ce3ff3387 in raise () at /lib64/libc.so.6 +1 0x00007f8ce3ff4a78 in abort () at /lib64/libc.so.6 +2 0x00007f8ce3fec1a6 in __assert_fail_base () at /lib64/libc.so.6 +3 0x00007f8ce3fec252 in () at /lib64/libc.so.6 +4 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:563 +5 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:558 +6 0x0000558f52d7329a in vhost_virtqueue_mask (hdev=0x558f55c01800, vdev=0x558f568f91f0, n=2, mask=) at ../hw/virtio/vhost.c:1557 +7 0x0000558f52c6b89a in virtio_pci_set_guest_notifier (d=d@entry=0x558f568f0f60, n=n@entry=2, assign=assign@entry=true, with_irqfd=with_irqfd@entry=false) + at ../hw/virtio/virtio-pci.c:974 +8 0x0000558f52c6c0d8 in virtio_pci_set_guest_notifiers (d=0x558f568f0f60, nvqs=3, assign=true) at ../hw/virtio/virtio-pci.c:1019 +9 0x0000558f52bf091d in vhost_net_start (dev=dev@entry=0x558f568f91f0, ncs=0x558f56937cd0, data_queue_pairs=data_queue_pairs@entry=1, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:361 +10 0x0000558f52d4e5e7 in virtio_net_set_status (status=, n=0x558f568f91f0) at ../hw/net/virtio-net.c:289 +11 0x0000558f52d4e5e7 in virtio_net_set_status (vdev=0x558f568f91f0, status=15 '\017') at ../hw/net/virtio-net.c:370 +12 0x0000558f52d6c4b2 in virtio_set_status (vdev=vdev@entry=0x558f568f91f0, val=val@entry=15 '\017') at ../hw/virtio/virtio.c:1945 +13 0x0000558f52c69eff in virtio_pci_common_write (opaque=0x558f568f0f60, addr=, val=, size=) at ../hw/virtio/virtio-pci.c:1292 +14 0x0000558f52d15d6e in memory_region_write_accessor (mr=0x558f568f19d0, addr=20, value=, size=1, shift=, mask=, attrs=...) + at ../softmmu/memory.c:492 +15 0x0000558f52d127de in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f8cdbffe748, size=size@entry=1, access_size_min=, access_size_max=, access_fn=0x558f52d15cf0 , mr=0x558f568f19d0, attrs=...) at ../softmmu/memory.c:554 +16 0x0000558f52d157ef in memory_region_dispatch_write (mr=mr@entry=0x558f568f19d0, addr=20, data=, op=, attrs=attrs@entry=...) + at ../softmmu/memory.c:1504 +17 0x0000558f52d078e7 in flatview_write_continue (fv=fv@entry=0x7f8accbc3b90, addr=addr@entry=103079215124, attrs=..., ptr=ptr@entry=0x7f8ce6300028, len=len@entry=1, addr1=, l=, mr=0x558f568f19d0) at /home/opc/qemu-upstream/include/qemu/host-utils.h:165 +18 0x0000558f52d07b06 in flatview_write (fv=0x7f8accbc3b90, addr=103079215124, attrs=..., buf=0x7f8ce6300028, len=1) at ../softmmu/physmem.c:2822 +19 0x0000558f52d0b36b in address_space_write (as=, addr=, attrs=..., buf=buf@entry=0x7f8ce6300028, len=) + at ../softmmu/physmem.c:2914 +20 0x0000558f52d0b3da in address_space_rw (as=, addr=, attrs=..., + attrs@entry=..., buf=buf@entry=0x7f8ce6300028, len=, is_write=) at ../softmmu/physmem.c:2924 +21 0x0000558f52dced09 in kvm_cpu_exec (cpu=cpu@entry=0x558f55c2da60) at ../accel/kvm/kvm-all.c:2903 +22 0x0000558f52dcfabd in kvm_vcpu_thread_fn (arg=arg@entry=0x558f55c2da60) at ../accel/kvm/kvm-accel-ops.c:49 +23 0x0000558f52f9f04a in qemu_thread_start (args=) at ../util/qemu-thread-posix.c:556 +24 0x00007f8ce4392ea5 in start_thread () at /lib64/libpthread.so.0 +25 0x00007f8ce40bb9fd in clone () at /lib64/libc.so.6 + +The cause for the assert failure is due to that the vhost_dev index +for the ctrl vq was not aligned with actual one in use by the guest. +Upon multiqueue feature negotiation in virtio_net_set_multiqueue(), +if guest doesn't support multiqueue, the guest vq layout would shrink +to a single queue pair, consisting of 3 vqs in total (rx, tx and ctrl). +This results in ctrl_vq taking a different vhost_dev group index than +the default. We can map vq to the correct vhost_dev group by checking +if MQ is supported by guest and successfully negotiated. Since the +MQ feature is only present along with CTRL_VQ, we ensure the index +2 is only meant for the control vq while MQ is not supported by guest. + +Fixes: 22288fe ("virtio-net: vhost control virtqueue support") +Suggested-by: Jason Wang +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-3-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 33 +++++++++++++++++++++++++++++++-- + 1 file changed, 31 insertions(+), 2 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 41bb4010b0..eed3fb5cd3 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + #include "qemu/atomic.h" + #include "qemu/iov.h" ++#include "qemu/log.h" + #include "qemu/main-loop.h" + #include "qemu/module.h" + #include "hw/virtio/virtio.h" +@@ -3193,8 +3194,22 @@ static NetClientInfo net_virtio_info = { + static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return false; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3202,8 +3217,22 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), + vdev, idx, mask); + } +-- +2.27.0 + diff --git a/virtio-net-bugfix-do-not-delete-netdev-before-virtio.patch b/virtio-net-bugfix-do-not-delete-netdev-before-virtio.patch new file mode 100644 index 0000000000000000000000000000000000000000..c328f9e30cfa2bc8bcced01feb645324a452fd79 --- /dev/null +++ b/virtio-net-bugfix-do-not-delete-netdev-before-virtio.patch @@ -0,0 +1,38 @@ +From 532566ba64b60f2dd2f8ff41d670712ccafe1e98 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 10:31:38 +0800 +Subject: [PATCH] virtio-net: bugfix: do not delete netdev before virtio net + +For the vhost-user net-card, it is allow to delete its +network backend while the virtio-net device still exists. +However, when the status of the device changes in guest, +QEMU will check whether the network backend exists, otherwise +it will crash. +So do not allowed to delete the network backend directly +without delete virtio-net device. + +Signed-off-by: Jinhua Cao +--- + net/net.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/net.c b/net/net.c +index f0d14dbfc1..ed4b1c1740 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -1202,6 +1202,12 @@ void qmp_netdev_del(const char *id, Error **errp) + return; + } + ++ if (nc->info->type == NET_CLIENT_DRIVER_VHOST_USER && nc->peer) { ++ error_setg(errp, "Device '%s' is a netdev for vhostuser," ++ "please delete the peer front-end device (virtio-net) first.", id); ++ return; ++ } ++ + qemu_del_net_client(nc); + + /* +-- +2.27.0 + diff --git a/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch b/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ead12105e612e01379c51549af24a0384a9ea74 --- /dev/null +++ b/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch @@ -0,0 +1,67 @@ +From 7c85ae20bc8a6bb2e08794d01e6f65af7626a05d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 24 Jan 2023 17:11:59 +0100 +Subject: [PATCH] virtio-net: clear guest_announce feature if no cvq backend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since GUEST_ANNOUNCE is emulated the feature bit could be set without +backend support. This happens in the vDPA case. + +However, backend vDPA parent may not have CVQ support. This causes an +incoherent feature set, and the driver may refuse to start. This +happens in virtio-net Linux driver. + +This may be solved differently in the future. Qemu is able to emulate a +CVQ just for guest_announce purposes, helping guest to notify the new +location with vDPA devices that does not support it. However, this is +left as a TODO as it is way more complex to backport. + +Tested with vdpa_net_sim, toggling manually VIRTIO_NET_F_CTRL_VQ in the +driver and migrating it with x-svq=on. + +Fixes: 980003debddd ("vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa") +Reported-by: Dawar, Gautam +Signed-off-by: Eugenio Pérez +Message-Id: <20230124161159.2182117-1-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: David Edmondson +Reviewed-by: Gautam Dawar +Tested-by: Gautam Dawar +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index bc26f5347a..ae37b3461b 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -771,6 +771,21 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, + features |= (1ULL << VIRTIO_NET_F_MTU); + } + ++ /* ++ * Since GUEST_ANNOUNCE is emulated the feature bit could be set without ++ * enabled. This happens in the vDPA case. ++ * ++ * Make sure the feature set is not incoherent, as the driver could refuse ++ * to start. ++ * ++ * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes, ++ * helping guest to notify the new location with vDPA devices that does not ++ * support it. ++ */ ++ if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) { ++ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE); ++ } ++ + return features; + } + +-- +2.27.0 + diff --git a/virtio-net-correctly-copy-vnet-header-when-flushing-.patch b/virtio-net-correctly-copy-vnet-header-when-flushing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..850fb293d1885c2f2efaeef68988c9cf3fee825a --- /dev/null +++ b/virtio-net-correctly-copy-vnet-header-when-flushing-.patch @@ -0,0 +1,72 @@ +From 15f89b0447956d16f9ff20e243fa9076e5dd9af1 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Tue, 2 Jan 2024 11:29:01 +0800 +Subject: [PATCH] virtio-net: correctly copy vnet header when flushing TX + (CVE-2023-6693) + +When HASH_REPORT is negotiated, the guest_hdr_len might be larger than +the size of the mergeable rx buffer header. Using +virtio_net_hdr_mrg_rxbuf during the header swap might lead a stack +overflow in this case. Fixing this by using virtio_net_hdr_v1_hash +instead. + +Reported-by: Xiao Lei +Cc: Yuri Benditovich +Cc: qemu-stable@nongnu.org +Cc: Mauro Matteo Cascella +Fixes: CVE-2023-6693 +Fixes: e22f0603fb2f ("virtio-net: reference implementation of hash report") +Reviewed-by: Michael Tokarev +Signed-off-by: Jason Wang +--- + hw/net/virtio-net.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index d7405c3bf1..cdf1313053 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -600,6 +600,11 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, + + n->mergeable_rx_bufs = mergeable_rx_bufs; + ++ /* ++ * Note: when extending the vnet header, please make sure to ++ * change the vnet header copying logic in virtio_net_flush_tx() ++ * as well. ++ */ + if (version_1) { + n->guest_hdr_len = hash_report ? + sizeof(struct virtio_net_hdr_v1_hash) : +@@ -2586,7 +2591,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + ssize_t ret; + unsigned int out_num; + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; +- struct virtio_net_hdr_mrg_rxbuf mhdr; ++ struct virtio_net_hdr_v1_hash vhdr; + + elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); + if (!elem) { +@@ -2603,7 +2608,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + } + + if (n->has_vnet_hdr) { +- if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < ++ if (iov_to_buf(out_sg, out_num, 0, &vhdr, n->guest_hdr_len) < + n->guest_hdr_len) { + virtio_error(vdev, "virtio-net header incorrect"); + virtqueue_detach_element(q->tx_vq, elem, 0); +@@ -2611,8 +2616,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + return -EINVAL; + } + if (n->needs_vnet_hdr_swap) { +- virtio_net_hdr_swap(vdev, (void *) &mhdr); +- sg2[0].iov_base = &mhdr; ++ virtio_net_hdr_swap(vdev, (void *) &vhdr); ++ sg2[0].iov_base = &vhdr; + sg2[0].iov_len = n->guest_hdr_len; + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, + out_sg, out_num, +-- +2.27.0 + diff --git a/virtio-net-delete-also-control-queue-when-TX-RX-dele.patch b/virtio-net-delete-also-control-queue-when-TX-RX-dele.patch deleted file mode 100644 index f955fbb1a7f6b0ae8e646a366d3c6401cf699788..0000000000000000000000000000000000000000 --- a/virtio-net-delete-also-control-queue-when-TX-RX-dele.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 358e2bfe2e1a65b1e926163d7d1ffaefd601d874 Mon Sep 17 00:00:00 2001 -From: Julia Suvorova -Date: Wed, 19 Feb 2020 21:34:31 +0000 -Subject: [PATCH] virtio-net: delete also control queue when TX/RX deleted - -RH-Author: Julia Suvorova -Message-id: <20200219213431.11913-5-jusual@redhat.com> -Patchwork-id: 93983 -O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 4/4] virtio-net: delete also control queue when TX/RX deleted -Bugzilla: 1791590 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Stefano Garzarella -RH-Acked-by: Michael S. Tsirkin - -From: Yuri Benditovich - -https://bugzilla.redhat.com/show_bug.cgi?id=1708480 -If the control queue is not deleted together with TX/RX, it -later will be ignored in freeing cache resources and hot -unplug will not be completed. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Yuri Benditovich -Message-Id: <20191226043649.14481-3-yuri.benditovich@daynix.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit d945d9f1731244ef341f74ede93120fc9de35913) -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 6adb0fe252..63f1bae99c 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -2803,7 +2803,8 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) - for (i = 0; i < max_queues; i++) { - virtio_net_del_queue(n, i); - } -- -+ /* delete also control vq */ -+ virtio_del_queue(vdev, max_queues * 2); - qemu_announce_timer_del(&n->announce_timer, false); - g_free(n->vqs); - qemu_del_nic(n->nic); --- -2.27.0 - diff --git a/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch b/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch new file mode 100644 index 0000000000000000000000000000000000000000..27e2366d5c734c1bc95f4f0820f7d2a7ef560662 --- /dev/null +++ b/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch @@ -0,0 +1,97 @@ +From f45beb1e364dc0a6d42425d716f5e31b69d7710d Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:18 -0700 +Subject: [PATCH] virtio-net: don't handle mq request in userspace handler for + vhost-vdpa + +virtio_queue_host_notifier_read() tends to read pending event +left behind on ioeventfd in the vhost_net_stop() path, and +attempts to handle outstanding kicks from userspace vq handler. +However, in the ctrl_vq handler, virtio_net_handle_mq() has a +recursive call into virtio_net_set_status(), which may lead to +segmentation fault as shown in below stack trace: + +0 0x000055f800df1780 in qdev_get_parent_bus (dev=0x0) at ../hw/core/qdev.c:376 +1 0x000055f800c68ad8 in virtio_bus_device_iommu_enabled (vdev=vdev@entry=0x0) at ../hw/virtio/virtio-bus.c:331 +2 0x000055f800d70d7f in vhost_memory_unmap (dev=) at ../hw/virtio/vhost.c:318 +3 0x000055f800d70d7f in vhost_memory_unmap (dev=, buffer=0x7fc19bec5240, len=2052, is_write=1, access_len=2052) at ../hw/virtio/vhost.c:336 +4 0x000055f800d71867 in vhost_virtqueue_stop (dev=dev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590, vq=0x55f8037cceb0, idx=0) at ../hw/virtio/vhost.c:1241 +5 0x000055f800d7406c in vhost_dev_stop (hdev=hdev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590) at ../hw/virtio/vhost.c:1839 +6 0x000055f800bf00a7 in vhost_net_stop_one (net=0x55f8037ccc30, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:315 +7 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +8 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +9 0x000055f800d4e628 in virtio_net_set_status (vdev=vdev@entry=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +10 0x000055f800d534d8 in virtio_net_handle_ctrl (iov_cnt=, iov=, cmd=0 '\000', n=0x55f8044ec590) at ../hw/net/virtio-net.c:1408 +11 0x000055f800d534d8 in virtio_net_handle_ctrl (vdev=0x55f8044ec590, vq=0x7fc1a7e888d0) at ../hw/net/virtio-net.c:1452 +12 0x000055f800d69f37 in virtio_queue_host_notifier_read (vq=0x7fc1a7e888d0) at ../hw/virtio/virtio.c:2331 +13 0x000055f800d69f37 in virtio_queue_host_notifier_read (n=n@entry=0x7fc1a7e8894c) at ../hw/virtio/virtio.c:3575 +14 0x000055f800c688e6 in virtio_bus_cleanup_host_notifier (bus=, n=n@entry=14) at ../hw/virtio/virtio-bus.c:312 +15 0x000055f800d73106 in vhost_dev_disable_notifiers (hdev=hdev@entry=0x55f8035b51b0, vdev=vdev@entry=0x55f8044ec590) + at ../../../include/hw/virtio/virtio-bus.h:35 +16 0x000055f800bf00b2 in vhost_net_stop_one (net=0x55f8035b51b0, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:316 +17 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +18 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +19 0x000055f800d4e628 in virtio_net_set_status (vdev=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +20 0x000055f800d6c4b2 in virtio_set_status (vdev=0x55f8044ec590, val=) at ../hw/virtio/virtio.c:1945 +21 0x000055f800d11d9d in vm_state_notify (running=running@entry=false, state=state@entry=RUN_STATE_SHUTDOWN) at ../softmmu/runstate.c:333 +22 0x000055f800d04e7a in do_vm_stop (state=state@entry=RUN_STATE_SHUTDOWN, send_stop=send_stop@entry=false) at ../softmmu/cpus.c:262 +23 0x000055f800d04e99 in vm_shutdown () at ../softmmu/cpus.c:280 +24 0x000055f800d126af in qemu_cleanup () at ../softmmu/runstate.c:812 +25 0x000055f800ad5b13 in main (argc=, argv=, envp=) at ../softmmu/main.c:51 + +For now, temporarily disable handling MQ request from the ctrl_vq +userspace hanlder to avoid the recursive virtio_net_set_status() +call. Some rework is needed to allow changing the number of +queues without going through a full virtio_net_set_status cycle, +particularly for vhost-vdpa backend. + +This patch will need to be reverted as soon as future patches of +having the change of #queues handled in userspace is merged. + +Fixes: 402378407db ("vhost-vdpa: multiqueue support") +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-8-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index eed3fb5cd3..512b37eb76 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1400,6 +1400,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + { + VirtIODevice *vdev = VIRTIO_DEVICE(n); + uint16_t queue_pairs; ++ NetClientState *nc = qemu_get_queue(n->nic); + + virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { +@@ -1431,6 +1432,18 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_ERR; + } + ++ /* Avoid changing the number of queue_pairs for vdpa device in ++ * userspace handler. A future fix is needed to handle the mq ++ * change in userspace handler with vhost-vdpa. Let's disable ++ * the mq handling from userspace for now and only allow get ++ * done through the kernel. Ripples may be seen when falling ++ * back to userspace, but without doing it qemu process would ++ * crash on a recursive entry to virtio_net_set_status(). ++ */ ++ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ++ return VIRTIO_NET_ERR; ++ } ++ + n->curr_queue_pairs = queue_pairs; + /* stop the backend before changing the number of queue_pairs to avoid handling a + * disabled queue */ +-- +2.27.0 + diff --git a/virtio-net-fix-map-leaking-on-error-during-receive.patch b/virtio-net-fix-map-leaking-on-error-during-receive.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8b59dc11e9416e64d8fdcce369363913c8c568f --- /dev/null +++ b/virtio-net-fix-map-leaking-on-error-during-receive.patch @@ -0,0 +1,39 @@ +From df98392ee2334462e9f1007b3c9f7a14938bd9ab Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Tue, 8 Mar 2022 10:42:51 +0800 +Subject: [PATCH 2/2] virtio-net: fix map leaking on error during receive + +Commit bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg") +tries to fix the use after free of the sg by caching the virtqueue +elements in an array and unmap them at once after receiving the +packets, But it forgot to unmap the cached elements on error which +will lead to leaking of mapping and other unexpected results. + +Fixing this by detaching the cached elements on error. This addresses +CVE-2022-26353. + +Reported-by: Victor Tom +Cc: qemu-stable@nongnu.org +Fixes: CVE-2022-26353 +Fixes: bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg") +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +--- + hw/net/virtio-net.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index e887589a30..d33da9b7ef 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1883,6 +1883,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + + err: + for (j = 0; j < i; j++) { ++ virtqueue_detach_element(q->rx_vq, elems[j], lens[j]); + g_free(elems[j]); + } + +-- +2.27.0 + diff --git a/virtio-net-fix-max-vring-buf-size-when-set-ring-num.patch b/virtio-net-fix-max-vring-buf-size-when-set-ring-num.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e2af0ce32cd04a7f50605e8d8be1cc5ac9e0ab8 --- /dev/null +++ b/virtio-net-fix-max-vring-buf-size-when-set-ring-num.patch @@ -0,0 +1,50 @@ +From 318f0eda68554af0c779e5374f16bf8cdb895fe7 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 10:48:27 +0800 +Subject: [PATCH] virtio-net: fix max vring buf size when set ring num + +Signed-off-by: Jinhua Cao +--- + hw/virtio/virtio.c | 9 +++++++-- + include/hw/virtio/virtio.h | 1 + + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index ec3e96af3b..03afa36e99 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2241,12 +2241,17 @@ void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc, + + void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) + { ++ int vq_max_size = VIRTQUEUE_MAX_SIZE; ++ ++ if (!strcmp(vdev->name, "virtio-net")) { ++ vq_max_size = VIRTIO_NET_VQ_MAX_SIZE; ++ } ++ + /* Don't allow guest to flip queue between existent and + * nonexistent states, or to set it to an invalid size. + */ + if (!!num != !!vdev->vq[n].vring.num || +- num > VIRTQUEUE_MAX_SIZE || +- num < 0) { ++ num > vq_max_size || num < 0) { + return; + } + vdev->vq[n].vring.num = num; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 8bab9cfb75..b3749ce34b 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -49,6 +49,7 @@ size_t virtio_feature_get_config_size(const VirtIOFeature *features, + typedef struct VirtQueue VirtQueue; + + #define VIRTQUEUE_MAX_SIZE 1024 ++#define VIRTIO_NET_VQ_MAX_SIZE (4096) + + typedef struct VirtQueueElement + { +-- +2.27.0 + diff --git a/virtio-net-prevent-offloads-reset-on-migration.patch b/virtio-net-prevent-offloads-reset-on-migration.patch deleted file mode 100644 index ab8fbe26115279359c6a3928e93bf134ca88a2cb..0000000000000000000000000000000000000000 --- a/virtio-net-prevent-offloads-reset-on-migration.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 4887acf574a573137660aa98d9d422ece0a41a5a Mon Sep 17 00:00:00 2001 -From: Mikhail Sennikovsky -Date: Fri, 11 Oct 2019 15:58:04 +0200 -Subject: [PATCH] virtio-net: prevent offloads reset on migration - -Currently offloads disabled by guest via the VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET -command are not preserved on VM migration. -Instead all offloads reported by guest features (via VIRTIO_PCI_GUEST_FEATURES) -get enabled. -What happens is: first the VirtIONet::curr_guest_offloads gets restored and offloads -are getting set correctly: - - #0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=0, tso6=0, ecn=0, ufo=0) at net/net.c:474 - #1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720 - #2 virtio_net_post_load_device (opaque=0x555557701ca0, version_id=11) at hw/net/virtio-net.c:2334 - #3 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577c80 , opaque=0x555557701ca0, version_id=11) - at migration/vmstate.c:168 - #4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2197 - #5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036 - #6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 , opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143 - #7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829 - #8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211 - #9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395 - #10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467 - #11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449 - -However later on the features are getting restored, and offloads get reset to -everything supported by features: - - #0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=1, tso6=1, ecn=0, ufo=0) at net/net.c:474 - #1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720 - #2 virtio_net_set_features (vdev=0x555557701ca0, features=5104441767) at hw/net/virtio-net.c:773 - #3 virtio_set_features_nocheck (vdev=0x555557701ca0, val=5104441767) at hw/virtio/virtio.c:2052 - #4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2220 - #5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036 - #6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 , opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143 - #7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829 - #8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211 - #9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395 - #10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467 - #11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449 - -Fix this by preserving the state in saved_guest_offloads field and -pushing out offload initialization to the new post load hook. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Mikhail Sennikovsky -Signed-off-by: Jason Wang -(cherry picked from commit 7788c3f2e21e35902d45809b236791383bbb613e) -Signed-off-by: Michael Roth ---- - hw/net/virtio-net.c | 27 ++++++++++++++++++++++++--- - include/hw/virtio/virtio-net.h | 2 ++ - 2 files changed, 26 insertions(+), 3 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index b9e1cd71cf..6adb0fe252 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -2330,9 +2330,13 @@ static int virtio_net_post_load_device(void *opaque, int version_id) - n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); - } - -- if (peer_has_vnet_hdr(n)) { -- virtio_net_apply_guest_offloads(n); -- } -+ /* -+ * curr_guest_offloads will be later overwritten by the -+ * virtio_set_features_nocheck call done from the virtio_load. -+ * Here we make sure it is preserved and restored accordingly -+ * in the virtio_net_post_load_virtio callback. -+ */ -+ n->saved_guest_offloads = n->curr_guest_offloads; - - virtio_net_set_queues(n); - -@@ -2367,6 +2371,22 @@ static int virtio_net_post_load_device(void *opaque, int version_id) - return 0; - } - -+static int virtio_net_post_load_virtio(VirtIODevice *vdev) -+{ -+ VirtIONet *n = VIRTIO_NET(vdev); -+ /* -+ * The actual needed state is now in saved_guest_offloads, -+ * see virtio_net_post_load_device for detail. -+ * Restore it back and apply the desired offloads. -+ */ -+ n->curr_guest_offloads = n->saved_guest_offloads; -+ if (peer_has_vnet_hdr(n)) { -+ virtio_net_apply_guest_offloads(n); -+ } -+ -+ return 0; -+} -+ - /* tx_waiting field of a VirtIONetQueue */ - static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = { - .name = "virtio-net-queue-tx_waiting", -@@ -2909,6 +2929,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) - vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; - vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; - vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); -+ vdc->post_load = virtio_net_post_load_virtio; - vdc->vmsd = &vmstate_virtio_net_device; - } - -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index b96f0c643f..07a9319f4b 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -182,6 +182,8 @@ struct VirtIONet { - char *netclient_name; - char *netclient_type; - uint64_t curr_guest_offloads; -+ /* used on saved state restore phase to preserve the curr_guest_offloads */ -+ uint64_t saved_guest_offloads; - AnnounceTimer announce_timer; - bool needs_vnet_hdr_swap; - bool mtu_bypass_backend; --- -2.23.0 diff --git a/virtio-net-set-the-max-of-queue-size-to-4096.patch b/virtio-net-set-the-max-of-queue-size-to-4096.patch new file mode 100644 index 0000000000000000000000000000000000000000..de0520ec279d7a0a3d95338c959dd3cc619b1582 --- /dev/null +++ b/virtio-net-set-the-max-of-queue-size-to-4096.patch @@ -0,0 +1,68 @@ +From 7beaecc21a8a573d43c7ad7604ac77cdf5bbf405 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Sat, 12 Feb 2022 17:22:38 +0800 +Subject: [PATCH] virtio-net: set the max of queue size to 4096 + +Signed-off-by: Jinhua Cao +--- + hw/net/virtio-net.c | 10 +++++----- + hw/virtio/virtio.c | 2 +- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 6874c88bc0..009dc9f3d1 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -637,7 +637,7 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n) + return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; + } + +- return VIRTQUEUE_MAX_SIZE; ++ return VIRTIO_NET_VQ_MAX_SIZE; + } + + static int peer_attach(VirtIONet *n, int index) +@@ -3394,23 +3394,23 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) + * help from us (using virtio 1 and up). + */ + if (n->net_conf.rx_queue_size < VIRTIO_NET_RX_QUEUE_MIN_SIZE || +- n->net_conf.rx_queue_size > VIRTQUEUE_MAX_SIZE || ++ n->net_conf.rx_queue_size > VIRTIO_NET_VQ_MAX_SIZE || + !is_power_of_2(n->net_conf.rx_queue_size)) { + error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), " + "must be a power of 2 between %d and %d.", + n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE, +- VIRTQUEUE_MAX_SIZE); ++ VIRTIO_NET_VQ_MAX_SIZE); + virtio_cleanup(vdev); + return; + } + + if (n->net_conf.tx_queue_size < VIRTIO_NET_TX_QUEUE_MIN_SIZE || +- n->net_conf.tx_queue_size > VIRTQUEUE_MAX_SIZE || ++ n->net_conf.tx_queue_size > VIRTIO_NET_VQ_MAX_SIZE || + !is_power_of_2(n->net_conf.tx_queue_size)) { + error_setg(errp, "Invalid tx_queue_size (= %" PRIu16 "), " + "must be a power of 2 between %d and %d", + n->net_conf.tx_queue_size, VIRTIO_NET_TX_QUEUE_MIN_SIZE, +- VIRTQUEUE_MAX_SIZE); ++ VIRTIO_NET_VQ_MAX_SIZE); + virtio_cleanup(vdev); + return; + } +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index b08fff9419..120672672e 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2401,7 +2401,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + break; + } + +- if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE) { ++ if (i == VIRTIO_QUEUE_MAX) { + qemu_log("unacceptable queue_size (%d) or num (%d)\n", + queue_size, i); + abort(); +-- +2.27.0 + diff --git a/virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch b/virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a31bd47ddab62d312cb011547b12a44b33f47b9 --- /dev/null +++ b/virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch @@ -0,0 +1,40 @@ +From 89409c7268be2feb85d33af1f3571c0cb62298fb Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:12 -0700 +Subject: [PATCH 5/5] virtio-net: setup vhost_dev and notifiers for cvq only + when feature is negotiated + +When the control virtqueue feature is absent or not negotiated, +vhost_net_start() still tries to set up vhost_dev and install +vhost notifiers for the control virtqueue, which results in +erroneous ioctl calls with incorrect queue index sending down +to driver. Do that only when needed. + +Fixes: 22288fe ("virtio-net: vhost control virtqueue support") +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-2-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: zhangxinhao +--- + hw/net/virtio-net.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index d33da9b7ef..918a7aba89 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -243,7 +243,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) + VirtIODevice *vdev = VIRTIO_DEVICE(n); + NetClientState *nc = qemu_get_queue(n->nic); + int queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; +- int cvq = n->max_ncs - n->max_queue_pairs; ++ int cvq = virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) ? ++ n->max_ncs - n->max_queue_pairs : 0; + + if (!get_vhost_net(nc->peer)) { + return; +-- +2.27.0 + diff --git a/virtio-net-tap-bugfix-del-net-client-if-net_init_tap.patch b/virtio-net-tap-bugfix-del-net-client-if-net_init_tap.patch new file mode 100644 index 0000000000000000000000000000000000000000..59b7c25ecfc6ad380a607659c408f24375cdd262 --- /dev/null +++ b/virtio-net-tap-bugfix-del-net-client-if-net_init_tap.patch @@ -0,0 +1,76 @@ +From cee545754b44b6283408ec6a43eb0e317c98ebb1 Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Wed, 9 Feb 2022 20:27:41 +0800 +Subject: [PATCH] virtio: net-tap: bugfix: del net client if net_init_tap_one + failed + +In net_init_tap_one(), if the net-tap initializes successful +but other actions failed during vhost-net hot-plugging, the +net-tap will remain in the net clients.causing next hot-plug +fails again. + +Signed-off-by: Jinhua Cao +--- + net/tap.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/net/tap.c b/net/tap.c +index c5cbeaa7a2..3f79cd06c2 100644 +--- a/net/tap.c ++++ b/net/tap.c +@@ -684,7 +684,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, + tap_set_sndbuf(s->fd, tap, &err); + if (err) { + error_propagate(errp, err); +- return; ++ goto fail; + } + + if (tap->has_fd || tap->has_fds) { +@@ -726,13 +726,13 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, + } else { + warn_report_err(err); + } +- return; ++ goto fail; + } + ret = qemu_try_set_nonblock(vhostfd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); +- return; ++ goto fail; + } + } else { + vhostfd = open("/dev/vhost-net", O_RDWR); +@@ -744,7 +744,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, + warn_report("tap: open vhost char device failed: %s", + strerror(errno)); + } +- return; ++ goto fail; + } + qemu_set_nonblock(vhostfd); + } +@@ -758,11 +758,17 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, + } else { + warn_report(VHOST_NET_INIT_FAILED); + } +- return; ++ goto fail; + } + } else if (vhostfdname) { + error_setg(errp, "vhostfd(s)= is not valid without vhost"); ++ goto fail; + } ++ ++ return; ++ ++fail: ++ qemu_del_net_client(&s->nc); + } + + static int get_fds(char *str, char *fds[], int max) +-- +2.27.0 + diff --git a/virtio-net-update-the-default-and-max-of-rx-tx_queue.patch b/virtio-net-update-the-default-and-max-of-rx-tx_queue.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d849f97421772a4af00443d60c450a444f6f499 --- /dev/null +++ b/virtio-net-update-the-default-and-max-of-rx-tx_queue.patch @@ -0,0 +1,104 @@ +From 88dfb4236c735c608f8ca91cfbfb5ac424d654aa Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 17:28:49 +0800 +Subject: [PATCH] virtio-net: update the default and max of rx/tx_queue_size + +Set the max of tx_queue_size to 4096 even if the backends +are not vhost-user. + +Set the default of rx/tx_queue_size to 2048 if the backends +are vhost-user, otherwise to 4096. + +Signed-off-by: Jinhua Cao +--- + hw/net/virtio-net.c | 41 +++++++++++++++++++++++++++++++---------- + 1 file changed, 31 insertions(+), 10 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 009dc9f3d1..e887589a30 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -51,12 +51,11 @@ + #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ + + /* previously fixed value */ +-#define VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 256 +-#define VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE 256 ++#define VIRTIO_NET_VHOST_USER_DEFAULT_SIZE 2048 + + /* for now, only allow larger queue_pairs; with virtio-1, guest can downsize */ +-#define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE +-#define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE ++#define VIRTIO_NET_RX_QUEUE_MIN_SIZE 256 ++#define VIRTIO_NET_TX_QUEUE_MIN_SIZE 256 + + #define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */ + +@@ -622,6 +621,28 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, + } + } + ++static void virtio_net_set_default_queue_size(VirtIONet *n) ++{ ++ NetClientState *peer = n->nic_conf.peers.ncs[0]; ++ ++ /* Default value is 0 if not set */ ++ if (n->net_conf.rx_queue_size == 0) { ++ if (peer && peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { ++ n->net_conf.rx_queue_size = VIRTIO_NET_VHOST_USER_DEFAULT_SIZE; ++ } else { ++ n->net_conf.rx_queue_size = VIRTIO_NET_VQ_MAX_SIZE; ++ } ++ } ++ ++ if (n->net_conf.tx_queue_size == 0) { ++ if (peer && peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { ++ n->net_conf.tx_queue_size = VIRTIO_NET_VHOST_USER_DEFAULT_SIZE; ++ } else { ++ n->net_conf.tx_queue_size = VIRTIO_NET_VQ_MAX_SIZE; ++ } ++ } ++} ++ + static int virtio_net_max_tx_queue_size(VirtIONet *n) + { + NetClientState *peer = n->nic_conf.peers.ncs[0]; +@@ -630,11 +651,11 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n) + * Backends other than vhost-user don't support max queue size. + */ + if (!peer) { +- return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; ++ return VIRTIO_NET_VQ_MAX_SIZE; + } + + if (peer->info->type != NET_CLIENT_DRIVER_VHOST_USER) { +- return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; ++ return VIRTIO_NET_VQ_MAX_SIZE; + } + + return VIRTIO_NET_VQ_MAX_SIZE; +@@ -3388,6 +3409,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) + virtio_net_set_config_size(n, n->host_features); + virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); + ++ virtio_net_set_default_queue_size(n); ++ + /* + * We set a lower limit on RX queue size to what it always was. + * Guests that want a smaller ring can always resize it without +@@ -3679,10 +3702,8 @@ static Property virtio_net_properties[] = { + TX_TIMER_INTERVAL), + DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST), + DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), +- DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, +- VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), +- DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size, +- VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE), ++ DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, 0), ++ DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size, 0), + DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), + DEFINE_PROP_BOOL("x-mtu-bypass-backend", VirtIONet, mtu_bypass_backend, + true), +-- +2.27.0 + diff --git a/virtio-new-post_load-hook.patch b/virtio-new-post_load-hook.patch deleted file mode 100644 index 974f286c6730c66cc3cb0a64b046bea341dd262b..0000000000000000000000000000000000000000 --- a/virtio-new-post_load-hook.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 8010d3fce008dd13f155bc0babfe236ea44a2712 Mon Sep 17 00:00:00 2001 -From: "Michael S. Tsirkin" -Date: Fri, 11 Oct 2019 15:58:03 +0200 -Subject: [PATCH] virtio: new post_load hook - -Post load hook in virtio vmsd is called early while device is processed, -and when VirtIODevice core isn't fully initialized. Most device -specific code isn't ready to deal with a device in such state, and -behaves weirdly. - -Add a new post_load hook in a device class instead. Devices should use -this unless they specifically want to verify the migration stream as -it's processed, e.g. for bounds checking. - -Cc: qemu-stable@nongnu.org -Suggested-by: "Dr. David Alan Gilbert" -Cc: Mikhail Sennikovsky -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Jason Wang -(cherry picked from commit 1dd713837cac8ec5a97d3b8492d72ce5ac94803c) -Signed-off-by: Michael Roth ---- - hw/virtio/virtio.c | 7 +++++++ - include/hw/virtio/virtio.h | 6 ++++++ - 2 files changed, 13 insertions(+) - -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index a94ea18a9c..7c3822c3a0 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -2287,6 +2287,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) - } - rcu_read_unlock(); - -+ if (vdc->post_load) { -+ ret = vdc->post_load(vdev); -+ if (ret) { -+ return ret; -+ } -+ } -+ - return 0; - } - -diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h -index b189788cb2..f9f62370e9 100644 ---- a/include/hw/virtio/virtio.h -+++ b/include/hw/virtio/virtio.h -@@ -158,6 +158,12 @@ typedef struct VirtioDeviceClass { - */ - void (*save)(VirtIODevice *vdev, QEMUFile *f); - int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); -+ /* Post load hook in vmsd is called early while device is processed, and -+ * when VirtIODevice isn't fully initialized. Devices should use this instead, -+ * unless they specifically want to verify the migration stream as it's -+ * processed, e.g. for bounds checking. -+ */ -+ int (*post_load)(VirtIODevice *vdev); - const VMStateDescription *vmsd; - } VirtioDeviceClass; - --- -2.23.0 diff --git a/virtio-pci-add-support-for-configure-interrupt-new.patch b/virtio-pci-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..91715da57a14a36eecc5550f7919f8d2d1b74d57 --- /dev/null +++ b/virtio-pci-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,261 @@ +From 7e8f9690b0558a99001d45751754df7caf2ff32b Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:51 +0800 +Subject: [PATCH] virtio-pci: add support for configure interrupt + +Add process to handle the configure interrupt, The function's +logic is the same with vq interrupt.Add extra process to check +the configure interrupt + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-11-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 118 ++++++++++++++++++++++++++++++++++------- + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 102 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..82706b8b32 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,7 +812,8 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; ++ *n = virtio_config_get_guest_notifier(vdev); ++ *vector = vdev->config_vector; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -872,7 +873,7 @@ undo: + } + return ret; + } +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_vq_use(VirtIOPCIProxy *proxy, int nvqs) + { + int queue_no; + int ret = 0; +@@ -887,6 +888,10 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + ++static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) ++{ ++ return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -911,7 +916,7 @@ static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++static void kvm_virtio_pci_vector_vq_release(VirtIOPCIProxy *proxy, int nvqs) + { + int queue_no; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +@@ -924,6 +929,11 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + ++static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) ++{ ++ kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} ++ + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1005,9 +1015,19 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- ++ /* unmask config intr */ ++ if (vector == vdev->config_vector) { ++ n = virtio_config_get_guest_notifier(vdev); ++ ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, ++ msg, n); ++ if (ret < 0) { ++ goto undo_config; ++ } ++ } + return 0; +- ++undo_config: ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1041,6 +1061,11 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } ++ ++ if (vector == vdev->config_vector) { ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); ++ } + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1072,6 +1097,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } ++ /* poll the config intr */ ++ ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, ++ &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector < vector_start || vector >= vector_end || ++ !msix_is_masked(dev, vector)) { ++ return; ++ } ++ if (k->guest_notifier_pending) { ++ if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { ++ msix_set_pending(dev, vector); ++ } ++ } else if (event_notifier_test_and_clear(notifier)) { ++ msix_set_pending(dev, vector); ++ } ++} ++ ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd) ++{ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); ++ } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1080,17 +1133,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, n); +- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); ++ VirtQueue *vq = NULL; ++ EventNotifier *notifier = NULL; ++ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ notifier = virtio_config_get_guest_notifier(vdev); ++ } else { ++ vq = virtio_get_queue(vdev, n); ++ notifier = virtio_queue_get_guest_notifier(vq); ++ } + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); + } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, ++ with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1128,10 +1189,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + proxy->nvqs_with_notifiers = nvqs; + + /* Must unset vector notifier while guest notifier is still assigned */ +- if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) { ++ if ((proxy->vector_irqfd || ++ (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && ++ !assign) { + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { +- kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_vq_release(proxy, nvqs); ++ kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1147,20 +1211,30 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- ++ r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, ++ with_irqfd); ++ if (r < 0) { ++ goto config_assign_error; ++ } + /* Must set vector notifier after guest notifier has been assigned */ +- if ((with_irqfd || k->guest_notifier_mask) && assign) { ++ if ((with_irqfd || ++ (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && ++ assign) { + if (with_irqfd) { + proxy->vector_irqfd = + g_malloc0(sizeof(*proxy->vector_irqfd) * + msix_nr_vectors_allocated(&proxy->pci_dev)); +- r = kvm_virtio_pci_vector_use(proxy, nvqs); ++ r = kvm_virtio_pci_vector_vq_use(proxy, nvqs); ++ if (r < 0) { ++ goto config_assign_error; ++ } ++ r = kvm_virtio_pci_vector_config_use(proxy); + if (r < 0) { +- goto assign_error; ++ goto config_error; + } + } +- r = msix_set_vector_notifiers(&proxy->pci_dev, +- virtio_pci_vector_unmask, ++ ++ r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1173,9 +1247,15 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + notifiers_error: + if (with_irqfd) { + assert(assign); +- kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_vq_release(proxy, nvqs); + } +- ++config_error: ++ if (with_irqfd) { ++ kvm_virtio_pci_vector_config_release(proxy); ++ } ++config_assign_error: ++ virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, ++ with_irqfd); + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index d95b1a13a5..6d8e071d8d 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,5 +256,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +- ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd); + #endif +-- +2.27.0 + diff --git a/virtio-pci-add-support-for-configure-interrupt.patch b/virtio-pci-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000000000000000000000000000000000000..9aa53c1c64c364e805dd0c2e7171858ea73dd2cd --- /dev/null +++ b/virtio-pci-add-support-for-configure-interrupt.patch @@ -0,0 +1,218 @@ +From ce91ab22c29c56e4e18ee2e861b65657f7bb3e90 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:54 +0800 +Subject: [PATCH] virtio-pci: add support for configure interrupt + +Add support for configure interrupt, The process is used kvm_irqfd_assign +to set the gsi to kernel. When the configure notifier was signal by +host, qemu will inject a msix interrupt to guest + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-11-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 92 ++++++++++++++++++++++++++++++++++++------ + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 83 insertions(+), 13 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..90237f523e 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,7 +812,8 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; ++ *n = virtio_config_get_guest_notifier(vdev); ++ *vector = vdev->config_vector; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -887,6 +888,10 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + ++static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) ++{ ++ return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -924,6 +929,11 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + ++static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) ++{ ++ kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} ++ + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1005,9 +1015,17 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- ++ /* unmask config intr */ ++ n = virtio_config_get_guest_notifier(vdev); ++ ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, ++ msg, n); ++ if (ret < 0) { ++ goto undo_config; ++ } + return 0; +- ++undo_config: ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1041,6 +1059,8 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1072,6 +1092,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } ++ /* poll the config intr */ ++ ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, ++ &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector < vector_start || vector >= vector_end || ++ !msix_is_masked(dev, vector)) { ++ return; ++ } ++ if (k->guest_notifier_pending) { ++ if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { ++ msix_set_pending(dev, vector); ++ } ++ } else if (event_notifier_test_and_clear(notifier)) { ++ msix_set_pending(dev, vector); ++ } ++} ++ ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd) ++{ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); ++ } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1080,17 +1128,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, n); +- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); ++ VirtQueue *vq = NULL; ++ EventNotifier *notifier = NULL; ++ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ notifier = virtio_config_get_guest_notifier(vdev); ++ } else { ++ vq = virtio_get_queue(vdev, n); ++ notifier = virtio_queue_get_guest_notifier(vq); ++ } + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); + } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, ++ with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1132,6 +1188,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { + kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1147,7 +1204,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- ++ r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, ++ with_irqfd); ++ if (r < 0) { ++ goto config_assign_error; ++ } + /* Must set vector notifier after guest notifier has been assigned */ + if ((with_irqfd || k->guest_notifier_mask) && assign) { + if (with_irqfd) { +@@ -1156,11 +1217,14 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_nr_vectors_allocated(&proxy->pci_dev)); + r = kvm_virtio_pci_vector_use(proxy, nvqs); + if (r < 0) { +- goto assign_error; ++ goto config_assign_error; + } + } +- r = msix_set_vector_notifiers(&proxy->pci_dev, +- virtio_pci_vector_unmask, ++ r = kvm_virtio_pci_vector_config_use(proxy); ++ if (r < 0) { ++ goto config_error; ++ } ++ r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1175,7 +1239,11 @@ notifiers_error: + assert(assign); + kvm_virtio_pci_vector_release(proxy, nvqs); + } +- ++config_error: ++ kvm_virtio_pci_vector_config_release(proxy); ++config_assign_error: ++ virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, ++ with_irqfd); + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index d95b1a13a5..6d8e071d8d 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,5 +256,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +- ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd); + #endif +-- +2.27.0 + diff --git a/virtio-pci-decouple-notifier-from-interrupt-process-new.patch b/virtio-pci-decouple-notifier-from-interrupt-process-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..89380b313ddfcdfa975def97a88d3cee55819342 --- /dev/null +++ b/virtio-pci-decouple-notifier-from-interrupt-process-new.patch @@ -0,0 +1,259 @@ +From e7e028565dd2620b86e884f953761b96a1ecdfdc Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:43 +0800 +Subject: [PATCH] virtio-pci: decouple notifier from interrupt process + +To reuse the notifier process. We add the virtio_pci_get_notifier +to get the notifier and vector. The INPUT for this function is IDX, +The OUTPUT is the notifier and the vector + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-3-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++++++++++++++--------------- + 1 file changed, 57 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 21c0ec3b1b..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,29 +789,41 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n , + unsigned int vector) + { +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } ++static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, ++ EventNotifier **n, unsigned int *vector) ++{ ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq; ++ ++ if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { ++ return -1; ++ } else { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; ++ } ++ *vector = virtio_queue_vector(vdev, queue_no); ++ vq = virtio_get_queue(vdev, queue_no); ++ *n = virtio_queue_get_guest_notifier(vq); ++ } ++ return 0; ++} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -820,12 +832,15 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- ++ EventNotifier *n; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -837,7 +852,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -853,7 +868,11 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -867,12 +886,16 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -880,21 +903,20 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg) ++ MSIMessage msg, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -921,14 +943,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + } + return ret; + } + +-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector) ++ unsigned int vector, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -939,7 +962,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + } + +@@ -949,6 +972,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -957,7 +981,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); ++ n = virtio_queue_get_guest_notifier(vq); ++ ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); + if (ret < 0) { + goto undo; + } +@@ -973,7 +998,8 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ n = virtio_queue_get_guest_notifier(vq); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -986,15 +1012,17 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); ++ n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1010,19 +1038,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- VirtQueue *vq; ++ int ret; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); ++ if (ret < 0) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } +- vq = virtio_get_queue(vdev, queue_no); +- notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/virtio-pci-decouple-notifier-from-interrupt-process.patch b/virtio-pci-decouple-notifier-from-interrupt-process.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c3d620898eab1936fde061c701def6ae7631721 --- /dev/null +++ b/virtio-pci-decouple-notifier-from-interrupt-process.patch @@ -0,0 +1,259 @@ +From 22998eab50bc17b9af19e377df04d1583a7ddbda Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:50 +0800 +Subject: [PATCH] virtio-pci: decouple notifier from interrupt process + +To reuse the notifier process in configure interrupt. +Use the virtio_pci_get_notifier function to get the notifier. +the INPUT of this function is the IDX, the OUTPUT is notifier and +the vector + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-3-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++++++++++++++--------------- + 1 file changed, 57 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 21c0ec3b1b..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,29 +789,41 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n , + unsigned int vector) + { +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } ++static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, ++ EventNotifier **n, unsigned int *vector) ++{ ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq; ++ ++ if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { ++ return -1; ++ } else { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; ++ } ++ *vector = virtio_queue_vector(vdev, queue_no); ++ vq = virtio_get_queue(vdev, queue_no); ++ *n = virtio_queue_get_guest_notifier(vq); ++ } ++ return 0; ++} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -820,12 +832,15 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- ++ EventNotifier *n; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -837,7 +852,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -853,7 +868,11 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -867,12 +886,16 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -880,21 +903,20 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg) ++ MSIMessage msg, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -921,14 +943,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + } + return ret; + } + +-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector) ++ unsigned int vector, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -939,7 +962,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + } + +@@ -949,6 +972,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -957,7 +981,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); ++ n = virtio_queue_get_guest_notifier(vq); ++ ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); + if (ret < 0) { + goto undo; + } +@@ -973,7 +998,8 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ n = virtio_queue_get_guest_notifier(vq); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -986,15 +1012,17 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); ++ n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1010,19 +1038,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- VirtQueue *vq; ++ int ret; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); ++ if (ret < 0) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } +- vq = virtio_get_queue(vdev, queue_no); +- notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch b/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch new file mode 100644 index 0000000000000000000000000000000000000000..1bff2796e481ac1ae801550ea65d7d9ec44a5f73 --- /dev/null +++ b/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch @@ -0,0 +1,198 @@ +From 99e35c22ecd4847c652f136334c5949651e8419d Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:44 +0800 +Subject: [PATCH] virtio-pci: decouple the single vector from the interrupt + process + +To reuse the interrupt process in configure interrupt +Need to decouple the single vector from the interrupt process. +We add new function kvm_virtio_pci_vector_use_one and _release_one. +These functions are used for the single vector, the whole process will +finish in the loop with vq number. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-4-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 +++++++++++++++++++++++------------------ + 1 file changed, 73 insertions(+), 58 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,7 +762,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -825,87 +824,103 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) + { ++ unsigned int vector; ++ int ret; ++ EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- unsigned int vector; +- int ret, queue_no; +- EventNotifier *n; +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- break; +- } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return 0; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, vector); ++ if (ret < 0) { ++ goto undo; ++ } ++ /* ++ * If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } +- /* If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); +- if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); +- goto undo; +- } +- } + } +- return 0; + ++ return 0; + undo: +- while (--queue_no >= 0) { +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; ++ ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return ret; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; + } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ return ret; ++} ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ int ret = 0; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; + } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + } + return ret; + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++ ++static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, ++ int queue_no) + { +- PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- int queue_no; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + EventNotifier *n; +- int ret ; ++ int ret; ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ PCIDevice *dev = &proxy->pci_dev; ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++} ++ ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- /* If guest supports masking, clean up irqfd now. +- * Otherwise, it was cleaned when masked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ kvm_virtio_pci_vector_release_one(proxy, queue_no); + } + } + +-- +2.27.0 + diff --git a/virtio-pci-decouple-the-single-vector-from-the-inter.patch b/virtio-pci-decouple-the-single-vector-from-the-inter.patch new file mode 100644 index 0000000000000000000000000000000000000000..a6989f9b42c0417ca792dfb6e16d630f044b37dc --- /dev/null +++ b/virtio-pci-decouple-the-single-vector-from-the-inter.patch @@ -0,0 +1,196 @@ +From b3223ddde84840ccc6bb2282dfc146616b85a362 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:51 +0800 +Subject: [PATCH] virtio-pci: decouple the single vector from the interrupt + process + +To reuse the interrupt process in configure interrupt +Need to decouple the single vector from the interrupt process. Add new function +kvm_virtio_pci_vector_use_one and _release_one. These functions are use +for the single vector, the whole process will finish in a loop for the vq number. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-4-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 +++++++++++++++++++++++------------------ + 1 file changed, 73 insertions(+), 58 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,7 +762,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -825,87 +824,103 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) + { ++ unsigned int vector; ++ int ret; ++ EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- unsigned int vector; +- int ret, queue_no; +- EventNotifier *n; +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- break; +- } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return 0; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, vector); ++ if (ret < 0) { ++ goto undo; ++ } ++ /* ++ * If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } +- /* If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); +- if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); +- goto undo; +- } +- } + } +- return 0; + ++ return 0; + undo: +- while (--queue_no >= 0) { +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; ++ ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return ret; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; + } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ return ret; ++} ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ int ret = 0; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; + } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + } + return ret; + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++ ++static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, ++ int queue_no) + { +- PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- int queue_no; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + EventNotifier *n; +- int ret ; ++ int ret; ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ PCIDevice *dev = &proxy->pci_dev; ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++} ++ ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- /* If guest supports masking, clean up irqfd now. +- * Otherwise, it was cleaned when masked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ kvm_virtio_pci_vector_release_one(proxy, queue_no); + } + } + +-- +2.27.0 + diff --git a/virtio-pci-fix-queue_enable-write.patch b/virtio-pci-fix-queue_enable-write.patch deleted file mode 100644 index 481b41bbf11f4ebb94ae8fd746b13ad4ac41555d..0000000000000000000000000000000000000000 --- a/virtio-pci-fix-queue_enable-write.patch +++ /dev/null @@ -1,58 +0,0 @@ -From aebd6a1512e03ba51f6824fcdbaa09f67e9ff5e2 Mon Sep 17 00:00:00 2001 -From: Jason Wang -Date: Wed, 10 Jun 2020 13:43:51 +0800 -Subject: [PATCH 11/11] virtio-pci: fix queue_enable write - -Spec said: The driver uses this to selectively prevent the device from -executing requests from this virtqueue. 1 - enabled; 0 - disabled. - -Though write 0 to queue_enable is forbidden by the spec, we should not -assume that the value is 1. - -Fix this by ignore the write value other than 1. - -Signed-off-by: Jason Wang -Message-Id: <20200610054351.15811-1-jasowang@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Stefano Garzarella -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: BiaoXiang Ye ---- - hw/virtio/virtio-pci.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index b4b0ed26..4b8845a6 100644 ---- a/hw/virtio/virtio-pci.c -+++ b/hw/virtio/virtio-pci.c -@@ -1259,16 +1259,20 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, - virtio_queue_set_vector(vdev, vdev->queue_sel, val); - break; - case VIRTIO_PCI_COMMON_Q_ENABLE: -- virtio_queue_set_num(vdev, vdev->queue_sel, -- proxy->vqs[vdev->queue_sel].num); -- virtio_queue_set_rings(vdev, vdev->queue_sel, -+ if (val == 1) { -+ virtio_queue_set_num(vdev, vdev->queue_sel, -+ proxy->vqs[vdev->queue_sel].num); -+ virtio_queue_set_rings(vdev, vdev->queue_sel, - ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 | - proxy->vqs[vdev->queue_sel].desc[0], - ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 | - proxy->vqs[vdev->queue_sel].avail[0], - ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 | - proxy->vqs[vdev->queue_sel].used[0]); -- proxy->vqs[vdev->queue_sel].enabled = 1; -+ proxy->vqs[vdev->queue_sel].enabled = 1; -+ } else { -+ virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val); -+ } - break; - case VIRTIO_PCI_COMMON_Q_DESCLO: - proxy->vqs[vdev->queue_sel].desc[0] = val; --- -2.27.0.dirty - diff --git a/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch b/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch deleted file mode 100644 index d8ed58faa8f5c6517d131ced73209bc41122158e..0000000000000000000000000000000000000000 --- a/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 637606d18c7208e21d8ab4f318cccde64ae58c76 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Tue, 25 Feb 2020 15:55:53 +0800 -Subject: [PATCH 2/9] virtio-pmem: do delete rq_vq in virtio_pmem_unrealize -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Similar to other virtio-devices, rq_vq forgot to delete in -virtio_pmem_unrealize, this patch fix it. This device has already -maintained a vq pointer, thus we use the new virtio_delete_queue -function directly to do the cleanup. - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Message-Id: <20200225075554.10835-4-pannengyuan@huawei.com> -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: AlexChen ---- - hw/virtio/virtio-pmem.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c -index 17c196d..c680b0a 100644 ---- a/hw/virtio/virtio-pmem.c -+++ b/hw/virtio/virtio-pmem.c -@@ -127,6 +127,7 @@ static void virtio_pmem_unrealize(DeviceState *dev, Error **errp) - VirtIOPMEM *pmem = VIRTIO_PMEM(dev); - - host_memory_backend_set_mapped(pmem->memdev, false); -+ virtio_delete_queue(pmem->rq_vq); - virtio_cleanup(vdev); - } - --- -1.8.3.1 - diff --git a/virtio-print-the-guest-virtio_net-features-that-host.patch b/virtio-print-the-guest-virtio_net-features-that-host.patch new file mode 100644 index 0000000000000000000000000000000000000000..5db0434aba861b8347915f104e313807418b01bf --- /dev/null +++ b/virtio-print-the-guest-virtio_net-features-that-host.patch @@ -0,0 +1,105 @@ +From 8a08b3b41400e152cc1786ae5a8a53507f8e925c Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Thu, 10 Feb 2022 14:16:17 +0800 +Subject: [PATCH] virtio: print the guest virtio_net features that host does + not support + +Signed-off-by: Jinhua Cao +--- + hw/net/virtio-net.c | 41 ++++++++++++++++++++++++++++++++++++++ + hw/virtio/virtio.c | 7 +++++++ + include/hw/virtio/virtio.h | 1 + + 3 files changed, 49 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index b3a5d0b19e..6874c88bc0 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3692,6 +3692,46 @@ static Property virtio_net_properties[] = { + DEFINE_PROP_END_OF_LIST(), + }; + ++static void virtio_net_print_features(uint64_t features) ++{ ++ Property *props = virtio_net_properties; ++ int feature_cnt = 0; ++ ++ if (!features) { ++ return; ++ } ++ printf("virtio_net_feature: "); ++ ++ for (; features && props->name; props++) { ++ /* The bitnr of property may be default(0) besides 'csum' property. */ ++ if (props->bitnr == 0 && strcmp(props->name, "csum")) { ++ continue; ++ } ++ ++ /* Features only support 64bit. */ ++ if (props->bitnr > 63) { ++ continue; ++ } ++ ++ if (virtio_has_feature(features, props->bitnr)) { ++ virtio_clear_feature(&features, props->bitnr); ++ if (feature_cnt != 0) { ++ printf(", "); ++ } ++ printf("%s", props->name); ++ feature_cnt++; ++ } ++ } ++ ++ if (features) { ++ if (feature_cnt != 0) { ++ printf(", "); ++ } ++ printf("unkown bits 0x%." PRIx64, features); ++ } ++ printf("\n"); ++} ++ + static void virtio_net_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); +@@ -3706,6 +3746,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) + vdc->set_config = virtio_net_set_config; + vdc->get_features = virtio_net_get_features; + vdc->set_features = virtio_net_set_features; ++ vdc->print_features = virtio_net_print_features; + vdc->bad_features = virtio_net_bad_features; + vdc->reset = virtio_net_reset; + vdc->set_status = virtio_net_set_status; +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 0af9684881..9a2a83d507 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2967,6 +2967,13 @@ static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) + { + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + bool bad = (val & ~(vdev->host_features)) != 0; ++ uint64_t feat = val & ~(vdev->host_features); ++ ++ if (bad && k->print_features) { ++ qemu_log("error: Please check host config, "\ ++ "because host does not support required feature bits 0x%" PRIx64 "\n", feat); ++ k->print_features(feat); ++ } + + val &= vdev->host_features; + if (k->set_features) { +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index b3749ce34b..7472145821 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -127,6 +127,7 @@ struct VirtioDeviceClass { + int (*validate_features)(VirtIODevice *vdev); + void (*get_config)(VirtIODevice *vdev, uint8_t *config); + void (*set_config)(VirtIODevice *vdev, const uint8_t *config); ++ void (*print_features)(uint64_t features); + void (*reset)(VirtIODevice *vdev); + void (*set_status)(VirtIODevice *vdev, uint8_t val); + /* For transitional devices, this is a bitmap of features +-- +2.27.0 + diff --git a/virtio-scsi-bugfix-fix-qemu-crash-for-hotplug-scsi-d.patch b/virtio-scsi-bugfix-fix-qemu-crash-for-hotplug-scsi-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..bca7db04571d8c014d6a3b51b5c7727f2dcc3aed --- /dev/null +++ b/virtio-scsi-bugfix-fix-qemu-crash-for-hotplug-scsi-d.patch @@ -0,0 +1,37 @@ +From 98cbb6d13484e79b6f9da064a40a281f2983be1d Mon Sep 17 00:00:00 2001 +From: Jinhua Cao +Date: Wed, 9 Feb 2022 19:58:21 +0800 +Subject: [PATCH] virtio-scsi: bugfix: fix qemu crash for hotplug scsi disk + with dataplane + +The vm will trigger a disk sweep operation after plugging +a controller who's io type is iothread. If attach a scsi +disk immediately, the sg_inqury request in vm will trigger +the assert in virtio_scsi_ctx_check(), which is called by +virtio_scsi_handle_cmd_req_prepare(). + +Add judgment in virtio_scsi_handle_cmd_req_prepare() and +return IO Error directly if the device has not been +initialized. + +Signed-off-by: Jinhua Cao +--- + hw/scsi/virtio-scsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 51fd09522a..781a37fe89 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -638,7 +638,7 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) + req->req.cmd.tag, req->req.cmd.cdb[0]); + + d = virtio_scsi_device_get(s, req->req.cmd.lun); +- if (!d) { ++ if (!d || !d->qdev.realized) { + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + virtio_scsi_complete_cmd_req(req); + return -ENOENT; +-- +2.27.0 + diff --git a/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch b/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch deleted file mode 100644 index 02069901b096cd09b0f30dbef9d55e3fe6dc920d..0000000000000000000000000000000000000000 --- a/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0d93f5455489274201b1054d987b12f8e8a6206e Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Mon, 9 Mar 2020 10:17:38 +0800 -Subject: [PATCH 11/14] virtio-serial-bus: Plug memory leak on realize() error - paths - -We neglect to free port->bh on the error paths. Fix that. -Reproducer: - {'execute': 'device_add', 'arguments': {'id': 'virtio_serial_pci0', 'driver': 'virtio-serial-pci', 'bus': 'pci.0', 'addr': '0x5'}, 'id': 'yVkZcGgV'} - {'execute': 'device_add', 'arguments': {'id': 'port1', 'driver': 'virtserialport', 'name': 'port1', 'chardev': 'channel1', 'bus': 'virtio_serial_pci0.0', 'nr': 1}, 'id': '3dXdUgJA'} - {'execute': 'device_add', 'arguments': {'id': 'port2', 'driver': 'virtserialport', 'name': 'port2', 'chardev': 'channel2', 'bus': 'virtio_serial_pci0.0', 'nr': 1}, 'id': 'qLzcCkob'} - {'execute': 'device_add', 'arguments': {'id': 'port2', 'driver': 'virtserialport', 'name': 'port2', 'chardev': 'channel2', 'bus': 'virtio_serial_pci0.0', 'nr': 2}, 'id': 'qLzcCkob'} - -The leak stack: -Direct leak of 40 byte(s) in 1 object(s) allocated from: - #0 0x7f04a8008ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) - #1 0x7f04a73cf1d5 in g_malloc (/lib64/libglib-2.0.so.0+0x531d5) - #2 0x56273eaee484 in aio_bh_new /mnt/sdb/backup/qemu/util/async.c:125 - #3 0x56273eafe9a8 in qemu_bh_new /mnt/sdb/backup/qemu/util/main-loop.c:532 - #4 0x56273d52e62e in virtser_port_device_realize /mnt/sdb/backup/qemu/hw/char/virtio-serial-bus.c:946 - #5 0x56273dcc5040 in device_set_realized /mnt/sdb/backup/qemu/hw/core/qdev.c:891 - #6 0x56273e5ebbce in property_set_bool /mnt/sdb/backup/qemu/qom/object.c:2238 - #7 0x56273e5e5a9c in object_property_set /mnt/sdb/backup/qemu/qom/object.c:1324 - #8 0x56273e5ef5f8 in object_property_set_qobject /mnt/sdb/backup/qemu/qom/qom-qobject.c:26 - #9 0x56273e5e5e6a in object_property_set_bool /mnt/sdb/backup/qemu/qom/object.c:1390 - #10 0x56273daa40de in qdev_device_add /mnt/sdb/backup/qemu/qdev-monitor.c:680 - #11 0x56273daa53e9 in qmp_device_add /mnt/sdb/backup/qemu/qdev-monitor.c:805 - -Fixes: 199646d81522509ac2dba6d28c31e8c7d807bc93 -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Reviewed-by: Markus Armbruster -Reviewed-by: Amit Shah -Message-Id: <20200309021738.30072-1-pannengyuan@huawei.com> -Reviewed-by: Laurent Vivier -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Signed-off-by: Peng Liang ---- - hw/char/virtio-serial-bus.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c -index f7a54f261b21..2d23dae6d2b7 100644 ---- a/hw/char/virtio-serial-bus.c -+++ b/hw/char/virtio-serial-bus.c -@@ -940,7 +940,6 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) - Error *err = NULL; - - port->vser = bus->vser; -- port->bh = qemu_bh_new(flush_queued_data_bh, port); - - assert(vsc->have_data); - -@@ -989,6 +988,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) - return; - } - -+ port->bh = qemu_bh_new(flush_queued_data_bh, port); - port->elem = NULL; - } - --- -2.26.2 - diff --git a/virtio-signal-after-wrapping-packed-used_idx.patch b/virtio-signal-after-wrapping-packed-used_idx.patch new file mode 100644 index 0000000000000000000000000000000000000000..3fa3b633aef0aab471da451e04fab95af43a30e1 --- /dev/null +++ b/virtio-signal-after-wrapping-packed-used_idx.patch @@ -0,0 +1,51 @@ +From 671f0830d70c1e35deb63cc66db7ce8b713e8967 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Tue, 30 Nov 2021 13:45:10 +0000 +Subject: [PATCH] virtio: signal after wrapping packed used_idx + +Packed Virtqueues wrap used_idx instead of letting it run freely like +Split Virtqueues do. If the used ring wraps more than once there is no +way to compare vq->signalled_used and vq->used_idx in +virtio_packed_should_notify() since they are modulo vq->vring.num. + +This causes the device to stop sending used buffer notifications when +when virtio_packed_should_notify() is called less than once each time +around the used ring. + +It is possible to trigger this with virtio-blk's dataplane +notify_guest_bh() irq coalescing optimization. The call to +virtio_notify_irqfd() (and virtio_packed_should_notify()) is deferred to +a BH. If the guest driver is polling it can complete and submit more +requests before the BH executes, causing the used ring to wrap more than +once. The result is that the virtio-blk device ceases to raise +interrupts and I/O hangs. + +Cc: Tiwei Bie +Cc: Jason Wang +Cc: Michael S. Tsirkin +Signed-off-by: Stefan Hajnoczi +Message-Id: <20211130134510.267382-1-stefanha@redhat.com> +Fixes: 86044b24e865fb9596ed77a4d0f3af8b90a088a1 ("virtio: basic packed virtqueue support") +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index d90cabe868..05409b84d1 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -885,6 +885,7 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count) + if (vq->used_idx >= vq->vring.num) { + vq->used_idx -= vq->vring.num; + vq->used_wrap_counter ^= 1; ++ vq->signalled_used_valid = false; + } + } + +-- +2.27.0 + diff --git a/virtio-vhost-vsock-don-t-double-close-vhostfd-remove.patch b/virtio-vhost-vsock-don-t-double-close-vhostfd-remove.patch new file mode 100644 index 0000000000000000000000000000000000000000..b554e7a1d728a2c82ec50d51f5bf246d7945bd0f --- /dev/null +++ b/virtio-vhost-vsock-don-t-double-close-vhostfd-remove.patch @@ -0,0 +1,57 @@ +From 1d888e71517be4a0793b5a03b4a2234c55953c8f Mon Sep 17 00:00:00 2001 +From: boringandboring +Date: Fri, 8 Dec 2023 10:02:51 +0800 +Subject: [PATCH] virtio/vhost-vsock: don't double close vhostfd, remove + redundant cleanup + +cherry picked from d731ab31196579144457c7f2fa3649338bfb21f2 + +In case of an error during initialization in vhost_dev_init, vhostfd is +closed in vhost_dev_cleanup. Remove close from err_virtio as it's both +redundant and causes a double close on vhostfd. + +Signed-off-by: Daniil Tatianin +Message-Id: <20211129125204.1108088-1-d-tatianin@yandex-team.ru> +Reviewed-by: Stefano Garzarella +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: boringandboring +--- + hw/virtio/vhost-vsock.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c +index 478c0c9a87..433d42d897 100644 +--- a/hw/virtio/vhost-vsock.c ++++ b/hw/virtio/vhost-vsock.c +@@ -171,6 +171,10 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) + ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd, + VHOST_BACKEND_TYPE_KERNEL, 0, errp); + if (ret < 0) { ++ /* ++ * vhostfd is closed by vhost_dev_cleanup, which is called ++ * by vhost_dev_init on initialization error. ++ */ + goto err_virtio; + } + +@@ -183,15 +187,10 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) + return; + + err_vhost_dev: +- vhost_dev_cleanup(&vvc->vhost_dev); + /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */ +- vhostfd = -1; ++ vhost_dev_cleanup(&vvc->vhost_dev); + err_virtio: + vhost_vsock_common_unrealize(vdev); +- if (vhostfd >= 0) { +- close(vhostfd); +- } +- return; + } + + static void vhost_vsock_device_unrealize(DeviceState *dev) +-- +2.27.0 + diff --git a/virtio_blk-Add-support-for-retry-on-errors.patch b/virtio_blk-Add-support-for-retry-on-errors.patch index e7d8efd7ed99ae35f5309bee2e90bedfcc1f5e86..1d7bd03846fe489f9aab23e1931f9d9f286e51fb 100644 --- a/virtio_blk-Add-support-for-retry-on-errors.patch +++ b/virtio_blk-Add-support-for-retry-on-errors.patch @@ -1,22 +1,23 @@ -From f3158cc327d435939d87ecee23485d082ebf3ba2 Mon Sep 17 00:00:00 2001 +From a81122e37595fe1cc9eaa2adbbfccbfdf8f988b8 Mon Sep 17 00:00:00 2001 From: Jiahui Cen Date: Thu, 21 Jan 2021 15:46:53 +0800 -Subject: [PATCH] virtio_blk: Add support for retry on errors +Subject: [PATCH 7/7] virtio_blk: Add support for retry on errors Insert failed requests into device's list for later retry and handle queued requests to implement retry_request_cb. Signed-off-by: Jiahui Cen Signed-off-by: Ying Fang +Signed-off-by: Alex Chen --- hw/block/virtio-blk.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index ddf525b9d7..2db9804cfe 100644 +index f139cd7cc9..c8d94a3dfb 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c -@@ -101,6 +101,10 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, +@@ -108,6 +108,10 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, block_acct_failed(blk_get_stats(s->blk), &req->acct); } virtio_blk_free_request(req); @@ -27,7 +28,7 @@ index ddf525b9d7..2db9804cfe 100644 } blk_error_action(s->blk, action, is_read, error); -@@ -142,6 +146,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) +@@ -149,6 +153,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) } } @@ -35,7 +36,7 @@ index ddf525b9d7..2db9804cfe 100644 virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); block_acct_done(blk_get_stats(s->blk), &req->acct); virtio_blk_free_request(req); -@@ -161,6 +166,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) +@@ -168,6 +173,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) } } @@ -43,7 +44,7 @@ index ddf525b9d7..2db9804cfe 100644 virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); block_acct_done(blk_get_stats(s->blk), &req->acct); virtio_blk_free_request(req); -@@ -183,6 +189,7 @@ static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret) +@@ -190,6 +196,7 @@ static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret) } } @@ -51,7 +52,7 @@ index ddf525b9d7..2db9804cfe 100644 virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); if (is_write_zeroes) { block_acct_done(blk_get_stats(s->blk), &req->acct); -@@ -811,12 +818,12 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +@@ -828,12 +835,12 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) { @@ -67,8 +68,8 @@ index ddf525b9d7..2db9804cfe 100644 while (req) { VirtIOBlockReq *next = req->next; if (virtio_blk_handle_request(req, &mrb)) { -@@ -1101,8 +1108,16 @@ static void virtio_blk_resize(void *opaque) - virtio_notify_config(vdev); +@@ -1138,8 +1145,16 @@ static void virtio_blk_resize(void *opaque) + aio_bh_schedule_oneshot(qemu_get_aio_context(), virtio_resize_cb, vdev); } +static void virtio_blk_retry_request(void *opaque) diff --git a/virtiofsd-Drop-membership-of-all-supplementary-group.patch b/virtiofsd-Drop-membership-of-all-supplementary-group.patch new file mode 100644 index 0000000000000000000000000000000000000000..cedcfc2d6760981f62b55674917f05af46933be6 --- /dev/null +++ b/virtiofsd-Drop-membership-of-all-supplementary-group.patch @@ -0,0 +1,101 @@ +From fa471a127c7bacd760b6dcb9d6a8434883eedf8c Mon Sep 17 00:00:00 2001 +From: Vivek Goyal +Date: Tue, 25 Jan 2022 13:51:14 -0500 +Subject: [PATCH 2/2] virtiofsd: Drop membership of all supplementary groups + (CVE-2022-0358) + +At the start, drop membership of all supplementary groups. This is +not required. + +If we have membership of "root" supplementary group and when we switch +uid/gid using setresuid/setsgid, we still retain membership of existing +supplemntary groups. And that can allow some operations which are not +normally allowed. + +For example, if root in guest creates a dir as follows. + +$ mkdir -m 03777 test_dir + +This sets SGID on dir as well as allows unprivileged users to write into +this dir. + +And now as unprivileged user open file as follows. + +$ su test +$ fd = open("test_dir/priviledge_id", O_RDWR|O_CREAT|O_EXCL, 02755); + +This will create SGID set executable in test_dir/. + +And that's a problem because now an unpriviliged user can execute it, +get egid=0 and get access to resources owned by "root" group. This is +privilege escalation. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2044863 +Fixes: CVE-2022-0358 +Reported-by: JIETAO XIAO +Suggested-by: Miklos Szeredi +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Vivek Goyal +Message-Id: +Signed-off-by: Dr. David Alan Gilbert + dgilbert: Fixed missing {}'s style nit +--- + tools/virtiofsd/passthrough_ll.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c +index 64b5b4fbb1..b3d0674f6d 100644 +--- a/tools/virtiofsd/passthrough_ll.c ++++ b/tools/virtiofsd/passthrough_ll.c +@@ -54,6 +54,7 @@ + #include + #include + #include ++#include + + #include "qemu/cutils.h" + #include "passthrough_helpers.h" +@@ -1161,6 +1162,30 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) + #define OURSYS_setresuid SYS_setresuid + #endif + ++static void drop_supplementary_groups(void) ++{ ++ int ret; ++ ++ ret = getgroups(0, NULL); ++ if (ret == -1) { ++ fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++ ++ if (!ret) { ++ return; ++ } ++ ++ /* Drop all supplementary groups. We should not need it */ ++ ret = setgroups(0, NULL); ++ if (ret == -1) { ++ fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++} ++ + /* + * Change to uid/gid of caller so that file is created with + * ownership of caller. +@@ -3926,6 +3951,8 @@ int main(int argc, char *argv[]) + + qemu_init_exec_dir(argv[0]); + ++ drop_supplementary_groups(); ++ + pthread_mutex_init(&lo.mutex, NULL); + lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal); + lo.root.fd = -1; +-- +2.27.0 + diff --git a/vl-Don-t-mismatch-g_strsplit-g_free.patch b/vl-Don-t-mismatch-g_strsplit-g_free.patch deleted file mode 100644 index dc1f4cc484e8b27af68fa7c533ce338fdfbcf7ad..0000000000000000000000000000000000000000 --- a/vl-Don-t-mismatch-g_strsplit-g_free.patch +++ /dev/null @@ -1,56 +0,0 @@ -From cad4a99e8cab2fe581fb2c6c1421f5547b451e96 Mon Sep 17 00:00:00 2001 -From: Pan Nengyuan -Date: Fri, 10 Jan 2020 17:17:09 +0800 -Subject: [PATCH] vl: Don't mismatch g_strsplit()/g_free() - -It's a mismatch between g_strsplit and g_free, it will cause a memory leak as follow: - -[root@localhost]# ./aarch64-softmmu/qemu-system-aarch64 -accel help -Accelerators supported in QEMU binary: -tcg -kvm -================================================================= -==1207900==ERROR: LeakSanitizer: detected memory leaks - -Direct leak of 8 byte(s) in 2 object(s) allocated from: - #0 0xfffd700231cb in __interceptor_malloc (/lib64/libasan.so.4+0xd31cb) - #1 0xfffd6ec57163 in g_malloc (/lib64/libglib-2.0.so.0+0x57163) - #2 0xfffd6ec724d7 in g_strndup (/lib64/libglib-2.0.so.0+0x724d7) - #3 0xfffd6ec73d3f in g_strsplit (/lib64/libglib-2.0.so.0+0x73d3f) - #4 0xaaab66be5077 in main /mnt/sdc/qemu-master/qemu-4.2.0-rc0/vl.c:3517 - #5 0xfffd6e140b9f in __libc_start_main (/lib64/libc.so.6+0x20b9f) - #6 0xaaab66bf0f53 (./build/aarch64-softmmu/qemu-system-aarch64+0x8a0f53) - -Direct leak of 2 byte(s) in 2 object(s) allocated from: - #0 0xfffd700231cb in __interceptor_malloc (/lib64/libasan.so.4+0xd31cb) - #1 0xfffd6ec57163 in g_malloc (/lib64/libglib-2.0.so.0+0x57163) - #2 0xfffd6ec7243b in g_strdup (/lib64/libglib-2.0.so.0+0x7243b) - #3 0xfffd6ec73e6f in g_strsplit (/lib64/libglib-2.0.so.0+0x73e6f) - #4 0xaaab66be5077 in main /mnt/sdc/qemu-master/qemu-4.2.0-rc0/vl.c:3517 - #5 0xfffd6e140b9f in __libc_start_main (/lib64/libc.so.6+0x20b9f) - #6 0xaaab66bf0f53 (./build/aarch64-softmmu/qemu-system-aarch64+0x8a0f53) - -Reported-by: Euler Robot -Signed-off-by: Pan Nengyuan -Message-Id: <20200110091710.53424-2-pannengyuan@huawei.com> -Signed-off-by: Paolo Bonzini ---- - vl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/vl.c b/vl.c -index b426b32134..cec0bfdb44 100644 ---- a/vl.c -+++ b/vl.c -@@ -3532,7 +3532,7 @@ int main(int argc, char **argv, char **envp) - gchar **optname = g_strsplit(typename, - ACCEL_CLASS_SUFFIX, 0); - printf("%s\n", optname[0]); -- g_free(optname); -+ g_strfreev(optname); - } - g_free(typename); - } --- -2.27.0 - diff --git a/vmstate-add-qom-interface-to-get-id.patch b/vmstate-add-qom-interface-to-get-id.patch deleted file mode 100644 index 53a004405a907109dfb0bbc9354a3b0ef979846f..0000000000000000000000000000000000000000 --- a/vmstate-add-qom-interface-to-get-id.patch +++ /dev/null @@ -1,210 +0,0 @@ -From d771fca664e40c7d7ec5dfa2c656a282bff705b7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 28 Aug 2019 16:00:19 +0400 -Subject: [PATCH] vmstate: add qom interface to get id -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add an interface to get the instance id, instead of depending on -Device and qdev_get_dev_path(). - -Signed-off-by: Marc-André Lureau -Reviewed-by: Daniel P. Berrangé -Acked-by: Dr. David Alan Gilbert ---- - MAINTAINERS | 2 ++ - hw/core/Makefile.objs | 1 + - hw/core/qdev.c | 14 +++++++++++++ - hw/core/vmstate-if.c | 23 +++++++++++++++++++++ - include/hw/vmstate-if.h | 40 ++++++++++++++++++++++++++++++++++++ - include/migration/register.h | 2 ++ - include/migration/vmstate.h | 2 ++ - tests/Makefile.include | 1 + - 8 files changed, 85 insertions(+) - create mode 100644 hw/core/vmstate-if.c - create mode 100644 include/hw/vmstate-if.h - -diff --git a/MAINTAINERS b/MAINTAINERS -index d6de200453..e2d74d7ec3 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -2135,6 +2135,8 @@ Migration - M: Juan Quintela - M: Dr. David Alan Gilbert - S: Maintained -+F: hw/core/vmstate-if.c -+F: include/hw/vmstate-if.h - F: include/migration/ - F: migration/ - F: scripts/vmstate-static-checker.py -diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs -index f8481d959f..54c51583d8 100644 ---- a/hw/core/Makefile.objs -+++ b/hw/core/Makefile.objs -@@ -8,6 +8,7 @@ common-obj-y += irq.o - common-obj-y += hotplug.o - common-obj-$(CONFIG_SOFTMMU) += nmi.o - common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o -+common-obj-y += vmstate-if.o - - common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o - common-obj-$(CONFIG_XILINX_AXI) += stream.o -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 4b32f2f46d..13931b1117 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -1048,9 +1048,18 @@ static void device_unparent(Object *obj) - } - } - -+static char * -+device_vmstate_if_get_id(VMStateIf *obj) -+{ -+ DeviceState *dev = DEVICE(obj); -+ -+ return qdev_get_dev_path(dev); -+} -+ - static void device_class_init(ObjectClass *class, void *data) - { - DeviceClass *dc = DEVICE_CLASS(class); -+ VMStateIfClass *vc = VMSTATE_IF_CLASS(class); - - class->unparent = device_unparent; - -@@ -1062,6 +1071,7 @@ static void device_class_init(ObjectClass *class, void *data) - */ - dc->hotpluggable = true; - dc->user_creatable = true; -+ vc->get_id = device_vmstate_if_get_id; - } - - void device_class_set_parent_reset(DeviceClass *dc, -@@ -1119,6 +1129,10 @@ static const TypeInfo device_type_info = { - .class_init = device_class_init, - .abstract = true, - .class_size = sizeof(DeviceClass), -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_VMSTATE_IF }, -+ { } -+ } - }; - - static void qdev_register_types(void) -diff --git a/hw/core/vmstate-if.c b/hw/core/vmstate-if.c -new file mode 100644 -index 0000000000..bf453620fe ---- /dev/null -+++ b/hw/core/vmstate-if.c -@@ -0,0 +1,23 @@ -+/* -+ * VMState interface -+ * -+ * Copyright (c) 2009-2019 Red Hat Inc -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/vmstate-if.h" -+ -+static const TypeInfo vmstate_if_info = { -+ .name = TYPE_VMSTATE_IF, -+ .parent = TYPE_INTERFACE, -+ .class_size = sizeof(VMStateIfClass), -+}; -+ -+static void vmstate_register_types(void) -+{ -+ type_register_static(&vmstate_if_info); -+} -+ -+type_init(vmstate_register_types); -diff --git a/include/hw/vmstate-if.h b/include/hw/vmstate-if.h -new file mode 100644 -index 0000000000..8ff7f0f292 ---- /dev/null -+++ b/include/hw/vmstate-if.h -@@ -0,0 +1,40 @@ -+/* -+ * VMState interface -+ * -+ * Copyright (c) 2009-2019 Red Hat Inc -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef VMSTATE_IF_H -+#define VMSTATE_IF_H -+ -+#include "qom/object.h" -+ -+#define TYPE_VMSTATE_IF "vmstate-if" -+ -+#define VMSTATE_IF_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(VMStateIfClass, (klass), TYPE_VMSTATE_IF) -+#define VMSTATE_IF_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(VMStateIfClass, (obj), TYPE_VMSTATE_IF) -+#define VMSTATE_IF(obj) \ -+ INTERFACE_CHECK(VMStateIf, (obj), TYPE_VMSTATE_IF) -+ -+typedef struct VMStateIf VMStateIf; -+ -+typedef struct VMStateIfClass { -+ InterfaceClass parent_class; -+ -+ char * (*get_id)(VMStateIf *obj); -+} VMStateIfClass; -+ -+static inline char *vmstate_if_get_id(VMStateIf *vmif) -+{ -+ if (!vmif) { -+ return NULL; -+ } -+ -+ return VMSTATE_IF_GET_CLASS(vmif)->get_id(vmif); -+} -+ -+#endif /* VMSTATE_IF_H */ -diff --git a/include/migration/register.h b/include/migration/register.h -index f3ba10b6ef..158130c8c4 100644 ---- a/include/migration/register.h -+++ b/include/migration/register.h -@@ -14,6 +14,8 @@ - #ifndef MIGRATION_REGISTER_H - #define MIGRATION_REGISTER_H - -+#include "hw/vmstate-if.h" -+ - typedef struct SaveVMHandlers { - /* This runs inside the iothread lock. */ - SaveStateHandler *save_state; -diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h -index 8abd2e3b80..8cc1e19fd9 100644 ---- a/include/migration/vmstate.h -+++ b/include/migration/vmstate.h -@@ -27,6 +27,8 @@ - #ifndef QEMU_VMSTATE_H - #define QEMU_VMSTATE_H - -+#include "hw/vmstate-if.h" -+ - typedef struct VMStateInfo VMStateInfo; - typedef struct VMStateDescription VMStateDescription; - typedef struct VMStateField VMStateField; -diff --git a/tests/Makefile.include b/tests/Makefile.include -index 3be60ab999..1c7772a230 100644 ---- a/tests/Makefile.include -+++ b/tests/Makefile.include -@@ -566,6 +566,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ - hw/core/irq.o \ - hw/core/fw-path-provider.o \ - hw/core/reset.o \ -+ hw/core/vmstate-if.o \ - $(test-qapi-obj-y) - tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ - migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \ --- -2.27.0 - diff --git a/vmxcap-correct-the-name-of-the-variables.patch b/vmxcap-correct-the-name-of-the-variables.patch deleted file mode 100644 index 3a402dfa1e6908d301ff51e2499af5b3443e3014..0000000000000000000000000000000000000000 --- a/vmxcap-correct-the-name-of-the-variables.patch +++ /dev/null @@ -1,44 +0,0 @@ -From de8779d10794312d1eb56dda5936df7ad6e3c87f Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 1 Jul 2019 16:51:24 +0200 -Subject: [PATCH] vmxcap: correct the name of the variables - -The low bits are 1 if the control must be one, the high bits -are 1 if the control can be one. Correct the variable names -as they are very confusing. - -Signed-off-by: Paolo Bonzini ---- - scripts/kvm/vmxcap | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap -index 99a8146aaa..2db683215d 100755 ---- a/scripts/kvm/vmxcap -+++ b/scripts/kvm/vmxcap -@@ -51,15 +51,15 @@ class Control(object): - return (val & 0xffffffff, val >> 32) - def show(self): - print(self.name) -- mbz, mb1 = self.read2(self.cap_msr) -- tmbz, tmb1 = 0, 0 -+ mb1, cb1 = self.read2(self.cap_msr) -+ tmb1, tcb1 = 0, 0 - if self.true_cap_msr: -- tmbz, tmb1 = self.read2(self.true_cap_msr) -+ tmb1, tcb1 = self.read2(self.true_cap_msr) - for bit in sorted(self.bits.keys()): -- zero = not (mbz & (1 << bit)) -- one = mb1 & (1 << bit) -- true_zero = not (tmbz & (1 << bit)) -- true_one = tmb1 & (1 << bit) -+ zero = not (mb1 & (1 << bit)) -+ one = cb1 & (1 << bit) -+ true_zero = not (tmb1 & (1 << bit)) -+ true_one = tcb1 & (1 << bit) - s= '?' - if (self.true_cap_msr and true_zero and true_one - and one and not zero): --- -2.27.0 - diff --git a/vnc-avoid-underflow-when-accessing-user-provided-add.patch b/vnc-avoid-underflow-when-accessing-user-provided-add.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d6b3acd95421e603afb782424e47291197d54b6 --- /dev/null +++ b/vnc-avoid-underflow-when-accessing-user-provided-add.patch @@ -0,0 +1,41 @@ +From 3d6a5be54f59b86db1d9513cff24ca6f7d002400 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 27 Jun 2023 17:39:56 +0800 +Subject: [PATCH] vnc: avoid underflow when accessing user-provided address + +cheery-pick from bfc532703f3c4f8d2744748c440ca36ce9798ccb + +If hostlen is zero, there is a possibility that addrstr[hostlen - 1] +underflows and, if a closing bracked is there, hostlen - 2 is passed +to g_strndup() on the next line. If websocket==false then +addrstr[0] would be a colon, but if websocket==true this could in +principle happen. + +Fix it by checking hostlen. + +Reported by Coverity. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 3f9c41c5df9617510d8533cf6588172efb3df34b) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + ui/vnc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 91e067ba7c..f4322a9065 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -3761,7 +3761,7 @@ static int vnc_display_get_address(const char *addrstr, + + addr->type = SOCKET_ADDRESS_TYPE_INET; + inet = &addr->u.inet; +- if (addrstr[0] == '[' && addrstr[hostlen - 1] == ']') { ++ if (hostlen && addrstr[0] == '[' && addrstr[hostlen - 1] == ']') { + inet->host = g_strndup(addrstr + 1, hostlen - 2); + } else { + inet->host = g_strndup(addrstr, hostlen); +-- +2.41.0.windows.1 + diff --git a/vnc-fix-memory-leak-when-vnc-disconnect.patch b/vnc-fix-memory-leak-when-vnc-disconnect.patch deleted file mode 100644 index 3eddde4aafc1a213623db042b0cc94a7942e9574..0000000000000000000000000000000000000000 --- a/vnc-fix-memory-leak-when-vnc-disconnect.patch +++ /dev/null @@ -1,1014 +0,0 @@ -From 6bf21f3d83e95bcc4ba35a7a07cc6655e8b010b0 Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Sat, 31 Aug 2019 08:39:22 -0700 -Subject: [PATCH] vnc: fix memory leak when vnc disconnect - -Currently when qemu receives a vnc connect, it creates a 'VncState' to -represent this connection. In 'vnc_worker_thread_loop' it creates a -local 'VncState'. The connection 'VcnState' and local 'VncState' exchange -data in 'vnc_async_encoding_start' and 'vnc_async_encoding_end'. -In 'zrle_compress_data' it calls 'deflateInit2' to allocate the libz library -opaque data. The 'VncState' used in 'zrle_compress_data' is the local -'VncState'. In 'vnc_zrle_clear' it calls 'deflateEnd' to free the libz -library opaque data. The 'VncState' used in 'vnc_zrle_clear' is the connection -'VncState'. In currently implementation there will be a memory leak when the -vnc disconnect. Following is the asan output backtrack: - -Direct leak of 29760 byte(s) in 5 object(s) allocated from: - 0 0xffffa67ef3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3) - 1 0xffffa65071cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb) - 2 0xffffa5e968f7 in deflateInit2_ (/lib64/libz.so.1+0x78f7) - 3 0xaaaacec58613 in zrle_compress_data ui/vnc-enc-zrle.c:87 - 4 0xaaaacec58613 in zrle_send_framebuffer_update ui/vnc-enc-zrle.c:344 - 5 0xaaaacec34e77 in vnc_send_framebuffer_update ui/vnc.c:919 - 6 0xaaaacec5e023 in vnc_worker_thread_loop ui/vnc-jobs.c:271 - 7 0xaaaacec5e5e7 in vnc_worker_thread ui/vnc-jobs.c:340 - 8 0xaaaacee4d3c3 in qemu_thread_start util/qemu-thread-posix.c:502 - 9 0xffffa544e8bb in start_thread (/lib64/libpthread.so.0+0x78bb) - 10 0xffffa53965cb in thread_start (/lib64/libc.so.6+0xd55cb) - -This is because the opaque allocated in 'deflateInit2' is not freed in -'deflateEnd'. The reason is that the 'deflateEnd' calls 'deflateStateCheck' -and in the latter will check whether 's->strm != strm'(libz's data structure). -This check will be true so in 'deflateEnd' it just return 'Z_STREAM_ERROR' and -not free the data allocated in 'deflateInit2'. - -The reason this happens is that the 'VncState' contains the whole 'VncZrle', -so when calling 'deflateInit2', the 's->strm' will be the local address. -So 's->strm != strm' will be true. - -To fix this issue, we need to make 'zrle' of 'VncState' to be a pointer. -Then the connection 'VncState' and local 'VncState' exchange mechanism will -work as expection. The 'tight' of 'VncState' has the same issue, let's also turn -it to a pointer. - -Reported-by: Ying Fang -Signed-off-by: Li Qiang -Message-id: 20190831153922.121308-1-liq3ea@163.com -Signed-off-by: Gerd Hoffmann ---- - ui/vnc-enc-tight.c | 219 +++++++++++++++++++++++++------------------------- - ui/vnc-enc-zlib.c | 11 +-- - ui/vnc-enc-zrle.c | 68 ++++++++-------- - ui/vnc-enc-zrle.inc.c | 2 +- - ui/vnc.c | 28 ++++--- - ui/vnc.h | 4 +- - 6 files changed, 170 insertions(+), 162 deletions(-) - -diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c -index 9084c22..1e08518 100644 ---- a/ui/vnc-enc-tight.c -+++ b/ui/vnc-enc-tight.c -@@ -116,7 +116,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h, - - static bool tight_can_send_png_rect(VncState *vs, int w, int h) - { -- if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) { -+ if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) { - return false; - } - -@@ -144,7 +144,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) - int pixels = 0; - int pix, left[3]; - unsigned int errors; -- unsigned char *buf = vs->tight.tight.buffer; -+ unsigned char *buf = vs->tight->tight.buffer; - - /* - * If client is big-endian, color samples begin from the second -@@ -215,7 +215,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) - int pixels = 0; \ - int sample, sum, left[3]; \ - unsigned int errors; \ -- unsigned char *buf = vs->tight.tight.buffer; \ -+ unsigned char *buf = vs->tight->tight.buffer; \ - \ - endian = 0; /* FIXME */ \ - \ -@@ -296,8 +296,8 @@ static int - tight_detect_smooth_image(VncState *vs, int w, int h) - { - unsigned int errors; -- int compression = vs->tight.compression; -- int quality = vs->tight.quality; -+ int compression = vs->tight->compression; -+ int quality = vs->tight->quality; - - if (!vs->vd->lossy) { - return 0; -@@ -309,7 +309,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) - return 0; - } - -- if (vs->tight.quality != (uint8_t)-1) { -+ if (vs->tight->quality != (uint8_t)-1) { - if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) { - return 0; - } -@@ -320,9 +320,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h) - } - - if (vs->client_pf.bytes_per_pixel == 4) { -- if (vs->tight.pixel24) { -+ if (vs->tight->pixel24) { - errors = tight_detect_smooth_image24(vs, w, h); -- if (vs->tight.quality != (uint8_t)-1) { -+ if (vs->tight->quality != (uint8_t)-1) { - return (errors < tight_conf[quality].jpeg_threshold24); - } - return (errors < tight_conf[compression].gradient_threshold24); -@@ -352,7 +352,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) - uint##bpp##_t c0, c1, ci; \ - int i, n0, n1; \ - \ -- data = (uint##bpp##_t *)vs->tight.tight.buffer; \ -+ data = (uint##bpp##_t *)vs->tight->tight.buffer; \ - \ - c0 = data[0]; \ - i = 1; \ -@@ -423,9 +423,9 @@ static int tight_fill_palette(VncState *vs, int x, int y, - { - int max; - -- max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor; -+ max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor; - if (max < 2 && -- count >= tight_conf[vs->tight.compression].mono_min_rect_size) { -+ count >= tight_conf[vs->tight->compression].mono_min_rect_size) { - max = 2; - } - if (max >= 256) { -@@ -558,7 +558,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h) - int x, y, c; - - buf32 = (uint32_t *)buf; -- memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); -+ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); - - if (1 /* FIXME */) { - shift[0] = vs->client_pf.rshift; -@@ -575,7 +575,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h) - upper[c] = 0; - here[c] = 0; - } -- prev = (int *)vs->tight.gradient.buffer; -+ prev = (int *)vs->tight->gradient.buffer; - for (x = 0; x < w; x++) { - pix32 = *buf32++; - for (c = 0; c < 3; c++) { -@@ -615,7 +615,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h) - int prediction; \ - int x, y, c; \ - \ -- memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \ -+ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); \ - \ - endian = 0; /* FIXME */ \ - \ -@@ -631,7 +631,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h) - upper[c] = 0; \ - here[c] = 0; \ - } \ -- prev = (int *)vs->tight.gradient.buffer; \ -+ prev = (int *)vs->tight->gradient.buffer; \ - for (x = 0; x < w; x++) { \ - pix = *buf; \ - if (endian) { \ -@@ -785,7 +785,7 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h, - static int tight_init_stream(VncState *vs, int stream_id, - int level, int strategy) - { -- z_streamp zstream = &vs->tight.stream[stream_id]; -+ z_streamp zstream = &vs->tight->stream[stream_id]; - - if (zstream->opaque == NULL) { - int err; -@@ -803,15 +803,15 @@ static int tight_init_stream(VncState *vs, int stream_id, - return -1; - } - -- vs->tight.levels[stream_id] = level; -+ vs->tight->levels[stream_id] = level; - zstream->opaque = vs; - } - -- if (vs->tight.levels[stream_id] != level) { -+ if (vs->tight->levels[stream_id] != level) { - if (deflateParams(zstream, level, strategy) != Z_OK) { - return -1; - } -- vs->tight.levels[stream_id] = level; -+ vs->tight->levels[stream_id] = level; - } - return 0; - } -@@ -839,11 +839,11 @@ static void tight_send_compact_size(VncState *vs, size_t len) - static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, - int level, int strategy) - { -- z_streamp zstream = &vs->tight.stream[stream_id]; -+ z_streamp zstream = &vs->tight->stream[stream_id]; - int previous_out; - - if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) { -- vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset); -+ vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset); - return bytes; - } - -@@ -852,13 +852,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, - } - - /* reserve memory in output buffer */ -- buffer_reserve(&vs->tight.zlib, bytes + 64); -+ buffer_reserve(&vs->tight->zlib, bytes + 64); - - /* set pointers */ -- zstream->next_in = vs->tight.tight.buffer; -- zstream->avail_in = vs->tight.tight.offset; -- zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset; -- zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset; -+ zstream->next_in = vs->tight->tight.buffer; -+ zstream->avail_in = vs->tight->tight.offset; -+ zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset; -+ zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset; - previous_out = zstream->avail_out; - zstream->data_type = Z_BINARY; - -@@ -868,14 +868,14 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, - return -1; - } - -- vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out; -+ vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out; - /* ...how much data has actually been produced by deflate() */ - bytes = previous_out - zstream->avail_out; - - tight_send_compact_size(vs, bytes); -- vnc_write(vs, vs->tight.zlib.buffer, bytes); -+ vnc_write(vs, vs->tight->zlib.buffer, bytes); - -- buffer_reset(&vs->tight.zlib); -+ buffer_reset(&vs->tight->zlib); - - return bytes; - } -@@ -927,16 +927,17 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h) - - vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ - -- if (vs->tight.pixel24) { -- tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset); -+ if (vs->tight->pixel24) { -+ tight_pack24(vs, vs->tight->tight.buffer, w * h, -+ &vs->tight->tight.offset); - bytes = 3; - } else { - bytes = vs->client_pf.bytes_per_pixel; - } - - bytes = tight_compress_data(vs, stream, w * h * bytes, -- tight_conf[vs->tight.compression].raw_zlib_level, -- Z_DEFAULT_STRATEGY); -+ tight_conf[vs->tight->compression].raw_zlib_level, -+ Z_DEFAULT_STRATEGY); - - return (bytes >= 0); - } -@@ -947,14 +948,14 @@ static int send_solid_rect(VncState *vs) - - vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */ - -- if (vs->tight.pixel24) { -- tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset); -+ if (vs->tight->pixel24) { -+ tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset); - bytes = 3; - } else { - bytes = vs->client_pf.bytes_per_pixel; - } - -- vnc_write(vs, vs->tight.tight.buffer, bytes); -+ vnc_write(vs, vs->tight->tight.buffer, bytes); - return 1; - } - -@@ -963,7 +964,7 @@ static int send_mono_rect(VncState *vs, int x, int y, - { - ssize_t bytes; - int stream = 1; -- int level = tight_conf[vs->tight.compression].mono_zlib_level; -+ int level = tight_conf[vs->tight->compression].mono_zlib_level; - - #ifdef CONFIG_VNC_PNG - if (tight_can_send_png_rect(vs, w, h)) { -@@ -991,26 +992,26 @@ static int send_mono_rect(VncState *vs, int x, int y, - uint32_t buf[2] = {bg, fg}; - size_t ret = sizeof (buf); - -- if (vs->tight.pixel24) { -+ if (vs->tight->pixel24) { - tight_pack24(vs, (unsigned char*)buf, 2, &ret); - } - vnc_write(vs, buf, ret); - -- tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg); -+ tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg); - break; - } - case 2: - vnc_write(vs, &bg, 2); - vnc_write(vs, &fg, 2); -- tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg); -+ tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg); - break; - default: - vnc_write_u8(vs, bg); - vnc_write_u8(vs, fg); -- tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg); -+ tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg); - break; - } -- vs->tight.tight.offset = bytes; -+ vs->tight->tight.offset = bytes; - - bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY); - return (bytes >= 0); -@@ -1040,7 +1041,7 @@ static void write_palette(int idx, uint32_t color, void *opaque) - static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) - { - int stream = 3; -- int level = tight_conf[vs->tight.compression].gradient_zlib_level; -+ int level = tight_conf[vs->tight->compression].gradient_zlib_level; - ssize_t bytes; - - if (vs->client_pf.bytes_per_pixel == 1) { -@@ -1050,23 +1051,23 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) - vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); - vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT); - -- buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int)); -+ buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int)); - -- if (vs->tight.pixel24) { -- tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h); -+ if (vs->tight->pixel24) { -+ tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h); - bytes = 3; - } else if (vs->client_pf.bytes_per_pixel == 4) { -- tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h); -+ tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h); - bytes = 4; - } else { -- tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h); -+ tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h); - bytes = 2; - } - -- buffer_reset(&vs->tight.gradient); -+ buffer_reset(&vs->tight->gradient); - - bytes = w * h * bytes; -- vs->tight.tight.offset = bytes; -+ vs->tight->tight.offset = bytes; - - bytes = tight_compress_data(vs, stream, bytes, - level, Z_FILTERED); -@@ -1077,7 +1078,7 @@ static int send_palette_rect(VncState *vs, int x, int y, - int w, int h, VncPalette *palette) - { - int stream = 2; -- int level = tight_conf[vs->tight.compression].idx_zlib_level; -+ int level = tight_conf[vs->tight->compression].idx_zlib_level; - int colors; - ssize_t bytes; - -@@ -1104,12 +1105,12 @@ static int send_palette_rect(VncState *vs, int x, int y, - palette_iter(palette, write_palette, &priv); - vnc_write(vs, header, sizeof(header)); - -- if (vs->tight.pixel24) { -+ if (vs->tight->pixel24) { - tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset); - vs->output.offset = old_offset + offset; - } - -- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette); -+ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette); - break; - } - case 2: -@@ -1119,7 +1120,7 @@ static int send_palette_rect(VncState *vs, int x, int y, - - palette_iter(palette, write_palette, &priv); - vnc_write(vs, header, sizeof(header)); -- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); -+ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette); - break; - } - default: -@@ -1127,7 +1128,7 @@ static int send_palette_rect(VncState *vs, int x, int y, - break; - } - bytes = w * h; -- vs->tight.tight.offset = bytes; -+ vs->tight->tight.offset = bytes; - - bytes = tight_compress_data(vs, stream, bytes, - level, Z_DEFAULT_STRATEGY); -@@ -1146,7 +1147,7 @@ static int send_palette_rect(VncState *vs, int x, int y, - static void jpeg_init_destination(j_compress_ptr cinfo) - { - VncState *vs = cinfo->client_data; -- Buffer *buffer = &vs->tight.jpeg; -+ Buffer *buffer = &vs->tight->jpeg; - - cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset; - cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset); -@@ -1156,7 +1157,7 @@ static void jpeg_init_destination(j_compress_ptr cinfo) - static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo) - { - VncState *vs = cinfo->client_data; -- Buffer *buffer = &vs->tight.jpeg; -+ Buffer *buffer = &vs->tight->jpeg; - - buffer->offset = buffer->capacity; - buffer_reserve(buffer, 2048); -@@ -1168,7 +1169,7 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo) - static void jpeg_term_destination(j_compress_ptr cinfo) - { - VncState *vs = cinfo->client_data; -- Buffer *buffer = &vs->tight.jpeg; -+ Buffer *buffer = &vs->tight->jpeg; - - buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer; - } -@@ -1187,7 +1188,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) - return send_full_color_rect(vs, x, y, w, h); - } - -- buffer_reserve(&vs->tight.jpeg, 2048); -+ buffer_reserve(&vs->tight->jpeg, 2048); - - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); -@@ -1222,9 +1223,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) - - vnc_write_u8(vs, VNC_TIGHT_JPEG << 4); - -- tight_send_compact_size(vs, vs->tight.jpeg.offset); -- vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset); -- buffer_reset(&vs->tight.jpeg); -+ tight_send_compact_size(vs, vs->tight->jpeg.offset); -+ vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset); -+ buffer_reset(&vs->tight->jpeg); - - return 1; - } -@@ -1240,7 +1241,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque) - VncState *vs = priv->vs; - png_colorp color = &priv->png_palette[idx]; - -- if (vs->tight.pixel24) -+ if (vs->tight->pixel24) - { - color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax; - color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax; -@@ -1267,10 +1268,10 @@ static void png_write_data(png_structp png_ptr, png_bytep data, - { - VncState *vs = png_get_io_ptr(png_ptr); - -- buffer_reserve(&vs->tight.png, vs->tight.png.offset + length); -- memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length); -+ buffer_reserve(&vs->tight->png, vs->tight->png.offset + length); -+ memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length); - -- vs->tight.png.offset += length; -+ vs->tight->png.offset += length; - } - - static void png_flush_data(png_structp png_ptr) -@@ -1295,8 +1296,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h, - png_infop info_ptr; - png_colorp png_palette = NULL; - pixman_image_t *linebuf; -- int level = tight_png_conf[vs->tight.compression].png_zlib_level; -- int filters = tight_png_conf[vs->tight.compression].png_filters; -+ int level = tight_png_conf[vs->tight->compression].png_zlib_level; -+ int filters = tight_png_conf[vs->tight->compression].png_filters; - uint8_t *buf; - int dy; - -@@ -1340,21 +1341,23 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h, - png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette)); - - if (vs->client_pf.bytes_per_pixel == 4) { -- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette); -+ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, -+ palette); - } else { -- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); -+ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, -+ palette); - } - } - - png_write_info(png_ptr, info_ptr); - -- buffer_reserve(&vs->tight.png, 2048); -+ buffer_reserve(&vs->tight->png, 2048); - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w); - buf = (uint8_t *)pixman_image_get_data(linebuf); - for (dy = 0; dy < h; dy++) - { - if (color_type == PNG_COLOR_TYPE_PALETTE) { -- memcpy(buf, vs->tight.tight.buffer + (dy * w), w); -+ memcpy(buf, vs->tight->tight.buffer + (dy * w), w); - } else { - qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy); - } -@@ -1372,27 +1375,27 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h, - - vnc_write_u8(vs, VNC_TIGHT_PNG << 4); - -- tight_send_compact_size(vs, vs->tight.png.offset); -- vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset); -- buffer_reset(&vs->tight.png); -+ tight_send_compact_size(vs, vs->tight->png.offset); -+ vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset); -+ buffer_reset(&vs->tight->png); - return 1; - } - #endif /* CONFIG_VNC_PNG */ - - static void vnc_tight_start(VncState *vs) - { -- buffer_reset(&vs->tight.tight); -+ buffer_reset(&vs->tight->tight); - - // make the output buffer be the zlib buffer, so we can compress it later -- vs->tight.tmp = vs->output; -- vs->output = vs->tight.tight; -+ vs->tight->tmp = vs->output; -+ vs->output = vs->tight->tight; - } - - static void vnc_tight_stop(VncState *vs) - { - // switch back to normal output/zlib buffers -- vs->tight.tight = vs->output; -- vs->output = vs->tight.tmp; -+ vs->tight->tight = vs->output; -+ vs->output = vs->tight->tmp; - } - - static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h, -@@ -1426,9 +1429,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h, - int ret; - - if (colors == 0) { -- if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full && -+ if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full && - tight_detect_smooth_image(vs, w, h))) { -- int quality = tight_conf[vs->tight.quality].jpeg_quality; -+ int quality = tight_conf[vs->tight->quality].jpeg_quality; - - ret = send_jpeg_rect(vs, x, y, w, h, quality); - } else { -@@ -1440,9 +1443,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h, - ret = send_mono_rect(vs, x, y, w, h, bg, fg); - } else if (colors <= 256) { - if (force || (colors > 96 && -- tight_jpeg_conf[vs->tight.quality].jpeg_idx && -+ tight_jpeg_conf[vs->tight->quality].jpeg_idx && - tight_detect_smooth_image(vs, w, h))) { -- int quality = tight_conf[vs->tight.quality].jpeg_quality; -+ int quality = tight_conf[vs->tight->quality].jpeg_quality; - - ret = send_jpeg_rect(vs, x, y, w, h, quality); - } else { -@@ -1480,20 +1483,20 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) - qemu_thread_atexit_add(&vnc_tight_cleanup_notifier); - } - -- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type); -+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type); - - vnc_tight_start(vs); - vnc_raw_send_framebuffer_update(vs, x, y, w, h); - vnc_tight_stop(vs); - - #ifdef CONFIG_VNC_JPEG -- if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) { -+ if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) { - double freq = vnc_update_freq(vs, x, y, w, h); - -- if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) { -+ if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) { - allow_jpeg = false; - } -- if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { -+ if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) { - force_jpeg = true; - vnc_sent_lossy_rect(vs, x, y, w, h); - } -@@ -1503,7 +1506,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) - colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_palette); - - #ifdef CONFIG_VNC_JPEG -- if (allow_jpeg && vs->tight.quality != (uint8_t)-1) { -+ if (allow_jpeg && vs->tight->quality != (uint8_t)-1) { - ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, - color_count_palette, force_jpeg); - } else { -@@ -1520,7 +1523,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) - - static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h) - { -- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type); -+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type); - - vnc_tight_start(vs); - vnc_raw_send_framebuffer_update(vs, x, y, w, h); -@@ -1538,8 +1541,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h, - int rw, rh; - int n = 0; - -- max_size = tight_conf[vs->tight.compression].max_rect_size; -- max_width = tight_conf[vs->tight.compression].max_rect_width; -+ max_size = tight_conf[vs->tight->compression].max_rect_size; -+ max_width = tight_conf[vs->tight->compression].max_rect_width; - - if (split && (w > max_width || w * h > max_size)) { - max_sub_width = (w > max_width) ? max_width : w; -@@ -1648,16 +1651,16 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y, - - if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF && - vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) { -- vs->tight.pixel24 = true; -+ vs->tight->pixel24 = true; - } else { -- vs->tight.pixel24 = false; -+ vs->tight->pixel24 = false; - } - - #ifdef CONFIG_VNC_JPEG -- if (vs->tight.quality != (uint8_t)-1) { -+ if (vs->tight->quality != (uint8_t)-1) { - double freq = vnc_update_freq(vs, x, y, w, h); - -- if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { -+ if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) { - return send_rect_simple(vs, x, y, w, h, false); - } - } -@@ -1669,8 +1672,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y, - - /* Calculate maximum number of rows in one non-solid rectangle. */ - -- max_rows = tight_conf[vs->tight.compression].max_rect_size; -- max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w); -+ max_rows = tight_conf[vs->tight->compression].max_rect_size; -+ max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w); - - return find_large_solid_color_rect(vs, x, y, w, h, max_rows); - } -@@ -1678,33 +1681,33 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y, - int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) - { -- vs->tight.type = VNC_ENCODING_TIGHT; -+ vs->tight->type = VNC_ENCODING_TIGHT; - return tight_send_framebuffer_update(vs, x, y, w, h); - } - - int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) - { -- vs->tight.type = VNC_ENCODING_TIGHT_PNG; -+ vs->tight->type = VNC_ENCODING_TIGHT_PNG; - return tight_send_framebuffer_update(vs, x, y, w, h); - } - - void vnc_tight_clear(VncState *vs) - { - int i; -- for (i=0; itight.stream); i++) { -- if (vs->tight.stream[i].opaque) { -- deflateEnd(&vs->tight.stream[i]); -+ for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) { -+ if (vs->tight->stream[i].opaque) { -+ deflateEnd(&vs->tight->stream[i]); - } - } - -- buffer_free(&vs->tight.tight); -- buffer_free(&vs->tight.zlib); -- buffer_free(&vs->tight.gradient); -+ buffer_free(&vs->tight->tight); -+ buffer_free(&vs->tight->zlib); -+ buffer_free(&vs->tight->gradient); - #ifdef CONFIG_VNC_JPEG -- buffer_free(&vs->tight.jpeg); -+ buffer_free(&vs->tight->jpeg); - #endif - #ifdef CONFIG_VNC_PNG -- buffer_free(&vs->tight.png); -+ buffer_free(&vs->tight->png); - #endif - } -diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c -index 33e9df2..900ae5b 100644 ---- a/ui/vnc-enc-zlib.c -+++ b/ui/vnc-enc-zlib.c -@@ -76,7 +76,8 @@ static int vnc_zlib_stop(VncState *vs) - zstream->zalloc = vnc_zlib_zalloc; - zstream->zfree = vnc_zlib_zfree; - -- err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS, -+ err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED, -+ MAX_WBITS, - MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); - - if (err != Z_OK) { -@@ -84,16 +85,16 @@ static int vnc_zlib_stop(VncState *vs) - return -1; - } - -- vs->zlib.level = vs->tight.compression; -+ vs->zlib.level = vs->tight->compression; - zstream->opaque = vs; - } - -- if (vs->tight.compression != vs->zlib.level) { -- if (deflateParams(zstream, vs->tight.compression, -+ if (vs->tight->compression != vs->zlib.level) { -+ if (deflateParams(zstream, vs->tight->compression, - Z_DEFAULT_STRATEGY) != Z_OK) { - return -1; - } -- vs->zlib.level = vs->tight.compression; -+ vs->zlib.level = vs->tight->compression; - } - - // reserve memory in output buffer -diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c -index 7493a84..17fd28a 100644 ---- a/ui/vnc-enc-zrle.c -+++ b/ui/vnc-enc-zrle.c -@@ -37,18 +37,18 @@ static const int bits_per_packed_pixel[] = { - - static void vnc_zrle_start(VncState *vs) - { -- buffer_reset(&vs->zrle.zrle); -+ buffer_reset(&vs->zrle->zrle); - - /* make the output buffer be the zlib buffer, so we can compress it later */ -- vs->zrle.tmp = vs->output; -- vs->output = vs->zrle.zrle; -+ vs->zrle->tmp = vs->output; -+ vs->output = vs->zrle->zrle; - } - - static void vnc_zrle_stop(VncState *vs) - { - /* switch back to normal output/zlib buffers */ -- vs->zrle.zrle = vs->output; -- vs->output = vs->zrle.tmp; -+ vs->zrle->zrle = vs->output; -+ vs->output = vs->zrle->tmp; - } - - static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, -@@ -56,24 +56,24 @@ static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, - { - Buffer tmp; - -- buffer_reset(&vs->zrle.fb); -- buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp); -+ buffer_reset(&vs->zrle->fb); -+ buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp); - - tmp = vs->output; -- vs->output = vs->zrle.fb; -+ vs->output = vs->zrle->fb; - - vnc_raw_send_framebuffer_update(vs, x, y, w, h); - -- vs->zrle.fb = vs->output; -+ vs->zrle->fb = vs->output; - vs->output = tmp; -- return vs->zrle.fb.buffer; -+ return vs->zrle->fb.buffer; - } - - static int zrle_compress_data(VncState *vs, int level) - { -- z_streamp zstream = &vs->zrle.stream; -+ z_streamp zstream = &vs->zrle->stream; - -- buffer_reset(&vs->zrle.zlib); -+ buffer_reset(&vs->zrle->zlib); - - if (zstream->opaque != vs) { - int err; -@@ -93,13 +93,13 @@ static int zrle_compress_data(VncState *vs, int level) - } - - /* reserve memory in output buffer */ -- buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64); -+ buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64); - - /* set pointers */ -- zstream->next_in = vs->zrle.zrle.buffer; -- zstream->avail_in = vs->zrle.zrle.offset; -- zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset; -- zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset; -+ zstream->next_in = vs->zrle->zrle.buffer; -+ zstream->avail_in = vs->zrle->zrle.offset; -+ zstream->next_out = vs->zrle->zlib.buffer + vs->zrle->zlib.offset; -+ zstream->avail_out = vs->zrle->zlib.capacity - vs->zrle->zlib.offset; - zstream->data_type = Z_BINARY; - - /* start encoding */ -@@ -108,8 +108,8 @@ static int zrle_compress_data(VncState *vs, int level) - return -1; - } - -- vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out; -- return vs->zrle.zlib.offset; -+ vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out; -+ return vs->zrle->zlib.offset; - } - - /* Try to work out whether to use RLE and/or a palette. We do this by -@@ -259,14 +259,14 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y, - size_t bytes; - int zywrle_level; - -- if (vs->zrle.type == VNC_ENCODING_ZYWRLE) { -- if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1 -- || vs->tight.quality == 9) { -+ if (vs->zrle->type == VNC_ENCODING_ZYWRLE) { -+ if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1 -+ || vs->tight->quality == 9) { - zywrle_level = 0; -- vs->zrle.type = VNC_ENCODING_ZRLE; -- } else if (vs->tight.quality < 3) { -+ vs->zrle->type = VNC_ENCODING_ZRLE; -+ } else if (vs->tight->quality < 3) { - zywrle_level = 3; -- } else if (vs->tight.quality < 6) { -+ } else if (vs->tight->quality < 6) { - zywrle_level = 2; - } else { - zywrle_level = 1; -@@ -337,30 +337,30 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y, - - vnc_zrle_stop(vs); - bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION); -- vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type); -+ vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type); - vnc_write_u32(vs, bytes); -- vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset); -+ vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset); - return 1; - } - - int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) - { -- vs->zrle.type = VNC_ENCODING_ZRLE; -+ vs->zrle->type = VNC_ENCODING_ZRLE; - return zrle_send_framebuffer_update(vs, x, y, w, h); - } - - int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) - { -- vs->zrle.type = VNC_ENCODING_ZYWRLE; -+ vs->zrle->type = VNC_ENCODING_ZYWRLE; - return zrle_send_framebuffer_update(vs, x, y, w, h); - } - - void vnc_zrle_clear(VncState *vs) - { -- if (vs->zrle.stream.opaque) { -- deflateEnd(&vs->zrle.stream); -+ if (vs->zrle->stream.opaque) { -+ deflateEnd(&vs->zrle->stream); - } -- buffer_free(&vs->zrle.zrle); -- buffer_free(&vs->zrle.fb); -- buffer_free(&vs->zrle.zlib); -+ buffer_free(&vs->zrle->zrle); -+ buffer_free(&vs->zrle->fb); -+ buffer_free(&vs->zrle->zlib); - } -diff --git a/ui/vnc-enc-zrle.inc.c b/ui/vnc-enc-zrle.inc.c -index abf6b86..c107d8a 100644 ---- a/ui/vnc-enc-zrle.inc.c -+++ b/ui/vnc-enc-zrle.inc.c -@@ -96,7 +96,7 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h, - static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, - int zywrle_level) - { -- VncPalette *palette = &vs->zrle.palette; -+ VncPalette *palette = &vs->zrle->palette; - - int runs = 0; - int single_pixels = 0; -diff --git a/ui/vnc.c b/ui/vnc.c -index bc43c4c..87b8045 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1307,6 +1307,8 @@ void vnc_disconnect_finish(VncState *vs) - object_unref(OBJECT(vs->sioc)); - vs->sioc = NULL; - vs->magic = 0; -+ g_free(vs->zrle); -+ g_free(vs->tight); - g_free(vs); - } - -@@ -2058,8 +2060,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) - - vs->features = 0; - vs->vnc_encoding = 0; -- vs->tight.compression = 9; -- vs->tight.quality = -1; /* Lossless by default */ -+ vs->tight->compression = 9; -+ vs->tight->quality = -1; /* Lossless by default */ - vs->absolute = -1; - - /* -@@ -2127,11 +2129,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) - vs->features |= VNC_FEATURE_LED_STATE_MASK; - break; - case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9: -- vs->tight.compression = (enc & 0x0F); -+ vs->tight->compression = (enc & 0x0F); - break; - case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9: - if (vs->vd->lossy) { -- vs->tight.quality = (enc & 0x0F); -+ vs->tight->quality = (enc & 0x0F); - } - break; - default: -@@ -3034,6 +3036,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, - int i; - - trace_vnc_client_connect(vs, sioc); -+ vs->zrle = g_new0(VncZrle, 1); -+ vs->tight = g_new0(VncTight, 1); - vs->magic = VNC_MAGIC; - vs->sioc = sioc; - object_ref(OBJECT(vs->sioc)); -@@ -3045,19 +3049,19 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, - buffer_init(&vs->output, "vnc-output/%p", sioc); - buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc); - -- buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc); -- buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc); -- buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc); -+ buffer_init(&vs->tight->tight, "vnc-tight/%p", sioc); -+ buffer_init(&vs->tight->zlib, "vnc-tight-zlib/%p", sioc); -+ buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc); - #ifdef CONFIG_VNC_JPEG -- buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc); -+ buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc); - #endif - #ifdef CONFIG_VNC_PNG -- buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc); -+ buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc); - #endif - buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc); -- buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc); -- buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc); -- buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc); -+ buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc); -+ buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc); -+ buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc); - - if (skipauth) { - vs->auth = VNC_AUTH_NONE; -diff --git a/ui/vnc.h b/ui/vnc.h -index 8643860..fea79c2 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -338,10 +338,10 @@ struct VncState - /* Encoding specific, if you add something here, don't forget to - * update vnc_async_encoding_start() - */ -- VncTight tight; -+ VncTight *tight; - VncZlib zlib; - VncHextile hextile; -- VncZrle zrle; -+ VncZrle *zrle; - VncZywrle zywrle; - - Notifier mouse_mode_notifier; --- -1.8.3.1 - diff --git a/vpc-Return-0-from-vpc_co_create-on-success.patch b/vpc-Return-0-from-vpc_co_create-on-success.patch deleted file mode 100644 index 46fbd90d1bd39f5549ce5d0185d58bbd437a82aa..0000000000000000000000000000000000000000 --- a/vpc-Return-0-from-vpc_co_create-on-success.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 97c478c355fee96eb2b740313f50561e69b6f305 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 2 Sep 2019 21:33:16 +0200 -Subject: [PATCH] vpc: Return 0 from vpc_co_create() on success - -blockdev_create_run() directly uses .bdrv_co_create()'s return value as -the job's return value. Jobs must return 0 on success, not just any -nonnegative value. Therefore, using blockdev-create for VPC images may -currently fail as the vpc driver may return a positive integer. - -Because there is no point in returning a positive integer anywhere in -the block layer (all non-negative integers are generally treated as -complete success), we probably do not want to add more such cases. -Therefore, fix this problem by making the vpc driver always return 0 in -case of success. - -Suggested-by: Kevin Wolf -Cc: qemu-stable@nongnu.org -Signed-off-by: Max Reitz -Signed-off-by: Kevin Wolf -(cherry picked from commit 1a37e3124407b5a145d44478d3ecbdb89c63789f) -Signed-off-by: Michael Roth ---- - block/vpc.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/block/vpc.c b/block/vpc.c -index d4776ee8a5..3a88e28e2b 100644 ---- a/block/vpc.c -+++ b/block/vpc.c -@@ -885,6 +885,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf, - goto fail; - } - -+ ret = 0; - fail: - return ret; - } -@@ -908,7 +909,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf, - return ret; - } - -- return ret; -+ return 0; - } - - static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts, --- -2.23.0 diff --git a/vtimer-Drop-vtimer-virtual-timer-adjust.patch b/vtimer-Drop-vtimer-virtual-timer-adjust.patch deleted file mode 100644 index 726498fb6c778f8d5739e9614ae451d54a11bb56..0000000000000000000000000000000000000000 --- a/vtimer-Drop-vtimer-virtual-timer-adjust.patch +++ /dev/null @@ -1,144 +0,0 @@ -From b1782119bcfac96d8a541d8d60ee00f954d721db Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Wed, 27 May 2020 17:48:54 +0800 -Subject: [PATCH] vtimer: Drop vtimer virtual timer adjust - -This patch drops the vtimer virtual timer adjust, cross version migration -from openEuler qemu-4.0.1 to qemu-4.1.0 is not supported as a consequence. - -By default openEuler qemu-4.1.0 use kvm_adjvtime as the virtual timer. - -Signed-off-by: Ying Fang - -diff --git a/cpus.c b/cpus.c -index 6a28bdef..927a00aa 100644 ---- a/cpus.c -+++ b/cpus.c -@@ -1066,34 +1066,6 @@ void cpu_synchronize_all_pre_loadvm(void) - } - } - --#ifdef __aarch64__ --static bool kvm_adjvtime_enabled(CPUState *cs) --{ -- ARMCPU *cpu = ARM_CPU(cs); -- return cpu->kvm_adjvtime == true; --} -- --static void get_vcpu_timer_tick(CPUState *cs) --{ -- CPUARMState *env = &ARM_CPU(cs)->env; -- int err; -- struct kvm_one_reg reg; -- uint64_t timer_tick; -- -- reg.id = KVM_REG_ARM_TIMER_CNT; -- reg.addr = (uintptr_t) &timer_tick; -- -- err = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); -- if (err < 0) { -- error_report("get vcpu tick failed, ret = %d", err); -- env->vtimer = 0; -- return; -- } -- env->vtimer = timer_tick; -- return; --} --#endif -- - static int do_vm_stop(RunState state, bool send_stop) - { - int ret = 0; -@@ -1101,17 +1073,6 @@ static int do_vm_stop(RunState state, bool send_stop) - if (runstate_is_running()) { - cpu_disable_ticks(); - pause_all_vcpus(); --#ifdef __aarch64__ -- /* vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime -- * is introduced in openEuler qemu-4.1.0. To maintain the compatibility -- * and enable cross version migration, let's enable vtimer adjust only -- * if kvm_adjvtime is not enabled, otherwise there may be conflicts -- * between vtimer adjust and kvm_adjvtime. -- */ -- if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { -- get_vcpu_timer_tick(first_cpu); -- } --#endif - runstate_set(state); - vm_state_notify(0, state); - if (send_stop) { -@@ -1957,46 +1918,11 @@ void cpu_resume(CPUState *cpu) - qemu_cpu_kick(cpu); - } - --#ifdef __aarch64__ -- --static void set_vcpu_timer_tick(CPUState *cs) --{ -- CPUARMState *env = &ARM_CPU(cs)->env; -- -- if (env->vtimer == 0) { -- return; -- } -- -- int err; -- struct kvm_one_reg reg; -- uint64_t timer_tick = env->vtimer; -- env->vtimer = 0; -- -- reg.id = KVM_REG_ARM_TIMER_CNT; -- reg.addr = (uintptr_t) &timer_tick; -- -- err = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); -- if (err < 0) { -- error_report("Set vcpu tick failed, ret = %d", err); -- return; -- } -- return; --} --#endif -- - void resume_all_vcpus(void) - { - CPUState *cpu; - - qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); --#ifdef __aarch64__ -- /* Enable vtimer adjust only if kvm_adjvtime is not enabled, otherwise -- * there may be conflicts between vtimer adjust and kvm_adjvtime. -- */ -- if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { -- set_vcpu_timer_tick(first_cpu); -- } --#endif - CPU_FOREACH(cpu) { - cpu_resume(cpu); - } -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index aec6a214..86eb79cd 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -262,8 +262,6 @@ typedef struct CPUARMState { - uint64_t sp_el[4]; /* AArch64 banked stack pointers */ - - -- uint64_t vtimer; /* Timer tick when vcpu stop */ -- - /* System control coprocessor (cp15) */ - struct { - uint32_t c0_cpuid; -diff --git a/target/arm/machine.c b/target/arm/machine.c -index ec28b839..ee3c59a6 100644 ---- a/target/arm/machine.c -+++ b/target/arm/machine.c -@@ -814,7 +814,6 @@ const VMStateDescription vmstate_arm_cpu = { - VMSTATE_UINT32(env.exception.syndrome, ARMCPU), - VMSTATE_UINT32(env.exception.fsr, ARMCPU), - VMSTATE_UINT64(env.exception.vaddress, ARMCPU), -- VMSTATE_UINT64(env.vtimer, ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), - { --- -2.23.0 - diff --git a/vtimer-compat-cross-version-migration-from-v4.0.1.patch b/vtimer-compat-cross-version-migration-from-v4.0.1.patch deleted file mode 100644 index f452948fd29818c9551899e5044de1e3b33bc235..0000000000000000000000000000000000000000 --- a/vtimer-compat-cross-version-migration-from-v4.0.1.patch +++ /dev/null @@ -1,41 +0,0 @@ -From aec34c33730c36b34e4442548885463f57100e13 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Fri, 8 May 2020 11:25:28 +0800 -Subject: [PATCH] vtimer: compat cross version migration from v4.0.1 - -vtimer feature was added to qemu v4.0.1 to record timer tick when vcpu -is stopped. However this feature is discared and the new virtual time -adjustment is introduced. - -This patch add the missing vtimer parameter to ARMCPUState in order -to compat cross version migration fromm v4.0.1 openEuler 2003 lts release. - -Singed-off-by: Ying Fang - -diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index 219c222b..2609113d 100644 ---- a/target/arm/cpu.h -+++ b/target/arm/cpu.h -@@ -261,6 +261,8 @@ typedef struct CPUARMState { - uint64_t elr_el[4]; /* AArch64 exception link regs */ - uint64_t sp_el[4]; /* AArch64 banked stack pointers */ - -+ uint64_t vtimer; /* Timer tick when vcpu is stopped */ -+ - /* System control coprocessor (cp15) */ - struct { - uint32_t c0_cpuid; -diff --git a/target/arm/machine.c b/target/arm/machine.c -index ee3c59a6..ec28b839 100644 ---- a/target/arm/machine.c -+++ b/target/arm/machine.c -@@ -814,6 +814,7 @@ const VMStateDescription vmstate_arm_cpu = { - VMSTATE_UINT32(env.exception.syndrome, ARMCPU), - VMSTATE_UINT32(env.exception.fsr, ARMCPU), - VMSTATE_UINT64(env.exception.vaddress, ARMCPU), -+ VMSTATE_UINT64(env.vtimer, ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), - { --- -2.23.0 diff --git a/x86-Add-AMX-CPUIDs-enumeration.patch b/x86-Add-AMX-CPUIDs-enumeration.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef7d5efe00c7a0fd348d12a4891e4a8a97f66a55 --- /dev/null +++ b/x86-Add-AMX-CPUIDs-enumeration.patch @@ -0,0 +1,138 @@ +From 42f96b9e73ff4a23fad56bc8fefea5e477ee95b9 Mon Sep 17 00:00:00 2001 +From: Jing Liu +Date: Wed, 16 Feb 2022 22:04:31 -0800 +Subject: [PATCH 06/10] x86: Add AMX CPUIDs enumeration + +from mainline-v7.0.0-rc0 +commit f21a48171cf3fa39532fc8553fd82e81b88b6474 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit f21a48171cf3 ("x86: Add AMX CPUIDs enumeration") + +---------------------------------------------- + +x86: Add AMX CPUIDs enumeration + +Add AMX primary feature bits XFD and AMX_TILE to +enumerate the CPU's AMX capability. Meanwhile, add +AMX TILE and TMUL CPUID leaf and subleaves which +exist when AMX TILE is present to provide the maximum +capability of TILE and TMUL. + +Signed-off-by: Jing Liu +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-6-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 55 ++++++++++++++++++++++++++++++++++++++++--- + target/i386/kvm/kvm.c | 4 +++- + 2 files changed, 55 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index da81e47dc3..1bc03d3eef 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -574,6 +574,18 @@ static CPUCacheInfo legacy_l3_cache = { + #define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */ + #define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */ + ++/* CPUID Leaf 0x1D constants: */ ++#define INTEL_AMX_TILE_MAX_SUBLEAF 0x1 ++#define INTEL_AMX_TOTAL_TILE_BYTES 0x2000 ++#define INTEL_AMX_BYTES_PER_TILE 0x400 ++#define INTEL_AMX_BYTES_PER_ROW 0x40 ++#define INTEL_AMX_TILE_MAX_NAMES 0x8 ++#define INTEL_AMX_TILE_MAX_ROWS 0x10 ++ ++/* CPUID Leaf 0x1E constants: */ ++#define INTEL_AMX_TMUL_MAX_K 0x10 ++#define INTEL_AMX_TMUL_MAX_N 0x40 ++ + void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3) + { +@@ -843,8 +855,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "avx512-vp2intersect", NULL, "md-clear", NULL, + NULL, NULL, "serialize", NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, +- NULL, NULL, NULL, "avx512-fp16", +- NULL, NULL, "spec-ctrl", "stibp", ++ NULL, NULL, "amx-bf16", "avx512-fp16", ++ "amx-tile", "amx-int8", "spec-ctrl", "stibp", + NULL, "arch-capabilities", "core-capability", "ssbd", + }, + .cpuid = { +@@ -909,7 +921,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + "xsaveopt", "xsavec", "xgetbv1", "xsaves", +- NULL, NULL, NULL, NULL, ++ "xfd", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +@@ -5605,6 +5617,43 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + } ++ case 0x1D: { ++ /* AMX TILE */ ++ *eax = 0; ++ *ebx = 0; ++ *ecx = 0; ++ *edx = 0; ++ if (!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE)) { ++ break; ++ } ++ ++ if (count == 0) { ++ /* Highest numbered palette subleaf */ ++ *eax = INTEL_AMX_TILE_MAX_SUBLEAF; ++ } else if (count == 1) { ++ *eax = INTEL_AMX_TOTAL_TILE_BYTES | ++ (INTEL_AMX_BYTES_PER_TILE << 16); ++ *ebx = INTEL_AMX_BYTES_PER_ROW | (INTEL_AMX_TILE_MAX_NAMES << 16); ++ *ecx = INTEL_AMX_TILE_MAX_ROWS; ++ } ++ break; ++ } ++ case 0x1E: { ++ /* AMX TMUL */ ++ *eax = 0; ++ *ebx = 0; ++ *ecx = 0; ++ *edx = 0; ++ if (!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE)) { ++ break; ++ } ++ ++ if (count == 0) { ++ /* Highest numbered palette subleaf */ ++ *ebx = INTEL_AMX_TMUL_MAX_K | (INTEL_AMX_TMUL_MAX_N << 8); ++ } ++ break; ++ } + case 0x40000000: + /* + * CPUID code in kvm_arch_init_vcpu() ignores stuff +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index e7f57d05a2..60ccdec5e8 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -1779,7 +1779,9 @@ int kvm_arch_init_vcpu(CPUState *cs) + c = &cpuid_data.entries[cpuid_i++]; + } + break; +- case 0x14: { ++ case 0x14: ++ case 0x1d: ++ case 0x1e: { + uint32_t times; + + c->function = i; +-- +2.27.0 + diff --git a/x86-Add-AMX-XTILECFG-and-XTILEDATA-components.patch b/x86-Add-AMX-XTILECFG-and-XTILEDATA-components.patch new file mode 100644 index 0000000000000000000000000000000000000000..d47f7361ae550ae542fbbead7cc4f2ef15483e77 --- /dev/null +++ b/x86-Add-AMX-XTILECFG-and-XTILEDATA-components.patch @@ -0,0 +1,115 @@ +From 98f5dbc3fd8390728401528786ac94b39f0581ee Mon Sep 17 00:00:00 2001 +From: Jing Liu +Date: Wed, 16 Feb 2022 22:04:28 -0800 +Subject: [PATCH 03/10] x86: Add AMX XTILECFG and XTILEDATA components + +from mainline-v7.0.0-rc0 +commit 1f16764f7d4515bfd5e4ae0aae814fa280a7d0c8 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 1f16764f7d45 ("x86: Add AMX XTILECFG and XTILEDATA components") + +------------------------------------------------------------- + +x86: Add AMX XTILECFG and XTILEDATA components + +The AMX TILECFG register and the TMMx tile data registers are +saved/restored via XSAVE, respectively in state component 17 +(64 bytes) and state component 18 (8192 bytes). + +Add AMX feature bits to x86_ext_save_areas array to set +up AMX components. Add structs that define the layout of +AMX XSAVE areas and use QEMU_BUILD_BUG_ON to validate the +structs sizes. + +Signed-off-by: Jing Liu +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-3-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 8 ++++++++ + target/i386/cpu.h | 18 +++++++++++++++++- + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 532ca45015..31d63be081 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1401,6 +1401,14 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { + [XSTATE_PKRU_BIT] = + { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, + .size = sizeof(XSavePKRU) }, ++ [XSTATE_XTILE_CFG_BIT] = { ++ .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, ++ .size = sizeof(XSaveXTILECFG), ++ }, ++ [XSTATE_XTILE_DATA_BIT] = { ++ .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, ++ .size = sizeof(XSaveXTILEDATA) ++ }, + }; + + static uint32_t xsave_area_size(uint64_t mask) +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 52330d1112..cc431b1d76 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -538,6 +538,8 @@ typedef enum X86Seg { + #define XSTATE_ZMM_Hi256_BIT 6 + #define XSTATE_Hi16_ZMM_BIT 7 + #define XSTATE_PKRU_BIT 9 ++#define XSTATE_XTILE_CFG_BIT 17 ++#define XSTATE_XTILE_DATA_BIT 18 + + #define XSTATE_FP_MASK (1ULL << XSTATE_FP_BIT) + #define XSTATE_SSE_MASK (1ULL << XSTATE_SSE_BIT) +@@ -846,6 +848,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) + /* AVX512_FP16 instruction */ + #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) ++/* AMX tile (two-dimensional register) */ ++#define CPUID_7_0_EDX_AMX_TILE (1U << 24) + /* Speculation Control */ + #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) + /* Single Thread Indirect Branch Predictors */ +@@ -1349,6 +1353,16 @@ typedef struct XSavePKRU { + uint32_t padding; + } XSavePKRU; + ++/* Ext. save area 17: AMX XTILECFG state */ ++typedef struct XSaveXTILECFG { ++ uint8_t xtilecfg[64]; ++} XSaveXTILECFG; ++ ++/* Ext. save area 18: AMX XTILEDATA state */ ++typedef struct XSaveXTILEDATA { ++ uint8_t xtiledata[8][1024]; ++} XSaveXTILEDATA; ++ + QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100); + QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); + QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40); +@@ -1356,6 +1370,8 @@ QEMU_BUILD_BUG_ON(sizeof(XSaveOpmask) != 0x40); + QEMU_BUILD_BUG_ON(sizeof(XSaveZMM_Hi256) != 0x200); + QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400); + QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); ++QEMU_BUILD_BUG_ON(sizeof(XSaveXTILECFG) != 0x40); ++QEMU_BUILD_BUG_ON(sizeof(XSaveXTILEDATA) != 0x2000); + + typedef struct ExtSaveArea { + uint32_t feature, bits; +@@ -1363,7 +1379,7 @@ typedef struct ExtSaveArea { + uint32_t ecx; + } ExtSaveArea; + +-#define XSAVE_STATE_AREA_COUNT (XSTATE_PKRU_BIT + 1) ++#define XSAVE_STATE_AREA_COUNT (XSTATE_XTILE_DATA_BIT + 1) + + extern ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT]; + +-- +2.27.0 + diff --git a/x86-Add-XFD-faulting-bit-for-state-components.patch b/x86-Add-XFD-faulting-bit-for-state-components.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b2edc2cff0a3dc03f8f32e6a415bf8b85d20e81 --- /dev/null +++ b/x86-Add-XFD-faulting-bit-for-state-components.patch @@ -0,0 +1,66 @@ +From 52eed626a2200da02e67aa93c2a8d59cb529737b Mon Sep 17 00:00:00 2001 +From: Jing Liu +Date: Wed, 16 Feb 2022 22:04:30 -0800 +Subject: [PATCH 05/10] x86: Add XFD faulting bit for state components + +from mainline-v7.0.0-rc0 +commit 0f17f6b30f3b051f0f96ccc98c9f7f395713699f +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 0f17f6b30f3b ("x86: Add XFD faulting bit for state +components") + +------------------------------------------------- + +x86: Add XFD faulting bit for state components + +Intel introduces XFD faulting mechanism for extended +XSAVE features to dynamically enable the features in +runtime. If CPUID (EAX=0Dh, ECX=n, n>1).ECX[2] is set +as 1, it indicates support for XFD faulting of this +state component. + +Signed-off-by: Jing Liu +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-5-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 3 ++- + target/i386/cpu.h | 2 ++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index fb6b4c86de..da81e47dc3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5515,7 +5515,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + const ExtSaveArea *esa = &x86_ext_save_areas[count]; + *eax = esa->size; + *ebx = esa->offset; +- *ecx = esa->ecx & ESA_FEATURE_ALIGN64_MASK; ++ *ecx = esa->ecx & ++ (ESA_FEATURE_ALIGN64_MASK | ESA_FEATURE_XFD_MASK); + } + } + break; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 93d1c60ac1..09c725ee13 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -556,8 +556,10 @@ typedef enum X86Seg { + #define XSTATE_DYNAMIC_MASK (XSTATE_XTILE_DATA_MASK) + + #define ESA_FEATURE_ALIGN64_BIT 1 ++#define ESA_FEATURE_XFD_BIT 2 + + #define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT) ++#define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) + + + /* CPUID feature words */ +-- +2.27.0 + diff --git a/x86-Fix-the-64-byte-boundary-enumeration-for-extende.patch b/x86-Fix-the-64-byte-boundary-enumeration-for-extende.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0aede1951081fc75ecb3f936e2a96412c35268b --- /dev/null +++ b/x86-Fix-the-64-byte-boundary-enumeration-for-extende.patch @@ -0,0 +1,91 @@ +From ab183c656a2bee466e7c609224cddb75b80d9d6f Mon Sep 17 00:00:00 2001 +From: Jing Liu +Date: Wed, 16 Feb 2022 22:04:27 -0800 +Subject: [PATCH 02/10] x86: Fix the 64-byte boundary enumeration for extended + state + +from mainline-v7.0.0-rc0 +commit 131266b7565bd437127bd231563572696bb27235 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 131266b7565b ("x86: Fix the 64-byte boundary enumeration for extended state") + +----------------------------------------------------------- + +x86: Fix the 64-byte boundary enumeration for extended state + +The extended state subleaves (EAX=0Dh, ECX=n, n>1).ECX[1] +indicate whether the extended state component locates +on the next 64-byte boundary following the preceding state +component when the compacted format of an XSAVE area is +used. + +Right now, they are all zero because no supported component +needed the bit to be set, but the upcoming AMX feature will +use it. Fix the subleaves value according to KVM's supported +cpuid. + +Signed-off-by: Jing Liu +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-2-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 1 + + target/i386/cpu.h | 6 ++++++ + target/i386/kvm/kvm-cpu.c | 1 + + 3 files changed, 8 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d9dca1dafb..532ca45015 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5507,6 +5507,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + const ExtSaveArea *esa = &x86_ext_save_areas[count]; + *eax = esa->size; + *ebx = esa->offset; ++ *ecx = esa->ecx & ESA_FEATURE_ALIGN64_MASK; + } + } + break; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index d9296a9abc..52330d1112 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -549,6 +549,11 @@ typedef enum X86Seg { + #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) + #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) + ++#define ESA_FEATURE_ALIGN64_BIT 1 ++ ++#define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT) ++ ++ + /* CPUID feature words */ + typedef enum FeatureWord { + FEAT_1_EDX, /* CPUID[1].EDX */ +@@ -1355,6 +1360,7 @@ QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); + typedef struct ExtSaveArea { + uint32_t feature, bits; + uint32_t offset, size; ++ uint32_t ecx; + } ExtSaveArea; + + #define XSAVE_STATE_AREA_COUNT (XSTATE_PKRU_BIT + 1) +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index d95028018e..ce27d3b1df 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -104,6 +104,7 @@ static void kvm_cpu_xsave_init(void) + if (sz != 0) { + assert(esa->size == sz); + esa->offset = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EBX); ++ esa->ecx = kvm_arch_get_supported_cpuid(s, 0xd, i, R_ECX); + } + } + } +-- +2.27.0 + diff --git a/x86-Grant-AMX-permission-for-guest.patch b/x86-Grant-AMX-permission-for-guest.patch new file mode 100644 index 0000000000000000000000000000000000000000..9ecbc461e04b66c984397ccb53cb4a99200bf1df --- /dev/null +++ b/x86-Grant-AMX-permission-for-guest.patch @@ -0,0 +1,218 @@ +From b7e588a4506ce61c13e78175c2da5b69b60af128 Mon Sep 17 00:00:00 2001 +From: Yang Zhong +Date: Wed, 16 Feb 2022 22:04:29 -0800 +Subject: [PATCH 04/10] x86: Grant AMX permission for guest + +from mainline-v7.0.0-rc0 +commit 19db68ca68a78fa033a21d419036b6e416554564 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit 19db68ca68a7 ("x86: Grant AMX permission for guest") + +-------------------------------------------------------- + +x86: Grant AMX permission for guest + +Kernel allocates 4K xstate buffer by default. For XSAVE features +which require large state component (e.g. AMX), Linux kernel +dynamically expands the xstate buffer only after the process has +acquired the necessary permissions. Those are called dynamically- +enabled XSAVE features (or dynamic xfeatures). + +There are separate permissions for native tasks and guests. + +Qemu should request the guest permissions for dynamic xfeatures +which will be exposed to the guest. This only needs to be done +once before the first vcpu is created. + +KVM implemented one new ARCH_GET_XCOMP_SUPP system attribute API to +get host side supported_xcr0 and Qemu can decide if it can request +dynamically enabled XSAVE features permission. +https://lore.kernel.org/all/20220126152210.3044876-1-pbonzini@redhat.com/ + +Suggested-by: Paolo Bonzini +Signed-off-by: Yang Zhong +Signed-off-by: Jing Liu +Message-Id: <20220217060434.52460-4-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 7 +++++ + target/i386/cpu.h | 4 +++ + target/i386/kvm/kvm-cpu.c | 12 ++++---- + target/i386/kvm/kvm.c | 57 ++++++++++++++++++++++++++++++++++++++ + target/i386/kvm/kvm_i386.h | 1 + + 5 files changed, 75 insertions(+), 6 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 31d63be081..fb6b4c86de 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6048,6 +6048,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) + CPUX86State *env = &cpu->env; + int i; + uint64_t mask; ++ static bool request_perm; + + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { + env->features[FEAT_XSAVE_COMP_LO] = 0; +@@ -6063,6 +6064,12 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) + } + } + ++ /* Only request permission for first vcpu */ ++ if (kvm_enabled() && !request_perm) { ++ kvm_request_xsave_components(cpu, mask); ++ request_perm = true; ++ } ++ + env->features[FEAT_XSAVE_COMP_LO] = mask; + env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; + } +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index cc431b1d76..93d1c60ac1 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -550,6 +550,10 @@ typedef enum X86Seg { + #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) + #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) + #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) ++#define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) ++#define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT) ++ ++#define XSTATE_DYNAMIC_MASK (XSTATE_XTILE_DATA_MASK) + + #define ESA_FEATURE_ALIGN64_BIT 1 + +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index ce27d3b1df..a35a1bf9fe 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -84,7 +84,7 @@ static void kvm_cpu_max_instance_init(X86CPU *cpu) + static void kvm_cpu_xsave_init(void) + { + static bool first = true; +- KVMState *s = kvm_state; ++ uint32_t eax, ebx, ecx, edx; + int i; + + if (!first) { +@@ -100,11 +100,11 @@ static void kvm_cpu_xsave_init(void) + ExtSaveArea *esa = &x86_ext_save_areas[i]; + + if (esa->size) { +- int sz = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EAX); +- if (sz != 0) { +- assert(esa->size == sz); +- esa->offset = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EBX); +- esa->ecx = kvm_arch_get_supported_cpuid(s, 0xd, i, R_ECX); ++ host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); ++ if (eax != 0) { ++ assert(esa->size == eax); ++ esa->offset = ebx; ++ esa->ecx = ecx; + } + } + } +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 5a698bde19..e7f57d05a2 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -17,6 +17,7 @@ + #include "qapi/error.h" + #include + #include ++#include + + #include + #include "standard-headers/asm-x86/kvm_para.h" +@@ -347,6 +348,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + struct kvm_cpuid2 *cpuid; + uint32_t ret = 0; + uint32_t cpuid_1_edx; ++ uint64_t bitmask; + + cpuid = get_supported_cpuid(s); + +@@ -404,6 +406,25 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + if (!has_msr_arch_capabs) { + ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; + } ++ } else if (function == 0xd && index == 0 && ++ (reg == R_EAX || reg == R_EDX)) { ++ struct kvm_device_attr attr = { ++ .group = 0, ++ .attr = KVM_X86_XCOMP_GUEST_SUPP, ++ .addr = (unsigned long) &bitmask ++ }; ++ ++ bool sys_attr = kvm_check_extension(s, KVM_CAP_SYS_ATTRIBUTES); ++ if (!sys_attr) { ++ warn_report("cannot get sys attribute capabilities %d", sys_attr); ++ } ++ ++ int rc = kvm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr); ++ if (rc == -1 && (errno == ENXIO || errno == EINVAL)) { ++ warn_report("KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) " ++ "error: %d", rc); ++ } ++ ret = (reg == R_EAX) ? bitmask : bitmask >> 32; + } else if (function == 0x80000001 && reg == R_ECX) { + /* + * It's safe to enable TOPOEXT even if it's not returned by +@@ -5050,3 +5071,39 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return !sev_es_enabled(); + } ++ ++#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 ++ ++void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask) ++{ ++ KVMState *s = kvm_state; ++ uint64_t supported; ++ ++ mask &= XSTATE_DYNAMIC_MASK; ++ if (!mask) { ++ return; ++ } ++ /* ++ * Just ignore bits that are not in CPUID[EAX=0xD,ECX=0]. ++ * ARCH_REQ_XCOMP_GUEST_PERM would fail, and QEMU has warned ++ * about them already because they are not supported features. ++ */ ++ supported = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); ++ supported |= (uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32; ++ mask &= supported; ++ ++ while (mask) { ++ int bit = ctz64(mask); ++ int rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit); ++ if (rc) { ++ /* ++ * Older kernel version (<5.17) do not support ++ * ARCH_REQ_XCOMP_GUEST_PERM, but also do not return ++ * any dynamic feature from kvm_arch_get_supported_cpuid. ++ */ ++ warn_report("prctl(ARCH_REQ_XCOMP_GUEST_PERM) failure " ++ "for feature bit %d", bit); ++ } ++ mask &= ~BIT_ULL(bit); ++ } ++} +diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h +index a978509d50..4124912c20 100644 +--- a/target/i386/kvm/kvm_i386.h ++++ b/target/i386/kvm/kvm_i386.h +@@ -52,5 +52,6 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp); + uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); + + bool kvm_enable_sgx_provisioning(KVMState *s); ++void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); + + #endif +-- +2.27.0 + diff --git a/x86-Intel-AVX512_BF16-feature-enabling.patch b/x86-Intel-AVX512_BF16-feature-enabling.patch deleted file mode 100644 index 175190f10c71a4670f32ab3d16a49fee127e1c29..0000000000000000000000000000000000000000 --- a/x86-Intel-AVX512_BF16-feature-enabling.patch +++ /dev/null @@ -1,179 +0,0 @@ -From e2fdc78f93d61be487c03a782aef6fdd8b26fa7e Mon Sep 17 00:00:00 2001 -From: Jing Liu -Date: Thu, 25 Jul 2019 14:14:16 +0800 -Subject: [PATCH] x86: Intel AVX512_BF16 feature enabling - -Intel CooperLake cpu adds AVX512_BF16 instruction, defining as -CPUID.(EAX=7,ECX=1):EAX[bit 05]. - -The patch adds a property for setting the subleaf of CPUID leaf 7 in -case that people would like to specify it. - -The release spec link as follows, -https://software.intel.com/sites/default/files/managed/c5/15/\ -architecture-instruction-set-extensions-programming-reference.pdf - -Signed-off-by: Jing Liu -Signed-off-by: Paolo Bonzini - -Signed-off-by: Jingyi Wang ---- - target/i386/cpu.c | 39 ++++++++++++++++++++++++++++++++++++++- - target/i386/cpu.h | 7 +++++++ - target/i386/kvm.c | 3 ++- - 3 files changed, 47 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 19751e37a7..1ade90c28b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -770,6 +770,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57) - #define TCG_7_0_EDX_FEATURES 0 -+#define TCG_7_1_EAX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -1095,6 +1096,25 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .tcg_features = TCG_7_0_EDX_FEATURES, - }, -+ [FEAT_7_1_EAX] = { -+ .type = CPUID_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ NULL, "avx512-bf16", NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid = { -+ .eax = 7, -+ .needs_ecx = true, .ecx = 1, -+ .reg = R_EAX, -+ }, -+ .tcg_features = TCG_7_1_EAX_FEATURES, -+ }, - [FEAT_8000_0007_EDX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -@@ -4292,13 +4312,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - case 7: - /* Structured Extended Feature Flags Enumeration Leaf */ - if (count == 0) { -- *eax = 0; /* Maximum ECX value for sub-leaves */ -+ /* Maximum ECX value for sub-leaves */ -+ *eax = env->cpuid_level_func7; - *ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */ - *ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */ - if ((*ecx & CPUID_7_0_ECX_PKU) && env->cr[4] & CR4_PKE_MASK) { - *ecx |= CPUID_7_0_ECX_OSPKE; - } - *edx = env->features[FEAT_7_0_EDX]; /* Feature flags */ -+ } else if (count == 1) { -+ *eax = env->features[FEAT_7_1_EAX]; -+ *ebx = 0; -+ *ecx = 0; -+ *edx = 0; - } else { - *eax = 0; - *ebx = 0; -@@ -4948,6 +4974,11 @@ static void x86_cpu_adjust_feat_level(X86CPU *cpu, FeatureWord w) - x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel2, eax); - break; - } -+ -+ if (eax == 7) { -+ x86_cpu_adjust_level(cpu, &env->cpuid_min_level_func7, -+ fi->cpuid.ecx); -+ } - } - - /* Calculate XSAVE components based on the configured CPU feature flags */ -@@ -5066,6 +5097,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_1_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); -@@ -5097,6 +5129,9 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - } - - /* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */ -+ if (env->cpuid_level_func7 == UINT32_MAX) { -+ env->cpuid_level_func7 = env->cpuid_min_level_func7; -+ } - if (env->cpuid_level == UINT32_MAX) { - env->cpuid_level = env->cpuid_min_level; - } -@@ -5868,6 +5903,8 @@ static Property x86_cpu_properties[] = { - DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), - DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), - DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), -+ DEFINE_PROP_UINT32("level-func7", X86CPU, env.cpuid_level_func7, -+ UINT32_MAX), - DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), - DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX), - DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, UINT32_MAX), -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 8b3dc5533e..488b4dc778 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -479,6 +479,7 @@ typedef enum FeatureWord { - FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ - FEAT_7_0_ECX, /* CPUID[EAX=7,ECX=0].ECX */ - FEAT_7_0_EDX, /* CPUID[EAX=7,ECX=0].EDX */ -+ FEAT_7_1_EAX, /* CPUID[EAX=7,ECX=1].EAX */ - FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ - FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ - FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ -@@ -692,6 +693,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30) /*Core Capability*/ - #define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */ - -+#define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) /* AVX512 BFloat16 Instruction */ -+ - #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and - do not invalidate cache */ - #define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ -@@ -1322,6 +1325,10 @@ typedef struct CPUX86State { - /* Fields after this point are preserved across CPU reset. */ - - /* processor features (e.g. for CPUID insn) */ -+ /* Minimum cpuid leaf 7 value */ -+ uint32_t cpuid_level_func7; -+ /* Actual cpuid leaf 7 value */ -+ uint32_t cpuid_min_level_func7; - /* Minimum level/xlevel/xlevel2, based on CPU model + features */ - uint32_t cpuid_min_level, cpuid_min_xlevel, cpuid_min_xlevel2; - /* Maximum level/xlevel/xlevel2 value for auto-assignment: */ -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index dbbb13772a..f55d4b4b97 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -1497,6 +1497,7 @@ int kvm_arch_init_vcpu(CPUState *cs) - c = &cpuid_data.entries[cpuid_i++]; - } - break; -+ case 0x7: - case 0x14: { - uint32_t times; - -@@ -1509,7 +1510,7 @@ int kvm_arch_init_vcpu(CPUState *cs) - for (j = 1; j <= times; ++j) { - if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { - fprintf(stderr, "cpuid_data is full, no space for " -- "cpuid(eax:0x14,ecx:0x%x)\n", j); -+ "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); - abort(); - } - c = &cpuid_data.entries[cpuid_i++]; --- -2.27.0 - diff --git a/x86-Support-XFD-and-AMX-xsave-data-migration.patch b/x86-Support-XFD-and-AMX-xsave-data-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..a33ad5b67a3367562192f4f26ca472d388c32c4c --- /dev/null +++ b/x86-Support-XFD-and-AMX-xsave-data-migration.patch @@ -0,0 +1,182 @@ +From bb1b53e5d0b67d97042ea3c33b5c4c80e33809f2 Mon Sep 17 00:00:00 2001 +From: Zeng Guang +Date: Wed, 16 Feb 2022 22:04:33 -0800 +Subject: [PATCH 08/10] x86: Support XFD and AMX xsave data migration + +from mainline-v7.0.0-rc0 +commit cdec2b753b487d9e8aab028231c35d87789ea083 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit cdec2b753b48 ("x86: Support XFD and AMX xsave data +migration") + +------------------------------------------------ + +x86: Support XFD and AMX xsave data migration + +XFD(eXtended Feature Disable) allows to enable a +feature on xsave state while preventing specific +user threads from using the feature. + +Support save and restore XFD MSRs if CPUID.D.1.EAX[4] +enumerate to be valid. Likewise migrate the MSRs and +related xsave state necessarily. + +Signed-off-by: Zeng Guang +Signed-off-by: Wei Wang +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-8-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.h | 9 +++++++++ + target/i386/kvm/kvm.c | 18 +++++++++++++++++ + target/i386/machine.c | 46 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 73 insertions(+) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 74e66c352c..eaa99c302f 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -506,6 +506,9 @@ typedef enum X86Seg { + + #define MSR_VM_HSAVE_PA 0xc0010117 + ++#define MSR_IA32_XFD 0x000001c4 ++#define MSR_IA32_XFD_ERR 0x000001c5 ++ + #define MSR_IA32_BNDCFGS 0x00000d90 + #define MSR_IA32_XSS 0x00000da0 + #define MSR_IA32_UMWAIT_CONTROL 0xe1 +@@ -871,6 +874,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) + /* AVX512 BFloat16 Instruction */ + #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) ++/* XFD Extend Feature Disabled */ ++#define CPUID_D_1_EAX_XFD (1U << 4) + + /* Packets which contain IP payload have LIP values */ + #define CPUID_14_0_ECX_LIP (1U << 31) +@@ -1612,6 +1617,10 @@ typedef struct CPUX86State { + uint64_t msr_rtit_cr3_match; + uint64_t msr_rtit_addrs[MAX_RTIT_ADDRS]; + ++ /* Per-VCPU XFD MSRs */ ++ uint64_t msr_xfd; ++ uint64_t msr_xfd_err; ++ + /* exception/interrupt handling */ + int error_code; + int exception_is_int; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index b0b22dcf7c..49fca5ea88 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -3219,6 +3219,13 @@ static int kvm_put_msrs(X86CPU *cpu, int level) + env->msr_ia32_sgxlepubkeyhash[3]); + } + ++ if (env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD) { ++ kvm_msr_entry_add(cpu, MSR_IA32_XFD, ++ env->msr_xfd); ++ kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, ++ env->msr_xfd_err); ++ } ++ + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see + * kvm_put_msr_feature_control. */ + } +@@ -3570,6 +3577,11 @@ static int kvm_get_msrs(X86CPU *cpu) + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, 0); + } + ++ if (env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD) { ++ kvm_msr_entry_add(cpu, MSR_IA32_XFD, 0); ++ kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); ++ } ++ + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); + if (ret < 0) { + return ret; +@@ -3866,6 +3878,12 @@ static int kvm_get_msrs(X86CPU *cpu) + env->msr_ia32_sgxlepubkeyhash[index - MSR_IA32_SGXLEPUBKEYHASH0] = + msrs[i].data; + break; ++ case MSR_IA32_XFD: ++ env->msr_xfd = msrs[i].data; ++ break; ++ case MSR_IA32_XFD_ERR: ++ env->msr_xfd_err = msrs[i].data; ++ break; + } + } + +diff --git a/target/i386/machine.c b/target/i386/machine.c +index 83c2b91529..3977e9d8f8 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -1455,6 +1455,48 @@ static const VMStateDescription vmstate_msr_intel_sgx = { + } + }; + ++static bool xfd_msrs_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return !!(env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD); ++} ++ ++static const VMStateDescription vmstate_msr_xfd = { ++ .name = "cpu/msr_xfd", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = xfd_msrs_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(env.msr_xfd, X86CPU), ++ VMSTATE_UINT64(env.msr_xfd_err, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++#ifdef TARGET_X86_64 ++static bool amx_xtile_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return !!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE); ++} ++ ++static const VMStateDescription vmstate_amx_xtile = { ++ .name = "cpu/intel_amx_xtile", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = amx_xtile_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT8_ARRAY(env.xtilecfg, X86CPU, 64), ++ VMSTATE_UINT8_ARRAY(env.xtiledata, X86CPU, 8192), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++#endif ++ + const VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -1593,6 +1635,10 @@ const VMStateDescription vmstate_x86_cpu = { + #endif + &vmstate_msr_tsx_ctrl, + &vmstate_msr_intel_sgx, ++ &vmstate_msr_xfd, ++#ifdef TARGET_X86_64 ++ &vmstate_amx_xtile, ++#endif + NULL + } + }; +-- +2.27.0 + diff --git a/x86-add-support-for-KVM_CAP_XSAVE2-and-AMX-state-mig.patch b/x86-add-support-for-KVM_CAP_XSAVE2-and-AMX-state-mig.patch new file mode 100644 index 0000000000000000000000000000000000000000..7331af7c22560f5a921ee4b72ccd423a16b1773c --- /dev/null +++ b/x86-add-support-for-KVM_CAP_XSAVE2-and-AMX-state-mig.patch @@ -0,0 +1,186 @@ +From e98958c23ea5b15a8e84642c373336a8898cd63f Mon Sep 17 00:00:00 2001 +From: Jing Liu +Date: Wed, 16 Feb 2022 22:04:32 -0800 +Subject: [PATCH 07/10] x86: add support for KVM_CAP_XSAVE2 and AMX state + migration + +from mainline-v7.0.0-rc0 +commit e56dd3c70abb31893c61ac834109fa7a38841330 +category: feature +feature: SPR AMX support for Qemu +bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB + +Intel-SIG: commit e56dd3c70abb ("x86: add support for KVM_CAP_XSAVE2 and +AMX state migration") + +------------------------------------------------------- + +x86: add support for KVM_CAP_XSAVE2 and AMX state migration + +When dynamic xfeatures (e.g. AMX) are used by the guest, the xsave +area would be larger than 4KB. KVM_GET_XSAVE2 and KVM_SET_XSAVE +under KVM_CAP_XSAVE2 works with a xsave buffer larger than 4KB. +Always use the new ioctls under KVM_CAP_XSAVE2 when KVM supports it. + +Signed-off-by: Jing Liu +Signed-off-by: Zeng Guang +Signed-off-by: Wei Wang +Signed-off-by: Yang Zhong +Message-Id: <20220217060434.52460-7-yang.zhong@intel.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/cpu.h | 4 ++++ + target/i386/kvm/kvm.c | 42 ++++++++++++++++++++++++-------------- + target/i386/xsave_helper.c | 28 +++++++++++++++++++++++++ + 3 files changed, 59 insertions(+), 15 deletions(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 09c725ee13..74e66c352c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1523,6 +1523,10 @@ typedef struct CPUX86State { + uint64_t opmask_regs[NB_OPMASK_REGS]; + YMMReg zmmh_regs[CPU_NB_REGS]; + ZMMReg hi16_zmm_regs[CPU_NB_REGS]; ++#ifdef TARGET_X86_64 ++ uint8_t xtilecfg[64]; ++ uint8_t xtiledata[8192]; ++#endif + + /* sysenter registers */ + uint32_t sysenter_cs; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 60ccdec5e8..b0b22dcf7c 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -123,6 +123,7 @@ static uint32_t num_architectural_pmu_gp_counters; + static uint32_t num_architectural_pmu_fixed_counters; + + static int has_xsave; ++static int has_xsave2; + static int has_xcrs; + static int has_pit_state2; + static int has_exception_payload; +@@ -1585,6 +1586,26 @@ static Error *invtsc_mig_blocker; + + #define KVM_MAX_CPUID_ENTRIES 100 + ++static void kvm_init_xsave(CPUX86State *env) ++{ ++ if (has_xsave2) { ++ env->xsave_buf_len = QEMU_ALIGN_UP(has_xsave2, 4096); ++ } else if (has_xsave) { ++ env->xsave_buf_len = sizeof(struct kvm_xsave); ++ } else { ++ return; ++ } ++ ++ env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len); ++ memset(env->xsave_buf, 0, env->xsave_buf_len); ++ /* ++ * The allocated storage must be large enough for all of the ++ * possible XSAVE state components. ++ */ ++ assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX) <= ++ env->xsave_buf_len); ++} ++ + int kvm_arch_init_vcpu(CPUState *cs) + { + struct { +@@ -1614,6 +1635,8 @@ int kvm_arch_init_vcpu(CPUState *cs) + + cpuid_i = 0; + ++ has_xsave2 = kvm_check_extension(cs->kvm_state, KVM_CAP_XSAVE2); ++ + r = kvm_arch_set_tsc_khz(cs); + if (r < 0) { + return r; +@@ -2003,19 +2026,7 @@ int kvm_arch_init_vcpu(CPUState *cs) + if (r) { + goto fail; + } +- +- if (has_xsave) { +- env->xsave_buf_len = sizeof(struct kvm_xsave); +- env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len); +- memset(env->xsave_buf, 0, env->xsave_buf_len); +- +- /* +- * The allocated storage must be large enough for all of the +- * possible XSAVE state components. +- */ +- assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX) +- <= env->xsave_buf_len); +- } ++ kvm_init_xsave(env); + + max_nested_state_len = kvm_max_nested_state_length(); + if (max_nested_state_len > 0) { +@@ -3263,13 +3274,14 @@ static int kvm_get_xsave(X86CPU *cpu) + { + CPUX86State *env = &cpu->env; + void *xsave = env->xsave_buf; +- int ret; ++ int type, ret; + + if (!has_xsave) { + return kvm_get_fpu(cpu); + } + +- ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XSAVE, xsave); ++ type = has_xsave2 ? KVM_GET_XSAVE2 : KVM_GET_XSAVE; ++ ret = kvm_vcpu_ioctl(CPU(cpu), type, xsave); + if (ret < 0) { + return ret; + } +diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c +index ac61a96344..996e9f3bfe 100644 +--- a/target/i386/xsave_helper.c ++++ b/target/i386/xsave_helper.c +@@ -126,6 +126,20 @@ void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) + + memcpy(pkru, &env->pkru, sizeof(env->pkru)); + } ++ ++ e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; ++ if (e->size && e->offset) { ++ XSaveXTILECFG *tilecfg = buf + e->offset; ++ ++ memcpy(tilecfg, &env->xtilecfg, sizeof(env->xtilecfg)); ++ } ++ ++ e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; ++ if (e->size && e->offset && buflen >= e->size + e->offset) { ++ XSaveXTILEDATA *tiledata = buf + e->offset; ++ ++ memcpy(tiledata, &env->xtiledata, sizeof(env->xtiledata)); ++ } + #endif + } + +@@ -247,5 +261,19 @@ void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen) + pkru = buf + e->offset; + memcpy(&env->pkru, pkru, sizeof(env->pkru)); + } ++ ++ e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; ++ if (e->size && e->offset) { ++ const XSaveXTILECFG *tilecfg = buf + e->offset; ++ ++ memcpy(&env->xtilecfg, tilecfg, sizeof(env->xtilecfg)); ++ } ++ ++ e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; ++ if (e->size && e->offset && buflen >= e->size + e->offset) { ++ const XSaveXTILEDATA *tiledata = buf + e->offset; ++ ++ memcpy(&env->xtiledata, tiledata, sizeof(env->xtiledata)); ++ } + #endif + } +-- +2.27.0 + diff --git a/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch b/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch deleted file mode 100644 index fc17f48b7a395bafffaf7ef9763d04bff110af0a..0000000000000000000000000000000000000000 --- a/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 725dfa851f8e1de8653f41a4bd38c7f98757eb40 Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Mon, 2 Sep 2019 08:02:22 -0400 -Subject: [PATCH] x86: do not advertise die-id in query-hotpluggbale-cpus if - '-smp dies' is not set - -Commit 176d2cda0 (i386/cpu: Consolidate die-id validity in smp context) added -new 'die-id' topology property to CPUs and exposed it via QMP command -query-hotpluggable-cpus, which broke -device/device_add cpu-foo for existing -users that do not support die-id/dies yet. That's would be fine if it happened -to new machine type only but it also happened to old machine types, -which breaks migration from old QEMU to the new one, for example following CLI: - - OLD-QEMU -M pc-i440fx-4.0 -smp 1,max_cpus=2 \ - -device qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id -is not able to start with new QEMU, complaining about invalid die-id. - -After discovering regression, the patch - "pc: Don't make die-id mandatory unless necessary" -makes die-id optional so old CLI would work. - -However it's not enough as new QEMU still exposes die-id via query-hotpluggbale-cpus -QMP command, so the users that started old machine type on new QEMU, using all -properties (including die-id) received from QMP command (as required), won't be -able to start old QEMU using the same properties since it doesn't support die-id. - -Fix it by hiding die-id in query-hotpluggbale-cpus for all machine types in case -'-smp dies' is not provided on CLI or -smp dies = 1', in which case smp_dies == 1 -and APIC ID is calculated in default way (as it was before DIE support) so we won't -need compat code as in both cases the topology provided to guest via CPUID is the same. - -Signed-off-by: Igor Mammedov -Message-Id: <20190902120222.6179-1-imammedo@redhat.com> -Reviewed-by: Eduardo Habkost -Signed-off-by: Eduardo Habkost -(cherry picked from commit c6c1bb89fb46f3b88f832e654cf5a6f7941aac51) -Signed-off-by: Michael Roth ---- - hw/i386/pc.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 947f81070f..d011733ff7 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -2887,8 +2887,10 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) - ms->smp.threads, &topo); - ms->possible_cpus->cpus[i].props.has_socket_id = true; - ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; -- ms->possible_cpus->cpus[i].props.has_die_id = true; -- ms->possible_cpus->cpus[i].props.die_id = topo.die_id; -+ if (pcms->smp_dies > 1) { -+ ms->possible_cpus->cpus[i].props.has_die_id = true; -+ ms->possible_cpus->cpus[i].props.die_id = topo.die_id; -+ } - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = topo.core_id; - ms->possible_cpus->cpus[i].props.has_thread_id = true; --- -2.23.0 diff --git a/xen-block-Avoid-leaks-on-new-error-path.patch b/xen-block-Avoid-leaks-on-new-error-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef430bc44d9319bc08e97c4aa43255268ce6e80d --- /dev/null +++ b/xen-block-Avoid-leaks-on-new-error-path.patch @@ -0,0 +1,80 @@ +From 67577f8a8310b1233bddfdaa1099bf6371b79d51 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Thu, 3 Aug 2023 11:01:42 +0800 +Subject: [PATCH] xen-block: Avoid leaks on new error path + +Commit 189829399070 ("xen-block: Use specific blockdev driver") +introduced a new error path, without taking care of allocated +resources. + +So only allocate the qdicts after the error check, and free both +`filename` and `driver` when we are about to return and thus taking +care of both success and error path. + +Coverity only spotted the leak of qdicts (*_layer variables). + +Reported-by: Peter Maydell +Fixes: Coverity CID 1508722, 1398649 +Fixes: 189829399070 ("xen-block: Use specific blockdev driver") +Signed-off-by: Anthony PERARD +Reviewed-by: Paul Durrant +Reviewed-by: Peter Maydell +Message-Id: <20230704171819.42564-1-anthony.perard@citrix.com> +Signed-off-by: Anthony PERARD + +Signed-off-by: Zhongrui Tang +--- + hw/block/xen-block.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c +index 674953f1ad..6d90621e02 100644 +--- a/hw/block/xen-block.c ++++ b/hw/block/xen-block.c +@@ -760,14 +760,15 @@ static XenBlockDrive *xen_block_drive_create(const char *id, + drive = g_new0(XenBlockDrive, 1); + drive->id = g_strdup(id); + +- file_layer = qdict_new(); +- driver_layer = qdict_new(); +- + rc = stat(filename, &st); + if (rc) { + error_setg_errno(errp, errno, "Could not stat file '%s'", filename); + goto done; + } ++ ++ file_layer = qdict_new(); ++ driver_layer = qdict_new(); ++ + if (S_ISBLK(st.st_mode)) { + qdict_put_str(file_layer, "driver", "host_device"); + } else { +@@ -775,7 +776,6 @@ static XenBlockDrive *xen_block_drive_create(const char *id, + } + + qdict_put_str(file_layer, "filename", filename); +- g_free(filename); + + if (mode && *mode != 'w') { + qdict_put_bool(file_layer, "read-only", true); +@@ -810,7 +810,6 @@ static XenBlockDrive *xen_block_drive_create(const char *id, + qdict_put_str(file_layer, "locking", "off"); + + qdict_put_str(driver_layer, "driver", driver); +- g_free(driver); + + qdict_put(driver_layer, "file", file_layer); + +@@ -821,6 +820,8 @@ static XenBlockDrive *xen_block_drive_create(const char *id, + qobject_unref(driver_layer); + + done: ++ g_free(filename); ++ g_free(driver); + if (*errp) { + xen_block_drive_destroy(drive, NULL); + return NULL; +-- +2.41.0.windows.1 + diff --git a/xen-pass-through-don-t-create-needless-register-grou.patch b/xen-pass-through-don-t-create-needless-register-grou.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c45f2be52dd8620f387617e0dd7a99fa55dac5d --- /dev/null +++ b/xen-pass-through-don-t-create-needless-register-grou.patch @@ -0,0 +1,63 @@ +From 125b3c3ef9db4cda5e6f08d2f1f5b3d1fe853ef7 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 24 Nov 2023 08:33:13 +0000 +Subject: [PATCH] xen/pass-through: don't create needless register group + mainline inclusion commit c0e86b7624cb9d6db03e0d48cf82659e5b89a6a6 category: + bugfix + +--------------------------------------------------------------- + +Currently we are creating a register group for the Intel IGD OpRegion +for every device we pass through, but the XEN_PCI_INTEL_OPREGION +register group is only valid for an Intel IGD. Add a check to make +sure the device is an Intel IGD and a check that the administrator has +enabled gfx_passthru in the xl domain configuration. Require both checks +to be true before creating the register group. Use the existing +is_igd_vga_passthrough() function to check for a graphics device from +any vendor and that the administrator enabled gfx_passthru in the xl +domain configuration, but further require that the vendor be Intel, +because only Intel IGD devices have an Intel OpRegion. These are the +same checks hvmloader and libxl do to determine if the Intel OpRegion +needs to be mapped into the guest's memory. Also, move the comment +about trapping 0xfc for the Intel OpRegion where it belongs after +applying this patch. + +Signed-off-by: Chuck Zmudzinski +Reviewed-by: Anthony PERARD +Message-Id: +Signed-off-by: Anthony PERARD + +Signed-off-by: tangbinzy +--- + hw/xen/xen_pt_config_init.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c +index e7bcbe4c4f..b9833d2fa7 100644 +--- a/hw/xen/xen_pt_config_init.c ++++ b/hw/xen/xen_pt_config_init.c +@@ -2031,12 +2031,16 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) + } + } + +- /* +- * By default we will trap up to 0x40 in the cfg space. +- * If an intel device is pass through we need to trap 0xfc, +- * therefore the size should be 0xff. +- */ + if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) { ++ if (!is_igd_vga_passthrough(&s->real_device) || ++ s->real_device.vendor_id != PCI_VENDOR_ID_INTEL) { ++ continue; ++ } ++ /* ++ * By default we will trap up to 0x40 in the cfg space. ++ * If an intel device is pass through we need to trap 0xfc, ++ * therefore the size should be 0xff. ++ */ + reg_grp_offset = XEN_PCI_INTEL_OPREGION; + } + +-- +2.27.0 + diff --git a/xen-pass-through-merge-emulated-bits-correctly.patch b/xen-pass-through-merge-emulated-bits-correctly.patch new file mode 100644 index 0000000000000000000000000000000000000000..e4bc9c4a56def04713a93624c2c4c6852449bf85 --- /dev/null +++ b/xen-pass-through-merge-emulated-bits-correctly.patch @@ -0,0 +1,67 @@ +From feec0d41c0737ce46860fd7b34324d41498fdb9d Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 24 Nov 2023 08:20:17 +0000 +Subject: [PATCH] xen/pass-through: merge emulated bits correctly mainline + inclusion commit be9c61da9fc57eb7d293f380d0805ca6f46c2657 category: bugfix + +--------------------------------------------------------------- + +In xen_pt_config_reg_init(), there is an error in the merging of the +emulated data with the host value. With the current Qemu, instead of +merging the emulated bits with the host bits as defined by emu_mask, +the emulated bits are merged with the host bits as defined by the +inverse of emu_mask. In some cases, depending on the data in the +registers on the host, the way the registers are setup, and the +initial values of the emulated bits, the end result will be that +the register is initialized with the wrong value. + +To correct this error, use the XEN_PT_MERGE_VALUE macro to help ensure +the merge is done correctly. + +This correction is needed to resolve Qemu project issue #1061, which +describes the failure of Xen HVM Linux guests to boot in certain +configurations with passed through PCI devices, that is, when this error +disables instead of enables the PCI_STATUS_CAP_LIST bit of the +PCI_STATUS register of a passed through PCI device, which in turn +disables the MSI-X capability of the device in Linux guests with the end +result being that the Linux guest never completes the boot process. + +Fixes: 2e87512eccf3 ("xen/pt: Sync up the dev.config and data values") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1061 +Buglink: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=988333 + +Signed-off-by: Chuck Zmudzinski +Reviewed-by: Anthony PERARD +Message-Id: +Signed-off-by: Anthony PERARD + +Signed-off-by: tangbinzy +--- + hw/xen/xen_pt_config_init.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c +index e7bcbe4c4f..d04c12ce3d 100644 +--- a/hw/xen/xen_pt_config_init.c ++++ b/hw/xen/xen_pt_config_init.c +@@ -1965,11 +1965,12 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s, + + if ((data & host_mask) != (val & host_mask)) { + uint32_t new_val; +- +- /* Mask out host (including past size). */ +- new_val = val & host_mask; +- /* Merge emulated ones (excluding the non-emulated ones). */ +- new_val |= data & host_mask; ++ /* ++ * Merge the emulated bits (data) with the host bits (val) ++ * and mask out the bits past size to enable restoration ++ * of the proper value for logging below. ++ */ ++ new_val = XEN_PT_MERGE_VALUE(val, data, host_mask) & size_mask; + /* Leave intact host and emulated values past the size - even though + * we do not care as we write per reg->size granularity, but for the + * logging below lets have the proper value. */ +-- +2.27.0 + diff --git a/xhci-Fix-memory-leak-in-xhci_address_slot.patch b/xhci-Fix-memory-leak-in-xhci_address_slot.patch deleted file mode 100644 index 1d0f858f3e6ea2975aff0a7e89a155083a9695b7..0000000000000000000000000000000000000000 --- a/xhci-Fix-memory-leak-in-xhci_address_slot.patch +++ /dev/null @@ -1,47 +0,0 @@ -From c0de0a04d03183f524c2f60cda8ae1e886197a7d Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 27 Aug 2019 10:54:48 +0800 -Subject: [PATCH] xhci: Fix memory leak in xhci_address_slot - -Address Sanitizer shows memory leak in xhci_address_slot -hw/usb/hcd-xhci.c:2156 and the stack is as bellow: - -Direct leak of 64 byte(s) in 4 object(s) allocated from: - #0 0xffff91c6f5ab in realloc (/lib64/libasan.so.4+0xd35ab) - #1 0xffff91987243 in g_realloc (/lib64/libglib-2.0.so.0+0x57243) - #2 0xaaaab0b26a1f in qemu_iovec_add util/iov.c:296 - #3 0xaaaab07e5ce3 in xhci_address_slot hw/usb/hcd-xhci.c:2156 - #4 0xaaaab07e5ce3 in xhci_process_commands hw/usb/hcd-xhci.c:2493 - #5 0xaaaab00058d7 in memory_region_write_accessor qemu/memory.c:507 - #6 0xaaaab0000d87 in access_with_adjusted_size memory.c:573 - #7 0xaaaab000abcf in memory_region_dispatch_write memory.c:1516 - #8 0xaaaaaff59947 in flatview_write_continue exec.c:3367 - #9 0xaaaaaff59c33 in flatview_write exec.c:3406 - #10 0xaaaaaff63b3b in address_space_write exec.c:3496 - #11 0xaaaab002f263 in kvm_cpu_exec accel/kvm/kvm-all.c:2288 - #12 0xaaaaaffee427 in qemu_kvm_cpu_thread_fn cpus.c:1290 - #13 0xaaaab0b1a943 in qemu_thread_start util/qemu-thread-posix.c:502 - #14 0xffff908ce8bb in start_thread (/lib64/libpthread.so.0+0x78bb) - #15 0xffff908165cb in thread_start (/lib64/libc.so.6+0xd55cb) - -Cc: zhanghailiang -Signed-off-by: Ying Fang ---- - hw/usb/hcd-xhci.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index f578264948..471759cd4c 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -2161,6 +2161,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, - DeviceOutRequest | USB_REQ_SET_ADDRESS, - slotid, 0, 0, NULL); - assert(p.status != USB_RET_ASYNC); -+ usb_packet_cleanup(&p); - } - - res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); --- -2.19.1 - diff --git a/xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch b/xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch deleted file mode 100644 index 7d226e65cdc2e6e6e9c19e4791567246e1851787..0000000000000000000000000000000000000000 --- a/xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch +++ /dev/null @@ -1,56 +0,0 @@ -From cf859d444770243fa184019fd4eab135b2653390 Mon Sep 17 00:00:00 2001 -From: Chen Qun -Date: Fri, 10 Jan 2020 18:36:24 +0800 -Subject: [PATCH] xhci: Fix memory leak in xhci_kick_epctx when poweroff - GuestOS -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -start vm with libvirt, when GuestOS running, enter poweroff command using -the xhci keyboard, then ASAN shows memory leak stack: - -Direct leak of 80 byte(s) in 5 object(s) allocated from: - #0 0xfffd1e6431cb in __interceptor_malloc (/lib64/libasan.so.4+0xd31cb) - #1 0xfffd1e107163 in g_malloc (/lib64/libglib-2.0.so.0+0x57163) - #2 0xaaad39051367 in qemu_sglist_init /qemu/dma-helpers.c:43 - #3 0xaaad3947c407 in pci_dma_sglist_init /qemu/include/hw/pci/pci.h:842 - #4 0xaaad3947c407 in xhci_xfer_create_sgl /qemu/hw/usb/hcd-xhci.c:1446 - #5 0xaaad3947c407 in xhci_setup_packet /qemu/hw/usb/hcd-xhci.c:1618 - #6 0xaaad3948625f in xhci_submit /qemu/hw/usb/hcd-xhci.c:1827 - #7 0xaaad3948625f in xhci_fire_transfer /qemu/hw/usb/hcd-xhci.c:1839 - #8 0xaaad3948625f in xhci_kick_epctx /qemu/hw/usb/hcd-xhci.c:1991 - #9 0xaaad3948f537 in xhci_doorbell_write /qemu/hw/usb/hcd-xhci.c:3158 - #10 0xaaad38bcbfc7 in memory_region_write_accessor /qemu/memory.c:483 - #11 0xaaad38bc654f in access_with_adjusted_size /qemu/memory.c:544 - #12 0xaaad38bd1877 in memory_region_dispatch_write /qemu/memory.c:1482 - #13 0xaaad38b1c77f in flatview_write_continue /qemu/exec.c:3167 - #14 0xaaad38b1ca83 in flatview_write /qemu/exec.c:3207 - #15 0xaaad38b268db in address_space_write /qemu/exec.c:3297 - #16 0xaaad38bf909b in kvm_cpu_exec /qemu/accel/kvm/kvm-all.c:2383 - #17 0xaaad38bb063f in qemu_kvm_cpu_thread_fn /qemu/cpus.c:1246 - #18 0xaaad39821c93 in qemu_thread_start /qemu/util/qemu-thread-posix.c:519 - #19 0xfffd1c8378bb (/lib64/libpthread.so.0+0x78bb) - #20 0xfffd1c77616b (/lib64/libc.so.6+0xd616b) - -Reported-by: Euler Robot -Signed-off-by: Chen Qun ---- - hw/usb/hcd-xhci.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 80988bb305..0d3d96d05a 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -2000,6 +2000,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) - if (xfer != NULL && xfer->running_retry) { - DPRINTF("xhci: xfer nacked, stopping schedule\n"); - epctx->retry = xfer; -+ xhci_xfer_unmap(xfer); - break; - } - if (count++ > TRANSFER_LIMIT) { --- -2.23.0 - diff --git a/xhci-Fix-memory-leak-in-xhci_kick_epctx.patch b/xhci-Fix-memory-leak-in-xhci_kick_epctx.patch deleted file mode 100644 index 398b1bcdd6e784cf1ecd87f41d0f1066d2780c6c..0000000000000000000000000000000000000000 --- a/xhci-Fix-memory-leak-in-xhci_kick_epctx.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 2212f37e0e477d8da0cff02cfc8b7a921ca11bef Mon Sep 17 00:00:00 2001 -From: fangying -Date: Wed, 28 Aug 2019 14:02:22 +0800 -Subject: [PATCH] xhci: Fix memory leak in xhci_kick_epctx - -Address Sanitizer shows memory leak in xhci_kick_epctx hw/usb/hcd-xhci.c:1912. -A sglist is leaked when a packet is retired and returns USB_RET_NAK status. -The leak stack is as bellow: - -Direct leak of 2688 byte(s) in 168 object(s) allocated from: - #0 0xffffae8b11db in __interceptor_malloc (/lib64/libasan.so.4+0xd31db) - #1 0xffffae5c9163 in g_malloc (/lib64/libglib-2.0.so.0+0x57163) - #2 0xaaaabb6fb3f7 in qemu_sglist_init dma-helpers.c:43 - #3 0xaaaabba705a7 in pci_dma_sglist_init include/hw/pci/pci.h:837 - #4 0xaaaabba705a7 in xhci_xfer_create_sgl hw/usb/hcd-xhci.c:1443 - #5 0xaaaabba705a7 in xhci_setup_packet hw/usb/hcd-xhci.c:1615 - #6 0xaaaabba77a6f in xhci_kick_epctx hw/usb/hcd-xhci.c:1912 - #7 0xaaaabbdaad27 in timerlist_run_timers util/qemu-timer.c:592 - #8 0xaaaabbdab19f in qemu_clock_run_timers util/qemu-timer.c:606 - #9 0xaaaabbdab19f in qemu_clock_run_all_timers util/qemu-timer.c:692 - #10 0xaaaabbdab9a3 in main_loop_wait util/main-loop.c:524 - #11 0xaaaabb6ff5e7 in main_loop vl.c:1806 - #12 0xaaaabb1e1453 in main vl.c:4488 - -Signed-off-by: Ying Fang ---- - hw/usb/hcd-xhci.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 6e1ec786..e10fbd3d 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1911,6 +1911,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) - } - usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - if (xfer->packet.status == USB_RET_NAK) { -+ xhci_xfer_unmap(xfer); - return; - } - xhci_try_complete_packet(xfer); --- -2.19.1 - diff --git a/xhci-check-reg-to-avoid-OOB-read.patch b/xhci-check-reg-to-avoid-OOB-read.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6a4c356578e4f686ad8cb0dbbcdd24e6cd8b816 --- /dev/null +++ b/xhci-check-reg-to-avoid-OOB-read.patch @@ -0,0 +1,47 @@ +From a95ada20170af0a71529c1583846e402cdbb850b Mon Sep 17 00:00:00 2001 +From: Yan Wang +Date: Thu, 10 Feb 2022 10:41:40 +0800 +Subject: [PATCH] xhci: check reg to avoid OOB read + +Add a sanity check to fix OOB read access. + +Signed-off-by: Yan Wang +--- + hw/usb/hcd-xhci.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index e01700039b..08cd63e159 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -27,6 +27,7 @@ + #include "hw/qdev-properties.h" + #include "trace.h" + #include "qapi/error.h" ++#include "qemu/log.h" + + #include "hcd-xhci.h" + +@@ -3017,14 +3018,17 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, + XHCIInterrupter *intr; + int v; + +- trace_usb_xhci_runtime_write(reg, val); +- + if (reg < 0x20) { + trace_usb_xhci_unimplemented("runtime write", reg); + return; + } + v = (reg - 0x20) / 0x20; ++ if (v >= xhci->numintrs) { ++ qemu_log("intr nr out of range (%d >= %d)\n", v, xhci->numintrs); ++ return; ++ } + intr = &xhci->intr[v]; ++ trace_usb_xhci_runtime_write(reg, val); + + switch (reg & 0x1f) { + case 0x00: /* IMAN */ +-- +2.27.0 + diff --git a/xhci-fix-valid.max_access_size-to-access-address-reg.patch b/xhci-fix-valid.max_access_size-to-access-address-reg.patch deleted file mode 100644 index 466cbf2667efaf26cc65c160c8223659abb0c288..0000000000000000000000000000000000000000 --- a/xhci-fix-valid.max_access_size-to-access-address-reg.patch +++ /dev/null @@ -1,62 +0,0 @@ -From a71d1847aa780b3c4062e582ab400a7fea0413b3 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Tue, 21 Jul 2020 10:33:22 +0200 -Subject: [PATCH 01/11] xhci: fix valid.max_access_size to access address - registers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -QEMU XHCI advertises AC64 (64-bit addressing) but doesn't allow -64-bit mode access in "runtime" and "operational" MemoryRegionOps. - -Set the max_access_size based on sizeof(dma_addr_t) as AC64 is set. - -XHCI specs: -"If the xHC supports 64-bit addressing (AC64 = ‘1’), then software -should write 64-bit registers using only Qword accesses. If a -system is incapable of issuing Qword accesses, then writes to the -64-bit address fields shall be performed using 2 Dword accesses; -low Dword-first, high-Dword second. If the xHC supports 32-bit -addressing (AC64 = ‘0’), then the high Dword of registers containing -64-bit address fields are unused and software should write addresses -using only Dword accesses" - -The problem has been detected with SLOF, as linux kernel always accesses -registers using 32-bit access even if AC64 is set and revealed by -5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid"") - -Suggested-by: Alexey Kardashevskiy -Signed-off-by: Laurent Vivier -Message-id: 20200721083322.90651-1-lvivier@redhat.com -Signed-off-by: Gerd Hoffmann -Signed-off-by: BiaoXiang Ye ---- - hw/usb/hcd-xhci.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index a21485fe..24565de1 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -3171,7 +3171,7 @@ static const MemoryRegionOps xhci_oper_ops = { - .read = xhci_oper_read, - .write = xhci_oper_write, - .valid.min_access_size = 4, -- .valid.max_access_size = 4, -+ .valid.max_access_size = sizeof(dma_addr_t), - .endianness = DEVICE_LITTLE_ENDIAN, - }; - -@@ -3187,7 +3187,7 @@ static const MemoryRegionOps xhci_runtime_ops = { - .read = xhci_runtime_read, - .write = xhci_runtime_write, - .valid.min_access_size = 4, -- .valid.max_access_size = 4, -+ .valid.max_access_size = sizeof(dma_addr_t), - .endianness = DEVICE_LITTLE_ENDIAN, - }; - --- -2.27.0.dirty - diff --git a/xhci-recheck-slot-status.patch b/xhci-recheck-slot-status.patch deleted file mode 100644 index d05c3c8344802c788827334b2f48693ec4b72edb..0000000000000000000000000000000000000000 --- a/xhci-recheck-slot-status.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 33d6a2bc0e432a85962b71bcb2c3b5eec39bf436 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 7 Jan 2020 09:36:06 +0100 -Subject: [PATCH] xhci: recheck slot status -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Factor out slot status check into a helper function. Add an additional -check after completing transfers. This is needed in case a guest -queues multiple transfers in a row and a device unplug happens while -qemu processes them. - -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1786413 -Signed-off-by: Gerd Hoffmann -Reviewed-by: Philippe Mathieu-Daudé -Message-id: 20200107083606.12393-1-kraxel@redhat.com ---- - hw/usb/hcd-xhci.c | 15 ++++++++++++--- - 1 file changed, 12 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 24565de1d1..4b42f53b9c 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1860,6 +1860,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, - xhci_kick_epctx(epctx, streamid); - } - -+static bool xhci_slot_ok(XHCIState *xhci, int slotid) -+{ -+ return (xhci->slots[slotid - 1].uport && -+ xhci->slots[slotid - 1].uport->dev && -+ xhci->slots[slotid - 1].uport->dev->attached); -+} -+ - static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) - { - XHCIState *xhci = epctx->xhci; -@@ -1877,9 +1884,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) - - /* If the device has been detached, but the guest has not noticed this - yet the 2 above checks will succeed, but we must NOT continue */ -- if (!xhci->slots[epctx->slotid - 1].uport || -- !xhci->slots[epctx->slotid - 1].uport->dev || -- !xhci->slots[epctx->slotid - 1].uport->dev->attached) { -+ if (!xhci_slot_ok(xhci, epctx->slotid)) { - return; - } - -@@ -1986,6 +1991,10 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) - } else { - xhci_fire_transfer(xhci, xfer, epctx); - } -+ if (!xhci_slot_ok(xhci, epctx->slotid)) { -+ /* surprise removal -> stop processing */ -+ break; -+ } - if (xfer->complete) { - /* update ring dequeue ptr */ - xhci_set_ep_state(xhci, epctx, stctx, epctx->state); --- -2.27.0 - diff --git a/xics-Don-t-deassert-outputs.patch b/xics-Don-t-deassert-outputs.patch deleted file mode 100644 index 083a9a2e885cd2b4c2d8fe701c2ad037b5bece00..0000000000000000000000000000000000000000 --- a/xics-Don-t-deassert-outputs.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5b137b37ef7c4941200798cca99200e80ef17a01 Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Wed, 4 Dec 2019 20:43:43 +0100 -Subject: [PATCH] xics: Don't deassert outputs - -The correct way to do this is to deassert the input pins on the CPU side. -This is the case since a previous change. - -Signed-off-by: Greg Kurz -Message-Id: <157548862298.3650476.1228720391270249433.stgit@bahia.lan> -Signed-off-by: David Gibson ---- - hw/intc/xics.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/hw/intc/xics.c b/hw/intc/xics.c -index faa976e2f8..d2d377fc85 100644 ---- a/hw/intc/xics.c -+++ b/hw/intc/xics.c -@@ -303,9 +303,6 @@ static void icp_reset_handler(void *dev) - icp->pending_priority = 0xff; - icp->mfrr = 0xff; - -- /* Make all outputs are deasserted */ -- qemu_set_irq(icp->output, 0); -- - if (kvm_irqchip_in_kernel()) { - Error *local_err = NULL; - --- -2.27.0 -