diff --git a/9pfs-Fully-restart-unreclaim-loop-CVE-2021-20181.patch b/9pfs-Fully-restart-unreclaim-loop-CVE-2021-20181.patch new file mode 100644 index 0000000000000000000000000000000000000000..59f695adc31d622d70a32ecce77bf94e5fe39c10 --- /dev/null +++ b/9pfs-Fully-restart-unreclaim-loop-CVE-2021-20181.patch @@ -0,0 +1,80 @@ +From 31012acf8fcf51131d1553bc3e04176ae51e8228 Mon Sep 17 00:00:00 2001 +From: Greg Kurz +Date: Tue, 8 Jun 2021 09:07:17 +0800 +Subject: [PATCH] 9pfs: Fully restart unreclaim loop (CVE-2021-20181) + +Fix CVE-2021-20181 + +Depending on the client activity, the server can be asked to open a huge +number of file descriptors and eventually hit RLIMIT_NOFILE. This is +currently mitigated using a reclaim logic : the server closes the file +descriptors of idle fids, based on the assumption that it will be able +to re-open them later. This assumption doesn't hold of course if the +client requests the file to be unlinked. In this case, we loop on the +entire fid list and mark all related fids as unreclaimable (the reclaim +logic will just ignore them) and, of course, we open or re-open their +file descriptors if needed since we're about to unlink the file. + +This is the purpose of v9fs_mark_fids_unreclaim(). Since the actual +opening of a file can cause the coroutine to yield, another client +request could possibly add a new fid that we may want to mark as +non-reclaimable as well. The loop is thus restarted if the re-open +request was actually transmitted to the backend. This is achieved +by keeping a reference on the first fid (head) before traversing +the list. + +This is wrong in several ways: +- a potential clunk request from the client could tear the first + fid down and cause the reference to be stale. This leads to a + use-after-free error that can be detected with ASAN, using a + custom 9p client +- fids are added at the head of the list : restarting from the + previous head will always miss fids added by a some other + potential request + +All these problems could be avoided if fids were being added at the +end of the list. This can be achieved with a QSIMPLEQ, but this is +probably too much change for a bug fix. For now let's keep it +simple and just restart the loop from the current head. + +Fixes: CVE-2021-20181 +Buglink: https://bugs.launchpad.net/qemu/+bug/1911666 +Reported-by: Zero Day Initiative +Reviewed-by: Christian Schoenebeck +Reviewed-by: Stefano Stabellini +Message-Id: <161064025265.1838153.15185571283519390907.stgit@bahia.lan> +Signed-off-by: Greg Kurz + +Signed-off-by: Jiajie Li +--- + hw/9pfs/9p.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 55821343e5..289d00b01a 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -498,9 +498,9 @@ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) + { + int err; + V9fsState *s = pdu->s; +- V9fsFidState *fidp, head_fid; ++ V9fsFidState *fidp; + +- head_fid.next = s->fid_list; ++again: + for (fidp = s->fid_list; fidp; fidp = fidp->next) { + if (fidp->path.size != path->size) { + continue; +@@ -520,7 +520,7 @@ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) + * switched to the worker thread + */ + if (err == 0) { +- fidp = &head_fid; ++ goto again; + } + } + } +-- +2.27.0 + 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..13653c66468664ca37c731fc4b6274b517e11824 --- /dev/null +++ b/9pfs-prevent-opening-special-files-CVE-2023-2861.patch @@ -0,0 +1,167 @@ +From 38a25ac5981388e645b01f0a4f00da32524656d7 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 6f132c5ff1..b4ab483113 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" +@@ -350,6 +351,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 +@@ -694,7 +717,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; + } +@@ -719,7 +742,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 79ed6b233e..6dcb574801 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, +@@ -43,6 +79,10 @@ static inline int openat_file(int dirfd, const char *name, int flags, + 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 similarity index 69% rename from ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch rename to ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch index 5727a1d482a732c900701024507156a0f999bf40..3012512988402756527c95341aa921a362c9e43e 100644 --- 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 @@ -1,8 +1,11 @@ -From f3c1fc4dce1582ccc1754899d5149d233e8629ff Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Thu, 3 Oct 2019 17:46:40 +0200 -Subject: [PATCH 3/3] ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for - smp_cpus > 256 +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 @@ -21,29 +24,30 @@ 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.] + ¦struct CpuTopology in MachineState at that time. See commit + ¦edeeec911702 for details.] Signed-off-by: Zenghui Yu --- - target/arm/kvm.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) + 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 f60185ad..383423c4 100644 +index 50e86f8b..cc7a46df 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c -@@ -174,6 +174,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - +@@ -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. */ -@@ -187,7 +188,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - +@@ -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)) { @@ -54,8 +58,7 @@ index f60185ad..383423c4 100644 + + return ret; } - - unsigned long kvm_arch_vcpu_id(CPUState *cpu) --- -2.19.1 + 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 index b2ad176f8d56fdc71b6663f36bad7cc93ed4429a..4681e9f33f6877f199768b7a06a65df5356e6a7f 100644 --- a/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch +++ b/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch @@ -1,6 +1,6 @@ -From d2fd6d1a5200b9a58863839d21d291cd4f76ac31 Mon Sep 17 00:00:00 2001 +From 4646a24045cf53f2cc5e0ef1974da88ef50ef676 Mon Sep 17 00:00:00 2001 From: Ying Fang -Date: Mon, 29 Jul 2019 15:47:27 +0800 +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 @@ -17,10 +17,10 @@ Signed-off-by: Ying Fang 3 files changed, 61 insertions(+) diff --git a/cpus.c b/cpus.c -index e83f72b4..f6ec48a2 100644 +index 927a00aa..b9aa51f8 100644 --- a/cpus.c +++ b/cpus.c -@@ -1063,6 +1063,28 @@ void cpu_synchronize_all_pre_loadvm(void) +@@ -1066,6 +1066,28 @@ void cpu_synchronize_all_pre_loadvm(void) } } @@ -49,7 +49,7 @@ index e83f72b4..f6ec48a2 100644 static int do_vm_stop(RunState state, bool send_stop) { int ret = 0; -@@ -1070,6 +1092,11 @@ static int do_vm_stop(RunState state, bool send_stop) +@@ -1073,6 +1095,11 @@ static int do_vm_stop(RunState state, bool send_stop) if (runstate_is_running()) { cpu_disable_ticks(); pause_all_vcpus(); @@ -61,7 +61,7 @@ index e83f72b4..f6ec48a2 100644 runstate_set(state); vm_state_notify(0, state); if (send_stop) { -@@ -1909,11 +1936,42 @@ void cpu_resume(CPUState *cpu) +@@ -1918,11 +1945,42 @@ void cpu_resume(CPUState *cpu) qemu_cpu_kick(cpu); } @@ -105,23 +105,23 @@ index e83f72b4..f6ec48a2 100644 cpu_resume(cpu); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index d4d28369..e107e395 100644 +index 86eb79cd..aec6a214 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h -@@ -270,6 +270,8 @@ typedef struct CPUARMState { - uint64_t elr_el[4]; /* AArch64 exception link regs */ +@@ -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 b2925496..d64a0057 100644 +index ee3c59a6..ec28b839 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c -@@ -792,6 +792,7 @@ const VMStateDescription vmstate_arm_cpu = { +@@ -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), diff --git a/Add-mtod_check.patch b/Add-mtod_check.patch new file mode 100644 index 0000000000000000000000000000000000000000..7309bc4342c71e6bf41d7835f589826e203e8a82 --- /dev/null +++ b/Add-mtod_check.patch @@ -0,0 +1,54 @@ +From 8cb4d202d4e5713e9b2b5f0ec817234941623f10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 15:58:25 +0400 +Subject: [PATCH 1/6] Add mtod_check() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Recent security issues demonstrate the lack of safety care when casting +a mbuf to a particular structure type. At least, it should check that +the buffer is large enough. The following patches will make use of this +function. + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/mbuf.c | 11 +++++++++++ + slirp/src/mbuf.h | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c +index 4fd62282..6d0653ed 100644 +--- a/slirp/src/mbuf.c ++++ b/slirp/src/mbuf.c +@@ -222,3 +222,14 @@ struct mbuf *dtom(Slirp *slirp, void *dat) + + return (struct mbuf *)0; + } ++ ++void *mtod_check(struct mbuf *m, size_t len) ++{ ++ if (m->m_len >= len) { ++ return m->m_data; ++ } ++ ++ DEBUG_ERROR("mtod failed"); ++ ++ return NULL; ++} +diff --git a/slirp/src/mbuf.h b/slirp/src/mbuf.h +index 546e7852..2015e323 100644 +--- a/slirp/src/mbuf.h ++++ b/slirp/src/mbuf.h +@@ -118,6 +118,7 @@ void m_inc(struct mbuf *, int); + void m_adj(struct mbuf *, int); + int m_copy(struct mbuf *, struct mbuf *, int, int); + struct mbuf *dtom(Slirp *, void *); ++void *mtod_check(struct mbuf *, size_t len); + + static inline void ifs_init(struct mbuf *ifm) + { +-- +2.27.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..f7fe83163b55b35eb17ff861a17aef24c5f43f15 --- /dev/null +++ b/Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch @@ -0,0 +1,32 @@ +From 905c910373b5e6362181f227a1564eb3bef5a353 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/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch b/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch new file mode 100644 index 0000000000000000000000000000000000000000..200e0b2df02607b11e3117863afd00a346419e27 --- /dev/null +++ b/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch @@ -0,0 +1,88 @@ +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-vtimer-compat-cross-version-migration-from-v4.patch b/Revert-vtimer-compat-cross-version-migration-from-v4.patch new file mode 100644 index 0000000000000000000000000000000000000000..082f1763f9b445ba3816e2051c47129a6c64528a --- /dev/null +++ b/Revert-vtimer-compat-cross-version-migration-from-v4.patch @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..bc1fd44d163beb57f08c3b58918d305772b0c362 --- /dev/null +++ b/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch @@ -0,0 +1,27 @@ +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/accel-kvm-Add-pre-park-vCPU-support.patch b/accel-kvm-Add-pre-park-vCPU-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..9bc81178581c30504ca1b32d1f47ba8cbc1a5b85 --- /dev/null +++ b/accel-kvm-Add-pre-park-vCPU-support.patch @@ -0,0 +1,63 @@ +From 135119d2e82e99adc67346572c761fbe54d73e4a 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 + +For that KVM do not support dynamic adjustment of vCPU count, +we must pre-park all possible vCPU at start. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + accel/kvm/kvm-all.c | 23 +++++++++++++++++++++++ + include/sysemu/kvm.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index f450f25295..84edbe8bb1 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -339,6 +339,29 @@ err: + return ret; + } + ++int kvm_create_parked_vcpu(unsigned long vcpu_id) ++{ ++ KVMState *s = kvm_state; ++ struct KVMParkedVcpu *vcpu = NULL; ++ int ret; ++ ++ DPRINTF("kvm_create_parked_vcpu\n"); ++ ++ ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); ++ if (ret < 0) { ++ DPRINTF("kvm_create_vcpu failed\n"); ++ goto err; ++ } ++ ++ vcpu = g_malloc0(sizeof(*vcpu)); ++ vcpu->vcpu_id = vcpu_id; ++ vcpu->kvm_fd = ret; ++ QLIST_INSERT_HEAD(&s->kvm_parked_vcpus, vcpu, node); ++ ++err: ++ return ret; ++} ++ + static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) + { + struct KVMParkedVcpu *cpu; +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index acd90aebb6..565adb4e2c 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -216,6 +216,7 @@ 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 diff --git a/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..0506d1b73c1586699dd0fe92254baa5d0af26a7b --- /dev/null +++ b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch @@ -0,0 +1,128 @@ +From 107c267ebe5b8c461268a4ff8384ad2f2b9e8ce0 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 + +We will reuse build_cpus_aml to build DSDT cpus aml in arm/virt +ACPI to realize cpu hotplug. Three points are added. + +1. Make ACPI IO address space configurable, because ARM64 platforms + don't use port IO for ACPI IO space. +2. Add GICC struct building support in _MAT of cpu aml. +3. Let the hotplug method parameter can be NULL, because ACPI GED + will realize it. + +Besides, CPU CPPC building is injected. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/acpi/cpu.c | 32 +++++++++++++++++++++++++------- + hw/i386/acpi-build.c | 2 +- + include/hw/acpi/cpu.h | 3 ++- + 3 files changed, 28 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 0c0bfe479a..72ad1fcff2 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -314,7 +314,8 @@ const VMStateDescription vmstate_cpu_hotplug = { + 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) + { + Aml *ifctx; + Aml *field; +@@ -342,13 +343,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)); ++ if (rs == AML_SYSTEM_IO) { ++ aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, ++ ACPI_CPU_HOTPLUG_REG_LEN)); ++ } else { ++ aml_append(crs, aml_memory32_fixed(io_base, ++ 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, + aml_append(dev, aml_name_decl("_UID", uid)); + } + ++ assert(adevc); ++ if (adevc->cpu_cppc) { ++ adevc->cpu_cppc(adev, i, arch_ids->len, dev); ++ } ++ + 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, + 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); ++ if (event_handler_method) { ++ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); ++ 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 +--- 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 + }; + 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 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -55,7 +55,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.19.1 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 new file mode 100644 index 0000000000000000000000000000000000000000..f4e0a25c050e7948c1c7e1e2e0721c0b43d27fcc --- /dev/null +++ b/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..57247e6797da5a977685f737e9454427ab2c41df --- /dev/null +++ b/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch @@ -0,0 +1,204 @@ +From 05d22b55133db1a2526cfe305102e075e883b5e2 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 + +This adds a new GED event called ACPI_GED_CPU_HOTPLUG_EVT. +The basic workflow is that: GED sends this event to guest, +then ACPI driver in guest will call _EVT method of GED aml, +then _EVT will call CSCN method in cpus aml to get status of +all cpus. + +The status of cpus is maintained by CPUHotplugState in GED and +is made accessable to guest through memory region. + +This also adds migration support to CPUHotplugState. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++- + hw/acpi/cpu.c | 1 - + hw/acpi/generic_event_device.c | 35 ++++++++++++++++++++++++++ + hw/arm/Kconfig | 1 + + include/hw/acpi/cpu.h | 2 ++ + include/hw/acpi/generic_event_device.h | 4 +++ + 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 +--- 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: + 0: Memory hotplug event + 1: System power down event +- 2-31: Reserved ++ 2: CPU hotplug event ++ 3-31: Reserved + + **write_access:** + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 72ad1fcff2..cb6bb67f3c 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 +--- 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[] = { + ACPI_GED_MEM_HOTPLUG_EVT, + ACPI_GED_PWR_DOWN_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), + aml_int(0x80))); + break; ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ aml_append(if_ctx, aml_call0("\\_SB.CPUS.CSCN")); ++ break; + 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)) { + 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) { + sel = ACPI_GED_PWR_DOWN_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 = { + } + }; + ++static const VMStateDescription vmstate_cpuhp_state = { ++ .name = "acpi-ged/cpuhp", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static const VMStateDescription vmstate_ged_state = { + .name = "acpi-ged-state", + .version_id = 1, +@@ -244,6 +262,7 @@ static const VMStateDescription vmstate_acpi_ged = { + }, + .subsections = (const VMStateDescription * []) { + &vmstate_memhp_state, ++ &vmstate_cpuhp_state, + NULL + } + }; +@@ -254,6 +273,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, + 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); ++ ++ mc = MACHINE_GET_CLASS(qdev_get_machine()); ++ if (!mc->possible_cpu_arch_ids) { ++ /* ++ * MachineClass should support possible_cpu_arch_ids in ++ * cpu_hotplug_hw_init below. ++ */ ++ return; ++ } ++ ++ memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container", ++ ACPI_CPU_HOTPLUG_REG_LEN); ++ sysbus_init_mmio(sbd, &s->container_cpuhp); ++ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), ++ &s->cpuhp_state, 0); + } + + static void acpi_ged_class_init(ObjectClass *class, void *data) +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index ad7f7c089b..15e18b0a48 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -24,6 +24,7 @@ config ARM_VIRT + select DIMM + select ACPI_MEMORY_HOTPLUG + select ACPI_HW_REDUCED ++ 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 +--- 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 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -62,6 +62,7 @@ + #include "hw/sysbus.h" + #include "hw/acpi/memory_hotplug.h" + #include "hw/arm/virt.h" ++#include "hw/acpi/cpu.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" + +@@ -83,6 +84,7 @@ + */ + #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 + #define ACPI_GED_PWR_DOWN_EVT 0x2 ++#define ACPI_GED_CPU_HOTPLUG_EVT 0x4 + + typedef struct GEDState { + MemoryRegion io; +@@ -93,6 +95,8 @@ typedef struct AcpiGedState { + SysBusDevice parent_obj; + MemHotplugState memhp_state; + MemoryRegion container_memhp; ++ CPUHotplugState cpuhp_state; ++ MemoryRegion container_cpuhp; + GEDState ged_state; + uint32_t ged_event_bitmap; + qemu_irq irq; +-- +2.19.1 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 new file mode 100644 index 0000000000000000000000000000000000000000..30f210b33b66332cc0c16b5d2ddb706a177a2130 --- /dev/null +++ b/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch @@ -0,0 +1,95 @@ +From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 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 + +The count of possible CPUs is exposed to guest through the count +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(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index dbe9acb148..efac788ba1 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)); ++ static bool pmu; ++ ++ if (uid == 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) + { + 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; ++ /* 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); ++ for (i = 0; i < num_cpu; i++) { ++ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data); + } + + 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 + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..6bda35c51a3952121a155081bf0a37ce3534da25 --- /dev/null +++ b/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch @@ -0,0 +1,108 @@ +From a3097eed8b642dc6fe891112340821e869b90cc2 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 + +To realize CPU hotplug, the cpus aml within ACPI DSDT should contain +_MAT mathod, which is equal to the GICC struct in ACPI MADT. Factor +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(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index f48733d9f2..4b6aace433 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); + } + ++void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *possible_cpus, GArray *entry) ++{ ++ 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)); ++ ++ 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); ++ } ++ 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)); ++ } ++} ++ + /* 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)); +- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); +- +- 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); +- } +- 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); + } + + if (vms->gic_version == 3) { +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 3dfefca93b..6b1f10b231 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -37,6 +37,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "hw/intc/arm_gicv3_common.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) + + void virt_acpi_setup(VirtMachineState *vms); ++void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *cpu_list, GArray *entry); + + /* Return the number of used redistributor regions */ + static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) +-- +2.19.1 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..d60205b9f325388508434a7fb1e55ed8caa14e91 --- /dev/null +++ b/add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch @@ -0,0 +1,73 @@ +From 3a3ed44feeb4f17530cd87c77e13dc4dd5aa1ebc Mon Sep 17 00:00:00 2001 +From: Jiadong Zeng +Date: Thu, 11 Nov 2021 14:25:38 +0800 +Subject: [PATCH] add Phytium's CPU models: FT-2000+ and Tengyun-S2500. + +Signed-off-by: Jiadong Zeng +--- + 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 133d36a400..f816d64575 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -194,6 +194,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("host"), + ARM_CPU_TYPE_NAME("max"), + }; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index a1649f8844..4cf5b89db0 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -327,6 +327,32 @@ static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name, + error_propagate(errp, err); + } + ++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; +@@ -442,6 +468,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 = "max", .initfn = aarch64_max_initfn }, + { .name = NULL } + }; +-- +2.27.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..7926e7fa0db4ef16737a89782ea661273ef8c4d3 --- /dev/null +++ b/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch @@ -0,0 +1,116 @@ +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/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch b/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch new file mode 100644 index 0000000000000000000000000000000000000000..b3e487ba8852dd073b059485187baed82a812d20 --- /dev/null +++ b/arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch @@ -0,0 +1,68 @@ +From 03211772cd6e20e8ea9d63fceffb895b08ead8ac Mon Sep 17 00:00:00 2001 +From: zhanghao1 +Date: Tue, 11 May 2021 19:55:52 +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 new file mode 100644 index 0000000000000000000000000000000000000000..84903c34d5a86cac12aadf7d35271295b49f143d --- /dev/null +++ b/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch @@ -0,0 +1,42 @@ +From d8e0b51447d8c64788cd7f9b0fa75c4ccb06f8eb 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 + +This hook will be called in get_cpu_status, which is called +during cpu hotplug. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + target/arm/cpu.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 39bbe7e2d7..1ccb30e5eb 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"); + } + ++static int64_t arm_cpu_get_arch_id(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ return cpu->mp_affinity; ++} ++ + 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; + 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 diff --git a/arm-virt-Add-CPU-hotplug-framework.patch b/arm-virt-Add-CPU-hotplug-framework.patch new file mode 100644 index 0000000000000000000000000000000000000000..5de672afeab55fe5af5da3d2ce58aa2e9ae1435d --- /dev/null +++ b/arm-virt-Add-CPU-hotplug-framework.patch @@ -0,0 +1,66 @@ +From 6d287b3f1d961cc4adda1c6a452f41db84466f5a 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 + +Establish the CPU hotplug framework for arm/virt, we will add +necessary code legs to this framework gradually to realize CPU +hotplug finally. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index d09a5773df..0bd37af26c 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2077,11 +2077,25 @@ out: + error_propagate(errp, local_err); + } + ++static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ /* Currently nothing to do */ ++} ++ ++static void virt_cpu_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ /* Currently nothing to do */ ++} ++ + 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); ++ } 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, + } + 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) || +- (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { ++ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || ++ object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + return HOTPLUG_HANDLER(machine); + } + +-- +2.19.1 diff --git a/arm-virt-Add-CPU-topology-support.patch b/arm-virt-Add-CPU-topology-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7813c637449328c5fecf7575d27a06fa1fa0700 --- /dev/null +++ b/arm-virt-Add-CPU-topology-support.patch @@ -0,0 +1,219 @@ +From cde57fcae2ed16a10e1ef7f2da0ec368883988ba 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 + +The CPU topology specified by user (through -smp options) is used in +ACPI PPTT. Now we will use this information to locate which CPU to +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(-) + create mode 100644 include/hw/arm/topology.h + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 0bd37af26c..64532b61b2 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -36,6 +36,7 @@ + #include "hw/sysbus.h" + #include "hw/arm/boot.h" + #include "hw/arm/primecell.h" ++#include "hw/arm/topology.h" + #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) + 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) + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { + ms->possible_cpus->cpus[n].type = ms->cpu_type; ++ ms->possible_cpus->cpus[n].vcpus_count = 1; + 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); ++ 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_core_id = true; ++ ms->possible_cpus->cpus[n].props.core_id = topo.core_id; + ms->possible_cpus->cpus[n].props.has_thread_id = true; +- ms->possible_cpus->cpus[n].props.thread_id = n; ++ ms->possible_cpus->cpus[n].props.thread_id = topo.smt_id; + } + return ms->possible_cpus; + } +@@ -2080,7 +2089,62 @@ out: + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- /* Currently nothing to do */ ++ CPUState *cs = CPU(dev); ++ ARMCPUTopoInfo topo; ++ ARMCPU *cpu = ARM_CPU(dev); ++ MachineState *ms = MACHINE(hotplug_dev); ++ 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 (cs->cpu_index == UNASSIGNED_CPU_INDEX) { ++ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; ++ 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->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); ++ return; ++ } ++ if (cpu->thread_id < 0 || cpu->thread_id >= smp_threads) { ++ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", ++ cpu->thread_id, smp_threads - 1); ++ return; ++ } ++ ++ topo.pkg_id = cpu->socket_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); ++ } ++ ++ /* if 'address' properties socket-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); ++ 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); ++ return; ++ } ++ cpu->socket_id = topo.pkg_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); ++ return; ++ } ++ cpu->core_id = topo.core_id; ++ ++ if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) { ++ error_setg(errp, "property thread-id: %u doesn't match set idx:" ++ " 0x%x (thread-id: %u)", cpu->thread_id, cs->cpu_index, topo.smt_id); ++ return; ++ } ++ 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 +--- /dev/null ++++ b/include/hw/arm/topology.h +@@ -0,0 +1,61 @@ ++/* ++ * ARM CPU topology data structures and functions ++ * ++ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD. ++ * ++ * 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 . ++ */ ++ ++#ifndef HW_ARM_TOPOLOGY_H ++#define HW_ARM_TOPOLOGY_H ++ ++typedef struct ARMCPUTopoInfo { ++ unsigned pkg_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, ++ unsigned nr_threads, ++ const ARMCPUTopoInfo *topo) ++{ ++ assert(nr_cores > 0); ++ assert(nr_threads > 0); ++ assert(topo != NULL); ++ ++ return topo->pkg_id * nr_cores * nr_threads + ++ topo->core_id * nr_threads + ++ topo->smt_id; ++} ++ ++/* Calculate thread/core/package topology ++ * based on (contiguous) CPU index ++ */ ++static inline void topo_ids_from_idx(unsigned cpu_index, ++ unsigned nr_cores, ++ unsigned nr_threads, ++ ARMCPUTopoInfo *topo) ++{ ++ 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; ++} ++ ++#endif /* HW_ARM_TOPOLOGY_H */ ++ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 1ccb30e5eb..91f1e36cd8 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2560,6 +2560,9 @@ 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("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 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -916,6 +916,9 @@ struct ARMCPU { + QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + + int32_t node_id; /* NUMA node this CPU belongs to */ ++ int32_t socket_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 diff --git a/arm-virt-Add-cpu_hotplug_enabled-field.patch b/arm-virt-Add-cpu_hotplug_enabled-field.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b8bc47f6d31dba63e1148c22cc803204ce82e70 --- /dev/null +++ b/arm-virt-Add-cpu_hotplug_enabled-field.patch @@ -0,0 +1,61 @@ +From 31873c4c0454fb17654f57adece2bc396415f8bf 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 + +Some conditions must be satisfied to support CPU hotplug, including +ACPI, GED, 64bit CPU, GICv3. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 7 +++++++ + include/hw/arm/virt.h | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index dda22194b5..304a4c2d31 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1645,6 +1645,7 @@ static void machvirt_init(MachineState *machine) + { + VirtMachineState *vms = VIRT_MACHINE(machine); + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); ++ MachineState *ms = MACHINE(machine); + 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) + 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) + + create_fdt(vms); + ++ cpu_class = object_class_by_name(ms->cpu_type); ++ vms->cpu_hotplug_enabled = has_ged && firmware_loaded && ++ acpi_enabled && vms->gic_version == 3 && ++ !!object_class_dynamic_cast(cpu_class, TYPE_AARCH64_CPU); ++ + possible_cpus = mc->possible_cpu_arch_ids(machine); + 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 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -126,6 +126,7 @@ typedef struct { + bool highmem_ecam; + bool its; + bool virt; ++ bool cpu_hotplug_enabled; + int32_t gic_version; + VirtIOMMUType iommu; + struct arm_boot_info bootinfo; +-- +2.19.1 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 new file mode 100644 index 0000000000000000000000000000000000000000..c81227d8a3ef4ff3ffc74f7b848b42e8cc79c762 --- /dev/null +++ b/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch @@ -0,0 +1,66 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..ade3ccfd9fe50a78c8ef33ded3463e52b5f6d6c3 --- /dev/null +++ b/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch @@ -0,0 +1,100 @@ +From d38d1d4e859450535ddc6bf0c7a59f6217b1403c 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 + +Attach cpus aml building and GED support for CPU hotplug to +arm/virt, but currently we make it diabled by not add CPU +hotplug event to GED. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 15 ++++++++++++++- + hw/arm/virt.c | 6 ++++++ + include/hw/arm/virt.h | 1 + + 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 +--- 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; + const int *irqmap = vms->irqmap; ++ bool cpu_aml_built = false; + + dsdt = init_aml_allocator(); + /* Reserve space for header */ +@@ -817,7 +818,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_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) + AML_SYSTEM_MEMORY, + memmap[VIRT_PCDIMM_ACPI].base); + } ++ ++ if (event & ACPI_GED_CPU_HOTPLUG_EVT) { ++ CPUHotplugFeatures opts = { ++ .acpi_1_compatible = false, .has_legacy_cphp = false ++ }; ++ build_cpus_aml(dsdt, ms, opts, memmap[VIRT_CPU_ACPI].base, ++ "\\_SB", NULL, AML_SYSTEM_MEMORY); ++ cpu_aml_built = true; ++ } ++ } ++ ++ if (!cpu_aml_built) { ++ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); + } + + acpi_dsdt_add_power_button(scope); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 8638aeedb7..d09a5773df 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 }, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, + [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; + } + ++ /* event |= ACPI_GED_CPU_HOTPLUG_EVT; ++ * Currently CPU hotplug is not enabled. ++ */ ++ + 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_mmio_map(SYS_BUS_DEVICE(dev), 2, 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); +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index cbdea7ff32..6880ebe07c 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -81,6 +81,7 @@ enum { + VIRT_SECURE_MEM, + VIRT_PCDIMM_ACPI, + VIRT_ACPI_GED, ++ VIRT_CPU_ACPI, + VIRT_LOWMEMMAP_LAST, + }; + +-- +2.19.1 diff --git a/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch b/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2d9a3cb0a48436433a30670e8517d7dafb9bca4 --- /dev/null +++ b/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch @@ -0,0 +1,124 @@ +From bf47ef282bfe8b0a98e1f87d8708051ffa7192a1 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 + +Establish all pre-sizing facilities based on cpu_hotplug_enabled +field. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 12 +++++++++++- + hw/arm/virt.c | 14 ++++++++++++-- + target/arm/kvm.c | 6 +++--- + 3 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index efac788ba1..2cfac7b84f 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; + ++ 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); + } +@@ -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 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -767,6 +767,9 @@ static void create_gic(VirtMachineState *vms) + 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) + 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"); ++ exit(1); ++ } ++ } ++ + if (n >= smp_cpus) { +- 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; +- 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 +--- 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) + + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); + +- if (smp_cpus > 256 && ++ if (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 diff --git a/arm-virt-Start-up-CPU-hot-plug.patch b/arm-virt-Start-up-CPU-hot-plug.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ba620a2215710682afa4ccdfd0d5cad53556680 --- /dev/null +++ b/arm-virt-Start-up-CPU-hot-plug.patch @@ -0,0 +1,159 @@ +From 11f9628ceff019259ff12ce469deafbf50eb3075 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 + +All the CPU hotplug facilities are ready. Assemble them +to start up CPU hot-plug capability for arm/virt. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + 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(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index c6a99e683a..112a6ae7cb 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -48,6 +48,8 @@ + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" + #include "sysemu/kvm.h" ++#include "sysemu/cpus.h" ++#include "sysemu/hw_accel.h" + #include "hw/loader.h" + #include "exec/address-spaces.h" + #include "qemu/bitops.h" +@@ -649,9 +651,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + event |= ACPI_GED_MEM_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); + 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); + } ++ ++ /* 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, + DeviceState *dev, Error **errp) + { +- /* Currently nothing to do */ ++ CPUArchId *cpu_slot; ++ CPUState *cs = CPU(dev); ++ int ncpu = cs->cpu_index; ++ MachineState *ms = MACHINE(hotplug_dev); ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ GICv3State *gicv3; ++ ARMGICv3CommonClass *agcc; ++ Error *local_err = NULL; ++ ++ if (dev->hotplugged) { ++ /* Realize GIC related parts of CPU */ ++ assert(vms->gic_version == 3); ++ gicv3 = ARM_GICV3_COMMON(vms->gic); ++ agcc = ARM_GICV3_COMMON_GET_CLASS(gicv3); ++ agcc->cpu_hotplug_realize(gicv3, ncpu); ++ connect_gic_cpu_irqs(vms, ncpu); ++ ++ /* 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 (vms->acpi_dev) { ++ hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ } ++ ++ vms->boot_cpus++; ++ if (vms->fw_cfg) { ++ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus); ++ } ++ ++ cpu_slot = &ms->possible_cpus->cpus[ncpu]; ++ cpu_slot->cpu = OBJECT(dev); ++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) + 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; ++ mc->has_hotpluggable_cpus = true; + 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/include/hw/arm/virt.h b/include/hw/arm/virt.h +index b4c53d920e..a9429bed25 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -140,6 +140,7 @@ typedef struct { + uint32_t msi_phandle; + uint32_t iommu_phandle; + int psci_conduit; ++ uint32_t boot_cpus; + 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 +--- 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; + ++ 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 diff --git a/arm-virt-Support-CPU-cold-plug.patch b/arm-virt-Support-CPU-cold-plug.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f96fede24c1e4f18d0f05c1987b20cc5a883b93 --- /dev/null +++ b/arm-virt-Support-CPU-cold-plug.patch @@ -0,0 +1,92 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..297ccf633fe69840b863f10109ee4271f16c11a1 --- /dev/null +++ b/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch @@ -0,0 +1,65 @@ +From 91fed8840b004ec7bc91969afa10f03e13f311c4 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 + +We will support CPU hotplug soon, so extend memory region size to +allow hotplugged CPU access cpufreq space. + +Signed-off-by: Keqian Zhu +--- + hw/acpi/cpufreq.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c +index d02a25a6de..38dcab5683 100644 +--- a/hw/acpi/cpufreq.c ++++ b/hw/acpi/cpufreq.c +@@ -84,6 +84,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, + uint64_t r; + 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) { + 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, + static void cpufreq_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) + { ++ CpuhzState *s = CPUFREQ(opaque); + 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) + 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..f08f83de6505d7810cb7b6753bd00034e3921862 --- /dev/null +++ b/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch @@ -0,0 +1,121 @@ +From 2fdece10dac6161cb6c1f0f05247391aa3269eed 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 + +When CPU hotplug is enabled, we will use build_cpus_aml instead of +acpi_dsdt_add_cpus, so factor out CPPC building and we can reuse it +in build_cpus_aml. + +Signed-off-by: Keqian Zhu +--- + hw/acpi/generic_event_device.c | 1 + + hw/arm/virt-acpi-build.c | 33 +++++++++++++++++----------- + 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 +--- 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) + aml_append(dev, aml_name_decl("_CPC", cpc)); + } + +-static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, +- const MemMapEntry *cppc_memmap) ++void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int ncpu, int num_cpu, Aml *dev) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); ++ const MemMapEntry *cppc_memmap = &vms->memmap[VIRT_CPUFREQ]; ++ ++ /* ++ * Append _CPC and _PSD to support CPU frequence show ++ * Check CPPC available by DESIRED_PERF register ++ */ ++ if (cppc_regs_offset[DESIRED_PERF] != -1) { ++ acpi_dsdt_add_cppc(dev, ++ cppc_memmap->base + ncpu * CPPC_REG_PER_CPU_STRIDE, ++ cppc_regs_offset); ++ acpi_dsdt_add_psd(dev, num_cpu); ++ } ++} ++ ++static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, VirtMachineState *vms) + { + uint16_t i; + +@@ -121,16 +137,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, + 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 +- */ +- if (cppc_regs_offset[DESIRED_PERF] != -1) { +- acpi_dsdt_add_cppc(dev, +- cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE, +- cppc_regs_offset); +- acpi_dsdt_add_psd(dev, smp_cpus); +- } ++ virt_acpi_dsdt_cpu_cppc(NULL, i, smp_cpus, dev); + + aml_append(scope, dev); + } +@@ -810,7 +817,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_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); +diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h +index adcb3a816c..2952914569 100644 +--- a/include/hw/acpi/acpi_dev_interface.h ++++ b/include/hw/acpi/acpi_dev_interface.h +@@ -3,6 +3,7 @@ + + #include "qom/object.h" + #include "hw/boards.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); + void (*madt_cpu)(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *apic_ids, GArray *entry); ++ 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 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -157,6 +157,8 @@ typedef struct { + void virt_acpi_setup(VirtMachineState *vms); + void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *cpu_list, GArray *entry); ++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 diff --git a/arm-virt-gic-Construct-irqs-connection-from-create_g.patch b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e9506425f1de938d2ba70a3fb31a83561a4154e --- /dev/null +++ b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch @@ -0,0 +1,123 @@ +From 92124743f4560c490780a229f53ea5881f706383 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 + +Make the irqs can be connected to for individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 90 ++++++++++++++++++++++++++++----------------------- + 1 file changed, 49 insertions(+), 41 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 83f4887e57..55d403bad6 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); + } + ++static void connect_gic_cpu_irqs(VirtMachineState *vms, int i) ++{ ++ DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); ++ SysBusDevice *gicbusdev = SYS_BUS_DEVICE(vms->gic); ++ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; ++ int num_cpus = object_property_get_uint(OBJECT(vms->gic), "num-cpu", NULL); ++ int gic_type = vms->gic_version; ++ int irq; ++ /* Mapping from the output timer irq lines from the CPU to the ++ * GIC PPI inputs we use for the virt board. ++ */ ++ const int timer_irq[] = { ++ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, ++ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, ++ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, ++ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, ++ }; ++ ++ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { ++ qdev_connect_gpio_out(cpudev, irq, ++ qdev_get_gpio_in(vms->gic, ++ ppibase + timer_irq[irq])); ++ } ++ ++ if (gic_type == 3) { ++ 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(vms->gic, ++ ppibase + ARCH_GIC_MAINT_IRQ); ++ sysbus_connect_irq(gicbusdev, i + 4 * num_cpus, irq); ++ } ++ ++ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, ++ qdev_get_gpio_in(vms->gic, ppibase ++ + VIRTUAL_PMU_IRQ)); ++ ++ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); ++ sysbus_connect_irq(gicbusdev, i + num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); ++ sysbus_connect_irq(gicbusdev, i + 2 * num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); ++ sysbus_connect_irq(gicbusdev, i + 3 * num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++} ++ + static void create_gic(VirtMachineState *vms) + { + MachineState *ms = MACHINE(vms); +@@ -775,47 +823,7 @@ static void create_gic(VirtMachineState *vms) + * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. + */ + for (i = 0; i < smp_cpus; i++) { +- DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); +- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; +- int irq; +- /* Mapping from the output timer irq lines from the CPU to the +- * GIC PPI inputs we use for the virt board. +- */ +- const int timer_irq[] = { +- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, +- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, +- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, +- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, +- }; +- +- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { +- qdev_connect_gpio_out(cpudev, irq, +- qdev_get_gpio_in(vms->gic, +- ppibase + timer_irq[irq])); +- } +- +- if (type == 3) { +- 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(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(vms->gic, ppibase +- + VIRTUAL_PMU_IRQ)); +- +- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); +- sysbus_connect_irq(gicbusdev, i + smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); +- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); +- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++ connect_gic_cpu_irqs(vms, i); + } + + fdt_add_gic_node(vms); +-- +2.19.1 diff --git a/async-use-explicit-memory-barriers.patch b/async-use-explicit-memory-barriers.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fb68c949ad4e95cc0f908c44042096b69cf9295 --- /dev/null +++ b/async-use-explicit-memory-barriers.patch @@ -0,0 +1,171 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..43f9e720e27cca7c1d5340993f6fe38776a24239 --- /dev/null +++ b/ati-check-x-y-display-parameter-values.patch @@ -0,0 +1,53 @@ +From e80d8d7f805e07ba6f012423739e83553ea024ef 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 new file mode 100644 index 0000000000000000000000000000000000000000..ca87976e21d0fc851d24b84fafb42fca6257fcdd --- /dev/null +++ b/ati-use-vga_read_byte-in-ati_cursor_define.patch @@ -0,0 +1,198 @@ +From 9bc85b4b6060287ee0178ceba35f3233a53e180a 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 new file mode 100644 index 0000000000000000000000000000000000000000..ef1d8b646c607a5afb6278ab229efc4a5a15965f --- /dev/null +++ b/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch @@ -0,0 +1,91 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..b80c9dc973015dd83e3d9c0c000dd0b15b303608 --- /dev/null +++ b/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch @@ -0,0 +1,59 @@ +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/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch b/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch new file mode 100644 index 0000000000000000000000000000000000000000..1dc656892b5f124d3ad732aed9c31b0f71a3363b --- /dev/null +++ b/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..4972f084649f70253978ad8fb1d3842bbf741d81 --- /dev/null +++ b/block-Add-bdrv_co_get_self_request.patch @@ -0,0 +1,59 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..11ddf50a6788d5470066b8666a4dda464c6d94c9 --- /dev/null +++ b/block-Add-error-retry-param-setting.patch @@ -0,0 +1,226 @@ +From d5de0271f824fe5f74a47252d78fc9177ef68b5a 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 + +Add "retry_interval" and "retry_timeout" parameter for drive and device +option. These parameter are valid only when werror/rerror=retry. + +eg. --drive file=image,rerror=retry,retry_interval=1000,retry_timeout=5000 + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + block/block-backend.c | 13 +++++++-- + blockdev.c | 50 ++++++++++++++++++++++++++++++++++ + hw/block/block.c | 10 +++++++ + include/hw/block/block.h | 7 ++++- + include/sysemu/block-backend.h | 5 ++++ + 5 files changed, 81 insertions(+), 4 deletions(-) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 0fe99ffe52..2d812e2254 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -31,9 +31,6 @@ + + static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); + +-/* block backend default retry interval */ +-#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000 +- + 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) + bdrv_drain_all_end(); + } + ++void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval) ++{ ++ blk->retry_interval = interval; ++} ++ ++void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout) ++{ ++ blk->retry_timeout = timeout; ++} ++ + static bool blk_error_retry_timeout(BlockBackend *blk) + { + /* No timeout set, infinite retries. */ +diff --git a/blockdev.c b/blockdev.c +index 0f49fd290e..99c92b96d2 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -470,6 +470,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; ++ int64_t retry_interval, retry_timeout; + 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, + } + } + ++ retry_interval = qemu_opt_get_number(opts, "retry_interval", ++ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL); ++ retry_timeout = qemu_opt_get_number(opts, "retry_timeout", 0); ++ + if (snapshot) { + bdrv_flags |= BDRV_O_SNAPSHOT; + } +@@ -629,6 +634,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); ++ if (on_read_error == BLOCKDEV_ON_ERROR_RETRY || ++ on_write_error == BLOCKDEV_ON_ERROR_RETRY) { ++ blk_set_on_error_retry_interval(blk, retry_interval); ++ blk_set_on_error_retry_timeout(blk, retry_timeout); ++ } + + if (!monitor_add_blk(blk, id, errp)) { + blk_unref(blk); +@@ -754,6 +764,14 @@ QemuOptsList qemu_legacy_drive_opts = { + .name = "werror", + .type = QEMU_OPT_STRING, + .help = "write error action", ++ },{ ++ .name = "retry_interval", ++ .type = QEMU_OPT_NUMBER, ++ .help = "interval for retry action in millisecond", ++ },{ ++ .name = "retry_timeout", ++ .type = QEMU_OPT_NUMBER, ++ .help = "timeout for retry action in millisecond", + },{ + .name = "copy-on-read", + .type = QEMU_OPT_BOOL, +@@ -776,6 +794,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; ++ int64_t retry_interval, retry_timeout; + 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, + qdict_put_str(bs_opts, "rerror", rerror); + } + ++ if (qemu_opt_find(legacy_opts, "retry_interval")) { ++ if ((werror == NULL || strcmp(werror, "retry")) && ++ (rerror == NULL || strcmp(rerror, "retry"))) { ++ error_setg(errp, "retry_interval is only supported " ++ "by werror/rerror=retry"); ++ goto fail; ++ } ++ retry_interval = qemu_opt_get_number(legacy_opts, "retry_interval", ++ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL); ++ qdict_put_int(bs_opts, "retry_interval", retry_interval); ++ } ++ ++ if (qemu_opt_find(legacy_opts, "retry_timeout")) { ++ if ((werror == NULL || strcmp(werror, "retry")) && ++ (rerror == NULL || strcmp(rerror, "retry"))) { ++ error_setg(errp, "retry_timeout is only supported " ++ "by werror/rerror=retry"); ++ goto fail; ++ } ++ retry_timeout = qemu_opt_get_number(legacy_opts, "retry_timeout", 0); ++ qdict_put_int(bs_opts, "retry_timeout", retry_timeout); ++ } ++ + /* Actual block device init: Functionality shared with blockdev-add */ + blk = blockdev_init(filename, bs_opts, &local_err); + bs_opts = NULL; +@@ -4593,6 +4635,14 @@ QemuOptsList qemu_common_drive_opts = { + .name = "werror", + .type = QEMU_OPT_STRING, + .help = "write error action", ++ },{ ++ .name = "retry_interval", ++ .type = QEMU_OPT_NUMBER, ++ .help = "interval for retry action in millisecond", ++ },{ ++ .name = "retry_timeout", ++ .type = QEMU_OPT_NUMBER, ++ .help = "timeout for retry action in millisecond", + },{ + .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 +--- a/hw/block/block.c ++++ b/hw/block/block.c +@@ -134,6 +134,16 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, + blk_set_enable_write_cache(blk, wce); + blk_set_on_error(blk, rerror, werror); + ++ if (rerror == BLOCKDEV_ON_ERROR_RETRY || ++ werror == BLOCKDEV_ON_ERROR_RETRY) { ++ if (conf->retry_interval >= 0) { ++ blk_set_on_error_retry_interval(blk, conf->retry_interval); ++ } ++ if (conf->retry_timeout >= 0) { ++ blk_set_on_error_retry_timeout(blk, conf->retry_timeout); ++ } ++ } ++ + return true; + } + +diff --git a/include/hw/block/block.h b/include/hw/block/block.h +index 607539057a..d12603aabd 100644 +--- a/include/hw/block/block.h ++++ b/include/hw/block/block.h +@@ -30,6 +30,8 @@ typedef struct BlockConf { + bool share_rw; + BlockdevOnError rerror; + BlockdevOnError werror; ++ int64_t retry_interval; ++ int64_t retry_timeout; + } 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) + DEFINE_PROP_BLOCKDEV_ON_ERROR("rerror", _state, _conf.rerror, \ + BLOCKDEV_ON_ERROR_AUTO), \ + DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \ +- BLOCKDEV_ON_ERROR_AUTO) ++ BLOCKDEV_ON_ERROR_AUTO), \ ++ DEFINE_PROP_INT64("retry_interval", _state, _conf.retry_interval, \ ++ -1), \ ++ DEFINE_PROP_INT64("retry_timeout", _state, _conf.retry_timeout, -1) + + /* Backend access helpers */ + +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index 58dde446ca..dc10e507ae 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -25,6 +25,9 @@ + */ + #include "block/block.h" + ++/* block backend default retry interval */ ++#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000 ++ + /* Callbacks for block device models */ + typedef struct BlockDevOps { + /* +@@ -184,6 +187,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); ++void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval); ++void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout); + void blk_error_retry_reset_timeout(BlockBackend *blk); + void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, + BlockdevOnError on_write_error); +-- +2.27.0 + diff --git a/block-Add-sanity-check-when-setting-retry-parameters.patch b/block-Add-sanity-check-when-setting-retry-parameters.patch new file mode 100644 index 0000000000000000000000000000000000000000..5fe7374a10d8f8c59f7fb2edcd514ded1c02a7f4 --- /dev/null +++ b/block-Add-sanity-check-when-setting-retry-parameters.patch @@ -0,0 +1,118 @@ +From 2e3652ca5ec63d6b153078ee9175ed4baa042df0 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 + +Add sanity check when setting retry parameters to avoid invalid retry +configuration. + +Signed-off-by: Jiahui Cen +--- + 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(-) + +diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c +index 81c97f48a7..02a824fc68 100644 +--- a/hw/core/qdev-properties.c ++++ b/hw/core/qdev-properties.c +@@ -620,6 +620,51 @@ const PropertyInfo qdev_prop_blockdev_on_error = { + .set_default_value = set_default_value_enum, + }; + ++static void set_retry_time(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ DeviceState *dev = DEVICE(obj); ++ Property *prop = opaque; ++ int64_t value, *ptr = qdev_get_prop_ptr(dev, prop); ++ Error *local_err = NULL; ++ ++ if (dev->realized) { ++ qdev_prop_set_after_realize(dev, name, errp); ++ return; ++ } ++ ++ visit_type_int64(v, name, &value, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ /* value should not be negative */ ++ if (value < 0) { ++ error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, ++ dev->id ? : "", name, (int64_t)value, 0L, LONG_MAX); ++ return; ++ } ++ ++ *ptr = value; ++} ++ ++const PropertyInfo qdev_prop_blockdev_retry_interval = { ++ .name = "BlockdevRetryInterval", ++ .description = "Interval for retry error handling policy", ++ .get = get_int64, ++ .set = set_retry_time, ++ .set_default_value = set_default_value_int, ++}; ++ ++const PropertyInfo qdev_prop_blockdev_retry_timeout = { ++ .name = "BlockdevRetryTimeout", ++ .description = "Timeout for retry error handling policy", ++ .get = get_int64, ++ .set = set_retry_time, ++ .set_default_value = set_default_value_int, ++}; ++ + /* --- BIOS CHS translation */ + + QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int)); +diff --git a/include/hw/block/block.h b/include/hw/block/block.h +index d12603aabd..c5276fec0d 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) + BLOCKDEV_ON_ERROR_AUTO), \ + DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \ + BLOCKDEV_ON_ERROR_AUTO), \ +- DEFINE_PROP_INT64("retry_interval", _state, _conf.retry_interval, \ +- -1), \ +- DEFINE_PROP_INT64("retry_timeout", _state, _conf.retry_timeout, -1) ++ DEFINE_PROP_BLOCKDEV_RETRY_INTERVAL("retry_interval", _state, \ ++ _conf.retry_interval, 1000), \ ++ DEFINE_PROP_BLOCKDEV_RETRY_TIMEOUT("retry_timeout", _state, \ ++ _conf.retry_timeout, 0) + + /* Backend access helpers */ + +diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h +index 1eae5ab056..4585c200df 100644 +--- a/include/hw/qdev-properties.h ++++ b/include/hw/qdev-properties.h +@@ -25,6 +25,8 @@ extern const PropertyInfo qdev_prop_macaddr; + extern const PropertyInfo qdev_prop_on_off_auto; + extern const PropertyInfo qdev_prop_losttickpolicy; + extern const PropertyInfo qdev_prop_blockdev_on_error; ++extern const PropertyInfo qdev_prop_blockdev_retry_interval; ++extern const PropertyInfo qdev_prop_blockdev_retry_timeout; + extern const PropertyInfo qdev_prop_bios_chs_trans; + extern const PropertyInfo qdev_prop_fdc_drive_type; + extern const PropertyInfo qdev_prop_drive; +@@ -211,6 +213,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) ++#define DEFINE_PROP_BLOCKDEV_RETRY_INTERVAL(_n, _s, _f, _d) \ ++ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_retry_interval, \ ++ int64_t) ++#define DEFINE_PROP_BLOCKDEV_RETRY_TIMEOUT(_n, _s, _f, _d) \ ++ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_blockdev_retry_timeout, \ ++ int64_t) + #define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) + #define DEFINE_PROP_BLOCKSIZE(_n, _s, _f) \ +-- +2.27.0 + diff --git a/block-Make-wait-mark-serialising-requests-public.patch b/block-Make-wait-mark-serialising-requests-public.patch new file mode 100644 index 0000000000000000000000000000000000000000..162463c7769093014562846d9d7c0da4e131b5e3 --- /dev/null +++ b/block-Make-wait-mark-serialising-requests-public.patch @@ -0,0 +1,131 @@ +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-backend-Add-device-specific-retry-callback.patch b/block-backend-Add-device-specific-retry-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0590b379b027e5a390873af326be1838ae748d2 --- /dev/null +++ b/block-backend-Add-device-specific-retry-callback.patch @@ -0,0 +1,53 @@ +From 272a438da65454a4d59091960061a0dc05c58e47 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 + +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' +on errors and the device supports retry action. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -958,6 +958,14 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, + blk->dev_ops = ops; + blk->dev_opaque = opaque; + ++ if ((blk->on_read_error == BLOCKDEV_ON_ERROR_RETRY || ++ blk->on_write_error == BLOCKDEV_ON_ERROR_RETRY) && ++ ops->retry_request_cb) { ++ blk->retry_timer = aio_timer_new(blk->ctx, QEMU_CLOCK_REALTIME, ++ SCALE_MS, ops->retry_request_cb, ++ opaque); ++ } ++ + /* Are we currently quiesced? Should we enforce this right now? */ + 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 +--- 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. + */ + void (*drained_end)(void *opaque); ++ /* ++ * Runs when retrying failed requests. ++ */ ++ void (*retry_request_cb)(void *opaque); + } BlockDevOps; + + /* This struct is embedded in (the private) BlockBackend struct and contains +-- +2.27.0 + diff --git a/block-backend-Add-timeout-support-for-retry.patch b/block-backend-Add-timeout-support-for-retry.patch new file mode 100644 index 0000000000000000000000000000000000000000..f431ba378edb3950ead64def3f72346a14797402 --- /dev/null +++ b/block-backend-Add-timeout-support-for-retry.patch @@ -0,0 +1,74 @@ +From 9791384b6919c436be49d9b0e1b4e1a247ac41ab 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 + +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 +successful retry. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1633,6 +1633,29 @@ void blk_drain_all(void) + bdrv_drain_all_end(); + } + ++static bool blk_error_retry_timeout(BlockBackend *blk) ++{ ++ /* No timeout set, infinite retries. */ ++ if (!blk->retry_timeout) { ++ return false; ++ } ++ ++ /* The first time an error occurs. */ ++ if (!blk->retry_start_time) { ++ blk->retry_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ++ return false; ++ } ++ ++ return qemu_clock_get_ms(QEMU_CLOCK_REALTIME) > (blk->retry_start_time + ++ blk->retry_timeout); ++} ++ ++void blk_error_retry_reset_timeout(BlockBackend *blk) ++{ ++ if (blk->retry_timer && blk->retry_start_time) ++ blk->retry_start_time = 0; ++} ++ + 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, + case BLOCKDEV_ON_ERROR_IGNORE: + return BLOCK_ERROR_ACTION_IGNORE; + case BLOCKDEV_ON_ERROR_RETRY: +- return (blk->retry_timer) ? ++ return (blk->retry_timer && !blk_error_retry_timeout(blk)) ? + BLOCK_ERROR_ACTION_RETRY : BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_AUTO: + default: +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index b58dc6bde8..58dde446ca 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -184,6 +184,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); ++void blk_error_retry_reset_timeout(BlockBackend *blk); + void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, + BlockdevOnError on_write_error); + BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read); +-- +2.27.0 + diff --git a/block-backend-Enable-retry-action-on-errors.patch b/block-backend-Enable-retry-action-on-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..8865ed7dcc9f8795e6fc5c790c8556a32fbce853 --- /dev/null +++ b/block-backend-Enable-retry-action-on-errors.patch @@ -0,0 +1,42 @@ +From acb77c68d6aba17436554d0255278a934fa70dda 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 + +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 +--- + 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 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1660,6 +1660,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; ++ case BLOCKDEV_ON_ERROR_RETRY: ++ return (blk->retry_timer) ? ++ BLOCK_ERROR_ACTION_RETRY : BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_AUTO: + default: + abort(); +@@ -1707,6 +1710,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); ++ } else if (action == BLOCK_ERROR_ACTION_RETRY) { ++ timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ++ blk->retry_interval); ++ send_qmp_error_event(blk, action, is_read, error); + } else { + send_qmp_error_event(blk, action, is_read, error); + } +-- +2.27.0 + diff --git a/block-backend-Introduce-retry-timer.patch b/block-backend-Introduce-retry-timer.patch new file mode 100644 index 0000000000000000000000000000000000000000..6f812b7e57bbd565e87c210fd02cc19d3c201cc5 --- /dev/null +++ b/block-backend-Introduce-retry-timer.patch @@ -0,0 +1,69 @@ +From c2f4b43ed0858a02138f8e893e2a49732317a3ba 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 + +Add a timer to regularly trigger retry on errors. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -31,6 +31,9 @@ + + static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); + ++/* block backend default retry interval */ ++#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000 ++ + typedef struct BlockBackendAioNotifier { + void (*attached_aio_context)(AioContext *new_context, void *opaque); + void (*detach_aio_context)(void *opaque); +@@ -88,6 +91,15 @@ struct BlockBackend { + * Accessed with atomic ops. + */ + unsigned int in_flight; ++ ++ /* Timer for retry on errors. */ ++ QEMUTimer *retry_timer; ++ /* Interval in ms to trigger next retry. */ ++ int64_t retry_interval; ++ /* Start time of the first error. Used to check timeout. */ ++ int64_t retry_start_time; ++ /* Retry timeout. 0 represents infinite retry. */ ++ int64_t retry_timeout; + }; + + typedef struct BlockBackendAIOCB { +@@ -337,6 +349,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; + ++ blk->retry_timer = NULL; ++ blk->retry_interval = BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL; ++ blk->retry_start_time = 0; ++ blk->retry_timeout = 0; ++ + block_acct_init(&blk->stats); + + notifier_list_init(&blk->remove_bs_notifiers); +@@ -423,6 +440,10 @@ static void blk_delete(BlockBackend *blk) + QTAILQ_REMOVE(&block_backends, blk, link); + drive_info_del(blk->legacy_dinfo); + block_acct_cleanup(&blk->stats); ++ if (blk->retry_timer) { ++ timer_del(blk->retry_timer); ++ timer_free(blk->retry_timer); ++ } + g_free(blk); + } + +-- +2.27.0 + diff --git a/block-backend-Stop-retrying-when-draining.patch b/block-backend-Stop-retrying-when-draining.patch new file mode 100644 index 0000000000000000000000000000000000000000..e956a76877bf71815ab1e11a235d37e0bb902e28 --- /dev/null +++ b/block-backend-Stop-retrying-when-draining.patch @@ -0,0 +1,37 @@ +From 0fbd80eac7bf2be0d6b0054a7f9195144d324f96 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 + +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 +virtual devices go back to work, they would retry those queued requests. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1741,9 +1741,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) { +- timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + +- blk->retry_interval); +- send_qmp_error_event(blk, action, is_read, error); ++ if (!blk->quiesce_counter) { ++ timer_mod(blk->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ++ blk->retry_interval); ++ send_qmp_error_event(blk, action, is_read, error); ++ } + } else { + send_qmp_error_event(blk, action, is_read, error); + } +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..73d2b9d0e5e490c3f855304e692ed68fd4029468 --- /dev/null +++ b/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch @@ -0,0 +1,95 @@ +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-file-posix-Let-post-EOF-fallocate-serialize.patch b/block-file-posix-Let-post-EOF-fallocate-serialize.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf7d34a3e54ffe24356a16185d1dfcaef603c455 --- /dev/null +++ b/block-file-posix-Let-post-EOF-fallocate-serialize.patch @@ -0,0 +1,69 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..69ceb453efac39a1fcfcc26488e04a7bb8eee0df --- /dev/null +++ b/block-file-posix-Reduce-xfsctl-use.patch @@ -0,0 +1,165 @@ +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-io-refactor-padding.patch b/block-io-refactor-padding.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a267147f5b5fbfa908edf342c02bd17481b3d70 --- /dev/null +++ b/block-io-refactor-padding.patch @@ -0,0 +1,481 @@ +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-nfs-tear-down-aio-before-nfs_close.patch b/block-nfs-tear-down-aio-before-nfs_close.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea116d0a381c18521da88b94d3ea914f0357939d --- /dev/null +++ b/block-nfs-tear-down-aio-before-nfs_close.patch @@ -0,0 +1,41 @@ +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-posix-Always-allocate-the-first-block.patch b/block-posix-Always-allocate-the-first-block.patch new file mode 100644 index 0000000000000000000000000000000000000000..166d73957ce0569929276d446a1934be17cad612 --- /dev/null +++ b/block-posix-Always-allocate-the-first-block.patch @@ -0,0 +1,343 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..f77cc06c60dd36ccd84a5ad5c5e9748bb2126c08 --- /dev/null +++ b/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch @@ -0,0 +1,66 @@ +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-snapshot-Restrict-set-of-snapshot-nodes.patch b/block-snapshot-Restrict-set-of-snapshot-nodes.patch new file mode 100644 index 0000000000000000000000000000000000000000..c29f30adc897f5b60bf8004b7f317b6e6257bf3a --- /dev/null +++ b/block-snapshot-Restrict-set-of-snapshot-nodes.patch @@ -0,0 +1,124 @@ +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/blockjob-update-nodes-head-while-removing-all-bdrv.patch b/blockjob-update-nodes-head-while-removing-all-bdrv.patch new file mode 100644 index 0000000000000000000000000000000000000000..36cedc77f7d38b124263a6f5d09e5f1dc97de5b8 --- /dev/null +++ b/blockjob-update-nodes-head-while-removing-all-bdrv.patch @@ -0,0 +1,61 @@ +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/bootp-check-bootp_input-buffer-size.patch b/bootp-check-bootp_input-buffer-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c4829eb123bc2a850da3660d22b93b641b6e73f --- /dev/null +++ b/bootp-check-bootp_input-buffer-size.patch @@ -0,0 +1,36 @@ +From ab454ca5f45a842b2517a0f4eb786b6ea3019d5a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 16:15:14 +0400 +Subject: [PATCH 3/6] bootp: check bootp_input buffer size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2021-3592 +Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44 + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/bootp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c +index 57543271..57891871 100644 +--- a/slirp/src/bootp.c ++++ b/slirp/src/bootp.c +@@ -366,9 +366,9 @@ udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + void bootp_input(struct mbuf *m) + { +- struct bootp_t *bp = mtod(m, struct bootp_t *); ++ struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t)); + +- if (bp->bp_op == BOOTP_REQUEST) { ++ if (bp && bp->bp_op == BOOTP_REQUEST) { + bootp_reply(m->slirp, bp, m_end(m)); + } + } +-- +2.27.0 + diff --git a/bootp-limit-vendor-specific-area-to-input-packet-mem.patch b/bootp-limit-vendor-specific-area-to-input-packet-mem.patch new file mode 100644 index 0000000000000000000000000000000000000000..07fe5cfd429f37a224d8910cecd7690c537d84c6 --- /dev/null +++ b/bootp-limit-vendor-specific-area-to-input-packet-mem.patch @@ -0,0 +1,161 @@ +From 3369988416bd98e97dc3d0400af165c0d9e536e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 19:25:28 +0400 +Subject: [PATCH 2/6] bootp: limit vendor-specific area to input packet memory + buffer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sizeof(bootp_t) currently holds DHCP_OPT_LEN. Remove this optional field +from the structure, to help with the following patch checking for +minimal header size. Modify the bootp_reply() function to take the +buffer boundaries and avoiding potential buffer overflow. + +Related to CVE-2021-3592. + +https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44 + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/bootp.c | 26 +++++++++++++++----------- + slirp/src/bootp.h | 2 +- + slirp/src/mbuf.c | 5 +++++ + slirp/src/mbuf.h | 1 + + 4 files changed, 22 insertions(+), 12 deletions(-) + +diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c +index 3f9ce255..57543271 100644 +--- a/slirp/src/bootp.c ++++ b/slirp/src/bootp.c +@@ -92,21 +92,22 @@ found: + return bc; + } + +-static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, ++static void dhcp_decode(const struct bootp_t *bp, ++ const uint8_t *bp_end, ++ int *pmsg_type, + struct in_addr *preq_addr) + { +- const uint8_t *p, *p_end; ++ const uint8_t *p; + int len, tag; + + *pmsg_type = 0; + preq_addr->s_addr = htonl(0L); + + p = bp->bp_vend; +- p_end = p + DHCP_OPT_LEN; + if (memcmp(p, rfc1533_cookie, 4) != 0) + return; + p += 4; +- while (p < p_end) { ++ while (p < bp_end) { + tag = p[0]; + if (tag == RFC1533_PAD) { + p++; +@@ -114,10 +115,10 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, + break; + } else { + p++; +- if (p >= p_end) ++ if (p >= bp_end) + break; + len = *p++; +- if (p + len > p_end) { ++ if (p + len > bp_end) { + break; + } + DPRINTF("dhcp: tag=%d len=%d\n", tag, len); +@@ -144,7 +145,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, + } + } + +-static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) ++static void bootp_reply(Slirp *slirp, ++ const struct bootp_t *bp, ++ const uint8_t *bp_end) + { + BOOTPClient *bc = NULL; + struct mbuf *m; +@@ -157,7 +160,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) + uint8_t client_ethaddr[ETH_ALEN]; + + /* extract exact DHCP msg type */ +- dhcp_decode(bp, &dhcp_msg_type, &preq_addr); ++ dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_addr); + DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); + if (preq_addr.s_addr != htonl(0L)) + DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); +@@ -179,9 +182,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) + return; + } + m->m_data += IF_MAXLINKHDR; ++ m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN); + rbp = (struct bootp_t *)m->m_data; + m->m_data += sizeof(struct udpiphdr); +- memset(rbp, 0, sizeof(struct bootp_t)); ++ memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN); + + if (dhcp_msg_type == DHCPDISCOVER) { + if (preq_addr.s_addr != htonl(0L)) { +@@ -235,7 +239,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) + rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ + + q = rbp->bp_vend; +- end = (uint8_t *)&rbp[1]; ++ end = rbp->bp_vend + DHCP_OPT_LEN; + memcpy(q, rfc1533_cookie, 4); + q += 4; + +@@ -365,6 +369,6 @@ void bootp_input(struct mbuf *m) + struct bootp_t *bp = mtod(m, struct bootp_t *); + + if (bp->bp_op == BOOTP_REQUEST) { +- bootp_reply(m->slirp, bp); ++ bootp_reply(m->slirp, bp, m_end(m)); + } + } +diff --git a/slirp/src/bootp.h b/slirp/src/bootp.h +index 03ece9bf..0d20a944 100644 +--- a/slirp/src/bootp.h ++++ b/slirp/src/bootp.h +@@ -114,7 +114,7 @@ struct bootp_t { + uint8_t bp_hwaddr[16]; + uint8_t bp_sname[64]; + uint8_t bp_file[128]; +- uint8_t bp_vend[DHCP_OPT_LEN]; ++ uint8_t bp_vend[]; + }; + + typedef struct { +diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c +index 6d0653ed..7db07c08 100644 +--- a/slirp/src/mbuf.c ++++ b/slirp/src/mbuf.c +@@ -233,3 +233,8 @@ void *mtod_check(struct mbuf *m, size_t len) + + return NULL; + } ++ ++void *m_end(struct mbuf *m) ++{ ++ return m->m_data + m->m_len; ++} +diff --git a/slirp/src/mbuf.h b/slirp/src/mbuf.h +index 2015e323..a9752a36 100644 +--- a/slirp/src/mbuf.h ++++ b/slirp/src/mbuf.h +@@ -119,6 +119,7 @@ void m_adj(struct mbuf *, int); + int m_copy(struct mbuf *, struct mbuf *, int, int); + struct mbuf *dtom(Slirp *, void *); + void *mtod_check(struct mbuf *, size_t len); ++void *m_end(struct mbuf *); + + static inline void ifs_init(struct mbuf *ifm) + { +-- +2.27.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 new file mode 100644 index 0000000000000000000000000000000000000000..2005979aec4f4401b512bd0ea72d6c12493f5ea1 --- /dev/null +++ b/bt-use-size_t-type-for-length-parameters-instead-of-.patch @@ -0,0 +1,794 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..e714cb10bef351cd6ed6df71d08f3666df879ed5 --- /dev/null +++ b/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch @@ -0,0 +1,44 @@ +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-Uninitialized-Free-Vulnerability.patch b/bugfix-fix-Uninitialized-Free-Vulnerability.patch new file mode 100644 index 0000000000000000000000000000000000000000..d51c9718dc923b736da9c94206e97ceae794e311 --- /dev/null +++ b/bugfix-fix-Uninitialized-Free-Vulnerability.patch @@ -0,0 +1,72 @@ +From 58fe713b575a7b24b4e4694154a16808ff4a9009 Mon Sep 17 00:00:00 2001 +From: imxcc +Date: Tue, 1 Jun 2021 20:38:59 +0800 +Subject: [PATCH] bugfix: fix Uninitialized Free Vulnerability + +Signed-off-by: nocjj <1250062498@qq.com> +Signed-off-by: imxcc +--- + hw/block/nvme.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index 36d6a8bb3a..387e8b5c8f 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -216,15 +216,26 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, + return NVME_SUCCESS; + + unmap: +- qemu_sglist_destroy(qsg); ++ if (iov && iov->iov) { ++ qemu_iovec_destroy(iov); ++ } ++ ++ if (qsg && qsg->sg) { ++ qemu_sglist_destroy(qsg); ++ } ++ + return NVME_INVALID_FIELD | NVME_DNR; + } + + static uint16_t nvme_dma_write_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + uint64_t prp1, uint64_t prp2) + { +- QEMUSGList qsg; +- QEMUIOVector iov; ++ QEMUSGList qsg = { ++ .sg = NULL, ++ }; ++ QEMUIOVector iov = { ++ .iov = NULL, ++ }; + uint16_t status = NVME_SUCCESS; + + if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) { +@@ -247,8 +258,12 @@ static uint16_t nvme_dma_write_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + uint64_t prp1, uint64_t prp2) + { +- QEMUSGList qsg; +- QEMUIOVector iov; ++ QEMUSGList qsg = { ++ .sg = NULL, ++ }; ++ QEMUIOVector iov = { ++ .iov = NULL, ++ }; + uint16_t status = NVME_SUCCESS; + + trace_nvme_dma_read(prp1, prp2); +@@ -500,7 +515,7 @@ static void nvme_init_sq(NvmeSQueue *sq, NvmeCtrl *n, uint64_t dma_addr, + sq->size = size; + sq->cqid = cqid; + sq->head = sq->tail = 0; +- sq->io_req = g_new(NvmeRequest, sq->size); ++ sq->io_req = g_new0(NvmeRequest, sq->size); + + QTAILQ_INIT(&sq->req_list); + QTAILQ_INIT(&sq->out_req_list); +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..9c36301706ffb552deefc980fcb11149483f7b75 --- /dev/null +++ b/build-smt-processor-structure-to-support-smt-topolog.patch @@ -0,0 +1,104 @@ +From 7cfcd8c8a2fe3bd59714c6d5c6d55eb86bf7bc99 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 74e950057b..8a3b51c835 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.27.0 + diff --git a/cadence_gem-switch-to-use-qemu_receive_packet-for-lo.patch b/cadence_gem-switch-to-use-qemu_receive_packet-for-lo.patch new file mode 100644 index 0000000000000000000000000000000000000000..afbe5ba945682039bbf7f8f795519bbbfd755d76 --- /dev/null +++ b/cadence_gem-switch-to-use-qemu_receive_packet-for-lo.patch @@ -0,0 +1,44 @@ +From 22aa1e5315508da1ce8ec4565bbf2e525e79c6c2 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov +Date: Fri, 14 May 2021 10:39:58 +0800 +Subject: [PATCH] cadence_gem: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Alexander Bulekov +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/cadence_gem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index d412085884..52205f36be 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -1221,8 +1221,8 @@ static void gem_transmit(CadenceGEMState *s) + /* Send the packet somewhere */ + if (s->phy_loop || (s->regs[GEM_NWCTRL] & + GEM_NWCTRL_LOCALLOOP)) { +- gem_receive(qemu_get_queue(s->nic), tx_packet, +- total_bytes); ++ qemu_receive_packet(qemu_get_queue(s->nic), tx_packet, ++ total_bytes); + } else { + qemu_send_packet(qemu_get_queue(s->nic), tx_packet, + total_bytes); +-- +2.27.0 + diff --git a/coroutine-Add-qemu_co_mutex_assert_locked.patch b/coroutine-Add-qemu_co_mutex_assert_locked.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb1f2589f3edd987f0311288d049951c726ddeb8 --- /dev/null +++ b/coroutine-Add-qemu_co_mutex_assert_locked.patch @@ -0,0 +1,50 @@ +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-Kunpeng-920-cpu-support.patch b/cpu-add-Kunpeng-920-cpu-support.patch index 149a1a123e8deae9de1e634aa025618518c7f56f..74e27645ac18a07c00a04283f428bec515cf259e 100644 --- a/cpu-add-Kunpeng-920-cpu-support.patch +++ b/cpu-add-Kunpeng-920-cpu-support.patch @@ -3,6 +3,8 @@ From: Xu Yandong Date: Wed, 28 Aug 2019 01:36:21 -0400 Subject: [PATCH] cpu: add Kunpeng-920 cpu support +Add the Kunpeng-920 CPU model. + Signed-off-by: Xu Yandong --- hw/arm/virt.c | 1 + @@ -28,7 +30,7 @@ index 228906f2..5581d5e1 100644 @@ -258,6 +258,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); @@ -60,6 +62,5 @@ index 228906f2..5581d5e1 100644 { .name = "max", .initfn = aarch64_max_initfn }, { .name = NULL } }; --- +-- 2.19.1 - diff --git a/cpu-parse-feature-to-avoid-failure.patch b/cpu-parse-feature-to-avoid-failure.patch index a241a5f140c371f792a75839c53fb5b8779f7060..78178bfa3dd2a9dd1413dd3c12bbc8e6ed6d2869 100644 --- a/cpu-parse-feature-to-avoid-failure.patch +++ b/cpu-parse-feature-to-avoid-failure.patch @@ -1,8 +1,11 @@ From ba1ca232cfa2ca273c610beda40bee2143f11964 Mon Sep 17 00:00:00 2001 -From: rpm-build +From: Xu Yandong Date: Tue, 3 Sep 2019 16:27:39 +0800 Subject: [PATCH] cpu: parse +/- feature to avoid failure +To avoid cpu feature parse failuer, +/- feature is added. + +Signed-off-by: Xu Yandong --- target/arm/cpu64.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/curses-Fixes-curses-compiling-errors.patch b/curses-Fixes-curses-compiling-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e53980a256aeb063719bb19d35ace61e4ab31f8 --- /dev/null +++ b/curses-Fixes-curses-compiling-errors.patch @@ -0,0 +1,60 @@ +From a90cb5bc6accc02d155d74f08e630a26f252f435 Mon Sep 17 00:00:00 2001 +From: Yonggang Luo +Date: Tue, 13 Oct 2020 07:43:46 +0800 +Subject: [PATCH 2/4] curses: Fixes curses compiling errors. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is the compiling error: +../ui/curses.c: In function 'curses_refresh': +../ui/curses.c:256:5: error: 'next_maybe_keycode' may be used uninitialized in this function [-Werror=maybe-uninitialized] + 256 | curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) + | ^~~~~~~~~~ +../ui/curses.c:302:32: note: 'next_maybe_keycode' was declared here + 302 | enum maybe_keycode next_maybe_keycode; + | ^~~~~~~~~~~~~~~~~~ +../ui/curses.c:256:5: error: 'maybe_keycode' may be used uninitialized in this function [-Werror=maybe-uninitialized] + 256 | curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) + | ^~~~~~~~~~ +../ui/curses.c:265:24: note: 'maybe_keycode' was declared here + 265 | enum maybe_keycode maybe_keycode; + | ^~~~~~~~~~~~~ +cc1.exe: all warnings being treated as errors + +gcc version 10.2.0 (Rev1, Built by MSYS2 project) + +Signed-off-by: Yonggang Luo +Reviewed-by: Gerd Hoffmann +Reviewed-by: Daniel P. Berrangé +Message-id: 20201012234348.1427-4-luoyonggang@gmail.com +Signed-off-by: Gerd Hoffmann +--- + ui/curses.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ui/curses.c b/ui/curses.c +index a6e260eb96..18fcfe82d8 100644 +--- a/ui/curses.c ++++ b/ui/curses.c +@@ -259,7 +259,7 @@ static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], + static void curses_refresh(DisplayChangeListener *dcl) + { + int chr, keysym, keycode, keycode_alt; +- enum maybe_keycode maybe_keycode; ++ enum maybe_keycode maybe_keycode = CURSES_KEYCODE; + + curses_winch_check(); + +@@ -296,7 +296,7 @@ static void curses_refresh(DisplayChangeListener *dcl) + + /* alt or esc key */ + if (keycode == 1) { +- enum maybe_keycode next_maybe_keycode; ++ enum maybe_keycode next_maybe_keycode = CURSES_KEYCODE; + int nextchr = console_getch(&next_maybe_keycode); + + if (nextchr != -1) { +-- +2.17.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..7fbd127541cea671a6aad05b69a4d02f57fc9242 --- /dev/null +++ b/display-qxl-render-fix-race-condition-in-qxl_cursor-.patch @@ -0,0 +1,38 @@ +From 5b4d6c4605900ecc22135af5a904270931220a4f Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Thu, 7 Apr 2022 10:11:06 +0200 +Subject: [PATCH 4/5] 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 14ad2b352d..4a63c382f6 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -259,7 +259,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-helpers-ensure-AIO-callback-is-invoked-after-can.patch b/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch new file mode 100644 index 0000000000000000000000000000000000000000..c61c9fd848c4e1d68baa778388c8440a8d28ec32 --- /dev/null +++ b/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch @@ -0,0 +1,79 @@ +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/docs-specs-Add-ACPI-GED-documentation.patch b/docs-specs-Add-ACPI-GED-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..46e8c17483ba33af2b75e954233c3cbdc5c7cddc --- /dev/null +++ b/docs-specs-Add-ACPI-GED-documentation.patch @@ -0,0 +1,107 @@ +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/dp8393x-switch-to-use-qemu_receive_packet-for-loopba.patch b/dp8393x-switch-to-use-qemu_receive_packet-for-loopba.patch new file mode 100644 index 0000000000000000000000000000000000000000..e103e063db59cd43009529dbb1ebbaf5a971d84c --- /dev/null +++ b/dp8393x-switch-to-use-qemu_receive_packet-for-loopba.patch @@ -0,0 +1,42 @@ +From 3c28d0dd733d8a7cf8417105fcd65d3cae226dce Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 14 May 2021 10:24:53 +0800 +Subject: [PATCH] dp8393x: switch to use qemu_receive_packet() for loopback + packet +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé + +Signed-off-by: Jiajie Li +--- + hw/net/dp8393x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c +index bdb0b3b2c2..a64da76bf3 100644 +--- a/hw/net/dp8393x.c ++++ b/hw/net/dp8393x.c +@@ -459,7 +459,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) + s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; + if (nc->info->can_receive(nc)) { + s->loopback_packet = 1; +- nc->info->receive(nc, s->tx_buffer, tx_len); ++ qemu_receive_packet(nc, s->tx_buffer, tx_len); + } + } else { + /* Transmit packet */ +-- +2.27.0 + diff --git a/e1000-fail-early-for-evil-descriptor.patch b/e1000-fail-early-for-evil-descriptor.patch new file mode 100644 index 0000000000000000000000000000000000000000..60eb78a3391828ede1a4f6fd75617956695ab021 --- /dev/null +++ b/e1000-fail-early-for-evil-descriptor.patch @@ -0,0 +1,50 @@ +From d9f04ba174842bfdbcdcec2c90a2a726b914b9fd Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Wed, 24 Feb 2021 13:45:28 +0800 +Subject: [PATCH 1/7] e1000: fail early for evil descriptor + +During procss_tx_desc(), driver can try to chain data descriptor with +legacy descriptor, when will lead underflow for the following +calculation in process_tx_desc() for bytes: + + if (tp->size + bytes > msh) + bytes = msh - tp->size; + +This will lead a infinite loop. So check and fail early if tp->size if +greater or equal to msh. + +Reported-by: Alexander Bulekov +Reported-by: Cheolwoo Myung +Reported-by: Ruhr-University Bochum +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang +--- + hw/net/e1000.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index a99aa3ccc3..f0219d363c 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -670,6 +670,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) + msh = tp->tso_props.hdr_len + tp->tso_props.mss; + do { + bytes = split_size; ++ if (tp->size >= msh) { ++ goto eop; ++ } + if (tp->size + bytes > msh) + bytes = msh - tp->size; + +@@ -695,6 +698,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) + tp->size += split_size; + } + ++eop: + if (!(txd_lower & E1000_TXD_CMD_EOP)) + return; + if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { +-- +2.17.1 + diff --git a/e1000-fix-tx-re-entrancy-problem.patch b/e1000-fix-tx-re-entrancy-problem.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca66d020a7f6b20123ee9ed91835834dbad59c17 --- /dev/null +++ b/e1000-fix-tx-re-entrancy-problem.patch @@ -0,0 +1,58 @@ +From c28382f7ef531e10a45d240cdb29145f8638232e Mon Sep 17 00:00:00 2001 +From: Jon Maloy +Date: Thu, 21 Oct 2021 12:10:47 -0400 +Subject: [PATCH 2/7] e1000: fix tx re-entrancy problem + +The fact that the MMIO handler is not re-entrant causes an infinite +loop under certain conditions: + +Guest write to TDT -> Loopback -> RX (DMA to TDT) -> TX + +We now eliminate the effect of this problem locally in e1000, by adding +a boolean in struct E1000State indicating when the TX side is busy. This +will cause any entering new call to return early instead of interfering +with the ongoing work, and eliminates any risk of looping. + +This is intended to address CVE-2021-20257. + +Signed-off-by: Jon Maloy +Signed-off-by: Jason Wang +--- + hw/net/e1000.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index f0219d363c..a41b5b116d 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -104,6 +104,7 @@ typedef struct E1000State_st { + e1000x_txd_props props; + e1000x_txd_props tso_props; + uint16_t tso_frames; ++ bool busy; + } tx; + + struct { +@@ -748,6 +749,11 @@ start_xmit(E1000State *s) + return; + } + ++ if (s->tx.busy) { ++ return; ++ } ++ s->tx.busy = true; ++ + while (s->mac_reg[TDH] != s->mac_reg[TDT]) { + base = tx_desc_base(s) + + sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; +@@ -774,6 +780,7 @@ start_xmit(E1000State *s) + break; + } + } ++ s->tx.busy = false; + set_ics(s, 0, cause); + } + +-- +2.17.1 + diff --git a/e1000-switch-to-use-qemu_receive_packet-for-loopback.patch b/e1000-switch-to-use-qemu_receive_packet-for-loopback.patch new file mode 100644 index 0000000000000000000000000000000000000000..4890e184eb8e4095e9f83709450ea7884fbabaae --- /dev/null +++ b/e1000-switch-to-use-qemu_receive_packet-for-loopback.patch @@ -0,0 +1,41 @@ +From 0eb0e31d48fa80dd1e57fc4b3c6ba288850ce380 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 14 May 2021 10:21:33 +0800 +Subject: [PATCH] e1000: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/e1000.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index a023ceb27c..a99aa3ccc3 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -546,7 +546,7 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size) + + NetClientState *nc = qemu_get_queue(s->nic); + if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { +- nc->info->receive(nc, buf, size); ++ qemu_receive_packet(nc, buf, size); + } else { + qemu_send_packet(nc, buf, size); + } +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..fb1e7a7cdfa6f8046b6aa2ebb270b557dcae14a5 --- /dev/null +++ b/es1370-check-total-frame-count-against-current-frame.patch @@ -0,0 +1,60 @@ +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/exec-set-map-length-to-zero-when-returning-NULL.patch b/exec-set-map-length-to-zero-when-returning-NULL.patch new file mode 100644 index 0000000000000000000000000000000000000000..64c918e8d9de6eb3dd357c955d75488ff5f11c48 --- /dev/null +++ b/exec-set-map-length-to-zero-when-returning-NULL.patch @@ -0,0 +1,54 @@ +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/fix-cve-2020-35504.patch b/fix-cve-2020-35504.patch new file mode 100644 index 0000000000000000000000000000000000000000..59ffebca1d2d8377b58d6056e1f985a9abab94f6 --- /dev/null +++ b/fix-cve-2020-35504.patch @@ -0,0 +1,30 @@ +From ad1af4b1ba099a9ab128129edf44f57dccc2e825 Mon Sep 17 00:00:00 2001 +From: imxcc +Date: Mon, 21 Jun 2021 17:15:39 +0800 +Subject: [PATCH] fix cve-2020-35504 + +esp: always check current_req is not NULL before use in DMA callbacks + +Signed-off-by: Mark Cave-Ayland +Signed-off-by: imxcc +--- + hw/scsi/esp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index 7508d035ca..d1f13b350e 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -253,6 +253,9 @@ static void esp_do_dma(ESPState *s) + s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + return; + } ++ if (!s->current_req) { ++ return; ++ } + if (s->async_len == 0) { + /* Defer until data is available. */ + return; +-- +2.27.0 + diff --git a/fix-cve-2020-35505.patch b/fix-cve-2020-35505.patch new file mode 100644 index 0000000000000000000000000000000000000000..adf31a1e81a8e71e82be78d984009ee3fc562e13 --- /dev/null +++ b/fix-cve-2020-35505.patch @@ -0,0 +1,46 @@ +From 3aedcaaaef0653a413174c35f183b1703ce10a4d Mon Sep 17 00:00:00 2001 +From: imxcc +Date: Mon, 21 Jun 2021 17:20:55 +0800 +Subject: [PATCH] fix cve-2020-35505 + +esp: ensure cmdfifo is not empty and current_dev is non-NULL + +Signed-off-by: Mark Cave-Ayland +Signed-off-by: imxcc +--- + hw/scsi/esp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index d1f13b350e..db6bed4f00 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -79,6 +79,7 @@ void esp_request_cancelled(SCSIRequest *req) + scsi_req_unref(s->current_req); + s->current_req = NULL; + s->current_dev = NULL; ++ s->async_len = 0; + } + } + +@@ -113,7 +114,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) + if (s->current_req) { + /* Started a new command before the old one finished. Cancel it. */ + scsi_req_cancel(s->current_req); +- s->async_len = 0; + } + + s->current_dev = scsi_device_find(&s->bus, 0, target, 0); +@@ -136,6 +136,9 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) + + trace_esp_do_busid_cmd(busid); + lun = busid & 7; ++ if (!s->current_dev) { ++ return; ++ } + current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); + s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); + datalen = scsi_req_enqueue(s->current_req); +-- +2.27.0 + diff --git a/hbitmap-handle-set-reset-with-zero-length.patch b/hbitmap-handle-set-reset-with-zero-length.patch new file mode 100644 index 0000000000000000000000000000000000000000..b346a970d8594e2fae6a730c8c66370dc66af0da --- /dev/null +++ b/hbitmap-handle-set-reset-with-zero-length.patch @@ -0,0 +1,50 @@ +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/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch b/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch new file mode 100644 index 0000000000000000000000000000000000000000..a463bb73f584208225a4483137213648ed9d9861 --- /dev/null +++ b/hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch @@ -0,0 +1,61 @@ +From 52fb9a5d089be68ca03d9504238ecea7b4c31c8f 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/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch b/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc57aa64dd12427afc1e59af0476206317065d1b --- /dev/null +++ b/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch @@ -0,0 +1,478 @@ +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-Do-not-create-memory-hotplug-method-when-han.patch b/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch new file mode 100644 index 0000000000000000000000000000000000000000..292687199fbe797b86b25ac2fb56063f7080a0f0 --- /dev/null +++ b/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch @@ -0,0 +1,46 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..cdf597b51566400b17ddac3e27dc93cb65a61bd6 --- /dev/null +++ b/hw-acpi-Make-ACPI-IO-address-space-configurable.patch @@ -0,0 +1,196 @@ +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-arm-Factor-out-powerdown-notifier-from-GPIO.patch b/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2c0f3900d05652a977be13df0babb8210c65b1b --- /dev/null +++ b/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch @@ -0,0 +1,72 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..140f59a2c71da40f47a2edd2bd2dd529227c3ddc --- /dev/null +++ b/hw-arm-Use-GED-for-system_powerdown-event.patch @@ -0,0 +1,167 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..2b2e530bb8e3555b4f9cf2a807b060ac62ccd9de --- /dev/null +++ b/hw-arm-acpi-enable-SHPC-native-hot-plug.patch @@ -0,0 +1,45 @@ +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-boot-Add-manually-register-and-trigger-of-CPU.patch b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..95abd07e5a2b62acd14c1a45e61ce471707f173e --- /dev/null +++ b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch @@ -0,0 +1,115 @@ +From de86ba0ff72a51b0c1cdbebf790869aea73ae9d3 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 + +We need to register and trigger CPU reset manually for hotplugged +CPU. Besides, we gather CPU reset handlers of all CPUs because CPU +reset should happen before GIC reset. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/boot.c | 18 ++++++++++++++++++ + hw/core/reset.c | 25 +++++++++++++++++++++++++ + include/hw/arm/boot.h | 3 +++ + include/sysemu/reset.h | 4 ++++ + 4 files changed, 50 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index fc4e021a38..3ab9de6456 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -789,6 +789,24 @@ static void do_cpu_reset(void *opaque) + } + } + ++void cpu_hotplug_register_reset(int ncpu) ++{ ++ CPUState *cpu_0 = qemu_get_cpu(0); ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ QEMUResetEntry *entry = qemu_get_reset_entry(do_cpu_reset, cpu_0); ++ ++ assert(entry); ++ /* Gather the reset handlers of all CPUs */ ++ qemu_register_reset_after(entry, do_cpu_reset, cpu); ++} ++ ++void cpu_hotplug_reset_manually(int ncpu) ++{ ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ ++ do_cpu_reset(cpu); ++} ++ + /** + * 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 +--- a/hw/core/reset.c ++++ b/hw/core/reset.c +@@ -47,6 +47,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) ++{ ++ QEMUResetEntry *re; ++ ++ QTAILQ_FOREACH(re, &reset_handlers, entry) { ++ if (re->func == func && re->opaque == opaque) { ++ return re; ++ } ++ } ++ ++ return NULL; ++} ++ ++void qemu_register_reset_after(QEMUResetEntry *entry, ++ QEMUResetHandler *func, ++ void *opaque) ++{ ++ QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry)); ++ ++ re->func = func; ++ re->opaque = opaque; ++ QTAILQ_INSERT_AFTER(&reset_handlers, entry, re, entry); ++} ++ + void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) + { + QEMUResetEntry *re; +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index c48cc4c2bc..9452ccd1fa 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -118,6 +118,9 @@ struct arm_boot_info { + arm_endianness endianness; + }; + ++void cpu_hotplug_register_reset(int ncpu); ++void cpu_hotplug_reset_manually(int ncpu); ++ + /** + * arm_load_kernel - Loads memory with everything needed to boot + * +diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h +index 0b0d6d7598..f3ff26c637 100644 +--- a/include/sysemu/reset.h ++++ 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..e7ca51a5deb7146de6d6b05aa1d8391b0c08adac --- /dev/null +++ b/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch @@ -0,0 +1,47 @@ +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-expose-host-CPU-frequency-info-to-guest.patch b/hw-arm-expose-host-CPU-frequency-info-to-guest.patch index 0b04076e5478d671dc55937313d677e603d23720..f0093812ed61e769afec350993e0298a4c5f9e10 100644 --- a/hw-arm-expose-host-CPU-frequency-info-to-guest.patch +++ b/hw-arm-expose-host-CPU-frequency-info-to-guest.patch @@ -1,54 +1,57 @@ -From 773b25c55c7428b64d21b23a6b08fc629a665ca5 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 29 Jul 2019 09:54:43 +0800 -Subject: [PATCH] hw/arm: expose host CPU frequency info to guest +From b70d020dba72283d7b16a77c377512c84aab5f81 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 -On ARM64, CPU frequency is fetched by ACPI CPPC, so we add virtual -CPPC registers and ACPI _CPC objects. +On ARM64 platform, cpu frequency is retrieved via ACPI CPPC. +A virtual cpufreq device based on ACPI CPPC is created to +present cpu frequency info to the guest. -The default frequency is set to the nominal frequency of Hi1616, which -will not support CPPC in future. On Hi1620 we are fetching the value -from Host CPPC sys file. +The default frequency is set to host cpu nominal frequency, +which is obtained from the host CPPC sysfs. Other performance +data are set to the same value, since we don't support guest +performance scaling here. -All performance data are set to the same value for we don't support -guest initiating performance scaling. - -We don't emulate performance counters and simply return 1 for all -counter readings, and guest Linux should fall back to use the desired +Performance counters are also not emulated and they simply +return 1 if read, and guest should fallback to use desired performance value as the current performance. -Signed-off-by: Heyi Guo -Signed-off-by: zhanghailiang +Guest kernel version above 4.18 is required to make it work. + +This series is backported from: +https://patchwork.kernel.org/cover/11379943/ + +Signed-off-by: Ying Fang --- default-configs/aarch64-softmmu.mak | 1 + hw/acpi/Makefile.objs | 1 + hw/acpi/aml-build.c | 22 +++ - hw/acpi/cpufreq.c | 278 ++++++++++++++++++++++++++++ + 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, 437 insertions(+), 2 deletions(-) + 10 files changed, 446 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 4ea9add0..37399c14 100644 +index 958b1e08..0a030e85 100644 --- a/default-configs/aarch64-softmmu.mak +++ b/default-configs/aarch64-softmmu.mak -@@ -10,3 +10,4 @@ CONFIG_XLNX_ZYNQMP=y +@@ -6,3 +6,4 @@ include arm-softmmu.mak CONFIG_XLNX_ZYNQMP_ARM=y CONFIG_XLNX_VERSAL=y - CONFIG_ARM_SMMUV3=y + CONFIG_SBSA_REF=y +CONFIG_CPUFREQ=y diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs -index 2d46e378..60979db9 100644 +index 9bb2101e..1a720c38 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs -@@ -12,6 +12,7 @@ common-obj-y += acpi_interface.o - common-obj-y += bios-linker-loader.o - common-obj-y += aml-build.o +@@ -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 @@ -89,10 +92,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..c123a22b +index 00000000..d02a25a6 --- /dev/null +++ b/hw/acpi/cpufreq.c -@@ -0,0 +1,278 @@ +@@ -0,0 +1,287 @@ +/* + * ACPI CPPC register device + * @@ -124,6 +127,7 @@ index 00000000..c123a22b +#include "hw/acpi/acpi-defs.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" ++#include "hw/boards.h" + +#define TYPE_CPUFREQ "cpufreq" +#define CPUFREQ(obj) OBJECT_CHECK(CpuhzState, (obj), TYPE_CPUFREQ) @@ -189,6 +193,9 @@ index 00000000..c123a22b + uint64_t r; + 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) { + warn_report("cpufreq_read: offset 0x%lx out of range", offset); + return 0; @@ -258,6 +265,8 @@ index 00000000..c123a22b + uint64_t value, unsigned size) +{ + 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) { + error_printf("cpufreq_write: offset 0x%lx out of range", offset); @@ -339,6 +348,9 @@ index 00000000..c123a22b + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + CpuhzState *s = CPUFREQ(obj); + ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ + s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE; + if (s->reg_size > MAX_SUPPORT_SPACE) { + error_report("Required space 0x%x excesses the max support 0x%x", @@ -372,7 +384,7 @@ index 00000000..c123a22b +type_init(cpufreq_register_types) + diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index bf9c0bc2..33a8e2e3 100644 +index 0afb3727..29494ebd 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -45,11 +45,73 @@ @@ -469,7 +481,7 @@ index bf9c0bc2..33a8e2e3 100644 aml_append(scope, dev); } } -@@ -740,7 +814,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -718,7 +792,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); @@ -479,10 +491,10 @@ index bf9c0bc2..33a8e2e3 100644 (irqmap[VIRT_UART] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index ce2664a3..ec6f00ab 100644 +index d9496c93..0fa355ba 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -132,6 +132,7 @@ static const MemMapEntry base_memmap[] = { +@@ -135,6 +135,7 @@ static const MemMapEntry base_memmap[] = { [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, [VIRT_SMMU] = { 0x09050000, 0x00020000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, @@ -490,7 +502,7 @@ index ce2664a3..ec6f00ab 100644 /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, -@@ -725,6 +726,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, +@@ -731,6 +732,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, g_free(nodename); } @@ -507,7 +519,7 @@ index ce2664a3..ec6f00ab 100644 static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; -@@ -1618,6 +1629,8 @@ static void machvirt_init(MachineState *machine) +@@ -1682,6 +1693,8 @@ static void machvirt_init(MachineState *machine) create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); @@ -517,10 +529,10 @@ index ce2664a3..ec6f00ab 100644 create_secure_ram(vms, secure_sysmem); create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); diff --git a/hw/char/Kconfig b/hw/char/Kconfig -index 6360c9ff..8cc3ae2a 100644 +index 40e7a8b8..2f61bf53 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig -@@ -40,3 +40,7 @@ config SCLPCONSOLE +@@ -46,3 +46,7 @@ config SCLPCONSOLE config TERMINAL3270 bool @@ -529,10 +541,10 @@ index 6360c9ff..8cc3ae2a 100644 + bool + default y diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h -index f9aa4bd3..b4899a32 100644 +index 57a3f58b..39ae91d3 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h -@@ -652,4 +652,42 @@ struct AcpiIortRC { +@@ -634,4 +634,42 @@ struct AcpiIortRC { } QEMU_PACKED; typedef struct AcpiIortRC AcpiIortRC; @@ -590,7 +602,7 @@ 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 507517c6..8465f9bd 100644 +index a7209420..43a6ce91 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -66,6 +66,7 @@ enum { @@ -602,5 +614,5 @@ index 507517c6..8465f9bd 100644 VIRT_RTC, VIRT_FW_CFG, -- -2.19.1 +2.23.0 diff --git a/hw-arm-virt-Add-memory-hotplug-framework.patch b/hw-arm-virt-Add-memory-hotplug-framework.patch new file mode 100644 index 0000000000000000000000000000000000000000..dcb0f21f5b63e10636d889f6cae99a4d738d1d0e --- /dev/null +++ b/hw-arm-virt-Add-memory-hotplug-framework.patch @@ -0,0 +1,130 @@ +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-Enable-device-memory-cold-hot-plug-with-.patch b/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b32b2a01929189ff6f89e94f011d4d9cc3811a3b --- /dev/null +++ b/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch @@ -0,0 +1,252 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..1e3befaf62920ca12cae4c8ead6d731800ef79a8 --- /dev/null +++ b/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch @@ -0,0 +1,170 @@ +From 3a0af1446395e74476a763ca12713b28c099a144 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 + +The init path of hotplugged CPU is pre_plug/realize/plug, so we +must move these init code in machvirt_init to pre_plug hook, to +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(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 64532b61b2..83f4887e57 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -196,6 +196,8 @@ static const char *valid_cpus[] = { + ARM_CPU_TYPE_NAME("max"), + }; + ++static MemoryRegion *secure_sysmem; ++ + static bool cpu_type_valid(const char *cpu) + { + int i; +@@ -1629,7 +1631,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; + int n, virt_max_cpus; + MemoryRegion *ram = g_new(MemoryRegion, 1); + bool firmware_loaded; +@@ -1752,57 +1753,10 @@ 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); ++ 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); +- } +- +- if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { +- object_property_set_bool(cpuobj, false, "has_el2", NULL); +- } +- +- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { +- object_property_set_int(cpuobj, vms->psci_conduit, +- "psci-conduit", NULL); +- +- /* Secondary CPUs start in PSCI powered-down state */ +- if (n > 0) { +- object_property_set_bool(cpuobj, true, +- "start-powered-off", NULL); +- } +- } +- +- 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); +- } +- +- if (object_property_find(cpuobj, "reset-cbar", NULL)) { +- object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, +- "reset-cbar", &error_abort); +- } +- +- object_property_set_link(cpuobj, OBJECT(sysmem), "memory", +- &error_abort); +- if (vms->secure) { +- object_property_set_link(cpuobj, OBJECT(secure_sysmem), +- "secure-memory", &error_abort); +- } +- + object_property_set_bool(cpuobj, true, "realized", &error_fatal); + object_unref(cpuobj); + } +@@ -2089,10 +2043,16 @@ out: + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- CPUState *cs = CPU(dev); + ARMCPUTopoInfo topo; ++ Object *cpuobj = OBJECT(dev); ++ CPUState *cs = CPU(dev); + ARMCPU *cpu = ARM_CPU(dev); + MachineState *ms = MACHINE(hotplug_dev); ++ MachineClass *mc = MACHINE_GET_CLASS(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); ++ MemoryRegion *sysmem = get_system_memory(); + 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, + 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); ++ ++ 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); ++ } ++ ++ if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { ++ object_property_set_bool(cpuobj, false, "has_el2", NULL); ++ } ++ ++ if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { ++ object_property_set_int(cpuobj, vms->psci_conduit, ++ "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); ++ } ++ } ++ ++ 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); ++ } ++ ++ if (object_property_find(cpuobj, "reset-cbar", NULL)) { ++ object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, ++ "reset-cbar", &error_abort); ++ } ++ ++ object_property_set_link(cpuobj, OBJECT(sysmem), "memory", ++ &error_abort); ++ if (vms->secure) { ++ object_property_set_link(cpuobj, OBJECT(secure_sysmem), ++ "secure-memory", &error_abort); ++ } + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, +-- +2.19.1 diff --git a/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch b/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..c124df5394121fdb0415b3b85d04fc3417a747aa --- /dev/null +++ b/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch @@ -0,0 +1,73 @@ +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 index 027a5112effa77c9d37642f88cf9d00120bc6f47..932f467fe274453668edf80bac5d023817d6f95b 100644 --- a/hw-arm-virt-Introduce-cpu-topology-support.patch +++ b/hw-arm-virt-Introduce-cpu-topology-support.patch @@ -1,6 +1,6 @@ -From 123b4eb3cb7b9b4e3e0705a9b5f974b37d3b8431 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 5 Aug 2019 15:04:31 +0800 +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 @@ -11,13 +11,13 @@ 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 | 50 ++++++++++++++++++++++++++++++++++++ + device_tree.c | 32 ++++++++++++++++++++++ + hw/acpi/aml-build.c | 53 ++++++++++++++++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 4 +++ - hw/arm/virt.c | 29 +++++++++++++++++++++ + hw/arm/virt.c | 32 +++++++++++++++++++++- include/hw/acpi/aml-build.h | 2 ++ include/sysemu/device_tree.h | 1 + - 6 files changed, 118 insertions(+) + 6 files changed, 123 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index f8b46b3c..03906a14 100644 @@ -26,7 +26,7 @@ index f8b46b3c..03906a14 100644 @@ -524,6 +524,38 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) return retval; } - + +/** + * qemu_fdt_add_path + * @fdt: Flattened Device Tree @@ -63,7 +63,7 @@ index f8b46b3c..03906a14 100644 { 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..9d39ad10 100644 +index 73f97751..f2c8c28f 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -25,6 +25,7 @@ @@ -71,13 +71,13 @@ index 73f97751..9d39ad10 100644 #include "qemu/bitops.h" #include "sysemu/numa.h" +#include "sysemu/cpus.h" - + static GArray *build_alloc_array(void) { -@@ -51,6 +52,55 @@ static void build_append_array(GArray *array, GArray *val) +@@ -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) + */ @@ -97,6 +97,9 @@ index 73f97751..9d39ad10 100644 +{ + 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)); + @@ -128,28 +131,28 @@ index 73f97751..9d39ad10 100644 +} + #define ACPI_NAMESEG_LEN 4 - + static void diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 33a8e2e3..18653e6d 100644 +index 29494ebd..fe54411f 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -870,6 +870,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) +@@ -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 57a78b16..16700a2e 100644 +index 0fa355ba..272455bc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -42,6 +42,7 @@ +@@ -44,6 +44,7 @@ #include "net/net.h" #include "sysemu/device_tree.h" #include "sysemu/numa.h" @@ -157,10 +160,20 @@ index 57a78b16..16700a2e 100644 #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/loader.h" -@@ -364,8 +365,36 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -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)); + @@ -192,7 +205,7 @@ index 57a78b16..16700a2e 100644 + 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 @@ -201,11 +214,11 @@ index 375335ab..bfb0b100 100644 @@ -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 @@ -216,9 +229,8 @@ index c16fd69b..d62fc873 100644 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.19.1 - +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..262cb508bcb8ba48bf93a3875957f2c9ace7698d --- /dev/null +++ b/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch @@ -0,0 +1,402 @@ +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-acpi-build-Add-PC-DIMM-in-SRAT.patch b/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch new file mode 100644 index 0000000000000000000000000000000000000000..0602ab8d4d0d7af63f034c9b66c984e5aed627a7 --- /dev/null +++ b/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..3d711678a6bbd365da89b3039509259f9ffe3c2e --- /dev/null +++ b/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch @@ -0,0 +1,25 @@ +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-arm64-add-vcpu-cache-info-support.patch b/hw-arm64-add-vcpu-cache-info-support.patch index c9e843719b59a99112ee1867475846378c84264e..79e1dede39def063dc9d8a4f4b87339bcd39c435 100644 --- a/hw-arm64-add-vcpu-cache-info-support.patch +++ b/hw-arm64-add-vcpu-cache-info-support.patch @@ -1,6 +1,6 @@ -From 8db6d888e3eb131900111506b93f6101413df5b4 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 5 Aug 2019 15:30:05 +0800 +From 5a0ed254f99ca37498bd81994b906b6984b5ffa9 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 Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. @@ -8,16 +8,16 @@ Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. Signed-off-by: zhanghailiang Signed-off-by: Honghao --- - hw/acpi/aml-build.c | 124 ++++++++++++++++++++++++++++++++++++ - hw/arm/virt.c | 76 +++++++++++++++++++++- + hw/acpi/aml-build.c | 126 ++++++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 80 ++++++++++++++++++++++- include/hw/acpi/aml-build.h | 46 +++++++++++++ - 3 files changed, 245 insertions(+), 1 deletion(-) + 3 files changed, 251 insertions(+), 1 deletion(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 9d39ad10..99209c0a 100644 +index f2c8c28f..74e95005 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c -@@ -55,6 +55,129 @@ static void build_append_array(GArray *array, GArray *val) +@@ -55,6 +55,131 @@ static void build_append_array(GArray *array, GArray *val) /* * ACPI 6.2 Processor Properties Topology Table (PPTT) */ @@ -115,6 +115,8 @@ index 9d39ad10..99209c0a 100644 + 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; + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + @@ -147,25 +149,27 @@ index 9d39ad10..99209c0a 100644 static void build_cpu_hierarchy(GArray *tbl, uint32_t flags, uint32_t parent, uint32_t id) { -@@ -100,6 +223,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) +@@ -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); } +#endif - + #define ACPI_NAMESEG_LEN 4 - + diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 16700a2e..96f56e2e 100644 +index 272455bc..9669c70b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -304,6 +304,77 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) +@@ -308,6 +308,81 @@ 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 */ @@ -191,6 +195,8 @@ index 16700a2e..96f56e2e 100644 +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; + + /* If current is not equal to max */ @@ -237,17 +243,17 @@ index 16700a2e..96f56e2e 100644 static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; -@@ -336,6 +407,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -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); + for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); -@@ -364,7 +438,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -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); } @@ -255,7 +261,7 @@ index 16700a2e..96f56e2e 100644 + 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 --- a/include/hw/acpi/aml-build.h @@ -263,7 +269,7 @@ index bfb0b100..0be3453a 100644 @@ -223,6 +223,52 @@ struct AcpiBuildTables { BIOSLinker *linker; } AcpiBuildTables; - + +#ifdef __aarch64__ +/* Definitions of the hardcoded cache info*/ + @@ -313,6 +319,5 @@ index bfb0b100..0be3453a 100644 /** * init_aml_allocator: * --- +-- 2.23.0 - diff --git a/hw-block-fdc-Extract-blk_create_empty_drive.patch b/hw-block-fdc-Extract-blk_create_empty_drive.patch new file mode 100644 index 0000000000000000000000000000000000000000..23b3ab3e3b832117529f3bf91564cab0f386aaf2 --- /dev/null +++ b/hw-block-fdc-Extract-blk_create_empty_drive.patch @@ -0,0 +1,49 @@ +From b05a7125bab12a5610db47c9fd4f85d93a552a4e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 24 Nov 2021 17:15:34 +0100 +Subject: [PATCH 1/5] hw/block/fdc: Extract blk_create_empty_drive() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We are going to re-use this code in the next commit, +so extract it as a new blk_create_empty_drive() function. + +Inspired-by: Hanna Reitz +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20211124161536.631563-2-philmd@redhat.com +Signed-off-by: John Snow +--- + hw/block/fdc.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/block/fdc.c b/hw/block/fdc.c +index 9b24cb9b85..deea339d70 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -56,6 +56,12 @@ + } while (0) + + ++/* Anonymous BlockBackend for empty drive */ ++static BlockBackend *blk_create_empty_drive(void) ++{ ++ return blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); ++} ++ + /********************************************************/ + /* qdev floppy bus */ + +@@ -539,8 +545,7 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) + } + + if (!dev->conf.blk) { +- /* Anonymous BlockBackend for an empty drive */ +- dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); ++ dev->conf.blk = blk_create_empty_drive(); + ret = blk_attach_dev(dev->conf.blk, qdev); + assert(ret == 0); + +-- +2.27.0 + diff --git a/hw-block-fdc-Kludge-missing-floppy-drive-to-fix-CVE-.patch b/hw-block-fdc-Kludge-missing-floppy-drive-to-fix-CVE-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c9c1809fd599c969cf13e4b92654d61535b3db8 --- /dev/null +++ b/hw-block-fdc-Kludge-missing-floppy-drive-to-fix-CVE-.patch @@ -0,0 +1,62 @@ +From c303ae575659493d747225f61430460dec809362 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 24 Nov 2021 17:15:35 +0100 +Subject: [PATCH 2/5] hw/block/fdc: Kludge missing floppy drive to fix + CVE-2021-20196 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Guest might select another drive on the bus by setting the +DRIVE_SEL bit of the DIGITAL OUTPUT REGISTER (DOR). +The current controller model doesn't expect a BlockBackend +to be NULL. A simple way to fix CVE-2021-20196 is to create +an empty BlockBackend when it is missing. All further +accesses will be safely handled, and the controller state +machines keep behaving correctly. + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2021-20196 +Reported-by: Gaoning Pan (Ant Security Light-Year Lab) +Reviewed-by: Darren Kenny +Reviewed-by: Hanna Reitz +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20211124161536.631563-3-philmd@redhat.com +BugLink: https://bugs.launchpad.net/qemu/+bug/1912780 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/338 +Reviewed-by: Darren Kenny +Reviewed-by: Hanna Reitz +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: John Snow +--- + hw/block/fdc.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hw/block/fdc.c b/hw/block/fdc.c +index deea339d70..47b6939d44 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -1358,7 +1358,19 @@ static FDrive *get_drv(FDCtrl *fdctrl, int unit) + + static FDrive *get_cur_drv(FDCtrl *fdctrl) + { +- return get_drv(fdctrl, fdctrl->cur_drv); ++ FDrive *cur_drv = get_drv(fdctrl, fdctrl->cur_drv); ++ ++ if (!cur_drv->blk) { ++ /* ++ * Kludge: empty drive line selected. Create an anonymous ++ * BlockBackend to avoid NULL deref with various BlockBackend ++ * API calls within this model (CVE-2021-20196). ++ * Due to the controller QOM model limitations, we don't ++ * attach the created to the controller device. ++ */ ++ cur_drv->blk = blk_create_empty_drive(); ++ } ++ return cur_drv; + } + + /* Status A register : 0x00 (read-only) */ +-- +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..c051b6d612d93b28a8167a6a8bb9390af94b14e1 --- /dev/null +++ b/hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch @@ -0,0 +1,86 @@ +From ebf78fa9023796eedda0253bfb60cad799045ffe 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] 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 47b6939d44..6401635053 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -1722,6 +1722,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-core-loader-Fix-possible-crash-in-rom_copy.patch b/hw-core-loader-Fix-possible-crash-in-rom_copy.patch new file mode 100644 index 0000000000000000000000000000000000000000..770f12b1acf9dfc3c4289e9a9bea7d5936df1968 --- /dev/null +++ b/hw-core-loader-Fix-possible-crash-in-rom_copy.patch @@ -0,0 +1,45 @@ +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-ehci-check-return-value-of-usb_packet_map.patch b/hw-ehci-check-return-value-of-usb_packet_map.patch new file mode 100644 index 0000000000000000000000000000000000000000..1bb7d9006d6aacb5289931ed19e722605689869c --- /dev/null +++ b/hw-ehci-check-return-value-of-usb_packet_map.patch @@ -0,0 +1,49 @@ +From e80eae822b8ed765e0ae08e18435389e46357fbd 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-ide-check-null-block-before-_cancel_dma_sync.patch b/hw-ide-check-null-block-before-_cancel_dma_sync.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fed06f544ce160861b6c5fc2c1610517aae0453 --- /dev/null +++ b/hw-ide-check-null-block-before-_cancel_dma_sync.patch @@ -0,0 +1,64 @@ +From 8785230bc823d4f32e39055ce24e292586a9be03 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 6d96c3a8c3..1bedad29de 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -705,6 +705,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 4c6fb9a68e..ac291858d7 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-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch b/hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ea9f9a4d4f03bc672a8048b147b857f10eda02f --- /dev/null +++ b/hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch @@ -0,0 +1,70 @@ +From 3c392b69da78fa025ea93f89ee90ec1a03104b4d 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..0bc56ea295e4a201c263d0cc47fddd2f5099c346 --- /dev/null +++ b/hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch @@ -0,0 +1,55 @@ +From 0bf2096f7967af3c28280c72803f25c7c226d218 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 3/4] 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 8645220d61..44368e285a 100644 +--- a/hw/intc/arm_gicv3_redist.c ++++ b/hw/intc/arm_gicv3_redist.c +@@ -450,7 +450,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); +@@ -507,7 +507,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-Replace-mis-used-MEMTX_-constants-.patch b/hw-intc-arm_gicv3-Replace-mis-used-MEMTX_-constants-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f353b2c57f8aa20000e7d3b52e91847e7d881d2 --- /dev/null +++ b/hw-intc-arm_gicv3-Replace-mis-used-MEMTX_-constants-.patch @@ -0,0 +1,637 @@ +From ecf1c65fd15dcb0d57cb8e029db185c7adaad3b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 26 Aug 2021 20:07:04 +0200 +Subject: [PATCH 2/4] hw/intc/arm_gicv3: Replace mis-used MEMTX_* constants by + booleans +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. + Arguably this is a bit of a misuse of the MEMTX_* constants and + perhaps we should have gicd_readl etc return a bool instead. + +Follow his suggestion and replace the MEMTX_* constants by +boolean values, simplifying a bit the gicv3_dist_read() / +gicv3_dist_write() handlers. + +Suggested-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20210826180704.2131949-3-philmd@redhat.com +Signed-off-by: Peter Maydell +--- + hw/intc/arm_gicv3_dist.c | 201 +++++++++++++++++++++------------------ + 1 file changed, 106 insertions(+), 95 deletions(-) + +diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c +index 7e9b393d9a..5beb7c4235 100644 +--- a/hw/intc/arm_gicv3_dist.c ++++ b/hw/intc/arm_gicv3_dist.c +@@ -262,8 +262,21 @@ static void gicd_write_irouter(GICv3State *s, MemTxAttrs attrs, int irq, + gicv3_update(s, irq, 1); + } + +-static MemTxResult gicd_readb(GICv3State *s, hwaddr offset, +- uint64_t *data, MemTxAttrs attrs) ++/** ++ * gicd_readb ++ * gicd_readw ++ * gicd_readl ++ * gicd_readq ++ * gicd_writeb ++ * gicd_writew ++ * gicd_writel ++ * gicd_writeq ++ * ++ * Return %true if the operation succeeded, %false otherwise. ++ */ ++ ++static bool gicd_readb(GICv3State *s, hwaddr offset, ++ uint64_t *data, MemTxAttrs attrs) + { + /* Most GICv3 distributor registers do not support byte accesses. */ + switch (offset) { +@@ -273,17 +286,17 @@ static MemTxResult gicd_readb(GICv3State *s, hwaddr offset, + /* This GIC implementation always has affinity routing enabled, + * so these registers are all RAZ/WI. + */ +- return MEMTX_OK; ++ return true; + case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: + *data = gicd_read_ipriorityr(s, attrs, offset - GICD_IPRIORITYR); +- return MEMTX_OK; ++ return true; + default: +- return MEMTX_ERROR; ++ return false; + } + } + +-static MemTxResult gicd_writeb(GICv3State *s, hwaddr offset, +- uint64_t value, MemTxAttrs attrs) ++static bool gicd_writeb(GICv3State *s, hwaddr offset, ++ uint64_t value, MemTxAttrs attrs) + { + /* Most GICv3 distributor registers do not support byte accesses. */ + switch (offset) { +@@ -293,25 +306,25 @@ static MemTxResult gicd_writeb(GICv3State *s, hwaddr offset, + /* This GIC implementation always has affinity routing enabled, + * so these registers are all RAZ/WI. + */ +- return MEMTX_OK; ++ return true; + case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: + { + int irq = offset - GICD_IPRIORITYR; + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + gicd_write_ipriorityr(s, attrs, irq, value); + gicv3_update(s, irq, 1); +- return MEMTX_OK; ++ return true; + } + default: +- return MEMTX_ERROR; ++ return false; + } + } + +-static MemTxResult gicd_readw(GICv3State *s, hwaddr offset, +- uint64_t *data, MemTxAttrs attrs) ++static bool gicd_readw(GICv3State *s, hwaddr offset, ++ uint64_t *data, MemTxAttrs attrs) + { + /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR + * support 16 bit accesses, and those registers are all part of the +@@ -319,11 +332,11 @@ static MemTxResult gicd_readw(GICv3State *s, hwaddr offset, + * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are + * reserved. + */ +- return MEMTX_ERROR; ++ return false; + } + +-static MemTxResult gicd_writew(GICv3State *s, hwaddr offset, +- uint64_t value, MemTxAttrs attrs) ++static bool gicd_writew(GICv3State *s, hwaddr offset, ++ uint64_t value, MemTxAttrs attrs) + { + /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR + * support 16 bit accesses, and those registers are all part of the +@@ -331,11 +344,11 @@ static MemTxResult gicd_writew(GICv3State *s, hwaddr offset, + * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are + * reserved. + */ +- return MEMTX_ERROR; ++ return false; + } + +-static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, +- uint64_t *data, MemTxAttrs attrs) ++static bool gicd_readl(GICv3State *s, hwaddr offset, ++ uint64_t *data, MemTxAttrs attrs) + { + /* Almost all GICv3 distributor registers are 32-bit. + * Note that WO registers must return an UNKNOWN value on reads, +@@ -363,7 +376,7 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + } else { + *data = s->gicd_ctlr; + } +- return MEMTX_OK; ++ return true; + case GICD_TYPER: + { + /* For this implementation: +@@ -387,61 +400,61 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + + *data = (1 << 25) | (1 << 24) | (sec_extn << 10) | + (0xf << 19) | itlinesnumber; +- return MEMTX_OK; ++ return true; + } + case GICD_IIDR: + /* We claim to be an ARM r0p0 with a zero ProductID. + * This is the same as an r0p0 GIC-500. + */ + *data = gicv3_iidr(); +- return MEMTX_OK; ++ return true; + case GICD_STATUSR: + /* RAZ/WI for us (this is an optional register and our implementation + * does not track RO/WO/reserved violations to report them to the guest) + */ + *data = 0; +- return MEMTX_OK; ++ return true; + case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: + { + int irq; + + if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { + *data = 0; +- return MEMTX_OK; ++ return true; + } + /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ + irq = (offset - GICD_IGROUPR) * 8; + if (irq < GIC_INTERNAL || irq >= s->num_irq) { + *data = 0; +- return MEMTX_OK; ++ return true; + } + *data = *gic_bmp_ptr32(s->group, irq); +- return MEMTX_OK; ++ return true; + } + case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, + offset - GICD_ISENABLER); +- return MEMTX_OK; ++ return true; + case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, + offset - GICD_ICENABLER); +- return MEMTX_OK; ++ return true; + case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, + offset - GICD_ISPENDR); +- return MEMTX_OK; ++ return true; + case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, + offset - GICD_ICPENDR); +- return MEMTX_OK; ++ return true; + case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, + offset - GICD_ISACTIVER); +- return MEMTX_OK; ++ return true; + case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: + *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, + offset - GICD_ICACTIVER); +- return MEMTX_OK; ++ return true; + case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: + { + int i, irq = offset - GICD_IPRIORITYR; +@@ -452,12 +465,12 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + value |= gicd_read_ipriorityr(s, attrs, i); + } + *data = value; +- return MEMTX_OK; ++ return true; + } + case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: + /* RAZ/WI since affinity routing is always enabled */ + *data = 0; +- return MEMTX_OK; ++ return true; + case GICD_ICFGR ... GICD_ICFGR + 0xff: + { + /* Here only the even bits are used; odd bits are RES0 */ +@@ -466,7 +479,7 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { + *data = 0; +- return MEMTX_OK; ++ return true; + } + + /* Since our edge_trigger bitmap is one bit per irq, we only need +@@ -478,7 +491,7 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + value = extract32(value, (irq & 0x1f) ? 16 : 0, 16); + value = half_shuffle32(value) << 1; + *data = value; +- return MEMTX_OK; ++ return true; + } + case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: + { +@@ -489,16 +502,16 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + * security enabled and this is an NS access + */ + *data = 0; +- return MEMTX_OK; ++ return true; + } + /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ + irq = (offset - GICD_IGRPMODR) * 8; + if (irq < GIC_INTERNAL || irq >= s->num_irq) { + *data = 0; +- return MEMTX_OK; ++ return true; + } + *data = *gic_bmp_ptr32(s->grpmod, irq); +- return MEMTX_OK; ++ return true; + } + case GICD_NSACR ... GICD_NSACR + 0xff: + { +@@ -507,7 +520,7 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { + *data = 0; +- return MEMTX_OK; ++ return true; + } + + if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { +@@ -515,17 +528,17 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + * security enabled and this is an NS access + */ + *data = 0; +- return MEMTX_OK; ++ return true; + } + + *data = s->gicd_nsacr[irq / 16]; +- return MEMTX_OK; ++ return true; + } + case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: + case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: + /* RAZ/WI since affinity routing is always enabled */ + *data = 0; +- return MEMTX_OK; ++ return true; + case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: + { + uint64_t r; +@@ -537,26 +550,26 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, + } else { + *data = (uint32_t)r; + } +- return MEMTX_OK; ++ return true; + } + case GICD_IDREGS ... GICD_IDREGS + 0x2f: + /* ID registers */ + *data = gicv3_idreg(offset - GICD_IDREGS); +- return MEMTX_OK; ++ return true; + case GICD_SGIR: + /* WO registers, return unknown value */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest read from WO register at offset " + TARGET_FMT_plx "\n", __func__, offset); + *data = 0; +- return MEMTX_OK; ++ return true; + default: +- return MEMTX_ERROR; ++ return false; + } + } + +-static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, +- uint64_t value, MemTxAttrs attrs) ++static bool gicd_writel(GICv3State *s, hwaddr offset, ++ uint64_t value, MemTxAttrs attrs) + { + /* Almost all GICv3 distributor registers are 32-bit. Note that + * RO registers must ignore writes, not abort. +@@ -600,68 +613,68 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); + } + gicv3_full_update(s); +- return MEMTX_OK; ++ return true; + } + case GICD_STATUSR: + /* RAZ/WI for our implementation */ +- return MEMTX_OK; ++ return true; + case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: + { + int irq; + + if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { +- return MEMTX_OK; ++ return true; + } + /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ + irq = (offset - GICD_IGROUPR) * 8; + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + *gic_bmp_ptr32(s->group, irq) = value; + gicv3_update(s, irq, 32); +- return MEMTX_OK; ++ return true; + } + case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: + gicd_write_set_bitmap_reg(s, attrs, s->enabled, NULL, + offset - GICD_ISENABLER, value); +- return MEMTX_OK; ++ return true; + case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: + gicd_write_clear_bitmap_reg(s, attrs, s->enabled, NULL, + offset - GICD_ICENABLER, value); +- return MEMTX_OK; ++ return true; + case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: + gicd_write_set_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, + offset - GICD_ISPENDR, value); +- return MEMTX_OK; ++ return true; + case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: + gicd_write_clear_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, + offset - GICD_ICPENDR, value); +- return MEMTX_OK; ++ return true; + case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: + gicd_write_set_bitmap_reg(s, attrs, s->active, NULL, + offset - GICD_ISACTIVER, value); +- return MEMTX_OK; ++ return true; + case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: + gicd_write_clear_bitmap_reg(s, attrs, s->active, NULL, + offset - GICD_ICACTIVER, value); +- return MEMTX_OK; ++ return true; + case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: + { + int i, irq = offset - GICD_IPRIORITYR; + + if (irq < GIC_INTERNAL || irq + 3 >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + + for (i = irq; i < irq + 4; i++, value >>= 8) { + gicd_write_ipriorityr(s, attrs, i, value); + } + gicv3_update(s, irq, 4); +- return MEMTX_OK; ++ return true; + } + case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: + /* RAZ/WI since affinity routing is always enabled */ +- return MEMTX_OK; ++ return true; + case GICD_ICFGR ... GICD_ICFGR + 0xff: + { + /* Here only the odd bits are used; even bits are RES0 */ +@@ -669,7 +682,7 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + uint32_t mask, oldval; + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + + /* Since our edge_trigger bitmap is one bit per irq, our input +@@ -687,7 +700,7 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + oldval = *gic_bmp_ptr32(s->edge_trigger, (irq & ~0x1f)); + value = (oldval & ~mask) | (value & mask); + *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f) = value; +- return MEMTX_OK; ++ return true; + } + case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: + { +@@ -697,16 +710,16 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + /* RAZ/WI if security disabled, or if + * security enabled and this is an NS access + */ +- return MEMTX_OK; ++ return true; + } + /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ + irq = (offset - GICD_IGRPMODR) * 8; + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + *gic_bmp_ptr32(s->grpmod, irq) = value; + gicv3_update(s, irq, 32); +- return MEMTX_OK; ++ return true; + } + case GICD_NSACR ... GICD_NSACR + 0xff: + { +@@ -714,41 +727,41 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + int irq = (offset - GICD_NSACR) * 4; + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + + if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { + /* RAZ/WI if security disabled, or if + * security enabled and this is an NS access + */ +- return MEMTX_OK; ++ return true; + } + + s->gicd_nsacr[irq / 16] = value; + /* No update required as this only affects access permission checks */ +- return MEMTX_OK; ++ return true; + } + case GICD_SGIR: + /* RES0 if affinity routing is enabled */ +- return MEMTX_OK; ++ return true; + case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: + case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: + /* RAZ/WI since affinity routing is always enabled */ +- return MEMTX_OK; ++ return true; + case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: + { + uint64_t r; + int irq = (offset - GICD_IROUTER) / 8; + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { +- return MEMTX_OK; ++ return true; + } + + /* Write half of the 64-bit register */ + r = gicd_read_irouter(s, attrs, irq); + r = deposit64(r, (offset & 7) ? 32 : 0, 32, value); + gicd_write_irouter(s, attrs, irq, r); +- return MEMTX_OK; ++ return true; + } + case GICD_IDREGS ... GICD_IDREGS + 0x2f: + case GICD_TYPER: +@@ -757,14 +770,14 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest write to RO register at offset " + TARGET_FMT_plx "\n", __func__, offset); +- return MEMTX_OK; ++ return true; + default: +- return MEMTX_ERROR; ++ return false; + } + } + +-static MemTxResult gicd_writeq(GICv3State *s, hwaddr offset, +- uint64_t value, MemTxAttrs attrs) ++static bool gicd_writeq(GICv3State *s, hwaddr offset, ++ uint64_t value, MemTxAttrs attrs) + { + /* Our only 64-bit registers are GICD_IROUTER */ + int irq; +@@ -773,14 +786,14 @@ static MemTxResult gicd_writeq(GICv3State *s, hwaddr offset, + case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: + irq = (offset - GICD_IROUTER) / 8; + gicd_write_irouter(s, attrs, irq, value); +- return MEMTX_OK; ++ return true; + default: +- return MEMTX_ERROR; ++ return false; + } + } + +-static MemTxResult gicd_readq(GICv3State *s, hwaddr offset, +- uint64_t *data, MemTxAttrs attrs) ++static bool gicd_readq(GICv3State *s, hwaddr offset, ++ uint64_t *data, MemTxAttrs attrs) + { + /* Our only 64-bit registers are GICD_IROUTER */ + int irq; +@@ -789,9 +802,9 @@ static MemTxResult gicd_readq(GICv3State *s, hwaddr offset, + case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: + irq = (offset - GICD_IROUTER) / 8; + *data = gicd_read_irouter(s, attrs, irq); +- return MEMTX_OK; ++ return true; + default: +- return MEMTX_ERROR; ++ return false; + } + } + +@@ -799,7 +812,7 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, + unsigned size, MemTxAttrs attrs) + { + GICv3State *s = (GICv3State *)opaque; +- MemTxResult r; ++ bool r; + + switch (size) { + case 1: +@@ -815,11 +828,11 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, + r = gicd_readq(s, offset, data, attrs); + break; + default: +- r = MEMTX_ERROR; ++ r = false; + break; + } + +- if (r == MEMTX_ERROR) { ++ if (!r) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest read at offset " TARGET_FMT_plx + "size %u\n", __func__, offset, size); +@@ -829,19 +842,18 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ +- r = MEMTX_OK; + *data = 0; + } else { + trace_gicv3_dist_read(offset, *data, size, attrs.secure); + } +- return r; ++ return MEMTX_OK; + } + + MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size, MemTxAttrs attrs) + { + GICv3State *s = (GICv3State *)opaque; +- MemTxResult r; ++ bool r; + + switch (size) { + case 1: +@@ -857,11 +869,11 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, + r = gicd_writeq(s, offset, data, attrs); + break; + default: +- r = MEMTX_ERROR; ++ r = false; + break; + } + +- if (r == MEMTX_ERROR) { ++ if (!r) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest write at offset " TARGET_FMT_plx + "size %u\n", __func__, offset, size); +@@ -871,11 +883,10 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ +- r = MEMTX_OK; + } else { + trace_gicv3_dist_write(offset, data, size, attrs.secure); + } +- return r; ++ return MEMTX_OK; + } + + void gicv3_dist_set_irq(GICv3State *s, int irq, int level) +-- +2.27.0 + diff --git a/hw-intc-arm_gicv3_dist-Rename-64-bit-accessors-with-.patch b/hw-intc-arm_gicv3_dist-Rename-64-bit-accessors-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2f1b83c30773db931ceee1aa3d856ddab5eae1ad --- /dev/null +++ b/hw-intc-arm_gicv3_dist-Rename-64-bit-accessors-with-.patch @@ -0,0 +1,67 @@ +From d8b202275adace1bfcce4fc735f5b05642a08406 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 26 Aug 2021 20:07:03 +0200 +Subject: [PATCH 1/4] hw/intc/arm_gicv3_dist: Rename 64-bit accessors with 'q' + suffix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU load/store API (docs/devel/loads-stores.rst) uses the 'q' +suffix for 64-bit accesses. Rename the current 'll' suffix to +have the GIC dist accessors better match the rest of the codebase. + +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20210826180704.2131949-2-philmd@redhat.com +Signed-off-by: Peter Maydell +--- + hw/intc/arm_gicv3_dist.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c +index b65f56f903..7e9b393d9a 100644 +--- a/hw/intc/arm_gicv3_dist.c ++++ b/hw/intc/arm_gicv3_dist.c +@@ -763,8 +763,8 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, + } + } + +-static MemTxResult gicd_writell(GICv3State *s, hwaddr offset, +- uint64_t value, MemTxAttrs attrs) ++static MemTxResult gicd_writeq(GICv3State *s, hwaddr offset, ++ uint64_t value, MemTxAttrs attrs) + { + /* Our only 64-bit registers are GICD_IROUTER */ + int irq; +@@ -779,8 +779,8 @@ static MemTxResult gicd_writell(GICv3State *s, hwaddr offset, + } + } + +-static MemTxResult gicd_readll(GICv3State *s, hwaddr offset, +- uint64_t *data, MemTxAttrs attrs) ++static MemTxResult gicd_readq(GICv3State *s, hwaddr offset, ++ uint64_t *data, MemTxAttrs attrs) + { + /* Our only 64-bit registers are GICD_IROUTER */ + int irq; +@@ -812,7 +812,7 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, + r = gicd_readl(s, offset, data, attrs); + break; + case 8: +- r = gicd_readll(s, offset, data, attrs); ++ r = gicd_readq(s, offset, data, attrs); + break; + default: + r = MEMTX_ERROR; +@@ -854,7 +854,7 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, + r = gicd_writel(s, offset, data, attrs); + break; + case 8: +- r = gicd_writell(s, offset, data, attrs); ++ r = gicd_writeq(s, offset, data, attrs); + break; + default: + r = MEMTX_ERROR; +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..2b77e0b0ce8a678b0c13b7f9f852522617b90c71 --- /dev/null +++ b/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch @@ -0,0 +1,170 @@ +From 6bbfb186c8d66b745aeb08143d3198fcedc52d6c 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 + +GICv3 exposes individual CPU realization capability through +this hook. It will be used for hotplugged CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3.c | 17 ++++++++++++++++- + hw/intc/arm_gicv3_common.c | 8 ++++++++ + hw/intc/arm_gicv3_kvm.c | 11 +++++++++++ + include/hw/intc/arm_gicv3.h | 2 ++ + include/hw/intc/arm_gicv3_common.h | 4 ++++ + 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 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -361,6 +361,19 @@ static const MemoryRegionOps gic_ops[] = { + } + }; + ++static void gicv3_cpu_realize(GICv3State *s, int i) ++{ ++ gicv3_init_one_cpuif(s, i); ++} ++ ++static void arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu) ++{ ++ ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); ++ ++ agc->parent_cpu_hotplug_realize(s, ncpu); ++ gicv3_cpu_realize(s, ncpu); ++} ++ + 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) + } + + 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) + 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 +--- 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) + 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); ++} ++ + 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) + + 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[] = { + 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; + 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 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -78,6 +78,7 @@ typedef 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) + 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); ++ ++ kagcc->parent_cpu_hotplug_realize(s, ncpu); ++ kvm_arm_gicv3_cpu_realize(s, ncpu); ++} ++ + 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) + 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 +--- a/include/hw/intc/arm_gicv3.h ++++ b/include/hw/intc/arm_gicv3.h +@@ -26,6 +26,8 @@ typedef 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 +--- 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) + ++typedef void (*CPUHotplugRealize)(GICv3State *s, int ncpu); ++ + typedef 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..c00ae6b288bf510f09655df7b0aec707734ecd2e --- /dev/null +++ b/hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch @@ -0,0 +1,46 @@ +From 745e9fea5485e564414a904ce0831bc79c11ac57 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-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 new file mode 100644 index 0000000000000000000000000000000000000000..15fcf5714818fbcaf4a8a73553c0336b83bd9ad3 --- /dev/null +++ b/hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch @@ -0,0 +1,40 @@ +From d65a00000e56ee2cec2f506b1408128d2df56ad9 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-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch b/hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..892ac3b2fca7e9c89354c8b2a6ad9c994d341b6e --- /dev/null +++ b/hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch @@ -0,0 +1,39 @@ +From 9997745aade411cc5fe27bb3c314f24698c7e20a 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 + +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 that by setting group->l2_flood.group_ids to NULL after free. + +Signed-off-by: Jiajie Li +Signed-off-by: Qiang Ning +--- + 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 +--- 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, + err_out: + group->l2_flood.group_count = 0; + g_free(group->l2_flood.group_ids); ++ group->l2_flood.group_ids = NULL; + g_free(tlvs); + + return err; +-- +2.27.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..778be3969efed4e27d4e4638ae5f298c5dcbbc1b --- /dev/null +++ b/hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch @@ -0,0 +1,58 @@ +From a80a85c7c358febb164ace0dfa75c468f43e0f02 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-pci-host-add-pci-intack-write-method.patch b/hw-pci-host-add-pci-intack-write-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..7aa079133005fc5428099bb87bdbb2d6622d7a8f --- /dev/null +++ b/hw-pci-host-add-pci-intack-write-method.patch @@ -0,0 +1,50 @@ +From 50402aa839e366f6365d9da5a46f3261f54dbd06 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-rdma-Fix-possible-mremap-overflow-in-the-pvrdma-d.patch b/hw-rdma-Fix-possible-mremap-overflow-in-the-pvrdma-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..d047ee316de5f6b6cfdb80de451da6ff232e51c7 --- /dev/null +++ b/hw-rdma-Fix-possible-mremap-overflow-in-the-pvrdma-d.patch @@ -0,0 +1,45 @@ +From be2098de6cafdce46c104d6ff277b7b780631e40 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum +Date: Wed, 16 Jun 2021 14:06:00 +0300 +Subject: [PATCH 1/3] hw/rdma: Fix possible mremap overflow in the pvrdma + device (CVE-2021-3582) + +Ensure mremap boundaries not trusting the guest kernel to +pass the correct buffer length. + +Fixes: CVE-2021-3582 +Reported-by: VictorV (Kunlun Lab) +Tested-by: VictorV (Kunlun Lab) +Signed-off-by: Marcel Apfelbaum +Message-Id: <20210616110600.20889-1-marcel.apfelbaum@gmail.com> +Reviewed-by: Yuval Shaia +Tested-by: Yuval Shaia +Reviewed-by: Prasad J Pandit +Signed-off-by: Marcel Apfelbaum +cherry-pick from: 284f191b4abad213aed04cb0458e1600fd18d7c4 +Signed-off-by: yezengruan +--- + hw/rdma/vmw/pvrdma_cmd.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c +index 8d70c0d23d..dca8f36693 100644 +--- a/hw/rdma/vmw/pvrdma_cmd.c ++++ b/hw/rdma/vmw/pvrdma_cmd.c +@@ -39,6 +39,13 @@ static void *pvrdma_map_to_pdir(PCIDevice *pdev, uint64_t pdir_dma, + return NULL; + } + ++ length = ROUND_UP(length, TARGET_PAGE_SIZE); ++ if (nchunks * TARGET_PAGE_SIZE != length) { ++ rdma_error_report("Invalid nchunks/length (%u, %lu)", nchunks, ++ (unsigned long)length); ++ return NULL; ++ } ++ + dir = rdma_pci_dma_map(pdev, pdir_dma, TARGET_PAGE_SIZE); + if (!dir) { + rdma_error_report("Failed to map to page directory"); +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..12c907453efdaa1141217b3adccf27d4099ee924 --- /dev/null +++ b/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch @@ -0,0 +1,132 @@ +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-scsi-disk-MODE_PAGE_ALLS-not-allowed-in-MODE.patch b/hw-scsi-scsi-disk-MODE_PAGE_ALLS-not-allowed-in-MODE.patch new file mode 100644 index 0000000000000000000000000000000000000000..432e6ccaa200722f2be1c9e18ee742461ae5458f --- /dev/null +++ b/hw-scsi-scsi-disk-MODE_PAGE_ALLS-not-allowed-in-MODE.patch @@ -0,0 +1,50 @@ +From 08438d7975713bbeed2dff8467bd4656b34221ad Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Thu, 4 Nov 2021 17:31:38 +0100 +Subject: [PATCH] hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT + commands + +This avoids an off-by-one read of 'mode_sense_valid' buffer in +hw/scsi/scsi-disk.c:mode_sense_page(). + +Fixes: CVE-2021-3930 +Cc: qemu-stable@nongnu.org +Reported-by: Alexander Bulekov +Fixes: a8f4bbe2900 ("scsi-disk: store valid mode pages in a table") +Fixes: #546 +Reported-by: Qiuhao Li +Signed-off-by: Mauro Matteo Cascella +Signed-off-by: Paolo Bonzini +cherry-pick from: b3af7fdf9cc537f8f0dd3e2423d83f5c99a457e8 +Signed-off-by: AlexChen +--- + hw/scsi/scsi-disk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index cd90cd780e..297efd5a72 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -1082,6 +1082,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, + uint8_t *p = *p_outbuf + 2; + int length; + ++ assert(page < ARRAY_SIZE(mode_sense_valid)); + if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) { + return -1; + } +@@ -1423,6 +1424,11 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, + return -1; + } + ++ /* MODE_PAGE_ALLS is only valid for MODE SENSE commands */ ++ if (page == MODE_PAGE_ALLS) { ++ return -1; ++ } ++ + p = mode_current; + memset(mode_current, 0, inlen + 2); + len = mode_sense_page(s, page, &p, 0); +-- +2.27.0 + diff --git a/hw-sd-sdcard-Do-not-allow-invalid-SD-card-sizes.patch b/hw-sd-sdcard-Do-not-allow-invalid-SD-card-sizes.patch new file mode 100644 index 0000000000000000000000000000000000000000..07e194f6e1f9ae248b8733e8ae07604a8bbd2249 --- /dev/null +++ b/hw-sd-sdcard-Do-not-allow-invalid-SD-card-sizes.patch @@ -0,0 +1,105 @@ +From ee7165e6dd077ebbe25f79b45fe0094a6c6779ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Tue, 7 Jul 2020 13:02:34 +0200 +Subject: [PATCH 5/7] hw/sd/sdcard: Do not allow invalid SD card sizes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU allows to create SD card with unrealistic sizes. This could +work, but some guests (at least Linux) consider sizes that are not +a power of 2 as a firmware bug and fix the card size to the next +power of 2. + +While the possibility to use small SD card images has been seen as +a feature, it became a bug with CVE-2020-13253, where the guest is +able to do OOB read/write accesses past the image size end. + +In a pair of commits we will fix CVE-2020-13253 as: + + Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + WP_VIOLATION errors are not modified: the error bit is set, we + stay in receive-data state, wait for a stop command. All further + data transfer is ignored. See the check on sd->card_status at the + beginning of sd_read_data() and sd_write_data(). + +While this is the correct behavior, in case QEMU create smaller SD +cards, guests still try to access past the image size end, and QEMU +considers this is an invalid address, thus "all further data transfer +is ignored". This is wrong and make the guest looping until +eventually timeouts. + +Fix by not allowing invalid SD card sizes (suggesting the expected +size as a hint): + + $ qemu-system-arm -M orangepi-pc -drive file=rootfs.ext2,if=sd,format=raw + qemu-system-arm: Invalid SD card size: 60 MiB + SD card size has to be a power of 2, e.g. 64 MiB. + You can resize disk images with 'qemu-img resize ' + (note that this will lose data if you make the image smaller than it currently is). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Reviewed-by: Peter Maydell +Message-Id: <20200713183209.26308-8-f4bug@amsat.org> +--- + hw/sd/sd.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index caac17e71b..263072a353 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -32,6 +32,7 @@ + + #include "qemu/osdep.h" + #include "qemu/units.h" ++#include "qemu-common.h" + #include "hw/qdev.h" + #include "hw/hw.h" + #include "hw/registerfields.h" +@@ -2091,11 +2092,35 @@ static void sd_realize(DeviceState *dev, Error **errp) + } + + if (sd->blk) { ++ int64_t blk_size; ++ + if (blk_is_read_only(sd->blk)) { + error_setg(errp, "Cannot use read-only drive as SD card"); + return; + } + ++ blk_size = blk_getlength(sd->blk); ++ if (blk_size > 0 && !is_power_of_2(blk_size)) { ++ int64_t blk_size_aligned = pow2ceil(blk_size); ++ char *blk_size_str; ++ ++ blk_size_str = size_to_str(blk_size); ++ error_setg(errp, "Invalid SD card size: %s", blk_size_str); ++ g_free(blk_size_str); ++ ++ blk_size_str = size_to_str(blk_size_aligned); ++ error_append_hint(errp, ++ "SD card size has to be a power of 2, e.g. %s.\n" ++ "You can resize disk images with" ++ " 'qemu-img resize '\n" ++ "(note that this will lose data if you make the" ++ " image smaller than it currently is).\n", ++ blk_size_str); ++ g_free(blk_size_str); ++ ++ return; ++ } ++ + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { +-- +2.17.1 + diff --git a/hw-sd-sdcard-Do-not-switch-to-ReceivingData-if-addre.patch b/hw-sd-sdcard-Do-not-switch-to-ReceivingData-if-addre.patch new file mode 100644 index 0000000000000000000000000000000000000000..70e73e2d680ac30cef0055959234e5ecd64638ba --- /dev/null +++ b/hw-sd-sdcard-Do-not-switch-to-ReceivingData-if-addre.patch @@ -0,0 +1,131 @@ +From 8d920e44e5bd5e719aca03887e9bcc5a02787a2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 4 Jun 2020 19:22:29 +0200 +Subject: [PATCH 7/7] hw/sd/sdcard: Do not switch to ReceivingData if address + is invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only move the state machine to ReceivingData if there is no +pending error. This avoids later OOB access while processing +commands queued. + + "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" + + 4.3.3 Data Read + + Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + 4.3.4 Data Write + + Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + +WP_VIOLATION errors are not modified: the error bit is set, we +stay in receive-data state, wait for a stop command. All further +data transfer is ignored. See the check on sd->card_status at the +beginning of sd_read_data() and sd_write_data(). + +Fixes: CVE-2020-13253 +Cc: qemu-stable@nongnu.org +Reported-by: Alexander Bulekov +Buglink: https://bugs.launchpad.net/qemu/+bug/1880822 +Reviewed-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Message-Id: <20200630133912.9428-6-f4bug@amsat.org> +--- + hw/sd/sd.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index ed796fb41f..79d5f1a5b9 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -1156,13 +1156,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + case 17: /* CMD17: READ_SINGLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: +- sd->state = sd_sendingdata_state; +- sd->data_start = addr; +- sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { ++ if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; + } ++ ++ sd->state = sd_sendingdata_state; ++ sd->data_start = addr; ++ sd->data_offset = 0; + return sd_r1; + + default: +@@ -1173,13 +1175,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: +- sd->state = sd_sendingdata_state; +- sd->data_start = addr; +- sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { ++ if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; + } ++ ++ sd->state = sd_sendingdata_state; ++ sd->data_start = addr; ++ sd->data_offset = 0; + return sd_r1; + + default: +@@ -1219,14 +1223,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; ++ ++ if (addr + sd->blk_len > sd->size) { ++ sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; ++ } ++ + sd->state = sd_receivingdata_state; + sd->data_start = addr; + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { +- sd->card_status |= ADDRESS_ERROR; +- } + if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; + } +@@ -1246,14 +1253,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; ++ ++ if (addr + sd->blk_len > sd->size) { ++ sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; ++ } ++ + sd->state = sd_receivingdata_state; + sd->data_start = addr; + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { +- sd->card_status |= ADDRESS_ERROR; +- } + if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; + } +-- +2.17.1 + diff --git a/hw-sd-sdcard-Restrict-Class-6-commands-to-SCSD-cards.patch b/hw-sd-sdcard-Restrict-Class-6-commands-to-SCSD-cards.patch new file mode 100644 index 0000000000000000000000000000000000000000..b48954ab04e873bfe4e6d3c057bd01f70b57bb2e --- /dev/null +++ b/hw-sd-sdcard-Restrict-Class-6-commands-to-SCSD-cards.patch @@ -0,0 +1,48 @@ +From 3fb16cbd24233829b3696e06abb12db317d68aac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 3 Jun 2020 19:59:16 +0200 +Subject: [PATCH 3/7] hw/sd/sdcard: Restrict Class 6 commands to SCSD cards +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only SCSD cards support Class 6 (Block Oriented Write Protection) +commands. + + "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" + + 4.3.14 Command Functional Difference in Card Capacity Types + + * Write Protected Group + + SDHC and SDXC do not support write-protected groups. Issuing + CMD28, CMD29 and CMD30 generates the ILLEGAL_COMMAND error. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Message-Id: <20200630133912.9428-7-f4bug@amsat.org> +--- + hw/sd/sd.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index 917195a65b..ed3eae930b 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -905,6 +905,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->multi_blk_cnt = 0; + } + ++ if (sd_cmd_class[req.cmd] == 6 && FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { ++ /* Only Standard Capacity cards support class 6 commands */ ++ return sd_illegal; ++ } ++ + switch (req.cmd) { + /* Basic commands (Class 0 and Class 1) */ + case 0: /* CMD0: GO_IDLE_STATE */ +-- +2.17.1 + diff --git a/hw-sd-sdcard-Simplify-realize-a-bit.patch b/hw-sd-sdcard-Simplify-realize-a-bit.patch new file mode 100644 index 0000000000000000000000000000000000000000..973a0b43fa104c20a0dfb7f987f9052532d9596c --- /dev/null +++ b/hw-sd-sdcard-Simplify-realize-a-bit.patch @@ -0,0 +1,43 @@ +From 3b8e4bca9d5d51219778950456d52226a9caffdf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Tue, 5 Jun 2018 22:28:51 -0300 +Subject: [PATCH 4/7] hw/sd/sdcard: Simplify realize() a bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We don't need to check if sd->blk is set twice. + +Reviewed-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Message-Id: <20200630133912.9428-18-f4bug@amsat.org> +--- + hw/sd/sd.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index ed3eae930b..caac17e71b 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -2090,12 +2090,12 @@ static void sd_realize(DeviceState *dev, Error **errp) + return; + } + +- if (sd->blk && blk_is_read_only(sd->blk)) { +- error_setg(errp, "Cannot use read-only drive as SD card"); +- return; +- } +- + if (sd->blk) { ++ if (blk_is_read_only(sd->blk)) { ++ error_setg(errp, "Cannot use read-only drive as SD card"); ++ return; ++ } ++ + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { +-- +2.17.1 + diff --git a/hw-sd-sdcard-Update-coding-style-to-make-checkpatch..patch b/hw-sd-sdcard-Update-coding-style-to-make-checkpatch..patch new file mode 100644 index 0000000000000000000000000000000000000000..95b38434da8826b1fdf8a5da4375b4dd58e7a622 --- /dev/null +++ b/hw-sd-sdcard-Update-coding-style-to-make-checkpatch..patch @@ -0,0 +1,87 @@ +From 29a65998b9c0e22983d6861efabae88106af591b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 13 Jul 2020 09:27:35 +0200 +Subject: [PATCH 6/7] hw/sd/sdcard: Update coding style to make checkpatch.pl + happy +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To make the next commit easier to review, clean this code first. + +Reviewed-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Reviewed-by: Alexander Bulekov +Message-Id: <20200630133912.9428-3-f4bug@amsat.org> +--- + hw/sd/sd.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index 263072a353..ed796fb41f 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -1160,8 +1160,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->data_start = addr; + sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ } + return sd_r1; + + default: +@@ -1176,8 +1177,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->data_start = addr; + sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ } + return sd_r1; + + default: +@@ -1222,12 +1224,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; +- if (sd_wp_addr(sd, sd->data_start)) ++ } ++ if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; +- if (sd->csd[14] & 0x30) ++ } ++ if (sd->csd[14] & 0x30) { + sd->card_status |= WP_VIOLATION; ++ } + return sd_r1; + + default: +@@ -1246,12 +1251,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; +- if (sd_wp_addr(sd, sd->data_start)) ++ } ++ if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; +- if (sd->csd[14] & 0x30) ++ } ++ if (sd->csd[14] & 0x30) { + sd->card_status |= WP_VIOLATION; ++ } + return sd_r1; + + default: +-- +2.17.1 + diff --git a/hw-sd-sdhci-Correctly-set-the-controller-status-for-.patch b/hw-sd-sdhci-Correctly-set-the-controller-status-for-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bcc2725e1ae86cd8c8cb4e04872e42a79a960b07 --- /dev/null +++ b/hw-sd-sdhci-Correctly-set-the-controller-status-for-.patch @@ -0,0 +1,75 @@ +From 8d286a071877216c5b282bb14f34ff3b09d3f3f8 Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Sat, 8 May 2021 10:51:37 +0800 +Subject: [PATCH] hw/sd: sdhci: Correctly set the controller status for ADMA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 + +When an ADMA transfer is started, the codes forget to set the +controller status to indicate a transfer is in progress. + +With this fix, the following 2 reproducers: + +https://paste.debian.net/plain/1185136 +https://paste.debian.net/plain/1185141 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov +Reported-by: Cornelius Aschermann (Ruhr-University Bochum) +Reported-by: Muhammad Ramdhan +Reported-by: Sergej Schumilo (Ruhr-University Bochum) +Reported-by: Simon Wrner (Ruhr-University Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Signed-off-by: Bin Meng +Tested-by: Alexander Bulekov +Reviewed-by: Philippe Mathieu-Daudé + +Signed-off-by: Jiajie Li +--- + hw/sd/sdhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index fdb59f44e6..8c857d1e40 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -776,8 +776,9 @@ static void sdhci_do_adma(SDHCIState *s) + + switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) { + case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */ +- ++ s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE; + if (s->trnmod & SDHC_TRNS_READ) { ++ s->prnsts |= SDHC_DOING_READ; + while (length) { + if (s->data_count == 0) { + for (n = 0; n < block_size; n++) { +@@ -807,6 +808,7 @@ static void sdhci_do_adma(SDHCIState *s) + } + } + } else { ++ s->prnsts |= SDHC_DOING_WRITE; + while (length) { + begin = s->data_count; + if ((length + begin) < block_size) { +-- +2.27.0 + diff --git a/hw-sd-sdhci-Don-t-transfer-any-data-when-command-tim.patch b/hw-sd-sdhci-Don-t-transfer-any-data-when-command-tim.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea461c09036af3fe2d0f5f506e8883d205fd8970 --- /dev/null +++ b/hw-sd-sdhci-Don-t-transfer-any-data-when-command-tim.patch @@ -0,0 +1,93 @@ +From e71b13a123d197f97bab5050377cb537516d1e0f Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Sat, 8 May 2021 10:39:15 +0800 +Subject: [PATCH] hw/sd: sdhci: Don't transfer any data when command time out +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 + +At the end of sdhci_send_command(), it starts a data transfer if the +command register indicates data is associated. But the data transfer +should only be initiated when the command execution has succeeded. + +With this fix, the following reproducer: + +outl 0xcf8 0x80001810 +outl 0xcfc 0xe1068000 +outl 0xcf8 0x80001804 +outw 0xcfc 0x7 +write 0xe106802c 0x1 0x0f +write 0xe1068004 0xc 0x2801d10101fffffbff28a384 +write 0xe106800c 0x1f +0x9dacbbcad9e8f7061524334251606f7e8d9cabbac9d8e7f60514233241505f +write 0xe1068003 0x28 +0x80d000251480d000252280d000253080d000253e80d000254c80d000255a80d000256880d0002576 +write 0xe1068003 0x1 0xfe + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -M pc-q35-5.0 \ + -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive \ + -monitor none -serial none -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov +Reported-by: Cornelius Aschermann (Ruhr-University Bochum) +Reported-by: Muhammad Ramdhan +Reported-by: Sergej Schumilo (Ruhr-University Bochum) +Reported-by: Simon Wrner (Ruhr-University Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Signed-off-by: Bin Meng +Acked-by: Alistair Francis +Tested-by: Alexander Bulekov +Tested-by: Philippe Mathieu-Daudé + +Signed-off-by: Jiajie Li +--- + hw/sd/sdhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index d4ee6bd01f..419782c25d 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -314,6 +314,7 @@ static void sdhci_send_command(SDHCIState *s) + SDRequest request; + uint8_t response[16]; + int rlen; ++ bool timeout = false; + + s->errintsts = 0; + s->acmd12errsts = 0; +@@ -337,6 +338,7 @@ static void sdhci_send_command(SDHCIState *s) + trace_sdhci_response16(s->rspreg[3], s->rspreg[2], + s->rspreg[1], s->rspreg[0]); + } else { ++ timeout = true; + trace_sdhci_error("timeout waiting for command response"); + if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { + s->errintsts |= SDHC_EIS_CMDTIMEOUT; +@@ -357,7 +359,7 @@ static void sdhci_send_command(SDHCIState *s) + + sdhci_update_irq(s); + +- if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { ++ if (!timeout && s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + s->data_count = 0; + sdhci_data_transfer(s); + } +-- +2.27.0 + diff --git a/hw-sd-sdhci-Don-t-write-to-SDHC_SYSAD-register-when-.patch b/hw-sd-sdhci-Don-t-write-to-SDHC_SYSAD-register-when-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7460614b6e876746f7306c124f8c54ec64fd0094 --- /dev/null +++ b/hw-sd-sdhci-Don-t-write-to-SDHC_SYSAD-register-when-.patch @@ -0,0 +1,106 @@ +From f95d0c3bb20d33cfef35378fbfbd61b02544b2d4 Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Sat, 8 May 2021 10:47:12 +0800 +Subject: [PATCH] hw/sd: sdhci: Don't write to SDHC_SYSAD register when + transfer is in progress + +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 + +Per "SD Host Controller Standard Specification Version 7.00" +chapter 2.2.1 SDMA System Address Register: + +This register can be accessed only if no transaction is executing +(i.e., after a transaction has stopped). + +With this fix, the following reproducer: + +outl 0xcf8 0x80001010 +outl 0xcfc 0xfbefff00 +outl 0xcf8 0x80001001 +outl 0xcfc 0x06000000 +write 0xfbefff2c 0x1 0x05 +write 0xfbefff0f 0x1 0x37 +write 0xfbefff0a 0x1 0x01 +write 0xfbefff0f 0x1 0x29 +write 0xfbefff0f 0x1 0x02 +write 0xfbefff0f 0x1 0x03 +write 0xfbefff04 0x1 0x01 +write 0xfbefff05 0x1 0x01 +write 0xfbefff07 0x1 0x02 +write 0xfbefff0c 0x1 0x33 +write 0xfbefff0e 0x1 0x20 +write 0xfbefff0f 0x1 0x00 +write 0xfbefff2a 0x1 0x01 +write 0xfbefff0c 0x1 0x00 +write 0xfbefff03 0x1 0x00 +write 0xfbefff05 0x1 0x00 +write 0xfbefff2a 0x1 0x02 +write 0xfbefff0c 0x1 0x32 +write 0xfbefff01 0x1 0x01 +write 0xfbefff02 0x1 0x01 +write 0xfbefff03 0x1 0x01 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov +Reported-by: Cornelius Aschermann (Ruhr-University Bochum) +Reported-by: Muhammad Ramdhan +Reported-by: Sergej Schumilo (Ruhr-University Bochum) +Reported-by: Simon Wrner (Ruhr-University Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Signed-off-by: Bin Meng +Tested-by: Alexander Bulekov + +Signed-off-by: Jiajie Li +--- + hw/sd/sdhci.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index 419782c25d..fdb59f44e6 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1117,15 +1117,17 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) + + switch (offset & ~0x3) { + case SDHC_SYSAD: +- s->sdmasysad = (s->sdmasysad & mask) | value; +- MASKED_WRITE(s->sdmasysad, mask, value); +- /* Writing to last byte of sdmasysad might trigger transfer */ +- if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt && +- s->blksize && SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { +- if (s->trnmod & SDHC_TRNS_MULTI) { +- sdhci_sdma_transfer_multi_blocks(s); +- } else { +- sdhci_sdma_transfer_single_block(s); ++ if (!TRANSFERRING_DATA(s->prnsts)) { ++ s->sdmasysad = (s->sdmasysad & mask) | value; ++ MASKED_WRITE(s->sdmasysad, mask, value); ++ /* Writing to last byte of sdmasysad might trigger transfer */ ++ if (!(mask & 0xFF000000) && s->blkcnt && s->blksize && ++ SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { ++ if (s->trnmod & SDHC_TRNS_MULTI) { ++ sdhci_sdma_transfer_multi_blocks(s); ++ } else { ++ sdhci_sdma_transfer_single_block(s); ++ } + } + } + break; +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..4d4533a0ec96b25b4e16953d487121f0816761e9 --- /dev/null +++ b/hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch @@ -0,0 +1,38 @@ +From d99d965c232c649686b4d8bc42dc11dcaf90dc0b 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 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'Transfer Block Size' field is 12-bit wide. + +See section '2.2.2. Block Size Register (Offset 004h)' in datasheet. + +Cc: qemu-stable@nongnu.org +Cc: Igor Mitsyanko +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Fixes: d7dfca0807a ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov +Signed-off-by: Philippe Mathieu-Daudé +--- + hw/sd/sdhci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index 7b80b1d93f..65a530aee4 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-sd-sdhci-Limit-block-size-only-when-SDHC_BLKSIZE-.patch b/hw-sd-sdhci-Limit-block-size-only-when-SDHC_BLKSIZE-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9176a4d9e8ea2286826e9f5b75a40a37b5e6781d --- /dev/null +++ b/hw-sd-sdhci-Limit-block-size-only-when-SDHC_BLKSIZE-.patch @@ -0,0 +1,55 @@ +From f52bb54b58a81e92956510adb077c8ab416749d0 Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Sat, 8 May 2021 11:02:27 +0800 +Subject: [PATCH] hw/sd: sdhci: Limit block size only when SDHC_BLKSIZE + register is writable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 + +The codes to limit the maximum block size is only necessary when +SDHC_BLKSIZE register is writable. + +Signed-off-by: Bin Meng +Tested-by: Alexander Bulekov +Reviewed-by: Philippe Mathieu-Daudé + +Signed-off-by: Jiajie Li +--- + hw/sd/sdhci.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index 8c857d1e40..4b8d9de50b 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1137,15 +1137,15 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) + if (!TRANSFERRING_DATA(s->prnsts)) { + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); +- } + +- /* Limit block size to the maximum buffer size */ +- if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ +- "the maximum buffer 0x%x", __func__, s->blksize, +- s->buf_maxsz); ++ /* Limit block size to the maximum buffer size */ ++ if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ ++ "the maximum buffer 0x%x\n", __func__, s->blksize, ++ s->buf_maxsz); + +- s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); ++ s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); ++ } + } + + break; +-- +2.27.0 + diff --git a/hw-sd-sdhci-Reset-the-data-pointer-of-s-fifo_buffer-.patch b/hw-sd-sdhci-Reset-the-data-pointer-of-s-fifo_buffer-.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5bc9569c58f29df1c4b928734bd8cf69dcba793 --- /dev/null +++ b/hw-sd-sdhci-Reset-the-data-pointer-of-s-fifo_buffer-.patch @@ -0,0 +1,96 @@ +From 6fd51eacd097284a68be623a455900ac26bb4604 Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Sat, 8 May 2021 11:05:47 +0800 +Subject: [PATCH] hw/sd: sdhci: Reset the data pointer of s->fifo_buffer[] when + a different block size is programmed + +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 + +If the block size is programmed to a different value from the +previous one, reset the data pointer of s->fifo_buffer[] so that +s->fifo_buffer[] can be filled in using the new block size in +the next transfer. + +With this fix, the following reproducer: + +outl 0xcf8 0x80001010 +outl 0xcfc 0xe0000000 +outl 0xcf8 0x80001001 +outl 0xcfc 0x06000000 +write 0xe000002c 0x1 0x05 +write 0xe0000005 0x1 0x02 +write 0xe0000007 0x1 0x01 +write 0xe0000028 0x1 0x10 +write 0x0 0x1 0x23 +write 0x2 0x1 0x08 +write 0xe000000c 0x1 0x01 +write 0xe000000e 0x1 0x20 +write 0xe000000f 0x1 0x00 +write 0xe000000c 0x1 0x32 +write 0xe0000004 0x2 0x0200 +write 0xe0000028 0x1 0x00 +write 0xe0000003 0x1 0x40 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov +Reported-by: Cornelius Aschermann (Ruhr-University Bochum) +Reported-by: Muhammad Ramdhan +Reported-by: Sergej Schumilo (Ruhr-University Bochum) +Reported-by: Simon Wrner (Ruhr-University Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Signed-off-by: Bin Meng +Tested-by: Alexander Bulekov + +Signed-off-by: Jiajie Li +--- + hw/sd/sdhci.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index 4b8d9de50b..bcfba25691 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1135,6 +1135,8 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) + break; + case SDHC_BLKSIZE: + if (!TRANSFERRING_DATA(s->prnsts)) { ++ uint16_t blksize = s->blksize; ++ + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); + +@@ -1146,6 +1148,16 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) + + s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); + } ++ ++ /* ++ * If the block size is programmed to a different value from ++ * the previous one, reset the data pointer of s->fifo_buffer[] ++ * so that s->fifo_buffer[] can be filled in using the new block ++ * size in the next transfer. ++ */ ++ if (blksize != s->blksize) { ++ s->data_count = 0; ++ } + } + + break; +-- +2.27.0 + diff --git a/hw-usb-core-fix-buffer-overflow.patch b/hw-usb-core-fix-buffer-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..494955788a2506fd2d28521ff234118025fbe674 --- /dev/null +++ b/hw-usb-core-fix-buffer-overflow.patch @@ -0,0 +1,46 @@ +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-hcd-ohci-check-for-processed-TD-before-retire.patch b/hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch new file mode 100644 index 0000000000000000000000000000000000000000..70830e1864f34ab292a9898b27d6e2a901684ca0 --- /dev/null +++ b/hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch @@ -0,0 +1,40 @@ +From 3cd5fd3c0c03b6c852586470e955334b6c4760b9 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 new file mode 100644 index 0000000000000000000000000000000000000000..be38b5a98e4c1781e3cd8fabb94a23d066e32943 --- /dev/null +++ b/hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch @@ -0,0 +1,99 @@ +From e82083e09bc20f3a864d208c7be14efd5ff32f51 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-xhci-check-return-value-of-usb_packet_map.patch b/hw-xhci-check-return-value-of-usb_packet_map.patch new file mode 100644 index 0000000000000000000000000000000000000000..7c31967fbd3588d7a797e9f3cd4c7eec55f12ac9 --- /dev/null +++ b/hw-xhci-check-return-value-of-usb_packet_map.patch @@ -0,0 +1,74 @@ +From ff7545a6911bc7b9d818a541130f666a81077b44 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 UAF issue. This is LP#1891341. +Following is the reproducer provided in: +-->https://bugs.launchpad.net/qemu/+bug/1891341 + +cat << EOF | ./i386-softmmu/qemu-system-i386 -device nec-usb-xhci \ +-trace usb\* -device usb-audio -device usb-storage,drive=mydrive \ +-drive id=mydrive,file=null-co://,size=2M,format=raw,if=none \ +-nodefaults -nographic -qtest stdio +outl 0xcf8 0x80001016 +outl 0xcfc 0x3c009f0d +outl 0xcf8 0x80001004 +outl 0xcfc 0xc77695e +writel 0x9f0d000000000040 0xffff3655 +writeq 0x9f0d000000002000 0xff2f9e0000000000 +write 0x1d 0x1 0x27 +write 0x2d 0x1 0x2e +write 0x17232 0x1 0x03 +write 0x17254 0x1 0x06 +write 0x17278 0x1 0x34 +write 0x3d 0x1 0x27 +write 0x40 0x1 0x2e +write 0x41 0x1 0x72 +write 0x42 0x1 0x01 +write 0x4d 0x1 0x2e +write 0x4f 0x1 0x01 +writeq 0x9f0d000000002000 0x5c051a0100000000 +write 0x34001d 0x1 0x13 +write 0x340026 0x1 0x30 +write 0x340028 0x1 0x08 +write 0x34002c 0x1 0xfe +write 0x34002d 0x1 0x08 +write 0x340037 0x1 0x5e +write 0x34003a 0x1 0x05 +write 0x34003d 0x1 0x05 +write 0x34004d 0x1 0x13 +writeq 0x9f0d000000002000 0xff00010100400009 +EOF + +This patch fixes this. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1891341 +Reported-by: Alexander Bulekov +Signed-off-by: Li Qiang +Message-id: 20200812153139.15146-1-liq3ea@163.com +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index a21485fe8a..3b25abcacd 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-MSR-feature-bit-for-MDS-NO.patch b/i386-Add-MSR-feature-bit-for-MDS-NO.patch new file mode 100644 index 0000000000000000000000000000000000000000..42c8fde4fa144b0bffa6a1b65d3aadc60d9b009c --- /dev/null +++ b/i386-Add-MSR-feature-bit-for-MDS-NO.patch @@ -0,0 +1,34 @@ +From 986fcd107eb251d11bae70a2777f950f06fdafa4 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 new file mode 100644 index 0000000000000000000000000000000000000000..6be044eaa2945085848c000436b8f468944a8f4f --- /dev/null +++ b/i386-Add-macro-for-stibp.patch @@ -0,0 +1,36 @@ +From 1e7b66433eaef14948869a39dbda3debe0a70eb0 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 new file mode 100644 index 0000000000000000000000000000000000000000..dbd048c7b7f6711ea1070e8179b9be5801c2b183 --- /dev/null +++ b/i386-Add-new-CPU-model-Cooperlake.patch @@ -0,0 +1,96 @@ +From f22c307bb6d7dc17ab1757af4dba78761b1959e8 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/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch b/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch new file mode 100644 index 0000000000000000000000000000000000000000..9570b46b755e06705212253195a6605d738db350 --- /dev/null +++ b/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch @@ -0,0 +1,89 @@ +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-ahci-add-check-to-avoid-null-dereference-CVE-201.patch b/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch new file mode 100644 index 0000000000000000000000000000000000000000..9759ed95ba07fbbee866521adc84efd6e42a3ad4 --- /dev/null +++ b/ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch @@ -0,0 +1,40 @@ +From 32804e8f8649b8b16fa641f91c36a4cf7da15b9b 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 + (CVE-2019-12067) + +Fix CVE-2019-12067 + +AHCI emulator while committing DMA buffer in ahci_commit_buf() +may do a NULL dereference if the command header 'ad->cur_cmd' +is null. Add check to avoid it. + +Reported-by: Bugs SysSec +Signed-off-by: Prasad J Pandit + +Signed-off-by: Jiajie Li +--- + 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 +--- 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) + { + AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); + +- tx_bytes += le32_to_cpu(ad->cur_cmd->status); +- ad->cur_cmd->status = cpu_to_le32(tx_bytes); ++ if (ad->cur_cmd) { ++ tx_bytes += le32_to_cpu(ad->cur_cmd->status); ++ ad->cur_cmd->status = cpu_to_le32(tx_bytes); ++ } + } + + static int ahci_dma_rw_buf(IDEDMA *dma, int 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 new file mode 100644 index 0000000000000000000000000000000000000000..ced254bda4b8b4de8b1a7d3addf087e6d7430243 --- /dev/null +++ b/ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch @@ -0,0 +1,52 @@ +From 892af81380c9ba24a7c8582b5fae4d37a2e5cf47 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/imx7-ccm-add-digprog-mmio-write-method.patch b/imx7-ccm-add-digprog-mmio-write-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..f145d3246d96d24955ee4d85630c01af13f47e1c --- /dev/null +++ b/imx7-ccm-add-digprog-mmio-write-method.patch @@ -0,0 +1,41 @@ +From b1fdcea193cd962d107da770c3344409c3c88e82 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/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch new file mode 100644 index 0000000000000000000000000000000000000000..30175fb5126a8a9b7138c206365b61c96bcddaf0 --- /dev/null +++ b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch @@ -0,0 +1,357 @@ +From 0a75312c069d89be94bcaa688429d8f60a0c528b 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 + +Currently GICv3 supports fixed smp_cpus CPUs, and all CPUs are +present always. Now we want to pre-sizing GICv3 to support max_cpus +CPUs and not all of them are present always, so some sizing codes +should be concerned. + +GIC irqs, GICR and GICC are pre-created for all possible CPUs at +start, but only smp_cpus CPUs are realize and irqs of smp_cpus CPUs +are connected. + +Other code changes are mainly for arm_gicv3, and we do little about +kvm_arm_gicv3 becasue KVM will deal with the sizing information properly. + +Signed-off-by: Keqian Zhu +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_cpuif.c | 4 ++++ + hw/intc/arm_gicv3_kvm.c | 28 ++++++++++++++++++++++++- + include/hw/arm/virt.h | 3 ++- + 6 files changed, 96 insertions(+), 22 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 55d403bad6..dda22194b5 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -761,14 +761,19 @@ static void create_gic(VirtMachineState *vms) + SysBusDevice *gicbusdev; + const char *gictype; + int type = vms->gic_version, i; ++ /* The max number of CPUs suppored by GIC */ ++ unsigned int num_cpus = ms->smp.cpus; ++ /* 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); + 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) + 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) + 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) + + /* 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. ++ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's ++ * inputs. ++ * ++ * The irqs of remaining CPUs (if we has) will be connected during ++ * hotplugging. + */ + 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 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -20,6 +20,7 @@ + #include "qemu/module.h" + #include "hw/sysbus.h" + #include "hw/intc/arm_gicv3.h" ++#include "qom/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) + 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) + * 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); +- break; ++ if (!cs->seenbetter && cs->hppi.prio != 0xff && ++ cs->hppi.irq >= start && cs->hppi.irq < start + len) { ++ gicv3_full_update_noirqset(s); ++ break; ++ } + } + } + } +@@ -268,7 +273,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]); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpuif_update(&s->cpu[i]); ++ } + } + } + +@@ -280,7 +287,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) + 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)) { ++ gicv3_redist_update_noirqset(&s->cpu[i]); ++ } + } + } + +@@ -304,7 +315,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]); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpuif_update(&s->cpu[i]); ++ } + } + } + +@@ -401,7 +414,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- gicv3_cpu_realize(s, i); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpu_realize(s, i); ++ } + } + } + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index 8740a52c9f..913bf068be 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -24,10 +24,12 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "qemu/module.h" ++#include "qemu/error-report.h" + #include "qom/cpu.h" + #include "hw/intc/arm_gicv3_common.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) + 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) + * VLPIS == 0 (virtual LPIs not supported) + * PLPIS == 0 (physical LPIs not supported) + */ +- cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); ++ if (cpu) { ++ cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); ++ } else { ++ if (!mc->possible_cpu_arch_ids) { ++ error_report("MachineClass must implement possible_cpu_arch_ids " ++ "hook to support pre-sizing GICv3"); ++ exit(1); ++ } ++ ++ 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 +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index 56aa5efede..a20aa693ea 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, + 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 +--- 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) + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + GICv3CPUState *c = &s->cpu[ncpu]; + ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + 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) + 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) + GICv3CPUState *c = &s->cpu[ncpu]; + int num_pri_bits; + ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + 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) + /* 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) + + if (redist_typer & GICR_TYPER_PLPIS) { + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + 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) + */ + + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + GICv3CPUState *c = &s->cpu[ncpu]; + int num_pri_bits; + +@@ -806,7 +830,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + } + + 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 +--- 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) + vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; + + assert(vms->gic_version == 3); ++ GICv3State *s = ARM_GICV3_COMMON(vms->gic); + +- return vms->smp_cpus > redist0_capacity ? 2 : 1; ++ return s->num_cpu > redist0_capacity ? 2 : 1; + } + + #endif /* QEMU_ARM_VIRT_H */ +-- +2.19.1 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 new file mode 100644 index 0000000000000000000000000000000000000000..5232d3f2aeda4d3a8a83a725173eaff72d2af8d5 --- /dev/null +++ b/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch @@ -0,0 +1,50 @@ +From a7391f391336024986a5997e3beae8882c983ed0 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 + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out realization code to let +it can be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3_common.c | 15 +++++++++++---- + 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 +--- 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, + } + } + ++static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) ++{ ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ ++ s->cpu[ncpu].cpu = cpu; ++ s->cpu[ncpu].gic = s; ++ /* Store GICv3CPUState in CPUARMState gicv3state pointer */ ++ gicv3_set_gicv3state(cpu, &s->cpu[ncpu]); ++} ++ + 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) + 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 diff --git a/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch new file mode 100644 index 0000000000000000000000000000000000000000..95c60b02c66e48b2fbe6d64c5e139aa3ecdcfae9 --- /dev/null +++ b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch @@ -0,0 +1,197 @@ +From de97ff4a01008ad98f7d69adc4b84843fff3ce19 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 + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out some code to let it can +be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3.c | 5 +- + hw/intc/arm_gicv3_cpuif.c | 122 ++++++++++++++++++-------------------- + hw/intc/gicv3_internal.h | 2 +- + 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 +--- 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) + 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; + } + +- 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 +--- 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) + gicv3_cpuif_update(cs); + } + +-void gicv3_init_cpuif(GICv3State *s) ++void gicv3_init_one_cpuif(GICv3State *s, int ncpu) + { + /* Called from the GICv3 realize function; register our system + * registers with the CPU + */ +- int i; +- +- for (i = 0; i < s->num_cpu; i++) { +- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); +- GICv3CPUState *cs = &s->cpu[i]; +- +- /* Note that we can't just use the GICv3CPUState as an opaque pointer +- * in define_arm_cp_regs_with_opaque(), because when we're called back +- * it might be with code translated by CPU 0 but run by CPU 1, in +- * 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]; ++ ++ /* Note that we can't just use the GICv3CPUState as an opaque pointer ++ * in define_arm_cp_regs_with_opaque(), because when we're called back ++ * it might be with code translated by CPU 0 but run by CPU 1, in ++ * 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; + +- 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. +- */ +- 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 +- * same encoding as the AArch64 LR) and LRC (the high part). +- */ +- ARMCPRegInfo lr_regset[] = { +- { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, +- .opc0 = 3, .opc1 = 4, .crn = 12, +- .crm = 12 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, +- .cp = 15, .opc1 = 4, .crn = 12, +- .crm = 14 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- REGINFO_SENTINEL +- }; +- define_arm_cp_regs(cpu, lr_regset); +- } +- if (cs->vprebits >= 6) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); +- } +- if (cs->vprebits == 7) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_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 ++ * same encoding as the AArch64 LR) and LRC (the high part). ++ */ ++ ARMCPRegInfo lr_regset[] = { ++ { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, ++ .opc0 = 3, .opc1 = 4, .crn = 12, ++ .crm = 12 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, ++ .cp = 15, .opc1 = 4, .crn = 12, ++ .crm = 14 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ REGINFO_SENTINEL ++ }; ++ define_arm_cp_regs(cpu, lr_regset); ++ } ++ if (cs->vprebits >= 6) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); ++ } ++ if (cs->vprebits == 7) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); + } +- arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } ++ 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 +--- 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); + 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..6af9a8f4f55fa4ce936c9d5898cd5c232abcaa9a --- /dev/null +++ b/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch @@ -0,0 +1,45 @@ +From f45964c7e0df4ef17457a9ea92bfd255064139e1 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 + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out realization code to let +it can be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3_kvm.c | 10 +++++++--- + 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 +--- 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, + } + } + ++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) + } + + 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 diff --git a/json-Fix-a-memleak-in-parse_pair.patch b/json-Fix-a-memleak-in-parse_pair.patch new file mode 100644 index 0000000000000000000000000000000000000000..11bb55ce4cd41ecb3566e0d8c83988dff3eabfb8 --- /dev/null +++ b/json-Fix-a-memleak-in-parse_pair.patch @@ -0,0 +1,116 @@ +From a2675f96bfcbe2bfe159775a920665e55a9cbdff 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/lan9118-switch-to-use-qemu_receive_packet-for-loopba.patch b/lan9118-switch-to-use-qemu_receive_packet-for-loopba.patch new file mode 100644 index 0000000000000000000000000000000000000000..38de5a26b56ee7b260bf1b17cd1e514963aa0379 --- /dev/null +++ b/lan9118-switch-to-use-qemu_receive_packet-for-loopba.patch @@ -0,0 +1,42 @@ +From 827610834ff2a32522c73bee48984fff5521c389 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov +Date: Fri, 14 May 2021 10:41:41 +0800 +Subject: [PATCH] lan9118: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/lan9118.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c +index f6120be219..f1a1d2351e 100644 +--- a/hw/net/lan9118.c ++++ b/hw/net/lan9118.c +@@ -662,7 +662,7 @@ static void do_tx_packet(lan9118_state *s) + /* FIXME: Honor TX disable, and allow queueing of packets. */ + if (s->phy_control & 0x4000) { + /* This assumes the receive routine doesn't touch the VLANClient. */ +- lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); ++ qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); + } else { + qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); + } +-- +2.27.0 + diff --git a/libvhost-user-fix-SLAVE_SEND_FD-handling.patch b/libvhost-user-fix-SLAVE_SEND_FD-handling.patch new file mode 100644 index 0000000000000000000000000000000000000000..71cbf7baa7b59006c74a8eadb9b74b10079a9a9d --- /dev/null +++ b/libvhost-user-fix-SLAVE_SEND_FD-handling.patch @@ -0,0 +1,42 @@ +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-KVM-ARM-Fix-256-vcpus.patch b/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch index 3d4e4ad5bb7e833e97c2d51f9ab2cf5ae555e823..731d06a74024c81bcc1ececeb79da2b873c2546f 100644 --- a/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch +++ b/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch @@ -1,7 +1,7 @@ -From 896b9892d4df316b85836daa973e442c0c64cec6 Mon Sep 17 00:00:00 2001 +From 27a9f40b308efd8ddcb81e286441865b5a0cb541 Mon Sep 17 00:00:00 2001 From: Zenghui Yu -Date: Fri, 3 Jan 2020 17:16:55 +0800 -Subject: [PATCH 1/3] linux headers: update against "KVM/ARM: Fix >256 vcpus" +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 . @@ -19,7 +19,7 @@ index e1f8b745..137a2730 100644 +++ 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 @@ -30,12 +30,12 @@ index e1f8b745..137a2730 100644 #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 e6a98c14..dfd3a028 100644 +index 2431ec35..cdfd5f33 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h -@@ -265,8 +265,10 @@ struct kvm_vcpu_events { +@@ -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 @@ -46,17 +46,16 @@ index e6a98c14..dfd3a028 100644 #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 b53ee597..086cea4d 100644 +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 + #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 /* Obsolete */ #define KVM_CAP_HYPERV_CPUID 167 +#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174 - - #ifdef KVM_CAP_IRQ_ROUTING - --- -2.19.1 - + #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/log-Add-some-logs-on-VM-runtime-path.patch b/log-Add-some-logs-on-VM-runtime-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..80eb8c39b4bcc4884c5a8fbfa43f28b808efb912 --- /dev/null +++ b/log-Add-some-logs-on-VM-runtime-path.patch @@ -0,0 +1,181 @@ +From 0c83403e6e3ab21a01941be4ec57b02388eeb9c4 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Fri, 22 May 2020 18:56:09 +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 + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index f6d2223..b4b0ed2 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) + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + bool modern = virtio_pci_modern(proxy); + bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + ++ qemu_log("unplug device name: %s\n", !vdev ? "NULL" : vdev->name); + virtio_pci_stop_ioeventfd(proxy); + + if (modern) { +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 7c3822c..79c2dcf 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -1172,7 +1172,14 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) + k->set_status(vdev, val); + } + vdev->status = val; +- ++ if (val) { ++ qemu_log("%s device status is %d that means %s\n", ++ vdev->name, val, ++ (val & VIRTIO_CONFIG_S_DRIVER_OK) ? "DRIVER OK" : ++ (val & VIRTIO_CONFIG_S_DRIVER) ? "DRIVER" : ++ (val & VIRTIO_CONFIG_S_ACKNOWLEDGE) ? "ACKNOWLEDGE" : ++ (val & VIRTIO_CONFIG_S_FAILED) ? "FAILED" : "UNKNOWN"); ++ } + return 0; + } + +@@ -1614,8 +1621,11 @@ 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 || queue_size > VIRTQUEUE_MAX_SIZE) { ++ qemu_log("unacceptable queue_size (%d) or num (%d)\n", ++ queue_size, i); + abort(); ++ } + + 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 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -28,6 +28,7 @@ + #include "qapi/qapi-emit-events.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) + { + Monitor *mon; + MonitorQMP *qmp_mon; ++ QString *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) + 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)); ++ } ++ qobject_unref(json); ++ } + } + } + } +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index e2c366e..6dfdad5 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" + #include "qapi/qmp/qbool.h" ++#include "qapi/qmp/qstring.h" + #include "sysemu/sysemu.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; + QObject *ret = NULL; + + dict = qmp_dispatch_check_obj(request, allow_oob, errp); +@@ -128,6 +131,19 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + qobject_ref(args); + } + ++ 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, qstring_get_str(json)); ++ } ++ qobject_unref(json); ++ } ++ + 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 @@ + #include "qemu/qemu-print.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) + if (path != NULL) { + bus = qbus_find(path, errp); + if (!bus) { ++ error_setg(errp, "can not find bus for %s", driver); + 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); + goto err_del_dev; + } + +@@ -636,6 +640,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + dev->opts = NULL; + 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 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..70bcc864d0fd976919e540165bc7167e5026c46e --- /dev/null +++ b/make-release-pull-in-edk2-submodules-so-we-can-build.patch @@ -0,0 +1,60 @@ +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/megasas-avoid-NULL-pointer-dereference.patch b/megasas-avoid-NULL-pointer-dereference.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7bc95901d82110b49e65ccab6cd9a84dc562aa0 --- /dev/null +++ b/megasas-avoid-NULL-pointer-dereference.patch @@ -0,0 +1,36 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..7e194395193623e061917b0a5e6315d6b8564a61 --- /dev/null +++ b/megasas-use-unsigned-type-for-positive-numeric-field.patch @@ -0,0 +1,97 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..507aeafb6911562d542f06f91c75a3dd90f43478 --- /dev/null +++ b/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch @@ -0,0 +1,51 @@ +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-clamp-cached-translation-in-case-it-points-to.patch b/memory-clamp-cached-translation-in-case-it-points-to.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb11fcdde8e65cfa5e8d92d78156b6b244800995 --- /dev/null +++ b/memory-clamp-cached-translation-in-case-it-points-to.patch @@ -0,0 +1,72 @@ +From fdcfc9cf131b905ef7ad851a132bc6d0097e4250 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-unref-the-memory-region-in-simplify-flatview.patch b/memory-unref-the-memory-region-in-simplify-flatview.patch deleted file mode 100644 index eb199646181ccf95dcfef2208a6b5592ff20b6d8..0000000000000000000000000000000000000000 --- a/memory-unref-the-memory-region-in-simplify-flatview.patch +++ /dev/null @@ -1,85 +0,0 @@ -From b9f43f0cca03586a31b53e47ade72e77db01cb4c Mon Sep 17 00:00:00 2001 -From: King Wang -Date: Fri, 12 Jul 2019 14:52:41 +0800 -Subject: [PATCH 2/5] memory: unref the memory region in simplify flatview - -The memory region reference is increased when insert a range -into flatview range array, then decreased by destroy flatview. -If some flat range merged by flatview_simplify, the memory region -reference can not be decreased by destroy flatview any more. - -In this case, start virtual machine by the command line: -qemu-system-x86_64 --name guest=ubuntu,debug-threads=on --machine pc,accel=kvm,usb=off,dump-guest-core=off --cpu host --m 16384 --realtime mlock=off --smp 8,sockets=2,cores=4,threads=1 --object memory-backend-file,id=ram-node0,prealloc=yes,mem-path=/dev/hugepages,share=yes,size=8589934592 --numa node,nodeid=0,cpus=0-3,memdev=ram-node0 --object memory-backend-file,id=ram-node1,prealloc=yes,mem-path=/dev/hugepages,share=yes,size=8589934592 --numa node,nodeid=1,cpus=4-7,memdev=ram-node1 --no-user-config --nodefaults --rtc base=utc --no-shutdown --boot strict=on --device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 --device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 --device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 --drive file=ubuntu.qcow2,format=qcow2,if=none,id=drive-virtio-disk0,cache=none,aio=native --device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 --chardev pty,id=charserial0 --device isa-serial,chardev=charserial0,id=serial0 --device usb-tablet,id=input0,bus=usb.0,port=1 --vnc 0.0.0.0:0 --device VGA,id=video0,vgamem_mb=16,bus=pci.0,addr=0x5 --device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6 --msg timestamp=on - -And run the script in guest OS: -while true -do - setpci -s 00:06.0 04.b=03 - setpci -s 00:06.0 04.b=07 -done - -I found the reference of node0 HostMemoryBackendFile is a big one. -(gdb) p numa_info[0]->node_memdev->parent.ref -$6 = 1636278 -(gdb) - -Signed-off-by: King Wang -Message-Id: <20190712065241.11784-1-king.wang@huawei.com> -Signed-off-by: Paolo Bonzini ---- - memory.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/memory.c b/memory.c -index 9fbca52..0b49281 100644 ---- a/memory.c -+++ b/memory.c -@@ -320,7 +320,7 @@ static bool can_merge(FlatRange *r1, FlatRange *r2) - /* Attempt to simplify a view by merging adjacent ranges */ - static void flatview_simplify(FlatView *view) - { -- unsigned i, j; -+ unsigned i, j, k; - - i = 0; - while (i < view->nr) { -@@ -331,6 +331,9 @@ static void flatview_simplify(FlatView *view) - ++j; - } - ++i; -+ for (k = i; k < j; k++) { -+ memory_region_unref(view->ranges[k].mr); -+ } - memmove(&view->ranges[i], &view->ranges[j], - (view->nr - j) * sizeof(view->ranges[j])); - view->nr -= j - i; --- -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 new file mode 100644 index 0000000000000000000000000000000000000000..79548949d7f449db1c57df2b747e347d7b220db5 --- /dev/null +++ b/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch @@ -0,0 +1,80 @@ +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-Create-migration_is_running.patch b/migration-Create-migration_is_running.patch new file mode 100644 index 0000000000000000000000000000000000000000..03c4a8de04911f42e6cfc59daed16b8f3f3e5ae3 --- /dev/null +++ b/migration-Create-migration_is_running.patch @@ -0,0 +1,107 @@ +From 0f5e5a7492af2e0a53758cd898d8c205b80bfacd Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:39:46 +0800 +Subject: [PATCH 25/31] 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 01740df471..3aa2a2ca8e 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 480c511b19..74b388da43 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1411,9 +1411,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-Don-t-send-data-if-we-have-stopped.patch b/migration-Don-t-send-data-if-we-have-stopped.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e98767402dda894be6bb893f4c8077342ad4172 --- /dev/null +++ b/migration-Don-t-send-data-if-we-have-stopped.patch @@ -0,0 +1,31 @@ +From be4e43905885b465d4d1a64cea24590147d4be13 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 22 Jan 2020 11:36:12 +0100 +Subject: [PATCH 24/31] 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 c28cfabfcc..49f742757f 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -3673,7 +3673,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 new file mode 100644 index 0000000000000000000000000000000000000000..d9dbab23e4f83d88595956668c61385618864fd7 --- /dev/null +++ b/migration-Make-global-sem_sync-semaphore-by-channel.patch @@ -0,0 +1,100 @@ +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-Maybe-VM-is-paused-when-migration-is-cance.patch b/migration-Maybe-VM-is-paused-when-migration-is-cance.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c918f3c17ca619dfb88e1856d3d26625419f465 --- /dev/null +++ b/migration-Maybe-VM-is-paused-when-migration-is-cance.patch @@ -0,0 +1,57 @@ +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-add-qemu_file_update_transfer-interface.patch b/migration-add-qemu_file_update_transfer-interface.patch new file mode 100644 index 0000000000000000000000000000000000000000..4222fd0adb202051cd57a3f0cab01e5ad52f8248 --- /dev/null +++ b/migration-add-qemu_file_update_transfer-interface.patch @@ -0,0 +1,50 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..690d9c9cf095cafdb2ff18025d70ee57a2527de2 --- /dev/null +++ b/migration-add-speed-limit-for-multifd-migration.patch @@ -0,0 +1,127 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..ccd0db9ab87204ca41e17c1120618748eb4383fe --- /dev/null +++ b/migration-always-initialise-ram_counters-for-a-new-m.patch @@ -0,0 +1,125 @@ +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-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch b/migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4c16e41c961bbed444383ba5d431176422f2ef4 --- /dev/null +++ b/migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch @@ -0,0 +1,54 @@ +From 71772aab12eb70408c9aa94efd49b19b14ec7852 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:21:58 +0800 +Subject: [PATCH 03/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..d8775ffbeaa4ae33d802eadb12d4cc7c5716724d --- /dev/null +++ b/migration-dirtyrate-Add-dirtyrate-statistics-series-.patch @@ -0,0 +1,93 @@ +From 16ae6c8e5cff5268df282d16c0f87c0578979853 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:21:59 +0800 +Subject: [PATCH 04/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..7987bb8cf8fb1861d24710e617d5238071ec7522 --- /dev/null +++ b/migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch @@ -0,0 +1,99 @@ +From 43c41bd0296af4698b031da4b2f3d29a419db0ff Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:07 +0800 +Subject: [PATCH 12/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..3be7ef2c11ae21a0bf58e753dc7ae25d49fe3d83 --- /dev/null +++ b/migration-dirtyrate-Compare-page-hash-results-for-re.patch @@ -0,0 +1,95 @@ +From ee90e6bb58e22207ae7c45fc4bd2f77fc8c87830 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:02 +0800 +Subject: [PATCH 07/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..e67fa15ae7635277c1c9103ab86efd25915de776 --- /dev/null +++ b/migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch @@ -0,0 +1,84 @@ +From 0d08b43b5499e77bac3fb28bb8ff1a12b9e356ce Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:05 +0800 +Subject: [PATCH 10/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..be7158cdf1d392ffdbbdf7247d98cbb8d5e1ee0d --- /dev/null +++ b/migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch @@ -0,0 +1,164 @@ +From ee26843a852d9de4408812891ac3475eb6d1dcaa Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:06 +0800 +Subject: [PATCH 11/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..ffe29c5318bb9c5d8552369b26ee5dfc58a0a463 --- /dev/null +++ b/migration-dirtyrate-Implement-set_sample_page_period.patch @@ -0,0 +1,75 @@ +From ed999f31105526f5dc343c4f27ac761d299ebfd9 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:04 +0800 +Subject: [PATCH 09/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..18ad1d822889f3584fea01b9a96d713945c571a3 --- /dev/null +++ b/migration-dirtyrate-Record-hash-results-for-each-sam.patch @@ -0,0 +1,149 @@ +From 93b9704b1d2b1e8748ba303f11f9484b34f28d22 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:01 +0800 +Subject: [PATCH 06/31] 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-add-DirtyRateStatus-to-denote-ca.patch b/migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4297ecf95927b027c629e09dad66374b60bac34 --- /dev/null +++ b/migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch @@ -0,0 +1,93 @@ +From 8b2c7a2ce631ccd908eb9e9a4e46565024e60a1d Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:21:57 +0800 +Subject: [PATCH 02/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..2f10ca848c0d14ea92e330c261c756c181c495ee --- /dev/null +++ b/migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch @@ -0,0 +1,84 @@ +From 49359b12589ce9fd0ffc689e62357ba7c6270fd1 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:00 +0800 +Subject: [PATCH 05/31] 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 840e35480b..8e80ee20ad 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 new file mode 100644 index 0000000000000000000000000000000000000000..1a6aaa0d5cda1a97dfc7c9c17267bf377087f43d --- /dev/null +++ b/migration-dirtyrate-present-dirty-rate-only-when-que.patch @@ -0,0 +1,69 @@ +From fd1c1f1f7bd07533a61f0a628dc9b956520eb700 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Tue, 29 Sep 2020 11:42:18 +0800 +Subject: [PATCH 14/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..2f95ca6248103cd3f1ca134f4384511b9ea0a1c8 --- /dev/null +++ b/migration-dirtyrate-record-start_time-and-calc_time-.patch @@ -0,0 +1,71 @@ +From ec54b40b9cef16e793a2cd323b3a16e3c08b1db5 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Tue, 29 Sep 2020 11:42:17 +0800 +Subject: [PATCH 13/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..f68dec2537a6bd0d6a38352fc306c80320ec2431 --- /dev/null +++ b/migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch @@ -0,0 +1,116 @@ +From 8577a6b59eac5566e3a2b39fa554ca93c550ffc9 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:21:56 +0800 +Subject: [PATCH 01/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..2ae8953be797abdc86f555539bcf1f43dcede255 --- /dev/null +++ b/migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch @@ -0,0 +1,43 @@ +From 7f6f248e2f245938c1fb7a9f7c979079050fc431 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Fri, 30 Oct 2020 11:58:01 +0800 +Subject: [PATCH 15/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..9c3ea8d9d3e84d3fd55b56361f9b47ea174d7f2d --- /dev/null +++ b/migration-dirtyrate-skip-sampling-ramblock-with-size.patch @@ -0,0 +1,92 @@ +From 0a079387a3176e5f05480f6cb14f970d43689986 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Wed, 16 Sep 2020 14:22:03 +0800 +Subject: [PATCH 08/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..cd6138fc048379217eb787d80dbdd5a1af36c5f9 --- /dev/null +++ b/migration-fix-COLO-broken-caused-by-a-previous-commi.patch @@ -0,0 +1,39 @@ +From e2e65d71494fb4c971cdc70db181a5ab242b183e Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:43:45 +0800 +Subject: [PATCH 26/31] 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 3aa2a2ca8e..1b2b22f4dc 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-memory-leak-in-qmp_migrate_set_paramet.patch b/migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch new file mode 100644 index 0000000000000000000000000000000000000000..a44578b1046708b9d268ff874a292a63b11074dd --- /dev/null +++ b/migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch @@ -0,0 +1,79 @@ +From ae0a4a9f990fbe1c27df657f7af530cfb5439799 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Fri, 5 Mar 2021 16:06:52 +0800 +Subject: [PATCH 29/31] 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 1b2b22f4dc..ffa6d1875f 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1260,12 +1260,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-multifd-fix-destroyed-mutex-access-in-term.patch b/migration-multifd-fix-destroyed-mutex-access-in-term.patch new file mode 100644 index 0000000000000000000000000000000000000000..a927ea533c253ff242c5867cde1055453668c1c5 --- /dev/null +++ b/migration-multifd-fix-destroyed-mutex-access-in-term.patch @@ -0,0 +1,64 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..776f87f4dd629fe34812e597d48e22c7a40279a9 --- /dev/null +++ b/migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch @@ -0,0 +1,83 @@ +From 6f1d0d80da4fa14de4b45d6fdc15449940e1b721 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:50:12 +0800 +Subject: [PATCH 27/31] 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 49f742757f..fe0b1601fe 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1213,6 +1213,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) +@@ -1228,12 +1241,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 new file mode 100644 index 0000000000000000000000000000000000000000..f2d278a135434e3b0838be7876b1fe2a616816cd --- /dev/null +++ b/migration-multifd-fix-nullptr-access-in-multifd_send.patch @@ -0,0 +1,62 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..d403b28f28a708a94d7799618053e53c7d75b939 --- /dev/null +++ b/migration-multifd-fix-nullptr-access-in-terminating-m.patch @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..6b8f18ce71abccf8987fb9261817654b3b10d631 --- /dev/null +++ b/migration-multifd-fix-potential-wrong-acception-orde.patch @@ -0,0 +1,302 @@ +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-ram-Do-error_free-after-migrate_set_error-.patch b/migration-ram-Do-error_free-after-migrate_set_error-.patch new file mode 100644 index 0000000000000000000000000000000000000000..0039f43d86d5506bfca2953904a215d3f178526a --- /dev/null +++ b/migration-ram-Do-error_free-after-migrate_set_error-.patch @@ -0,0 +1,69 @@ +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-memleaks-in-multifd_new_send_chann.patch b/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9cb2bf652b90968144c673fd6c59655acfd785f --- /dev/null +++ b/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch @@ -0,0 +1,54 @@ +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-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch b/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e0fb101d827377551a7858f225cf365367e12b7 --- /dev/null +++ b/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch @@ -0,0 +1,43 @@ +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-tls-add-error-handling-in-multifd_tls_hand.patch b/migration-tls-add-error-handling-in-multifd_tls_hand.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f90e2f42687c0bbc566c379cd2ce7a571b47801 --- /dev/null +++ b/migration-tls-add-error-handling-in-multifd_tls_hand.patch @@ -0,0 +1,42 @@ +From 7e31bbdd4ee42fcd1af80c4c882b04184bf8b8bf Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Fri, 5 Mar 2021 16:10:57 +0800 +Subject: [PATCH 31/31] 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 5d4c7eb754..c6cd5c0c7a 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1210,7 +1210,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 new file mode 100644 index 0000000000000000000000000000000000000000..591488476496163445777c92cf104174bffd7527 --- /dev/null +++ b/migration-tls-add-support-for-multifd-tls-handshake.patch @@ -0,0 +1,125 @@ +From 906a3b501ba85c6320141d376ef0b22cd387677e Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 11:38:37 +0800 +Subject: [PATCH 20/31] 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 3c79bc6017..88b7019df2 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" +@@ -1193,6 +1194,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) + { +@@ -1222,8 +1294,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 new file mode 100644 index 0000000000000000000000000000000000000000..48ad3f74e879340658610836b75bd229615db074 --- /dev/null +++ b/migration-tls-add-tls_hostname-into-MultiFDSendParam.patch @@ -0,0 +1,66 @@ +From 07514c032bd20e6012b59ecbf07595eb41fd5ff5 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 11:25:44 +0800 +Subject: [PATCH 18/31] 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 8e80ee20ad..e9b25f78a6 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 */ +@@ -1035,6 +1037,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; +@@ -1222,10 +1226,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); +@@ -1246,6 +1252,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 new file mode 100644 index 0000000000000000000000000000000000000000..5a4cf2bb8dc1404a32166b72d0bb11258ee03b87 --- /dev/null +++ b/migration-tls-add-trace-points-for-multifd-tls.patch @@ -0,0 +1,73 @@ +From a801cd3ed905e18b51fcb3add82b826c099dc6a9 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 13:56:11 +0800 +Subject: [PATCH 21/31] 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 88b7019df2..30c95397c3 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1205,7 +1205,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); + } + +@@ -1222,6 +1226,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, +@@ -1237,6 +1242,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 new file mode 100644 index 0000000000000000000000000000000000000000..e638d36427256485243f2fc1ca7739501a3d3103 --- /dev/null +++ b/migration-tls-extract-cleanup-function-for-common-us.patch @@ -0,0 +1,82 @@ +From c1eb9f8be8cc6e52c1634ec13fcc5a158ebf75eb Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 11:32:44 +0800 +Subject: [PATCH 19/31] 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 e9b25f78a6..3c79bc6017 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1193,6 +1193,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; +@@ -1200,25 +1217,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 new file mode 100644 index 0000000000000000000000000000000000000000..b05eb19f0652ab481794965e44142f7178ee846b --- /dev/null +++ b/migration-tls-extract-migration_tls_client_create-fo.patch @@ -0,0 +1,109 @@ +From 38f80174ada1076fe1dd365fdd95b782808c9039 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Tue, 15 Sep 2020 11:03:58 +0800 +Subject: [PATCH 17/31] 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 new file mode 100644 index 0000000000000000000000000000000000000000..87d81713f42b690d343f2ac0e83f89bf742cf43b --- /dev/null +++ b/migration-tls-fix-inverted-semantics-in-multifd_chan.patch @@ -0,0 +1,55 @@ +From bf463c0511fce696dc676e87fe040a467ed55c54 Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Fri, 5 Mar 2021 16:09:29 +0800 +Subject: [PATCH 30/31] 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 7fc2b9108d..5d4c7eb754 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1269,9 +1269,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 */ +@@ -1279,10 +1279,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, +@@ -1314,7 +1314,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 new file mode 100644 index 0000000000000000000000000000000000000000..e56b4d22ebedebccb490b2128d37eb7d499af7ae --- /dev/null +++ b/migration-tls-save-hostname-into-MigrationState.patch @@ -0,0 +1,77 @@ +From 202ff21fd91eabffca41c15cc93b9483a0b8778c Mon Sep 17 00:00:00 2001 +From: Chuan Zheng +Date: Tue, 15 Sep 2020 11:03:57 +0800 +Subject: [PATCH 16/31] 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 8f2fc2b4ff..01740df471 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 new file mode 100644 index 0000000000000000000000000000000000000000..838380403f1ac31df0f2befd62a14711cee71e58 --- /dev/null +++ b/migration-update-ram_counters-for-multifd-sync-packe.patch @@ -0,0 +1,35 @@ +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/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch b/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch new file mode 100644 index 0000000000000000000000000000000000000000..52f07f951aef929e9fe58740955f97af25e5ba85 --- /dev/null +++ b/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch @@ -0,0 +1,52 @@ +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/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch b/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch index 51f4113b4a67e8c9dfd67d5f21011ee998e04d13..791449b59540fd0d66cac0c367af8436abb55741 100644 --- a/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +++ b/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch @@ -1,6 +1,6 @@ -From 6f7a7f18f4460b0891eabbe1ca69e599216427b7 Mon Sep 17 00:00:00 2001 +From 117082ef493e62e6e2cd972b309e0cd72682ab02 Mon Sep 17 00:00:00 2001 From: Chen Qun -Date: Mon, 16 Mar 2020 14:26:06 +0800 +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, @@ -25,14 +25,14 @@ Reported-by: Euler Robot Signed-off-by: Chen Qun (cherry picked from commit a661614de18c89f58cad3fc1bb8aab44e820183a) --- - monitor.c | 1 + + monitor/misc.c | 1 + 1 file changed, 1 insertion(+) -diff --git a/monitor.c b/monitor.c -index 4807bbe..b5b15b5 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2596,6 +2596,7 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) +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); @@ -40,6 +40,5 @@ index 4807bbe..b5b15b5 100644 if (QLIST_EMPTY(&mon_fdset->dup_fds)) { monitor_fdset_cleanup(mon_fdset); } --- -1.8.3.1 - +-- +2.23.0 diff --git a/msix-add-valid.accepts-methods-to-check-address.patch b/msix-add-valid.accepts-methods-to-check-address.patch new file mode 100644 index 0000000000000000000000000000000000000000..1adbe53dad07926b888fe108a18386e073f7de8b --- /dev/null +++ b/msix-add-valid.accepts-methods-to-check-address.patch @@ -0,0 +1,78 @@ +From 3813c0df1d0486db6ed696a7834e6bcdfdd89cc9 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 new file mode 100644 index 0000000000000000000000000000000000000000..713a9b00b0b549206fac813d369fcfb833d45cb4 --- /dev/null +++ b/multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch @@ -0,0 +1,63 @@ +From c1d1732010d97fb14bc661bc9cd1872699348501 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:31:07 +0800 +Subject: [PATCH 23/31] 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 30c95397c3..c28cfabfcc 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -3604,7 +3604,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; +@@ -3673,12 +3673,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; + } +@@ -3732,9 +3734,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 new file mode 100644 index 0000000000000000000000000000000000000000..51a2e18cfce8ce9b291d80eb4430b42f712ab782 --- /dev/null +++ b/multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch @@ -0,0 +1,37 @@ +From 7e90a0c75ff4ecc444d34a90158dc4c5daf90692 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:51:51 +0800 +Subject: [PATCH 28/31] 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 fe0b1601fe..7fc2b9108d 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1239,6 +1239,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/net-colo-compare.c-Check-that-colo-compare-is-active.patch b/net-colo-compare.c-Check-that-colo-compare-is-active.patch new file mode 100644 index 0000000000000000000000000000000000000000..5fd4652b73ecd9c5539b4958e2fe2fbbf4474b8f --- /dev/null +++ b/net-colo-compare.c-Check-that-colo-compare-is-active.patch @@ -0,0 +1,129 @@ +From 5fa5c68cc2dc4c2dad6272670e84767d7830eb1e Mon Sep 17 00:00:00 2001 +From: Lukas Straub +Date: Fri, 22 May 2020 15:53:55 +0800 +Subject: [PATCH 4/4] net/colo-compare.c: Check that colo-compare is active + +If the colo-compare object is removed before failover and a +checkpoint happens, qemu crashes because it tries to lock +the destroyed event_mtx in colo_notify_compares_event. + +Fix this by checking if everything is initialized by +introducing a new variable colo_compare_active which +is protected by a new mutex colo_compare_mutex. The new mutex +also protects against concurrent access of the net_compares +list and makes sure that colo_notify_compares_event isn't +active while we destroy event_mtx and event_complete_cond. + +With this it also is again possible to use colo without +colo-compare (periodic mode) and to use multiple colo-compare +for multiple network interfaces. + +Signed-off-by: Lukas Straub +Tested-by: Lukas Straub +Reviewed-by: Zhang Chen +Signed-off-by: Zhang Chen +Signed-off-by: Jason Wang +--- + net/colo-compare.c | 35 +++++++++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 6 deletions(-) + +diff --git a/net/colo-compare.c b/net/colo-compare.c +index 7ee17f2cf8..ca07d3016b 100644 +--- a/net/colo-compare.c ++++ b/net/colo-compare.c +@@ -51,6 +51,8 @@ static NotifierList colo_compare_notifiers = + /* TODO: Should be configurable */ + #define REGULAR_PACKET_CHECK_MS 3000 + ++static QemuMutex colo_compare_mutex; ++static bool colo_compare_active; + static QemuMutex event_mtx; + static QemuCond event_complete_cond; + static int event_unhandled_count; +@@ -829,6 +831,12 @@ static void check_old_packet_regular(void *opaque) + void colo_notify_compares_event(void *opaque, int event, Error **errp) + { + CompareState *s; ++ qemu_mutex_lock(&colo_compare_mutex); ++ ++ if (!colo_compare_active) { ++ qemu_mutex_unlock(&colo_compare_mutex); ++ return; ++ } + + qemu_mutex_lock(&event_mtx); + QTAILQ_FOREACH(s, &net_compares, next) { +@@ -842,6 +850,7 @@ void colo_notify_compares_event(void *opaque, int event, Error **errp) + } + + qemu_mutex_unlock(&event_mtx); ++ qemu_mutex_unlock(&colo_compare_mutex); + } + + static void colo_compare_timer_init(CompareState *s) +@@ -1119,13 +1128,17 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) + s->vnet_hdr); + } + ++ qemu_mutex_lock(&colo_compare_mutex); ++ if (!colo_compare_active) { ++ qemu_mutex_init(&event_mtx); ++ qemu_cond_init(&event_complete_cond); ++ colo_compare_active = true; ++ } + QTAILQ_INSERT_TAIL(&net_compares, s, next); ++ qemu_mutex_unlock(&colo_compare_mutex); + + g_queue_init(&s->conn_list); + +- qemu_mutex_init(&event_mtx); +- qemu_cond_init(&event_complete_cond); +- + s->connection_track_table = g_hash_table_new_full(connection_key_hash, + connection_key_equal, + g_free, +@@ -1208,12 +1221,19 @@ static void colo_compare_finalize(Object *obj) + + qemu_bh_delete(s->event_bh); + ++ qemu_mutex_lock(&colo_compare_mutex); + QTAILQ_FOREACH(tmp, &net_compares, next) { + if (tmp == s) { + QTAILQ_REMOVE(&net_compares, s, next); + break; + } + } ++ if (QTAILQ_EMPTY(&net_compares)) { ++ colo_compare_active = false; ++ qemu_mutex_destroy(&event_mtx); ++ qemu_cond_destroy(&event_complete_cond); ++ } ++ qemu_mutex_unlock(&colo_compare_mutex); + + /* Release all unhandled packets after compare thead exited */ + g_queue_foreach(&s->conn_list, colo_flush_packets, s); +@@ -1228,15 +1248,18 @@ static void colo_compare_finalize(Object *obj) + object_unref(OBJECT(s->iothread)); + } + +- qemu_mutex_destroy(&event_mtx); +- qemu_cond_destroy(&event_complete_cond); +- + g_free(s->pri_indev); + g_free(s->sec_indev); + g_free(s->outdev); + g_free(s->notify_dev); + } + ++static void __attribute__((__constructor__)) colo_compare_init_globals(void) ++{ ++ colo_compare_active = false; ++ qemu_mutex_init(&colo_compare_mutex); ++} ++ + static const TypeInfo colo_compare_info = { + .name = TYPE_COLO_COMPARE, + .parent = TYPE_OBJECT, +-- +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..cad2123d024224f53bbd15c81636fb030913b6e1 --- /dev/null +++ b/net-dump.c-Suppress-spurious-compiler-warning.patch @@ -0,0 +1,51 @@ +From 55dee3d51d658d72edecd28168be69f822bff970 Mon Sep 17 00:00:00 2001 +From: liuxiangdong +Date: Tue, 8 Feb 2022 15:10:25 +0800 +Subject: [PATCH 3/4] 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 23b3628dde..3cf9fe869d 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.17.1 + diff --git a/net-introduce-qemu_receive_packet.patch b/net-introduce-qemu_receive_packet.patch new file mode 100644 index 0000000000000000000000000000000000000000..8bf6242b5bf68cdd059f5aa558a012b72a4d1c5c --- /dev/null +++ b/net-introduce-qemu_receive_packet.patch @@ -0,0 +1,167 @@ +From f34f6b6e78b8b3f401cc31a0d7c06a1c9ea9ad08 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 14 May 2021 10:14:02 +0800 +Subject: [PATCH] net: introduce qemu_receive_packet() + +Fix CVE-2021-3416 + +Some NIC supports loopback mode and this is done by calling +nc->info->receive() directly which in fact suppresses the effort of +reentrancy check that is done in qemu_net_queue_send(). + +Unfortunately we can use qemu_net_queue_send() here since for loop +back there's no sender as peer, so this patch introduce a +qemu_receive_packet() which is used for implementing loopback mode +for a NIC with this check. + +NIC that supports loopback mode will be converted to this helper. + +Signed-off-by: Jason Wang +Signed-off-by: Jiajie Li +--- + include/net/net.h | 5 +++++ + include/net/queue.h | 8 ++++++++ + net/net.c | 38 +++++++++++++++++++++++++++++++------- + net/queue.c | 22 ++++++++++++++++++++++ + 4 files changed, 66 insertions(+), 7 deletions(-) + +diff --git a/include/net/net.h b/include/net/net.h +index acf0451fc4..5609b2ecba 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -143,12 +143,17 @@ void *qemu_get_nic_opaque(NetClientState *nc); + void qemu_del_net_client(NetClientState *nc); + typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); + void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); ++int qemu_can_receive_packet(NetClientState *nc); + int qemu_can_send_packet(NetClientState *nc); + ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, + int iovcnt); + ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, + int iovcnt, NetPacketSent *sent_cb); + ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); ++ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf,int size); ++ssize_t qemu_receive_packet_iov(NetClientState *nc, ++ const struct iovec *iov, ++ int iovcnt); + ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size); + ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, + int size, NetPacketSent *sent_cb); +diff --git a/include/net/queue.h b/include/net/queue.h +index c0269bb1dc..9f2f289d77 100644 +--- a/include/net/queue.h ++++ b/include/net/queue.h +@@ -55,6 +55,14 @@ void qemu_net_queue_append_iov(NetQueue *queue, + + void qemu_del_net_queue(NetQueue *queue); + ++ssize_t qemu_net_queue_receive(NetQueue *queue, ++ const uint8_t *data, ++ size_t size); ++ ++ssize_t qemu_net_queue_receive_iov(NetQueue *queue, ++ const struct iovec *iov, ++ int iovcnt); ++ + ssize_t qemu_net_queue_send(NetQueue *queue, + NetClientState *sender, + unsigned flags, +diff --git a/net/net.c b/net/net.c +index 7d4098254f..3b5631879c 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -514,6 +514,17 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) + #endif + } + ++int qemu_can_receive_packet(NetClientState *nc) ++{ ++ if (nc->receive_disabled) { ++ return 0; ++ } else if (nc->info->can_receive && ++ !nc->info->can_receive(nc)) { ++ return 0; ++ } ++ return 1; ++} ++ + int qemu_can_send_packet(NetClientState *sender) + { + int vm_running = runstate_is_running(); +@@ -526,13 +537,7 @@ int qemu_can_send_packet(NetClientState *sender) + return 1; + } + +- if (sender->peer->receive_disabled) { +- return 0; +- } else if (sender->peer->info->can_receive && +- !sender->peer->info->can_receive(sender->peer)) { +- return 0; +- } +- return 1; ++ return qemu_can_receive_packet(sender->peer); + } + + static ssize_t filter_receive_iov(NetClientState *nc, +@@ -665,6 +670,25 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) + return qemu_send_packet_async(nc, buf, size, NULL); + } + ++ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) ++{ ++ if (!qemu_can_receive_packet(nc)) { ++ return 0; ++ } ++ ++ return qemu_net_queue_receive(nc->incoming_queue, buf, size); ++} ++ ++ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, ++ int iovcnt) ++{ ++ if (!qemu_can_receive_packet(nc)) { ++ return 0; ++ } ++ ++ return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); ++} ++ + ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) + { + return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, +diff --git a/net/queue.c b/net/queue.c +index 61276ca4be..7c0b72c8ef 100644 +--- a/net/queue.c ++++ b/net/queue.c +@@ -182,6 +182,28 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, + return ret; + } + ++ssize_t qemu_net_queue_receive(NetQueue *queue, ++ const uint8_t *data, ++ size_t size) ++{ ++ if (queue->delivering) { ++ return 0; ++ } ++ ++ return qemu_net_queue_deliver(queue, NULL, 0, data, size); ++} ++ ++ssize_t qemu_net_queue_receive_iov(NetQueue *queue, ++ const struct iovec *iov, ++ int iovcnt) ++{ ++ if (queue->delivering) { ++ return 0; ++ } ++ ++ return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt); ++} ++ + ssize_t qemu_net_queue_send(NetQueue *queue, + NetClientState *sender, + unsigned flags, +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..917695b398ec36386ebdf088a80bdab5779e6027 --- /dev/null +++ b/net-remove-an-assert-call-in-eth_get_gso_type.patch @@ -0,0 +1,49 @@ +From 82ea222162a837397f6c21aa7a818824c3e61c0e 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-vmxnet3-validate-configuration-values-during-act.patch b/net-vmxnet3-validate-configuration-values-during-act.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d62dc1cf842b8bce88269bdfa36feac94da9ac6 --- /dev/null +++ b/net-vmxnet3-validate-configuration-values-during-act.patch @@ -0,0 +1,79 @@ +From 281a70c0251695d5cba2314b43eace9c6bc98f9d 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/nvram-add-nrf51_soc-flash-read-method.patch b/nvram-add-nrf51_soc-flash-read-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..6f0bd2197eb774b84941c6ffd529b0600065ff76 --- /dev/null +++ b/nvram-add-nrf51_soc-flash-read-method.patch @@ -0,0 +1,44 @@ +From 0f754e16372feda4996054c6986b496e244d9bed 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/pc-Don-t-make-die-id-mandatory-unless-necessary.patch b/pc-Don-t-make-die-id-mandatory-unless-necessary.patch new file mode 100644 index 0000000000000000000000000000000000000000..c51b40f33020e36547f44b895b040acc07bf741c --- /dev/null +++ b/pc-Don-t-make-die-id-mandatory-unless-necessary.patch @@ -0,0 +1,102 @@ +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/pci-check-bus-pointer-before-dereference.patch b/pci-check-bus-pointer-before-dereference.patch new file mode 100644 index 0000000000000000000000000000000000000000..520e12f2af3afdb886ead37cd63a62f823f6d86e --- /dev/null +++ b/pci-check-bus-pointer-before-dereference.patch @@ -0,0 +1,50 @@ +From 0d0abe293c0516f7d530af3d6a5305d2cc36935a 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 + +fix CVE-2020-25742 + +patch link: https://lists.nongnu.org/archive/html/qemu-devel/2020-09/msg05294.html + +While mapping IRQ level in pci_change_irq_level() routine, +it does not check if pci_get_bus() returned a valid pointer. +It may lead to a NULL pointer dereference issue. Add check to +avoid it. + + -> https://ruhr-uni-bochum.sciebo.de/s/NNWP2GfwzYKeKwE?path=%2Flsi_nullptr1 + ==1183858==Hint: address points to the zero page. + #0 pci_change_irq_level hw/pci/pci.c:259 + #1 pci_irq_handler hw/pci/pci.c:1445 + #2 pci_set_irq hw/pci/pci.c:1463 + #3 lsi_set_irq hw/scsi/lsi53c895a.c:488 + #4 lsi_update_irq hw/scsi/lsi53c895a.c:523 + #5 lsi_script_scsi_interrupt hw/scsi/lsi53c895a.c:554 + #6 lsi_execute_script hw/scsi/lsi53c895a.c:1149 + #7 lsi_reg_writeb hw/scsi/lsi53c895a.c:1984 + #8 lsi_io_write hw/scsi/lsi53c895a.c:2146 + ... + +Reported-by: Ruhr-University +Signed-off-by: Prasad J Pandit +--- + hw/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 8076a80ab3..602fc566cc 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -249,6 +249,9 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) + PCIBus *bus; + for (;;) { + bus = pci_get_bus(pci_dev); ++ if (!bus) { ++ return; ++ } + irq_num = bus->map_irq(pci_dev, irq_num); + if (bus->set_irq) + break; +-- +2.23.0 + diff --git a/pci-host-add-pcie-msi-read-method.patch b/pci-host-add-pcie-msi-read-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..349d9dbb5e020df77d077727892239f62f672a23 --- /dev/null +++ b/pci-host-add-pcie-msi-read-method.patch @@ -0,0 +1,56 @@ +From 0e7715733eff67efae448d15c7bd995b316c71ec 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/pcnet-switch-to-use-qemu_receive_packet-for-loopback.patch b/pcnet-switch-to-use-qemu_receive_packet-for-loopback.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ae51204790e42f2b75aa33bc29f79234dab300b --- /dev/null +++ b/pcnet-switch-to-use-qemu_receive_packet-for-loopback.patch @@ -0,0 +1,43 @@ +From 90e95b8873d1aa42ffc15f8d0e054d2b52453c5e Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov +Date: Fri, 14 May 2021 10:37:29 +0800 +Subject: [PATCH] pcnet: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Buglink: https://bugs.launchpad.net/qemu/+bug/1917085 +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/pcnet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index 16683091c9..9e8d267536 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1249,7 +1249,7 @@ txagain: + if (BCR_SWSTYLE(s) == 1) + add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); + s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; +- pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); ++ qemu_receive_packet(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); + s->looptest = 0; + } else { + if (s->nic) { +-- +2.27.0 + diff --git a/pr-manager-Fix-invalid-g_free-crash-bug.patch b/pr-manager-Fix-invalid-g_free-crash-bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..b171cdb5ae34dab7135926c2250541814d543a02 --- /dev/null +++ b/pr-manager-Fix-invalid-g_free-crash-bug.patch @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..aff8dc80e83526817cc298cf6969493c76f1201d --- /dev/null +++ b/prep-add-ppc-parity-write-method.patch @@ -0,0 +1,50 @@ +From aedfad7d11fd23087bc5da6480b5a8b1ad0319a7 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/pvrdma-Ensure-correct-input-on-ring-init-CVE-2021-36.patch b/pvrdma-Ensure-correct-input-on-ring-init-CVE-2021-36.patch new file mode 100644 index 0000000000000000000000000000000000000000..2be31292ab46766606bb656c8d07cda5dc2438c1 --- /dev/null +++ b/pvrdma-Ensure-correct-input-on-ring-init-CVE-2021-36.patch @@ -0,0 +1,41 @@ +From 0383586640e2c9712376c795d4d2ea27aadeed78 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum +Date: Wed, 30 Jun 2021 14:46:34 +0300 +Subject: [PATCH 2/3] pvrdma: Ensure correct input on ring init (CVE-2021-3607) + +Check the guest passed a non zero page count +for pvrdma device ring buffers. + +Fixes: CVE-2021-3607 +Reported-by: VictorV (Kunlun Lab) +Reviewed-by: VictorV (Kunlun Lab) +Signed-off-by: Marcel Apfelbaum +Message-Id: <20210630114634.2168872-1-marcel@redhat.com> +Reviewed-by: Yuval Shaia +Tested-by: Yuval Shaia +Signed-off-by: Marcel Apfelbaum +cherry-pick from: 32e5703cfea07c91e6e84bcb0313f633bb146534 +Signed-off-by: yezengruan +--- + hw/rdma/vmw/pvrdma_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c +index adcf79cd63..1d9f84e89a 100644 +--- a/hw/rdma/vmw/pvrdma_main.c ++++ b/hw/rdma/vmw/pvrdma_main.c +@@ -93,6 +93,11 @@ static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state, + uint64_t *dir, *tbl; + int rc = 0; + ++ if (!num_pages) { ++ rdma_error_report("Ring pages count must be strictly positive"); ++ 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); +-- +2.27.0 + diff --git a/pvrdma-Fix-the-ring-init-error-flow-CVE-2021-3608.patch b/pvrdma-Fix-the-ring-init-error-flow-CVE-2021-3608.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed54c1b6c9d1ad4e06e38d7d5e66c04d86e83784 --- /dev/null +++ b/pvrdma-Fix-the-ring-init-error-flow-CVE-2021-3608.patch @@ -0,0 +1,41 @@ +From ad63c75ceea0b9d6fe1dbb008cad41527a29f923 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum +Date: Wed, 30 Jun 2021 14:52:46 +0300 +Subject: [PATCH 3/3] pvrdma: Fix the ring init error flow (CVE-2021-3608) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not unmap uninitialized dma addresses. + +Fixes: CVE-2021-3608 +Reviewed-by: VictorV (Kunlun Lab) +Tested-by: VictorV (Kunlun Lab) +Signed-off-by: Marcel Apfelbaum +Message-Id: <20210630115246.2178219-1-marcel@redhat.com> +Tested-by: Yuval Shaia +Reviewed-by: Yuval Shaia +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Marcel Apfelbaum +cherry-pick from: 66ae37d8cc313f89272e711174a846a229bcdbd3 +Signed-off-by: yezengruan +--- + hw/rdma/vmw/pvrdma_dev_ring.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c +index d7bc7f5ccc..2a620ad5bc 100644 +--- a/hw/rdma/vmw/pvrdma_dev_ring.c ++++ b/hw/rdma/vmw/pvrdma_dev_ring.c +@@ -41,7 +41,7 @@ int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, + atomic_set(&ring->ring_state->cons_head, 0); + */ + ring->npages = npages; +- ring->pages = g_malloc(npages * sizeof(void *)); ++ ring->pages = g_malloc0(npages * sizeof(void *)); + + for (i = 0; i < npages; i++) { + if (!tbl[i]) { +-- +2.27.0 + diff --git a/qapi-block-core-Add-retry-option-for-error-action.patch b/qapi-block-core-Add-retry-option-for-error-action.patch new file mode 100644 index 0000000000000000000000000000000000000000..524d561e8910ef3c1db6f422d4cc94154178b70e --- /dev/null +++ b/qapi-block-core-Add-retry-option-for-error-action.patch @@ -0,0 +1,52 @@ +From 80f85c1b2e41ea89b00ac3df8ebd969e324a6a55 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 + +Add a new error action 'retry' to support retry on errors. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- a/blockdev.c ++++ b/blockdev.c +@@ -319,6 +319,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; ++ } else if (!strcmp(buf, "retry")) { ++ return BLOCKDEV_ON_ERROR_RETRY; + } else { + 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 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1113,7 +1113,7 @@ + # Since: 1.3 + ## + { 'enum': 'BlockdevOnError', +- 'data': ['report', 'ignore', 'enospc', 'stop', 'auto'] } ++ 'data': ['report', 'ignore', 'enospc', 'stop', 'auto', 'retry'] } + + ## + # @MirrorSyncMode: +@@ -4894,7 +4894,7 @@ + # Since: 2.1 + ## + { 'enum': 'BlockErrorAction', +- 'data': [ 'ignore', 'report', 'stop' ] } ++ 'data': [ 'ignore', 'report', 'stop', 'retry' ] } + + + ## +-- +2.27.0 + diff --git a/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch b/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2a4e5c26f50c820eb9122e8a8449b76713a8db7 --- /dev/null +++ b/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch @@ -0,0 +1,35 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..b4c25806d7f7b99408a0419987c22c2175f4fee3 --- /dev/null +++ b/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch @@ -0,0 +1,71 @@ +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-the-calculation-of-the-maximum-L2-cache-si.patch b/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch new file mode 100644 index 0000000000000000000000000000000000000000..be2c3c72ced8b33f569fabef0c1f01dd382993ef --- /dev/null +++ b/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch @@ -0,0 +1,58 @@ +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/qemu-4.0.1.tar.xz b/qemu-4.1.0.tar.xz similarity index 79% rename from qemu-4.0.1.tar.xz rename to qemu-4.1.0.tar.xz index 703a6c2ff7a99ef107bc55570fc0d52b5e79f0a9..79ad0661eda38092de13a677ef70eeaece3ad848 100644 Binary files a/qemu-4.0.1.tar.xz and b/qemu-4.1.0.tar.xz differ diff --git a/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch b/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch deleted file mode 100644 index 8cd599a13bf7a4e4e2b45ab014cd05809051e4f7..0000000000000000000000000000000000000000 --- a/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 3283dde4b5b5cce0f96f48d536bebff66d97ce0b Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 23 Jul 2019 16:17:53 +0530 -Subject: [PATCH 2/2] qemu-bridge-helper: move repeating code in parse_acl_file -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Move repeating error handling sequence in parse_acl_file routine -to an 'err' label. - -This patch fixes CVE-2019-13164. - -Signed-off-by: Prasad J Pandit -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Daniel P. Berrangé -Reviewed-by: Li Qiang -Signed-off-by: Jason Wang -(cherry-picked from commit 3283dde4b5b5cce0f96f48d536bebff66d97ce0b) ---- - qemu-bridge-helper.c | 19 +++++++++---------- - 1 file changed, 9 insertions(+), 10 deletions(-) - -diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c -index 2058e10454..3d50ec094c 100644 ---- a/qemu-bridge-helper.c -+++ b/qemu-bridge-helper.c -@@ -102,9 +102,7 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - - if (arg == NULL) { - fprintf(stderr, "Invalid config line:\n %s\n", line); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - - *arg = 0; -@@ -121,9 +119,7 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - - if (!g_str_equal(cmd, "include") && strlen(arg) >= IFNAMSIZ) { - fprintf(stderr, "name `%s' too long: %zu\n", arg, strlen(arg)); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - - if (strcmp(cmd, "deny") == 0) { -@@ -149,15 +145,18 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - parse_acl_file(arg, acl_list); - } else { - fprintf(stderr, "Unknown command `%s'\n", cmd); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - } - - fclose(f); -- - return 0; -+ -+err: -+ fclose(f); -+ errno = EINVAL; -+ return -1; -+ - } - - static bool has_vnet_hdr(int fd) --- -2.19.1 - diff --git a/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch b/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch deleted file mode 100644 index b6dc25e4dfdc9e204c78c545ad5582c52c07dc26..0000000000000000000000000000000000000000 --- a/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 6f5d8671225dc77190647f18a27a0d156d4ca97a Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 23 Jul 2019 16:17:52 +0530 -Subject: [PATCH 1/2] qemu-bridge-helper: restrict interface name to IFNAMSIZ -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The network interface name in Linux is defined to be of size -IFNAMSIZ(=16), including the terminating null('\0') byte. -The same is applied to interface names read from 'bridge.conf' -file to form ACL rules. If user supplied '--br=bridge' name -is not restricted to the same length, it could lead to ACL bypass -issue. Restrict interface name to IFNAMSIZ, including null byte. - -This patch fixes CVE-2019-13164. - -Reported-by: Riccardo Schirone -Signed-off-by: Prasad J Pandit -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Daniel P. Berrangé -Reviewed-by: Li Qiang -Signed-off-by: Jason Wang -(cherry-picked from commit 6f5d8671225dc77190647f18a27a0d156d4ca97a) ---- - qemu-bridge-helper.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c -index 95624bc300..2058e10454 100644 ---- a/qemu-bridge-helper.c -+++ b/qemu-bridge-helper.c -@@ -119,6 +119,13 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - } - *argend = 0; - -+ if (!g_str_equal(cmd, "include") && strlen(arg) >= IFNAMSIZ) { -+ fprintf(stderr, "name `%s' too long: %zu\n", arg, strlen(arg)); -+ fclose(f); -+ errno = EINVAL; -+ return -1; -+ } -+ - if (strcmp(cmd, "deny") == 0) { - acl_rule = g_malloc(sizeof(*acl_rule)); - if (strcmp(arg, "all") == 0) { -@@ -269,6 +276,10 @@ int main(int argc, char **argv) - usage(); - return EXIT_FAILURE; - } -+ if (strlen(bridge) >= IFNAMSIZ) { -+ fprintf(stderr, "name `%s' too long: %zu\n", bridge, strlen(bridge)); -+ return EXIT_FAILURE; -+ } - - /* parse default acl file */ - QSIMPLEQ_INIT(&acl_list); --- -2.19.1 - diff --git a/qemu-file-Don-t-do-IO-after-shutdown.patch b/qemu-file-Don-t-do-IO-after-shutdown.patch new file mode 100644 index 0000000000000000000000000000000000000000..84032a5d8ad1a8fd5e3c750d1a07a9ddbc97e5f4 --- /dev/null +++ b/qemu-file-Don-t-do-IO-after-shutdown.patch @@ -0,0 +1,81 @@ +From 6ff76ab1455c520d936e2b9badd2a346a7c71466 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 2 Dec 2020 14:25:13 +0800 +Subject: [PATCH 22/31] 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.spec b/qemu.spec index eb3cc8989b070c63b09c4a33f53e6f507c59dc65..82b26f72ba73e999865713cddf82079d0e1885a7 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,66 +1,378 @@ Name: qemu -Version: 4.0.1 -Release: 11 +Version: 4.1.0 +Release: 72 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer -License: GPLv2 and BSD and MIT and CC-BY +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 Source1: 80-kvm.rules Source2: 99-qemu-guest-agent.rules Source3: bridge.conf -Patch0001: qxl-check-release-info-object.patch -Patch0002: ARM64-record-vtimer-tick-when-cpu-is-stopped.patch -Patch0003: pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch -Patch0004: pl031-support-rtc-timer-property-for-pl031.patch -Patch0005: vhost-cancel-migration-when-vhost-user-restarted.patch -Patch0006: qcow2-fix-memory-leak-in-qcow2_read_extensions.patch -Patch0007: hw-arm-expose-host-CPU-frequency-info-to-guest.patch -Patch0008: qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch -Patch0009: qemu-bridge-helper-move-repeating-code-in-parse_acl.patch -Patch0010: smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch -Patch0011: hw-arm-virt-Introduce-cpu-topology-support.patch -Patch0012: hw-arm64-add-vcpu-cache-info-support.patch -Patch0013: xhci-Fix-memory-leak-in-xhci_address_slot.patch -Patch0014: xhci-Fix-memory-leak-in-xhci_kick_epctx.patch -Patch0015: ehci-fix-queue-dev-null-ptr-dereference.patch -Patch0016: memory-unref-the-memory-region-in-simplify-flatview.patch -Patch0017: util-async-hold-AioContext-ref-to-prevent-use-after-free.patch -Patch0018: vhost-user-scsi-prevent-using-uninitialized-vqs.patch -Patch0019: cpu-add-Kunpeng-920-cpu-support.patch -Patch0020: cpu-parse-feature-to-avoid-failure.patch -Patch0021: cpu-add-Cortex-A72-processor-kvm-target-support.patch -Patch0022: vnc-fix-memory-leak-when-vnc-disconnect.patch -Patch0023: pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch -Patch0024: linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch -Patch0025: intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch -Patch0026: ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch -Patch0027: 9pfs-local-Fix-possible-memory-leak-in-local_link.patch -Patch0028: scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch -Patch0029: arm-translate-a64-fix-uninitialized-variable-warning.patch -Patch0030: nbd-fix-uninitialized-variable-warning.patch -Patch0031: xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch -Patch0032: block-fix-memleaks-in-bdrv_refresh_filename.patch -Patch0033: iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch -Patch0034: tcp_emu-Fix-oob-access.patch -Patch0035: slirp-use-correct-size-while-emulating-IRC-commands.patch -Patch0036: slirp-use-correct-size-while-emulating-commands.patch -Patch0037: tcp_emu-fix-unsafe-snprintf-usages.patch -Patch0038: block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch -Patch0039: monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +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: slirp-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: slirp-util-add-slirp_fmt-helpers.patch +Patch0035: slirp-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: memory-Align-MemoryRegionSections-fields.patch -Patch0042: memory-Provide-an-equality-function-for-MemoryRegion.patch -Patch0043: file-posix-Handle-undetectable-alignment.patch -Patch0044: block-backup-fix-max_transfer-handling-for-copy_rang.patch -Patch0045: block-backup-fix-backup_cow_with_offload-for-last-cl.patch -Patch0046: qcow2-Limit-total-allocation-range-to-INT_MAX.patch -Patch0047: mirror-Do-not-dereference-invalid-pointers.patch -Patch0048: COLO-compare-Fix-incorrect-if-logic.patch -Patch0049: qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch -Patch0050: pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch -Patch0051: pcie-Compat-with-devices-which-do-not-support-Link-W.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: slirp-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: es1370-check-total-frame-count-against-current-frame.patch +Patch0167: exec-set-map-length-to-zero-when-returning-NULL.patch +Patch0168: ati-vga-check-mm_index-before-recursive-call-CVE-202.patch +Patch0169: megasas-use-unsigned-type-for-reply_queue_head-and-c.patch +Patch0170: megasas-avoid-NULL-pointer-dereference.patch +Patch0171: megasas-use-unsigned-type-for-positive-numeric-field.patch +Patch0172: hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch +Patch0173: hw-arm-acpi-enable-SHPC-native-hot-plug.patch +Patch0174: hw-usb-core-fix-buffer-overflow.patch +Patch0175: slirp-drop-bogus-IPv6-messages.patch +Patch0176: hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch +Patch0177: hw-xhci-check-return-value-of-usb_packet_map.patch +Patch0178: hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch +Patch0179: hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch +Patch0180: sm501-Convert-printf-abort-to-qemu_log_mask.patch +Patch0181: sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch +Patch0182: sm501-Use-BIT-x-macro-to-shorten-constant.patch +Patch0183: sm501-Clean-up-local-variables-in-sm501_2d_operation.patch +Patch0184: sm501-Replace-hand-written-implementation-with-pixma.patch +Patch0185: pci-check-bus-pointer-before-dereference.patch +Patch0186: hw-ide-check-null-block-before-_cancel_dma_sync.patch +Patch0187: target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch +Patch0188: target-arm-Add-ID_AA64MMFR2_EL1.patch +Patch0189: target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch +Patch0190: target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch +Patch0191: target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch +Patch0192: target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch +Patch0193: target-arm-Stop-assuming-DBGDIDR-always-exists.patch +Patch0194: target-arm-Move-DBGDIDR-into-ARMISARegisters.patch +Patch0195: target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch +Patch0196: target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch +Patch0197: target-arm-Read-debug-related-ID-registers-from-KVM.patch +Patch0198: target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch +Patch0199: target-arm-monitor-query-cpu-model-expansion-crashed.patch +Patch0200: target-arm-convert-isar-regs-to-array.patch +Patch0201: target-arm-parse-cpu-feature-related-options.patch +Patch0202: target-arm-register-CPU-features-for-property.patch +Patch0203: target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch +Patch0204: target-arm-introduce-CPU-feature-dependency-mechanis.patch +Patch0205: target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch +Patch0206: target-arm-Add-CPU-features-to-query-cpu-model-expan.patch +Patch0207: target-arm-Update-ID-fields.patch +Patch0208: target-arm-Add-more-CPU-features.patch +Patch0209: target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch +Patch0210: target-arm-Update-the-ID-registers-of-Kunpeng-920.patch +Patch0211: target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch +Patch0212: target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch +Patch0213: ati-check-x-y-display-parameter-values.patch +Patch0214: net-remove-an-assert-call-in-eth_get_gso_type.patch +Patch0215: json-Fix-a-memleak-in-parse_pair.patch +Patch0216: tests-Disalbe-filemonitor-testcase.patch +Patch0217: hostmem-Fix-up-free-host_nodes-list-right-after-visi.patch +Patch0218: slirp-check-pkt_len-before-reading-protocol-header.patch +Patch0219: hw-usb-hcd-ohci-check-for-processed-TD-before-retire.patch +Patch0220: hw-ehci-check-return-value-of-usb_packet_map.patch +Patch0221: hw-usb-hcd-ohci-check-len-and-frame_number-variables.patch +Patch0222: hw-net-e1000e-advance-desc_offset-in-case-of-null-de.patch +Patch0223: target-arm-Fix-write-redundant-values-to-kvm.patch +Patch0224: memory-clamp-cached-translation-in-case-it-points-to.patch +Patch0225: ati-use-vga_read_byte-in-ati_cursor_define.patch +Patch0226: sd-sdhci-assert-data_count-is-within-fifo_buffer.patch +Patch0227: msix-add-valid.accepts-methods-to-check-address.patch +Patch0228: ide-atapi-check-io_buffer_index-in-ide_atapi_cmd_rep.patch +Patch0229: net-vmxnet3-validate-configuration-values-during-act.patch +Patch0230: scsi-bus-Refactor-the-code-that-retries-requests.patch +Patch0231: scsi-disk-Add-support-for-retry-on-errors.patch +Patch0232: qapi-block-core-Add-retry-option-for-error-action.patch +Patch0233: block-backend-Introduce-retry-timer.patch +Patch0234: block-backend-Add-device-specific-retry-callback.patch +Patch0235: block-backend-Enable-retry-action-on-errors.patch +Patch0236: block-backend-Add-timeout-support-for-retry.patch +Patch0237: block-Add-error-retry-param-setting.patch +Patch0238: virtio-blk-Refactor-the-code-that-processes-queued-r.patch +Patch0239: virtio-blk-On-restart-process-queued-requests-in-the.patch +Patch0240: virtio_blk-Add-support-for-retry-on-errors.patch +Patch0241: block-backend-Stop-retrying-when-draining.patch +Patch0242: block-Add-sanity-check-when-setting-retry-parameters.patch +Patch0243: build-smt-processor-structure-to-support-smt-topolog.patch +Patch0244: Bugfix-hw-acpi-Use-max_cpus-instead-of-cpus-when-bui.patch +Patch0245: migration-dirtyrate-setup-up-query-dirtyrate-framwor.patch +Patch0246: migration-dirtyrate-add-DirtyRateStatus-to-denote-ca.patch +Patch0247: migration-dirtyrate-Add-RamblockDirtyInfo-to-store-s.patch +Patch0248: migration-dirtyrate-Add-dirtyrate-statistics-series-.patch +Patch0249: migration-dirtyrate-move-RAMBLOCK_FOREACH_MIGRATABLE.patch +Patch0250: migration-dirtyrate-Record-hash-results-for-each-sam.patch +Patch0251: migration-dirtyrate-Compare-page-hash-results-for-re.patch +Patch0252: migration-dirtyrate-skip-sampling-ramblock-with-size.patch +Patch0253: migration-dirtyrate-Implement-set_sample_page_period.patch +Patch0254: migration-dirtyrate-Implement-calculate_dirtyrate-fu.patch +Patch0255: migration-dirtyrate-Implement-qmp_cal_dirty_rate-qmp.patch +Patch0256: migration-dirtyrate-Add-trace_calls-to-make-it-easie.patch +Patch0257: migration-dirtyrate-record-start_time-and-calc_time-.patch +Patch0258: migration-dirtyrate-present-dirty-rate-only-when-que.patch +Patch0259: migration-dirtyrate-simplify-includes-in-dirtyrate.c.patch +Patch0260: migration-tls-save-hostname-into-MigrationState.patch +Patch0261: migration-tls-extract-migration_tls_client_create-fo.patch +Patch0262: migration-tls-add-tls_hostname-into-MultiFDSendParam.patch +Patch0263: migration-tls-extract-cleanup-function-for-common-us.patch +Patch0264: migration-tls-add-support-for-multifd-tls-handshake.patch +Patch0265: migration-tls-add-trace-points-for-multifd-tls.patch +Patch0266: qemu-file-Don-t-do-IO-after-shutdown.patch +Patch0267: multifd-Make-sure-that-we-don-t-do-any-IO-after-an-e.patch +Patch0268: migration-Don-t-send-data-if-we-have-stopped.patch +Patch0269: migration-Create-migration_is_running.patch +Patch0270: migration-fix-COLO-broken-caused-by-a-previous-commi.patch +Patch0271: migration-multifd-fix-hangup-with-TLS-Multifd-due-to.patch +Patch0272: multifd-tls-fix-memoryleak-of-the-QIOChannelSocket-o.patch +Patch0273: migration-fix-memory-leak-in-qmp_migrate_set_paramet.patch +Patch0274: migration-tls-fix-inverted-semantics-in-multifd_chan.patch +Patch0275: migration-tls-add-error-handling-in-multifd_tls_hand.patch +Patch0276: arm-cpu-Fixed-function-undefined-error-at-compile-ti.patch +Patch0277: scsi-mptsas-dequeue-request-object-in-case-of-an-err.patch +Patch0278: hw-sd-sdhci-Don-t-transfer-any-data-when-command-tim.patch +Patch0279: hw-sd-sdhci-Don-t-write-to-SDHC_SYSAD-register-when-.patch +Patch0280: hw-sd-sdhci-Correctly-set-the-controller-status-for-.patch +Patch0281: hw-sd-sdhci-Limit-block-size-only-when-SDHC_BLKSIZE-.patch +Patch0282: hw-sd-sdhci-Reset-the-data-pointer-of-s-fifo_buffer-.patch +Patch0283: net-introduce-qemu_receive_packet.patch +Patch0284: e1000-switch-to-use-qemu_receive_packet-for-loopback.patch +Patch0285: dp8393x-switch-to-use-qemu_receive_packet-for-loopba.patch +Patch0286: sungem-switch-to-use-qemu_receive_packet-for-loopbac.patch +Patch0287: tx_pkt-switch-to-use-qemu_receive_packet_iov-for-loo.patch +Patch0288: rtl8139-switch-to-use-qemu_receive_packet-for-loopba.patch +Patch0289: pcnet-switch-to-use-qemu_receive_packet-for-loopback.patch +Patch0290: cadence_gem-switch-to-use-qemu_receive_packet-for-lo.patch +Patch0291: lan9118-switch-to-use-qemu_receive_packet-for-loopba.patch +Patch0292: hw-pci-host-add-pci-intack-write-method.patch +Patch0293: pci-host-add-pcie-msi-read-method.patch +Patch0294: vfio-add-quirk-device-write-method.patch +Patch0295: prep-add-ppc-parity-write-method.patch +Patch0296: nvram-add-nrf51_soc-flash-read-method.patch +Patch0297: spapr_pci-add-spapr-msi-read-method.patch +Patch0298: tz-ppc-add-dummy-read-write-methods.patch +Patch0299: imx7-ccm-add-digprog-mmio-write-method.patch +Patch0300: bugfix-fix-Uninitialized-Free-Vulnerability.patch +Patch0301: 9pfs-Fully-restart-unreclaim-loop-CVE-2021-20181.patch +Patch0302: vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch +Patch0303: vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch +Patch0304: vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch +Patch0305: vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch +Patch0306: vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch +Patch0307: vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch +Patch0308: vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch +Patch0309: ide-ahci-add-check-to-avoid-null-dereference-CVE-201.patch +Patch0310: hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch +Patch0311: usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch +Patch0312: hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch +Patch0313: x86-Intel-AVX512_BF16-feature-enabling.patch +Patch0314: i386-Add-MSR-feature-bit-for-MDS-NO.patch +Patch0315: i386-Add-macro-for-stibp.patch +Patch0316: i386-Add-new-CPU-model-Cooperlake.patch +Patch0317: target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch +Patch0318: target-i386-Add-missed-security-features-to-Cooperla.patch +Patch0319: target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch +Patch0320: target-i386-Export-TAA_NO-bit-to-guests.patch +Patch0321: usbredir-fix-free-call.patch +Patch0322: hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch +Patch0323: uas-add-stream-number-sanity-checks.patch +Patch0324: virtio-net-fix-use-after-unmap-free-for-sg.patch +Patch0325: Add-mtod_check.patch +Patch0326: bootp-limit-vendor-specific-area-to-input-packet-mem.patch +Patch0327: bootp-check-bootp_input-buffer-size.patch +Patch0328: upd6-check-udp6_input-buffer-size.patch +Patch0329: tftp-check-tftp_input-buffer-size.patch +Patch0330: tftp-introduce-a-header-structure.patch +Patch0331: fix-cve-2020-35504.patch +Patch0332: fix-cve-2020-35505.patch +Patch0333: virtio-balloon-apply-upstream-patch.patch +Patch0334: add-Phytium-s-CPU-models-FT-2000-and-Tengyun-S2500.patch +Patch0335: hw-scsi-scsi-disk-MODE_PAGE_ALLS-not-allowed-in-MODE.patch +Patch0336: hw-rdma-Fix-possible-mremap-overflow-in-the-pvrdma-d.patch +Patch0337: pvrdma-Ensure-correct-input-on-ring-init-CVE-2021-36.patch +Patch0338: pvrdma-Fix-the-ring-init-error-flow-CVE-2021-3608.patch +Patch0339: vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch +Patch0340: virtio-net-fix-map-leaking-on-error-during-receive.patch +Patch0341: hw-block-fdc-Extract-blk_create_empty_drive.patch +Patch0342: hw-block-fdc-Kludge-missing-floppy-drive-to-fix-CVE-.patch +Patch0343: tests-fdc-test-Add-a-regression-test-for-CVE-2021-20.patch +Patch0344: display-qxl-render-fix-race-condition-in-qxl_cursor-.patch +Patch0345: ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch +Patch0346: hw-intc-arm_gicv3_dist-Rename-64-bit-accessors-with-.patch +Patch0347: hw-intc-arm_gicv3-Replace-mis-used-MEMTX_-constants-.patch +Patch0348: hw-intc-arm_gicv3-Check-for-MEMTX_OK-instead-of-MEMT.patch +Patch0349: net-colo-compare.c-Check-that-colo-compare-is-active.patch +Patch0350: e1000-fail-early-for-evil-descriptor.patch +Patch0351: e1000-fix-tx-re-entrancy-problem.patch +Patch0352: hw-sd-sdcard-Restrict-Class-6-commands-to-SCSD-cards.patch +Patch0353: hw-sd-sdcard-Simplify-realize-a-bit.patch +Patch0354: hw-sd-sdcard-Do-not-allow-invalid-SD-card-sizes.patch +Patch0355: hw-sd-sdcard-Update-coding-style-to-make-checkpatch..patch +Patch0356: hw-sd-sdcard-Do-not-switch-to-ReceivingData-if-addre.patch +Patch0357: scsi-qemu-pr-helper-Fix-out-of-bounds-access-to-trnp.patch +Patch0358: curses-Fixes-curses-compiling-errors.patch +Patch0359: net-dump.c-Suppress-spurious-compiler-warning.patch +Patch0360: tests-Replace-deprecated-ASN1-code.patch +Patch0361: hw-block-fdc-Prevent-end-of-track-overrun-CVE-2021-3.patch +Patch0362: softmmu-Always-initialize-xlat-in-address_space_tran.patch +Patch0363: 9pfs-prevent-opening-special-files-CVE-2023-2861.patch BuildRequires: flex BuildRequires: bison @@ -103,6 +415,10 @@ BuildRequires: libudev-devel BuildRequires: pam-devel BuildRequires: perl-Test-Harness BuildRequires: python3-devel +BuildRequires: librbd-devel +BuildRequires: krb5-devel +BuildRequires: libssh-devel +BuildRequires: glib2 %ifarch aarch64 BuildRequires: libfdt-devel BuildRequires: virglrenderer-devel @@ -114,6 +430,8 @@ Requires(post): /usr/sbin/useradd Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units +Requires(postun): qemu-block-iscsi +Requires(postun): qemu-block-curl %description QEMU is a FAST! processor emulator using dynamic translation to achieve good emulation speed. @@ -150,6 +468,26 @@ Summary: QEMU command line tool for manipulating disk images %description img This package provides a command line tool for manipulating disk images +%package block-rbd +Summary: Qemu-block-rbd +%description block-rbd +This package provides RBD support for Qemu + +%package block-ssh +Summary: Qemu-block-ssh +%description block-ssh +This package provides block-ssh support for Qemu + +%package block-iscsi +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 + %ifarch %{ix86} x86_64 %package seabios Summary: QEMU seabios @@ -187,7 +525,6 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --with-pkgversion=%{name}-%{version}-%{release} \ --python=/usr/bin/python3 \ --disable-strip \ - --disable-werror \ --disable-slirp \ --enable-gtk \ --enable-docs \ @@ -203,6 +540,8 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --enable-linux-aio \ --enable-cap-ng \ --enable-vhost-user \ + --enable-modules \ + --enable-libssh \ %ifarch aarch64 --enable-fdt \ --enable-virglrenderer \ @@ -247,7 +586,9 @@ install -D -m 0644 %{_sourcedir}/99-qemu-guest-agent.rules %{buildroot}%{_udevdi mkdir -p %{buildroot}%{_localstatedir}/log 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 chmod -x %{buildroot}%{_mandir}/man1/* @@ -262,6 +603,9 @@ 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}/openbios-* rm -rf %{buildroot}%{_datadir}/%{name}/slof.bin rm -rf %{buildroot}%{_datadir}/%{name}/QEMU,*.bin @@ -277,6 +621,23 @@ rm -rf %{buildroot}%{_datadir}/%{name}/skiboot.lid rm -rf %{buildroot}%{_datadir}/%{name}/spapr-* rm -rf %{buildroot}%{_datadir}/%{name}/u-boot* 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-gluster.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}%{_libexecdir}/vhost-user-gpu +rm -rf %{buildroot}%{_datadir}/%{name}/vhost-user/50-qemu-gpu.json + +strip %{buildroot}%{_libdir}/%{name}/block-rbd.so +strip %{buildroot}%{_libdir}/%{name}/block-iscsi.so +strip %{buildroot}%{_libdir}/%{name}/block-curl.so +strip %{buildroot}%{_libdir}/%{name}/block-ssh.so for f in %{buildroot}%{_bindir}/* %{buildroot}%{_libdir}/* \ %{buildroot}%{_libexecdir}/*; do @@ -389,6 +750,18 @@ getent passwd qemu >/dev/null || \ %{_bindir}/qemu-io %{_bindir}/qemu-nbd +%files block-rbd +%{_libdir}/%{name}/block-rbd.so + +%files block-ssh +%{_libdir}/%{name}/block-ssh.so + +%files block-iscsi +%{_libdir}/%{name}/block-iscsi.so + +%files block-curl +%{_libdir}/%{name}/block-curl.so + %ifarch %{ix86} x86_64 %files seabios %{_datadir}/%{name}/bios-256k.bin @@ -396,89 +769,438 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Wed Mar 18 2020 Huawei Technologies Co., Ltd. +* Fri Jul 21 2022 Jiabo Feng +- 9pfs: prevent opening special files (CVE-2023-2861) + +* Tue Jul 19 2022 yezengruan +- softmmu: Always initialize xlat in address_space_translate_for_iotlb (CVE-2022-35414) + +* Thu Jun 02 2022 yezengruan +- hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507) + +* Sat May 28 2022 sundongxu +- e1000: fail early for evil descriptor +- e1000: fix tx re-entrancy problem +- hw/sd/sdcard: Do not allow invalid SD card sizes +- hw/sd/sdcard: Do not switch to ReceivingData if address is invalid +- hw/sd/sdcard: Restrict Class 6 commands to SCSD cards +- hw/sd/sdcard: Simplify realize() a bit +- hw/sd/sdcard: Update coding style to make checkpatch.pl happy +- scsi/qemu-pr-helper: Fix out-of-bounds access to trnptid_list[] +- curses: Fixes curses compiling errors. +- net/dump.c: Suppress spurious compiler warning +- tests: Replace deprecated ASN1 code + +* Sat May 21 2022 yezengruan +- hw/intc/arm_gicv3_dist: Rename 64-bit accessors with 'q' suffix +- hw/intc/arm_gicv3: Replace mis-used MEMTX_* constants by booleans +- hw/intc/arm_gicv3: Check for !MEMTX_OK instead of MEMTX_ERROR (CVE-2021-3750) +- net/colo-compare.c: Check that colo-compare is active + +* Tue May 10 2022 yezengruan +- hw/block/fdc: Extract blk_create_empty_drive() +- hw/block/fdc: Kludge missing floppy drive to fix CVE-2021-20196 +- tests/fdc-test: Add a regression test for CVE-2021-20196 +- display/qxl-render: fix race condition in qxl_cursor (CVE-2021-4207) +- ui/cursor: fix integer overflow in cursor_alloc (CVE-2021-4206) + +* Fri Apr 15 2022 yezengruan +- 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 Apr 06 2022 yezengruan +- hw/rdma: Fix possible mremap overflow in the pvrdma device (CVE-2021-3582) +- pvrdma: Ensure correct input on ring init (CVE-2021-3607) +- pvrdma: Fix the ring init error flow (CVE-2021-3608) + +* Mon Mar 28 2022 Jinhao Gao +- hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT commands(fix CVE-2021-3930) + +* Tue Dec 21 2021 imxcc +- add Phytium's CPU models: FT-2000+ and Tengyun-S2500 + +* Fri Dec 03 2021 Chen Qun +- virtio-balloon: apply upstream patch. + +* Wed Oct 27 2021 Chen Qun +- fix cve-2020-35504 +- fix cve-2020-35505 + +* Tue Oct 19 2021 imxcc +- fix cve-2021-3592 cve-2021-3593 cve-2021-3595 + +* Sun Sep 26 2021 Chen Qun +- virtio-net: fix use after unmap/free for sg + +* Wed Sep 15 2021 Chen Qun +- uas: add stream number sanity checks. + +* Tue Aug 31 2021 imxcc +- hw/arm/virt:Init PMU for hotplugged vCPU + +* Thu Aug 19 2021 Jiajie Li +- add qemu-block-curl package +- add qemu-block-curl requirement for qemu. + +* Mon Aug 16 2021 Chen Qun +- usbredir: fix free call + +* Fri Jul 16 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 + +* Tue Jul 13 2021 Chen Qun +- hw/net/rocker_of_dpa: fix double free bug of rocker device + +* 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) + +* Tue Jun 08 2021 Chen Qun +- 9pfs: Fully restart unreclaim loop (CVE-2021-20181) + +* Wed Jun 02 2021 imxcc +- add strip for block-iscsi.so, block-rbd.so and block-ssh.so + +* Wed Jun 02 2021 Chen Qun +- bugfix: fix Uninitialized Free Vulnerability + +* Tue Jun 01 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 May 20 2021 Chen Qun +- hw/sd: sdhci: Don't transfer any data when command time out +- hw/sd: sdhci: Don't write to SDHC_SYSAD register when transfer is in progress +- hw/sd: sdhci: Correctly set the controller status for ADMA +- hw/sd: sdhci: Limit block size only when SDHC_BLKSIZE register is writable +- hw/sd: sdhci: Reset the data pointer of s->fifo_buffer[] when a different block size is programmed +- net: introduce qemu_receive_packet() +- e1000: switch to use qemu_receive_packet() for loopback +- dp8393x: switch to use qemu_receive_packet() for loopback packet +- sungem: switch to use qemu_receive_packet() for loopback +- tx_pkt: switch to use qemu_receive_packet_iov() for loopback +- rtl8139: switch to use qemu_receive_packet() for loopback +- pcnet: switch to use qemu_receive_packet() for loopback +- cadence_gem: switch to use qemu_receive_packet() for loopback +- lan9118: switch to use qemu_receive_packet() for loopback + +* Wed May 19 2021 Chen Qun +- scsi: mptsas: dequeue request object in case of an error + +* Tue May 11 2021 Chen Qun +- arm/cpu: Fixed function undefined error at compile time under arm + +* Tue May 11 2021 Ming Yang +- add qemu-block-iscsi installing requirement + +* Sun Apr 25 2021 Chuan Zheng +- migration/dirtyrate: add dirtyrate fearure for migration +- migration/multifd-tls: add multifd for tls migration + +* Sun Apr 25 2021 imxcc +- hw/acpi: build smt processor structure to support smt topology +- hw/acpi: Use max_cpus instead of cpus when build PPTT + +* Sun Apr 25 2021 Chen Qun +- scsi-bus: Refactor the code that retries requests +- scsi-disk: Add support for retry on errors +- 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 +- block-backend: Stop retrying when draining +- block: Add sanity check when setting retry parameters + +* Sat Apr 17 2021 Chuan Zheng +- dirtyrate: add migration dirtyrate feature + +* Fri Apr 16 2021 Huawei Technologies Co., Ltd +- add qemu-block-rbd package +- add qemu-block-ssh package + +* Thu Mar 18 2021 Chen Qun +- net: vmxnet3: validate configuration values during activate (CVE-2021-20203) + +* 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 + +* Mon Jan 18 2021 Huawei Technologies Co., Ltd +- reorder the changelog + +* Fri Jan 15 2021 Huawei Technologies Co., Ltd +- memory: clamp cached translation in case it points to an MMIO region + +* 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 + +* Fri Dec 11 2020 Huawei Technologies Co., Ltd +- hostmem: Fix up free host_nodes list right after visited + +* Wed Dec 9 2020 Huawei Technologies Co., Ltd +- target/arm: Fix write redundant values to kvm + +* 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 + +* 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 + +* Thu Sep 24 2020 Huawei Technologies Co., Ltd +- enrich commit info for some patches +- rename some patches for slirp + +* Mon Sep 21 2020 Huawei Technologies Co., Ltd +- target/arm: Add isar_feature tests for PAN + ATS1E1 +- target/arm: Add ID_AA64MMFR2_EL1 +- target/arm: Add and use FIELD definitions for ID_AA64DFR0_EL1 +- target/arm: Use FIELD macros for clearing ID_DFR0 PERFMON field +- target/arm: Define an aa32_pmu_8_1 isar feature test function +- target/arm: Add _aa64_ and _any_ versions of pmu_8_1 isar checks +- target/arm: Stop assuming DBGDIDR always exists +- target/arm: Move DBGDIDR into ARMISARegisters +- target/arm: Enable ARMv8.2-ATS1E1 in -cpu max +- target/arm: Test correct register in aa32_pan and aa32_ats1e1 checks +- target/arm: Read debug-related ID registers from KVM +- target/arm/monitor: Introduce qmp_query_cpu_model_expansion +- target/arm/monitor: query-cpu-model-expansion crashed qemu when using machine type none +- 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: Update ID fields +- target/arm: Add more CPU features +- target/arm: ignore evtstrm and cpuid CPU features +- target/arm: Update the ID registers of Kunpeng-920 +- target/arm: only set ID_PFR1_EL1.GIC for AArch32 guest +- target/arm: clear EL2 and EL3 only when kvm is not enabled + +* 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 vulnerablity + +* Thu Aug 27 2020 Huawei Technologies Co., Ltd +- hw/usb/core.c: fix buffer overflow in do_token_setup function + +* Wed Aug 12 2020 Huawei Technologies Co., Ltd +- backport upstream patch to support SHPCHotplug in arm + +* Thu Aug 6 2020 Huawei Technologies Co., Ltd +- tests: Disalbe filemonitor testcase + +* Fri Jul 24 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 + +* 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 + +* Thu May 21 2020 BALATON Zoltan +- hw/net/xgmac: Fix buffer overflow in xgmac_enet_send() +- hw/net/net_tx_pkt: fix assertion failure in net_tx_pkt_add_raw_fragment() +- sm501: Convert printf + abort to qemu_log_mask +- sm501: Shorten long variable names in sm501_2d_operation +- sm501: Use BIT(x) macro to shorten constant +- sm501: Clean up local variables in sm501_2d_operation +- sm501: Replace hand written implementation with pixman where possible + +* 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 +- pcie: Compat with devices which do not support Link Width, such as ioh3420 -* Tue Mar 17 2020 Huawei Technologies Co., Ltd. -- Put linuxboot_dma.bin and pvh.bin in x86 package +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- qcow2-bitmap: Fix uint64_t left-shift overflow -* Mon Mar 16 2020 backport some bug fix patches from upstream -- Patch from number 0040 to 0049 are picked from stable-4.1.1 +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- COLO-compare: Fix incorrect `if` logic -* Mon Mar 16 2020 Huawei Technologies Co., Ltd. -- moniter: fix memleak in monitor_fdset_dup_fd_find_remove +* 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 -* Wed Mar 11 2020 backport from qemu upstream -- tcp_emu: Fix oob access -- slirp: use correct size while emulating IRC commands -- slirp: use correct size while emulating commands +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. - tcp_emu: fix unsafe snprintf() usages - -* Mon Mar 9 2020 backport from qemu upstream +- 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 Feb 6 2020 Huawei Technologies Co., Ltd. -- spec: remove fno-inline option for configure - -* Thu Jan 16 2020 Huawei Technologies Co., Ltd. +* 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 -* Mon Jan 13 2020 Huawei Technologies Co., Ltd. -- 9pfs: Fix a possible memory leak in local_link -- scsi-disk: disk define props in scsi_block to avoid memleaks -- arm/translate-a64: fix uninitialized variable warning -- nbd: fix uninitialized variable warning -- xhci: Fix memory leak in xhci_kick_epctx when poweroff +* 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 > -* Mon Jan 6 2020 backport from qemu upstream -- linux headers: update against "KVM/ARM: Fix >256 vcp -- intc/arm_gic: Support IRQ injection for more than 256 vpus -- ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > 256 +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- vnc: fix memory leak when vnc disconnect -* Thu Dec 12 2019 backport from qemu upstream v4.0.1 release -- tpm: Exit in reset when backend indicates failure -- tpm_emulator: Translate TPM error codes to strings +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- pcie: disable the PCI_EXP_LINKSTA_DLLA cap for pcie-root-port by default -* Thu Oct 17 2019 backport from qemu upstream -- vnc-fix-memory-leak-when-vnc-disconnect.patch +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- cpu: add Kunpeng-920 cpu support +- cpu: parse +/- feature to avoid failure +- cpu: add Cortex-A72 processor kvm target support -* Mon Sep 9 2019 backport from qemu upstream -- ehci-fix-queue-dev-null-ptr-dereference.patch -- memory-unref-the-memory-region-in-simplify-flatview.patch -- util-async-hold-AioContext-ref-to-prevent-use-after-.patch -- vhost-user-scsi-prevent-using-uninitialized-vqs.patch +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- vhost-user-scsi: prevent using uninitialized vqs -* Fri Aug 30 2019 Huawei Technologies Co., Ltd. +* 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 -* Wed Aug 7 2019 Huawei Technologies Co., Ltd. +* 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 -* Tue Aug 6 2019 Huawei Technologies Co., Ltd. -- Update release version to 4.0.0-2 - -* Mon Aug 5 2019 Huawei Technologies Co., Ltd. -- enable make check +* Wed Apr 15 2020 Huawei Technologies Co., Ltd. - smbios: Add missing member of type 4 for smbios 3.0 -* Mon Aug 5 2019 fix CVE-2019-13164 -- qemu-bridge-helper: restrict interface name to IFNAMSIZ -- qemu-bridge-helper: move repeating code in parse_acl_file +* 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 -* Tue Jul 30 2019 Huawei Technologies Co., Ltd. - qcow2: fix memory leak in qcow2_read_extensions -- hw/arm: expose host CPU frequency info to guest -* Fri Jul 26 2019 Huawei Technologies Co., Ltd. -- vhost: cancel migration when vhost-user restarted +* Wed Apr 15 2020 Huawei Technologies Co., Ltd. +- pl011: reset read FIFIO when UARTTIMSC=0 & UARTICR=0xff - pl031: support rtc-timer property for pl031 -- pl011: reset read FIFO when UARTTIMSC=0 & UARTICR=0xffff -- ARM64: record vtimer tick when cpu is stopped +- vhost: cancel migration when vhost-user restarted -* Tue Jul 23 2019 openEuler Buildteam - version-release +* Mon Apr 13 2020 openEuler Buildteam - version-release - Package init - diff --git a/qxl-check-release-info-object.patch b/qxl-check-release-info-object.patch deleted file mode 100644 index aeddbe467c34aa83a3c7b8bca6b98b44abf546a6..0000000000000000000000000000000000000000 --- a/qxl-check-release-info-object.patch +++ /dev/null @@ -1,36 +0,0 @@ -From cbed4e0108ca1403f1f47cde292330b87a0d8bf2 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Apr 2019 12:05:34 +0530 -Subject: [PATCH] qxl: check release info object - -When releasing spice resources in release_resource() routine, -if release info object 'ext.info' is null, it leads to null -pointer dereference. Add check to avoid it. - -(This is cherry-pick d52680fc932efb8a2f334cc6993e705ed1e31e99) - -Reported-by: Bugs SysSec -Signed-off-by: Prasad J Pandit -Message-id: 20190425063534.32747-1-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann ---- - hw/display/qxl.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/display/qxl.c b/hw/display/qxl.c -index c8ce578..632923a 100644 ---- a/hw/display/qxl.c -+++ b/hw/display/qxl.c -@@ -777,6 +777,9 @@ static void interface_release_resource(QXLInstance *sin, - QXLReleaseRing *ring; - uint64_t *item, id; - -+ if (!ext.info) { -+ return; -+ } - if (ext.group_id == MEMSLOT_GROUP_HOST) { - /* host group -> vga mode update request */ - QXLCommandExt *cmdext = (void *)(intptr_t)(ext.info->id); --- -1.8.3.1 - 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 new file mode 100644 index 0000000000000000000000000000000000000000..00e672662ddd5d848fc031967a0efdcf9dc4432b --- /dev/null +++ b/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch @@ -0,0 +1,54 @@ +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/rtl8139-switch-to-use-qemu_receive_packet-for-loopba.patch b/rtl8139-switch-to-use-qemu_receive_packet-for-loopba.patch new file mode 100644 index 0000000000000000000000000000000000000000..070b88af9128e894bb63bace7f66d2b5f1944728 --- /dev/null +++ b/rtl8139-switch-to-use-qemu_receive_packet-for-loopba.patch @@ -0,0 +1,43 @@ +From beaa8c1788fa201ca4e4c8dc58b96c8d67ae8389 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov +Date: Fri, 14 May 2021 10:35:11 +0800 +Subject: [PATCH] rtl8139: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Buglink: https://bugs.launchpad.net/qemu/+bug/1910826 +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/rtl8139.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index 09273171e5..79584fbb17 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -1792,7 +1792,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, + } + + DPRINTF("+++ transmit loopback mode\n"); +- rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt); ++ qemu_receive_packet(qemu_get_queue(s->nic), buf, size); + + if (iov) { + g_free(buf2); +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..99f36430199db330e667a47391cd497a77e9b567 --- /dev/null +++ b/scsi-bus-Refactor-the-code-that-retries-requests.patch @@ -0,0 +1,68 @@ +From d870d50c1ddb07c1929eaecd0165d6297c113c9a 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 + +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 +retry_request_cb() of scsi-disk in a future patch. + +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +--- + 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 +--- 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); + } + +-static void scsi_dma_restart_bh(void *opaque) ++void scsi_retry_requests(SCSIDevice *s) + { +- SCSIDevice *s = opaque; + SCSIRequest *req, *next; + +- qemu_bh_delete(s->bh); +- s->bh = NULL; +- + 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)); + } + ++static void scsi_dma_restart_bh(void *opaque) ++{ ++ SCSIDevice *s = opaque; ++ ++ qemu_bh_delete(s->bh); ++ s->bh = NULL; ++ ++ scsi_retry_requests(s); ++} ++ + void scsi_req_retry(SCSIRequest *req) + { + /* 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 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -184,6 +184,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); ++void scsi_retry_requests(SCSIDevice *s); + void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); + void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); + void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..9b6ab5db5fe7d85fa080dfef684c013448d3b2bc --- /dev/null +++ b/scsi-disk-Add-support-for-retry-on-errors.patch @@ -0,0 +1,76 @@ +From 86bd26f21c3dd3a90b0c35203f77a9551e2db60d 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 + +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 +--- + 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 +--- 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) + + 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) { + 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); + } + ++ 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) + } + } + ++static void scsi_disk_retry_request(void *opaque) ++{ ++ SCSIDiskState *s = opaque; ++ ++ scsi_retry_requests(&s->qdev); ++} ++ + 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 = { + .is_medium_locked = scsi_cd_is_medium_locked, + + .resize_cb = scsi_disk_resize_cb, ++ .retry_request_cb = scsi_disk_retry_request, + }; + + static const BlockDevOps scsi_disk_block_ops = { + .resize_cb = scsi_disk_resize_cb, ++ .retry_request_cb = scsi_disk_retry_request, + }; + + static void scsi_disk_unit_attention_reported(SCSIDevice *dev) +-- +2.27.0 + diff --git a/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch b/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d20a9f009c9bd52f9eef578344c5b0012ee8942 --- /dev/null +++ b/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch @@ -0,0 +1,104 @@ +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-mptsas-dequeue-request-object-in-case-of-an-err.patch b/scsi-mptsas-dequeue-request-object-in-case-of-an-err.patch new file mode 100644 index 0000000000000000000000000000000000000000..610b9d7fd6608155ae782b7dc4bbb728b09932c4 --- /dev/null +++ b/scsi-mptsas-dequeue-request-object-in-case-of-an-err.patch @@ -0,0 +1,41 @@ +From 27b68c47d739a3c4e5ece95ab002ee852103e11f Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Mon, 17 May 2021 14:24:49 +0800 +Subject: [PATCH] scsi: mptsas: dequeue request object in case of an error + +Fix CVE-2021-3392 + +While processing SCSI i/o requests in mptsas_process_scsi_io_request(), +the Megaraid emulator appends new MPTSASRequest object 'req' to +the 's->pending' queue. In case of an error, this same object gets +dequeued in mptsas_free_request() only if SCSIRequest object +'req->sreq' is initialised. This may lead to a use-after-free issue. +Unconditionally dequeue 'req' object from 's->pending' to avoid it. + +Fixes: CVE-2021-3392 +Buglink: https://bugs.launchpad.net/qemu/+bug/1914236 +Reported-by: Cheolwoo Myung +Signed-off-by: Prasad J Pandit + +Signed-off-by: Jiajie Li +--- + hw/scsi/mptsas.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c +index 3f94d5ab55..4d23f045d7 100644 +--- a/hw/scsi/mptsas.c ++++ b/hw/scsi/mptsas.c +@@ -259,8 +259,8 @@ static void mptsas_free_request(MPTSASRequest *req) + req->sreq->hba_private = NULL; + scsi_req_unref(req->sreq); + req->sreq = NULL; +- QTAILQ_REMOVE(&s->pending, req, next); + } ++ QTAILQ_REMOVE(&s->pending, req, next); + qemu_sglist_destroy(&req->qsg); + g_free(req); + } +-- +2.27.0 + diff --git a/scsi-qemu-pr-helper-Fix-out-of-bounds-access-to-trnp.patch b/scsi-qemu-pr-helper-Fix-out-of-bounds-access-to-trnp.patch new file mode 100644 index 0000000000000000000000000000000000000000..687c9f0f5e5947db439e679a1f141a82c9deeb8f --- /dev/null +++ b/scsi-qemu-pr-helper-Fix-out-of-bounds-access-to-trnp.patch @@ -0,0 +1,95 @@ +From 36a343cbba2752fab2995fd0d9848c192f0c9579 Mon Sep 17 00:00:00 2001 +From: Christophe de Dinechin +Date: Fri, 28 Feb 2020 16:00:59 +0100 +Subject: [PATCH 1/4] scsi/qemu-pr-helper: Fix out-of-bounds access to + trnptid_list[] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Compile error reported by gcc 10.0.1: + +scsi/qemu-pr-helper.c: In function ‘multipath_pr_out’: +scsi/qemu-pr-helper.c:523:32: error: array subscript is outside array bounds of ‘struct transportid *[0]’ [-Werror=array-bounds] + 523 | paramp.trnptid_list[paramp.num_transportid++] = id; + | ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ +In file included from scsi/qemu-pr-helper.c:36: +/usr/include/mpath_persist.h:168:22: note: while referencing ‘trnptid_list’ + 168 | struct transportid *trnptid_list[]; + | ^~~~~~~~~~~~ +scsi/qemu-pr-helper.c:424:35: note: defined here ‘paramp’ + 424 | struct prout_param_descriptor paramp; + | ^~~~~~ + +This highlights an actual implementation issue in function multipath_pr_out. +The variable paramp is declared with type `struct prout_param_descriptor`, +which is a struct terminated by an empty array in mpath_persist.h: + + struct transportid *trnptid_list[]; + +That empty array was filled with code that looked like that: + + trnptid_list[paramp.descr.num_transportid++] = id; + +This is an actual out-of-bounds access. + +The fix is to malloc `paramp`. + +Signed-off-by: Christophe de Dinechin +Signed-off-by: Paolo Bonzini +--- + scsi/qemu-pr-helper.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index a256ce490b..aa135df1f9 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -421,10 +421,13 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, + int rq_servact = cdb[1]; + int rq_scope = cdb[2] >> 4; + int rq_type = cdb[2] & 0xf; +- struct prout_param_descriptor paramp; ++ g_autofree struct prout_param_descriptor *paramp = NULL; + char transportids[PR_HELPER_DATA_SIZE]; + int r; + ++ paramp = g_malloc0(sizeof(struct prout_param_descriptor) ++ + sizeof(struct transportid *) * MPATH_MX_TIDS); ++ + if (sz < PR_OUT_FIXED_PARAM_SIZE) { + /* Illegal request, Parameter list length error. This isn't fatal; + * we have read the data, send an error without closing the socket. +@@ -454,10 +457,9 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, + * used by libmpathpersist (which, of course, will immediately + * do the opposite). + */ +- memset(¶mp, 0, sizeof(paramp)); +- memcpy(¶mp.key, ¶m[0], 8); +- memcpy(¶mp.sa_key, ¶m[8], 8); +- paramp.sa_flags = param[20]; ++ memcpy(¶mp->key, ¶m[0], 8); ++ memcpy(¶mp->sa_key, ¶m[8], 8); ++ paramp->sa_flags = param[20]; + if (sz > PR_OUT_FIXED_PARAM_SIZE) { + size_t transportid_len; + int i, j; +@@ -520,12 +522,13 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, + return CHECK_CONDITION; + } + +- paramp.trnptid_list[paramp.num_transportid++] = id; ++ assert(paramp->num_transportid < MPATH_MX_TIDS); ++ paramp->trnptid_list[paramp->num_transportid++] = id; + } + } + + r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, +- ¶mp, noisy, verbose); ++ paramp, noisy, verbose); + return mpath_reconstruct_sense(fd, r, sense); + } + #endif +-- +2.17.1 + diff --git a/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch b/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a4a9ee8c708b845773b51d866a8cbc80da48085 --- /dev/null +++ b/sd-sdhci-assert-data_count-is-within-fifo_buffer.patch @@ -0,0 +1,65 @@ +From 9335a22d0fff7d52cc791f1cdd8d18ce16ec21df 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 65a530aee4..d4ee6bd01f 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/slirp-check-pkt_len-before-reading-protocol-header.patch b/slirp-check-pkt_len-before-reading-protocol-header.patch new file mode 100644 index 0000000000000000000000000000000000000000..506e31e1cb809bba769e857177c4e2ad70f4293f --- /dev/null +++ b/slirp-check-pkt_len-before-reading-protocol-header.patch @@ -0,0 +1,61 @@ +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-drop-bogus-IPv6-messages.patch b/slirp-drop-bogus-IPv6-messages.patch new file mode 100644 index 0000000000000000000000000000000000000000..2fc1e0e780e34b1570fbcfcc4581138c79e7fa46 --- /dev/null +++ b/slirp-drop-bogus-IPv6-messages.patch @@ -0,0 +1,30 @@ +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/slirp-ip_reass-Fix-use-after-free.patch b/slirp-ip_reass-Fix-use-after-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..b26e8afb629d7d768608fdc471a9cf754be36f7e --- /dev/null +++ b/slirp-ip_reass-Fix-use-after-free.patch @@ -0,0 +1,40 @@ +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/slirp-tcp_emu-Fix-oob-access.patch b/slirp-tcp_emu-Fix-oob-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..807dfef08e28fe33a65fede676bbb076f5d9e393 --- /dev/null +++ b/slirp-tcp_emu-Fix-oob-access.patch @@ -0,0 +1,37 @@ +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/slirp-tcp_emu-fix-unsafe-snprintf-usages.patch b/slirp-tcp_emu-fix-unsafe-snprintf-usages.patch new file mode 100644 index 0000000000000000000000000000000000000000..2f6850a60c2fb942ecc7ef15030686d3dd94aa9c --- /dev/null +++ b/slirp-tcp_emu-fix-unsafe-snprintf-usages.patch @@ -0,0 +1,103 @@ +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/slirp-tftp-restrict-relative-path-access.patch b/slirp-tftp-restrict-relative-path-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7f09462525437c9048b4ab249b6e4208adda4ef --- /dev/null +++ b/slirp-tftp-restrict-relative-path-access.patch @@ -0,0 +1,37 @@ +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 index 4503688dd1502c85f7a8e0fee1e5a36bcca838b2..1b4039e1da3c0bcd08b97f4c61983ef3adac3823 100644 --- a/slirp-use-correct-size-while-emulating-IRC-commands.patch +++ b/slirp-use-correct-size-while-emulating-IRC-commands.patch @@ -1,6 +1,6 @@ -From 882149fd8401f8ff667ea384bb68008354fd110f Mon Sep 17 00:00:00 2001 +From 011880f527ff317a40769ea8673a6353e5db53ac Mon Sep 17 00:00:00 2001 From: Prasad J Pandit -Date: Wed, 11 Mar 2020 18:19:36 +0800 +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 @@ -13,40 +13,42 @@ 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 | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) + 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 4608942f..2053b11b 100644 +index 9c94c03a..2a15b16a 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -786,7 +786,7 @@ 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, -+ 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); -@@ -797,7 +797,7 @@ 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, -+ m->m_len += 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); -@@ -808,7 +808,7 @@ 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, -+ m->m_len += 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.21.1 (Apple Git-122.3) - +@@ -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 index 76507a4d82f3c769540cf34294d855242ac0737f..25f64e2738e2ae3cbff541719b726dff963007d2 100644 --- a/slirp-use-correct-size-while-emulating-commands.patch +++ b/slirp-use-correct-size-while-emulating-commands.patch @@ -1,6 +1,6 @@ -From 66e2f47a01ffcaafe11acae0a191efd1805f86c6 Mon Sep 17 00:00:00 2001 +From 662aa4f1d168b32335a4dc40782e816329afcac0 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit -Date: Wed, 11 Mar 2020 18:27:22 +0800 +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 @@ -10,42 +10,40 @@ 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 | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) + 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 2053b11b..e898fd03 100644 +index 2a15b16a..019b637a 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -707,7 +707,7 @@ 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; -@@ -740,7 +740,7 @@ 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), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - -@@ -766,8 +766,8 @@ tcp_emu(struct socket *so, struct mbuf *m) - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (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; -+ m->m_len = snprintf(m->m_data, M_ROOM(m), -+ "%d", ntohs(so->so_fport)) + 1; - return 1; - - case EMU_IRC: --- -2.21.1 (Apple Git-122.3) +@@ -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/slirp-util-add-slirp_fmt-helpers.patch b/slirp-util-add-slirp_fmt-helpers.patch new file mode 100644 index 0000000000000000000000000000000000000000..b752f1293a0b88ef0ae01410a2fc63f9ff875df8 --- /dev/null +++ b/slirp-util-add-slirp_fmt-helpers.patch @@ -0,0 +1,124 @@ +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/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch b/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch new file mode 100644 index 0000000000000000000000000000000000000000..70d87926dcf2417b0ab72e78ee81cbe3defe9f4f --- /dev/null +++ b/sm501-Clean-up-local-variables-in-sm501_2d_operation.patch @@ -0,0 +1,95 @@ +From b08fddd2931fa2e3d12d2c26074835956b114d56 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 new file mode 100644 index 0000000000000000000000000000000000000000..a1516561cef965bfc355297d552f6361200b342e --- /dev/null +++ b/sm501-Convert-printf-abort-to-qemu_log_mask.patch @@ -0,0 +1,159 @@ +From c52852158aa010d534ee6d1c7a44f72ef87857a3 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 new file mode 100644 index 0000000000000000000000000000000000000000..67842bea54e5a5fefbd55e38ba2d77003cb03f9a --- /dev/null +++ b/sm501-Replace-hand-written-implementation-with-pixma.patch @@ -0,0 +1,261 @@ +From 2f57a288065de4fffcf182deacd3c75aec90a9ef 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 new file mode 100644 index 0000000000000000000000000000000000000000..9214016bd45894b310b14b616882a3f0e68c9b9f --- /dev/null +++ b/sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch @@ -0,0 +1,134 @@ +From 54c647d867891b58084d6b36ac2db794c19bed22 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 new file mode 100644 index 0000000000000000000000000000000000000000..dbd41270113657aa0231f783fafbca2d64c299b1 --- /dev/null +++ b/sm501-Use-BIT-x-macro-to-shorten-constant.patch @@ -0,0 +1,42 @@ +From a2622f39d8050c86100b40e47b2586d0ebf3b541 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 c45af3e6aa3ba4b5c58583f5605c7a6b9f90e508..cfd1842d3f199ec1db6e324e448df37b4553ea2a 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,21 +1,19 @@ -From e52fdbd850b49304c5bbd5f19c9f518b80efef42 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Wed, 31 Jul 2019 15:40:55 +0800 +From 2b8ad77678da175cb92c902955cb85827e661de3 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 According to smbios 3.0 spec, for processor information (type 4), -it adds three new members (Core Count 2, Core enabled 2, thread count 2) for 3.0, - -Without this three members, we can not get correct cpu frequency from dmi, +it adds three new members (Core Count 2, Core enabled 2, thread count 2) for 3.0, Without this three members, we can not get correct cpu frequency from dmi, Because it will failed to check the length of Processor Infomation in DMI. The corresponding codes in kernel is like: - if (dm->type == DMI_ENTRY_PROCESSOR && - dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { - u16 val = (u16)get_unaligned((const u16 *) - (dmi_data + DMI_PROCESSOR_MAX_SPEED)); - *mhz = val > *mhz ? val : *mhz; - } + if (dm->type == DMI_ENTRY_PROCESSOR && + dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { + u16 val = (u16)get_unaligned((const u16 *) + (dmi_data + DMI_PROCESSOR_MAX_SPEED)); + *mhz = val > *mhz ? val : *mhz; + } Signed-off-by: zhanghailiang --- @@ -24,11 +22,11 @@ Signed-off-by: zhanghailiang 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c -index 47be9071..b11ec6e3 100644 +index 7bcd67b0..51b00d44 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c -@@ -600,7 +600,9 @@ static void smbios_build_type_4_table(unsigned instance) - t->thread_count = smp_threads; +@@ -603,7 +603,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 */ - @@ -39,7 +37,7 @@ index 47be9071..b11ec6e3 100644 smbios_type4_count++; } diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h -index 6fef32a3..70eb7304 100644 +index 02a0ced0..6887bca4 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -193,6 +193,9 @@ struct smbios_type_4 { @@ -50,8 +48,7 @@ index 6fef32a3..70eb7304 100644 + uint16_t enabledcorecount2; + uint16_t threadcount2; } QEMU_PACKED; - - /* SMBIOS type 11 - OEM strings */ --- -2.19.1 + /* SMBIOS type 11 - OEM strings */ +-- +2.23.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..75f86387c9ee1c3a87d128ef963d7880c272e20a --- /dev/null +++ b/softmmu-Always-initialize-xlat-in-address_space_tran.patch @@ -0,0 +1,68 @@ +From f9b1194f6cf3c0b916e01cc6e76f2e6226cf11c5 Mon Sep 17 00:00:00 2001 +From: yinyongkang +Date: Fri, 15 Jul 2022 10:49:38 +0800 +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> +--- + exec.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/exec.c b/exec.c +index 8822c241d8..e785178d73 100644 +--- a/exec.c ++++ b/exec.c +@@ -719,7 +719,7 @@ static void tcg_iommu_free_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) + { +@@ -728,6 +728,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 = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); + + for (;;) { +@@ -771,6 +772,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]; + } + #endif +-- +2.27.0 + diff --git a/spapr_pci-add-spapr-msi-read-method.patch b/spapr_pci-add-spapr-msi-read-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..e187efdb6f2ea9520bfc7e92958bb65e2468c4a7 --- /dev/null +++ b/spapr_pci-add-spapr-msi-read-method.patch @@ -0,0 +1,61 @@ +From 91050bc3c22fbfe88d0cd41e2115f258d7efcc0d 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/sungem-switch-to-use-qemu_receive_packet-for-loopbac.patch b/sungem-switch-to-use-qemu_receive_packet-for-loopbac.patch new file mode 100644 index 0000000000000000000000000000000000000000..eff54c5795a8b065cfb5eb5e8a05467d9053f93f --- /dev/null +++ b/sungem-switch-to-use-qemu_receive_packet-for-loopbac.patch @@ -0,0 +1,43 @@ +From e36764a070b9caccf2ac7502f4656a81e2283823 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 14 May 2021 10:30:23 +0800 +Subject: [PATCH] sungem: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Mark Cave-Ayland +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alistair Francis +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/sungem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/sungem.c b/hw/net/sungem.c +index 89bcf749d1..37b62f62b8 100644 +--- a/hw/net/sungem.c ++++ b/hw/net/sungem.c +@@ -303,7 +303,7 @@ static void sungem_send_packet(SunGEMState *s, const uint8_t *buf, + NetClientState *nc = qemu_get_queue(s->nic); + + if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) { +- nc->info->receive(nc, buf, size); ++ qemu_receive_packet(nc, buf, size); + } else { + qemu_send_packet(nc, buf, size); + } +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..34958f1ed40794675171915d71d038ce29475c18 --- /dev/null +++ b/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch @@ -0,0 +1,90 @@ +From 5d9d03aee0407e27f38ec3e4996c9312d8a81f57 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:58 +0800 +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 +features. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit e39f3e8e4d945a87a936388204b3125041da4032) +--- + target/arm/cpu.c | 27 +++++++++++++++++++++++++++ + target/arm/cpu.h | 2 ++ + target/arm/monitor.c | 2 ++ + 3 files changed, 31 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index db46afba7b..dcf9f49ed3 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -25,6 +25,8 @@ + #include "qemu/module.h" + #include "qapi/error.h" + #include "qapi/visitor.h" ++#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[] = { + }, + }; + ++void arm_cpu_features_to_dict(ARMCPU *cpu, QDict *features) ++{ ++ Object *obj = OBJECT(cpu); ++ const char *name; ++ ObjectProperty *prop; ++ bool is_32bit = !arm_feature(&cpu->env, ARM_FEATURE_AARCH64); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(cpu_features); ++i) { ++ if (is_32bit != cpu_features[i].is_32bit) { ++ continue; ++ } ++ ++ name = cpu_features[i].name; ++ prop = object_property_find(obj, name, NULL); ++ if (prop) { ++ QObject *value; ++ ++ assert(prop->get); ++ value = object_property_get_qobject(obj, name, &error_abort); ++ qdict_put_obj(features, name, value); ++ } ++ } ++} ++ + static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 7bb481fb4d..068c3fa2ad 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) + #define cpu_isar_feature(name, cpu) \ + ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); }) + ++void arm_cpu_features_to_dict(ARMCPU *cpu, QDict *features); ++ + #endif +diff --git a/target/arm/monitor.c b/target/arm/monitor.c +index e2b1d117a4..7c2ff3c06e 100644 +--- a/target/arm/monitor.c ++++ b/target/arm/monitor.c +@@ -219,6 +219,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, + } + } + ++ arm_cpu_features_to_dict(ARM_CPU(obj), qdict_out); ++ + if (!qdict_size(qdict_out)) { + qobject_unref(qdict_out); + } else { +-- +2.23.0 + diff --git a/target-arm-Add-ID_AA64MMFR2_EL1.patch b/target-arm-Add-ID_AA64MMFR2_EL1.patch new file mode 100644 index 0000000000000000000000000000000000000000..f424d7b35606d4e59012fb6e23b33c767355cf98 --- /dev/null +++ b/target-arm-Add-ID_AA64MMFR2_EL1.patch @@ -0,0 +1,89 @@ +From 07dae4b3fdc5ad7c4b24d0e6aa5d3f4025212b3f Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:58:13 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 64761e10af2742a916c08271828890274137b9e8) +Signed-off-by: Peng Liang +--- + 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 fe3108281a..3e65bc50a4 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 b74c23a9bc..c50b1ba1c9 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 4f0bf00070..b794108a06 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.23.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..2dbcde8067c0d5fb5c3e8da1397ee6176a73b96d --- /dev/null +++ b/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch @@ -0,0 +1,168 @@ +From 3602361df4f43e4e5d5dc56e9e767ee93b8176bd Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:04 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 2a609df87d9b886fd38a190a754dbc241ff707e8) +Signed-off-by: Peng Liang +--- + 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 7e9b85a289..bb2edf4e18 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 2d8d27e80a..230130be81 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 afdabbebbf..aa96548f10 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 3f06ca1964..a71f4ef62d 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.23.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..b21440826bf043e4d85b52b082e6e77ff413124a --- /dev/null +++ b/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch @@ -0,0 +1,77 @@ +From 21d5d53e9114c3b4d3d8c888b1c5fdec1667ecc7 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:01 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit ceb2744b47a1ef4184dca56a158eb3156b6eba36) +Signed-off-by: Peng Liang +--- + 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 811e5c6365..dbd05e0113 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 3e65bc50a4..91cc02b43f 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 c50b1ba1c9..419be64037 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.23.0 + diff --git a/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch b/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch new file mode 100644 index 0000000000000000000000000000000000000000..920a36b59afd034e64dfb593a0f1bd20658f4461 --- /dev/null +++ b/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch @@ -0,0 +1,79 @@ +From ee8de09f5b23c067f991f55d4f4ae6a6dc6de11c Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:57:59 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 3d6ad6bb466f487bcc861f99e2c9054230df1076) +Signed-off-by: Peng Liang +--- + target/arm/cpu.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 86eb79cd02..fe3108281a 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.23.0 + diff --git a/target-arm-Add-more-CPU-features.patch b/target-arm-Add-more-CPU-features.patch new file mode 100644 index 0000000000000000000000000000000000000000..550c52cc9ff0406ae2ba45136807f51ec08f8762 --- /dev/null +++ b/target-arm-Add-more-CPU-features.patch @@ -0,0 +1,31 @@ +From f4948980bd6ede3255643982afe01f56c93fec71 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Tue, 11 Aug 2020 10:28:10 +0800 +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 +(cherry-picked from commit 8acf8dd1a20c53453d028a7b86f593019329d8c1) +--- + target/arm/cpu.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index dcf9f49ed3..7ae2d3da56 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1132,6 +1132,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), ++ FIELD_INFO("i8mm", ID_AA64ISAR1, I8MM, false, 1, 0, false), ++ FIELD_INFO("bf16", ID_AA64ISAR1, BF16, false, 1, 0, false), ++ FIELD_INFO("dgh", ID_AA64ISAR1, DGH, false, 1, 0, false), + + FIELD_INFO("cmaintva", ID_MMFR3, CMAINTVA, false, 1, 0, true), + FIELD_INFO("cmaintsw", ID_MMFR3, CMAINTSW, false, 1, 0, true), +-- +2.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..49c7dc63022ec1196b8c225b1c5291fbbe10e1ad --- /dev/null +++ b/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..37a2daab9d82903d4327b9a33460849a21e226ac --- /dev/null +++ b/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch @@ -0,0 +1,161 @@ +From ad9e15e9ea89f29cece5c9f96517ec3c055178d0 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:40 +0800 +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: +1. write to the values of system registers from CPU state to + (index,value) list by write_cpustate_to_list; +2. write the values in (index,value) list to KVM by + write_list_to_kvmstate; + +In step 1, the values of constant system registers are not allowed to +write to (index,value) list. However, a constant system register is +CONSTANT for guest but not for QEMU, which means, QEMU can set/modify +the value of constant system registers that is different from phsical +registers when startup. But if KVM is enabled, guest can not read the +values of the system registers which QEMU set unless they can be written +to (index,value) list. And why not try to write to KVM if kvm_sync is +true? + +At the moment we call write_cpustate_to_list, all ID registers are +contant, including ID_PFR1_EL1 and ID_AA64PFR0_EL1 because GIC has been +initialized. Hence, let's give all ID registers a chance to write to +KVM. If the write is successful, then write to (index,value) list. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit f4e592d1235bbb1290b8bc3684cb57c4304d63dc) +--- + target/arm/helper.c | 31 ++++++++++++++++++++----------- + target/arm/kvm.c | 38 ++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 3 +++ + 3 files changed, 61 insertions(+), 11 deletions(-) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 459af43101..97b6b86197 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -32,6 +32,7 @@ + #include "arm_ldst.h" + #include "exec/cpu_ldst.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) + ok = false; + continue; + } +- if (ri->type & ARM_CP_NO_RAW) { ++ /* ++ * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), ++ * where 1<=crm<8, 0<=op2<8. Let's give ID registers a chance to ++ * synchronize to kvm. ++ */ ++ if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && ++ ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && ri->crm > 0)) { + continue; + } + + newval = read_raw_cp_reg(&cpu->env, ri); + if (kvm_sync) { +- /* +- * Only sync if the previous list->cpustate sync succeeded. +- * Rather than tracking the success/failure state for every +- * item in the list, we just recheck "does the raw write we must +- * have made in write_list_to_cpustate() read back OK" here. +- */ +- uint64_t oldval = cpu->cpreg_values[i]; ++ /* Only sync if we can sync to KVM successfully. */ ++ uint64_t oldval; ++ uint64_t kvmval; + ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { ++ continue; ++ } + if (oldval == newval) { + continue; + } + +- write_raw_cp_reg(&cpu->env, ri, oldval); +- if (read_raw_cp_reg(&cpu->env, ri) != oldval) { ++ if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { ++ continue; ++ } ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || ++ kvmval != newval) { + continue; + } + +- write_raw_cp_reg(&cpu->env, ri, newval); ++ kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); + } + cpu->cpreg_values[i] = newval; + } +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 4f131f687d..229b17cea0 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -457,6 +457,44 @@ out: + return ret; + } + ++int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *target) ++{ ++ uint32_t v32; ++ int ret; ++ ++ switch (regidx & KVM_REG_SIZE_MASK) { ++ case KVM_REG_SIZE_U32: ++ ret = kvm_get_one_reg(CPU(cpu), regidx, &v32); ++ if (ret == 0) { ++ *target = v32; ++ } ++ return ret; ++ case KVM_REG_SIZE_U64: ++ return kvm_get_one_reg(CPU(cpu), regidx, target); ++ default: ++ return -1; ++ } ++} ++ ++int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *source) ++{ ++ uint32_t v32; ++ ++ switch (regidx & KVM_REG_SIZE_MASK) { ++ case KVM_REG_SIZE_U32: ++ v32 = *source; ++ if (v32 != *source) { ++ error_report("the value of source is too large"); ++ return -1; ++ } ++ return kvm_set_one_reg(CPU(cpu), regidx, &v32); ++ case KVM_REG_SIZE_U64: ++ return kvm_set_one_reg(CPU(cpu), regidx, source); ++ default: ++ return -1; ++ } ++} ++ + bool write_kvmstate_to_list(ARMCPU *cpu) + { + CPUState *cs = CPU(cpu); +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 0de5f83ee8..9b7104d622 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) + } + } + ++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.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..ca4b796b58600aa35771d26a247690dfca413cc9 --- /dev/null +++ b/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch @@ -0,0 +1,41 @@ +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-Define-an-aa32_pmu_8_1-isar-feature-test-.patch b/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ba539994ac35ccde104ad6959eb611516da97d6 --- /dev/null +++ b/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch @@ -0,0 +1,249 @@ +From 3c44da3e72185d52af1412516156a180ecb8079e Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:03 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit a617953855b65a602d36364b9643f7e5bc31288e) +Signed-off-by: Peng Liang +--- + 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 9f8f0d3ff5..0741db7b0b 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 6ad211b138..7e9b85a289 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 91cc02b43f..2d8d27e80a 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 15f4ee9215..afdabbebbf 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 419be64037..3f06ca1964 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.23.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..b6796e25b8b04c76a117ad129cb807a0da93da45 --- /dev/null +++ b/target-arm-Don-t-abort-on-M-profile-exception-return.patch @@ -0,0 +1,103 @@ +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-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch b/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch new file mode 100644 index 0000000000000000000000000000000000000000..020c7ea88801d8d6b8c4dd36d8e3483a4fc357c7 --- /dev/null +++ b/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch @@ -0,0 +1,59 @@ +From af3515aafaeea4744ffdd0e6816306db050f1606 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:58:12 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit e0fe7309a7c21ef2386de50d37c86aea0d671c08) +Signed-off-by: Peng Liang +--- + 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 a23c71dbf7..119bd27558 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 7ad8b5e237..a0d07fd78e 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.23.0 + diff --git a/target-arm-Fix-PAuth-sbox-functions.patch b/target-arm-Fix-PAuth-sbox-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac8d05065f766eb8ca90cd00de6a60350c2306c3 --- /dev/null +++ b/target-arm-Fix-PAuth-sbox-functions.patch @@ -0,0 +1,49 @@ +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-write-redundant-values-to-kvm.patch b/target-arm-Fix-write-redundant-values-to-kvm.patch new file mode 100644 index 0000000000000000000000000000000000000000..195554a5cdc07215c2ea31e0fcc76c220667d642 --- /dev/null +++ b/target-arm-Fix-write-redundant-values-to-kvm.patch @@ -0,0 +1,118 @@ +From 02d02b4ff77a03a9b8b4839891d517dd6db31c5d 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 + +After modifying the value of a ID register, we'd better to try to write +it to KVM so that we can known the value is acceptable for KVM. +Because it may modify the registers' values of KVM, it's not suitable +for other registers. + +(cherry-picked from a0d7a9de807639fcfcbe1fe037cb8772d459a9cf) +Signed-off-by: Peng Liang +--- + 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 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -252,6 +252,16 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) + return true; + } + ++static bool is_id_reg(const ARMCPRegInfo *ri) ++{ ++ /* ++ * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), ++ * where 1<=crm<8, 0<=op2<8. ++ */ ++ return ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && ++ ri->crm > 0 && ri->crm < 8; ++} ++ + 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) + ok = false; + continue; + } +- /* +- * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), +- * where 1<=crm<8, 0<=op2<8. Let's give ID registers a chance to +- * synchronize to kvm. +- */ +- if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && +- ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && ri->crm > 0)) { ++ if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && is_id_reg(ri))) { + continue; + } + + newval = read_raw_cp_reg(&cpu->env, ri); + if (kvm_sync) { +- /* Only sync if we can sync to KVM successfully. */ +- uint64_t oldval; +- uint64_t kvmval; ++ if (is_id_reg(ri)) { ++ /* Only sync if we can sync to KVM successfully. */ ++ uint64_t oldval; ++ uint64_t kvmval; + +- if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { +- continue; +- } +- if (oldval == newval) { +- continue; +- } ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { ++ continue; ++ } ++ if (oldval == newval) { ++ continue; ++ } + +- if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { +- continue; +- } +- if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || +- kvmval != newval) { +- continue; +- } ++ if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { ++ continue; ++ } ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || ++ kvmval != newval) { ++ continue; ++ } ++ ++ kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); ++ } else { ++ /* ++ * Only sync if the previous list->cpustate sync succeeded. ++ * Rather than tracking the success/failure state for every ++ * item in the list, we just recheck "does the raw write we must ++ * have made in write_list_to_cpustate() read back OK" here. ++ */ ++ uint64_t oldval = cpu->cpreg_values[i]; ++ ++ if (oldval == newval) { ++ continue; ++ } + +- kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); ++ write_raw_cp_reg(&cpu->env, ri, oldval); ++ if (read_raw_cp_reg(&cpu->env, ri) != oldval) { ++ continue; ++ } ++ ++ write_raw_cp_reg(&cpu->env, ri, newval); ++ } + } + cpu->cpreg_values[i] = newval; + } +-- +2.27.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a46232f8ba04e1e2a956d8493dc1515fcf1f272a --- /dev/null +++ b/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch @@ -0,0 +1,40 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..f742b984332a3ca70479155d5f45a07f1d039553 --- /dev/null +++ b/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch @@ -0,0 +1,160 @@ +From d90d85c86d98a35a6a51e0ef6edb95ca7f6de6ba Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:06 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 4426d3617d64922d97b74ed22e67e33b6fb7de0a) +Signed-off-by: Peng Liang +--- + 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 bb2edf4e18..a23c71dbf7 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 4b1ae32bd2..3040aa4027 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 aa96548f10..7ad8b5e237 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 c1ff4b6bd0..60ff7c0fa1 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 a72d0a6cd1..1d01ecc413 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.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..ec1706a46b42ec829444bcf7db4a57d43d1c6826 --- /dev/null +++ b/target-arm-Read-debug-related-ID-registers-from-KVM.patch @@ -0,0 +1,133 @@ +From 58cd6440c5a50d5ef9cc85c0566486683a8bf0f4 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:07 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 1548a7b2ad621a31b4216ed703b6d658a2ecf0d0) +Signed-off-by: Peng Liang +--- + 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 a78c30c355..56d8cd8ce6 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 2247148e25..e984d52dd2 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 276d146600..2a88b8df37 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.23.0 + diff --git a/target-arm-Stop-assuming-DBGDIDR-always-exists.patch b/target-arm-Stop-assuming-DBGDIDR-always-exists.patch new file mode 100644 index 0000000000000000000000000000000000000000..14efa830fdc6b758df1c7d81dc91fa0cbbfd637b --- /dev/null +++ b/target-arm-Stop-assuming-DBGDIDR-always-exists.patch @@ -0,0 +1,188 @@ +From 1c7e6ebd21275e25e74445521d44d6242e40ff39 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:05 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 88ce6c6ee85d902f59dc65afc3ca86b34f02b9ed) +Signed-off-by: Peng Liang +--- + 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 230130be81..4b1ae32bd2 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 dde80273ff..3f8f667df7 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 a71f4ef62d..c1ff4b6bd0 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 232d963875..a72d0a6cd1 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.23.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..276ddb69ffdefbb193b7fcf9320fc35fc7dd1de3 --- /dev/null +++ b/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch @@ -0,0 +1,455 @@ +From bb4c4e28a538076f384f9735c1d250ab39aacd07 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:13 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 10054016eda1b13bdd8340d100fd029cc8b58f36) +Signed-off-by: Peng Liang +--- + 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 0741db7b0b..f7ef6ad141 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 119bd27558..c3728e3d95 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 3040aa4027..a78c30c355 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 a0d07fd78e..d450b8c8d7 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 60ff7c0fa1..49cd7a7ee4 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 ee1588305d..2247148e25 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 b794108a06..276d146600 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.23.0 + diff --git a/target-arm-Update-ID-fields.patch b/target-arm-Update-ID-fields.patch new file mode 100644 index 0000000000000000000000000000000000000000..233034aa43a097e000b098789a5ec8ae81bd8e14 --- /dev/null +++ b/target-arm-Update-ID-fields.patch @@ -0,0 +1,85 @@ +From e6c94219b9f6a201853b19c8db0b02ef8ee4a9d5 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Tue, 11 Aug 2020 10:18:57 +0800 +Subject: [PATCH] target/arm: Update ID fields + +Update definitions for ID fields, up to ARMv8.6. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit f87ed4385cdadf4af38b76385d2aa581b7ade6c9) +--- + target/arm/cpu.h | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 068c3fa2ad..eb875e112a 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.23.0 + diff --git a/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch b/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch new file mode 100644 index 0000000000000000000000000000000000000000..a86bf0bf9001211a9ef11078688416450aebd63a --- /dev/null +++ b/target-arm-Update-the-ID-registers-of-Kunpeng-920.patch @@ -0,0 +1,58 @@ +From 8e19c7e6d89bb4da69a46934469c7bb74e088524 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 + +The values of some ID registers in Kunpeng-920 are not exactly correct. +Let's update them. The values are read from Kunpeng-920 by calling +read_sysreg_s. + +Signed-off-by: Peng Liang +(cherry-picked from commit b54ca94f19a9b22537712638ae05d2095258eb80) +--- + 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 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -275,10 +275,33 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; +- cpu->isar.regs[ID_AA64PFR0] = 0x11001111; ++ cpu->isar.regs[ID_ISAR0] = 0; ++ cpu->isar.regs[ID_ISAR1] = 0; ++ cpu->isar.regs[ID_ISAR2] = 0; ++ cpu->isar.regs[ID_ISAR3] = 0; ++ cpu->isar.regs[ID_ISAR4] = 0; ++ cpu->isar.regs[ID_ISAR5] = 0; ++ cpu->isar.regs[ID_MMFR0] = 0; ++ cpu->isar.regs[ID_MMFR1] = 0; ++ cpu->isar.regs[ID_MMFR2] = 0; ++ cpu->isar.regs[ID_MMFR3] = 0; ++ cpu->isar.regs[ID_MMFR4] = 0; ++ cpu->isar.regs[MVFR0] = 0; ++ cpu->isar.regs[MVFR1] = 0; ++ cpu->isar.regs[MVFR2] = 0; ++ cpu->isar.regs[ID_DFR0] = 0; ++ 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_AA64PFR0] = 0x0000010011111111; + cpu->isar.regs[ID_AA64DFR0] = 0x110305408; +- cpu->isar.regs[ID_AA64ISAR0] = 0x10211120; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x0001100010211120; ++ cpu->isar.regs[ID_AA64ISAR1] = 0x00011001; + cpu->isar.regs[ID_AA64MMFR0] = 0x101125; ++ cpu->isar.regs[ID_AA64MMFR1] = 0x10211122; ++ cpu->isar.regs[ID_AA64MMFR2] = 0x00001011; + } + + static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, +-- +2.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..149191a6929a1ad45ba65931427bb7a8d08332f7 --- /dev/null +++ b/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch @@ -0,0 +1,38 @@ +From 47338f4586001deb0e8cb04016e091ee7b2a24da Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:02 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit d52c061e541982a3663ad5c65bd3b518dbe85b87) +Signed-off-by: Peng Liang +--- + 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 dbd05e0113..6ad211b138 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.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..a323a3f9af91a7c8b4209dafbbf81f89d1bb09ca --- /dev/null +++ b/target-arm-clear-EL2-and-EL3-only-when-kvm-is-not-en.patch @@ -0,0 +1,43 @@ +From 0004cdfd44cd1aafd7b2142385e67acdd632ad30 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 + +When has_el2 and has_el3 are disabled, which is the default value for +virt machine, QEMU will clear the corresponding field in ID_PFR1_EL1 and +ID_AA64PFR0_EL1 to not expose EL3 and EL2 to guest. Because KVM doesn't +support to emulate ID registers in AArch64 before, it will not take +effect. Hence, clear EL2 and EL3 only when kvm is not enabled for +backwards compatibility. + +Signed-off-by: Peng Liang +(cherry-picked from commit ad6ce039cab07b6a99ccaa36fbb0043ae85a74c9) +--- + 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 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1996,7 +1996,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + } + } + +- if (!cpu->has_el3) { ++ if (!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) + cpu->pmceid1 = 0; + } + +- if (!arm_feature(env, ARM_FEATURE_EL2)) { ++ if (!arm_feature(env, ARM_FEATURE_EL2) && !kvm_enabled()) { + /* Disable the hypervisor feature bits in the processor feature + * registers if we don't have EL2. These are id_pfr1[15:12] and + * id_aa64pfr0_el1[11:8]. +-- +2.23.0 + diff --git a/target-arm-convert-isar-regs-to-array.patch b/target-arm-convert-isar-regs-to-array.patch new file mode 100644 index 0000000000000000000000000000000000000000..d696e9baa04cc14148c248c9fe0097983ceca349 --- /dev/null +++ b/target-arm-convert-isar-regs-to-array.patch @@ -0,0 +1,1909 @@ +From 94bca008d78e1b493657c3947449401ea9e5f12e Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:25 +0800 +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. +So let's change it to an array first and add an enum as the index of the +array for convenience. Since we will never access high 32-bits of ID +registers in AArch32, it's harmless to change the ID registers in +AArch32 to 64-bits. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit 5b5976d6d99a55bdaf0f1596c8b0706366d0df92) +--- + 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(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index f7ef6ad141..5013ec978c 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) + case 0xd44: /* PFR1. */ + return cpu->id_pfr1; + case 0xd48: /* DFR0. */ +- return cpu->isar.id_dfr0; ++ return cpu->isar.regs[ID_DFR0]; + case 0xd4c: /* AFR0. */ + return cpu->id_afr0; + case 0xd50: /* MMFR0. */ +- return cpu->isar.id_mmfr0; ++ return cpu->isar.regs[ID_MMFR0]; + case 0xd54: /* MMFR1. */ +- return cpu->isar.id_mmfr1; ++ return cpu->isar.regs[ID_MMFR1]; + case 0xd58: /* MMFR2. */ +- return cpu->isar.id_mmfr2; ++ return cpu->isar.regs[ID_MMFR2]; + case 0xd5c: /* MMFR3. */ +- return cpu->isar.id_mmfr3; ++ return cpu->isar.regs[ID_MMFR3]; + case 0xd60: /* ISAR0. */ +- return cpu->isar.id_isar0; ++ return cpu->isar.regs[ID_ISAR0]; + case 0xd64: /* ISAR1. */ +- return cpu->isar.id_isar1; ++ return cpu->isar.regs[ID_ISAR1]; + case 0xd68: /* ISAR2. */ +- return cpu->isar.id_isar2; ++ return cpu->isar.regs[ID_ISAR2]; + case 0xd6c: /* ISAR3. */ +- return cpu->isar.id_isar3; ++ return cpu->isar.regs[ID_ISAR3]; + case 0xd70: /* ISAR4. */ +- return cpu->isar.id_isar4; ++ return cpu->isar.regs[ID_ISAR4]; + case 0xd74: /* ISAR5. */ +- 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) + } + return cpu->env.v7m.fpdscr[attrs.secure]; + case 0xf40: /* MVFR0 */ +- return cpu->isar.mvfr0; ++ return cpu->isar.regs[MVFR0]; + case 0xf44: /* MVFR1 */ +- return cpu->isar.mvfr1; ++ return cpu->isar.regs[MVFR1]; + case 0xf48: /* MVFR2 */ +- return cpu->isar.mvfr2; ++ return cpu->isar.regs[MVFR2]; + default: + 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 c3728e3d95..5bcdad0c5e 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -170,9 +170,9 @@ static void arm_cpu_reset(CPUState *s) + g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu); + + env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; +- env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.mvfr0; +- env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1; +- env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.mvfr2; ++ env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.regs[MVFR0]; ++ 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); + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0); +- 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, FP, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- u = cpu->isar.id_isar6; ++ u = cpu->isar.regs[ID_ISAR6]; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0); +- cpu->isar.id_isar6 = u; ++ cpu->isar.regs[ID_ISAR6] = u; + +- u = cpu->isar.mvfr0; ++ 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); +- cpu->isar.mvfr0 = u; ++ cpu->isar.regs[MVFR0] = u; + +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, FPFTZ, 0); + u = FIELD_DP32(u, MVFR1, FPDNAN, 0); + u = FIELD_DP32(u, MVFR1, FPHP, 0); +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; + +- u = cpu->isar.mvfr2; ++ u = cpu->isar.regs[MVFR2]; + u = FIELD_DP32(u, MVFR2, FPMISC, 0); +- cpu->isar.mvfr2 = u; ++ cpu->isar.regs[MVFR2] = u; + } + + if (!cpu->has_neon) { +@@ -1290,56 +1290,56 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_NEON); + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[ID_AA64ISAR0]; + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0); +- 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, FCMA, 0); +- 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, ADVSIMD, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- u = cpu->isar.id_isar5; ++ u = cpu->isar.regs[ID_ISAR5]; + u = FIELD_DP32(u, ID_ISAR5, RDM, 0); + u = FIELD_DP32(u, ID_ISAR5, VCMA, 0); +- 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, DP, 0); + u = FIELD_DP32(u, ID_ISAR6, FHM, 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 (!cpu->has_neon && !cpu->has_vfp) { + uint64_t t; + uint32_t u; + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[ID_AA64ISAR0]; + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0); +- 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, FRINTTS, 0); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- u = cpu->isar.mvfr0; ++ u = cpu->isar.regs[MVFR0]; + u = FIELD_DP32(u, MVFR0, SIMDREG, 0); +- cpu->isar.mvfr0 = u; ++ cpu->isar.regs[MVFR0] = u; + } + + if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) { +@@ -1347,19 +1347,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_THUMB_DSP); + +- u = cpu->isar.id_isar1; ++ u = cpu->isar.regs[ID_ISAR1]; + u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1); +- cpu->isar.id_isar1 = u; ++ cpu->isar.regs[ID_ISAR1] = u; + +- u = cpu->isar.id_isar2; ++ u = cpu->isar.regs[ID_ISAR2]; + u = FIELD_DP32(u, ID_ISAR2, MULTU, 1); + u = FIELD_DP32(u, ID_ISAR2, MULTS, 1); +- cpu->isar.id_isar2 = u; ++ cpu->isar.regs[ID_ISAR2] = u; + +- u = cpu->isar.id_isar3; ++ u = cpu->isar.regs[ID_ISAR3]; + u = FIELD_DP32(u, ID_ISAR3, SIMD, 1); + u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0); +- cpu->isar.id_isar3 = u; ++ cpu->isar.regs[ID_ISAR3] = u; + } + + /* Some features automatically imply others: */ +@@ -1499,7 +1499,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. + */ + cpu->id_pfr1 &= ~0xf0; +- cpu->isar.id_aa64pfr0 &= ~0xf000; ++ cpu->isar.regs[ID_AA64PFR0] &= ~0xf000; + } + + if (!cpu->has_el2) { +@@ -1522,9 +1522,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu); + #endif + } else { +- 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->isar.regs[ID_AA64DFR0] = ++ FIELD_DP64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER, 0); ++ cpu->isar.regs[ID_DFR0] = FIELD_DP32(cpu->isar.regs[ID_DFR0], ID_DFR0, ++ PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; + } +@@ -1534,7 +1535,7 @@ 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.regs[ID_AA64PFR0] &= ~0xf00; + cpu->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. + */ +- 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 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); + + { + /* 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; + } + +@@ -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; + } + +@@ -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; + } + +@@ -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; + } + +@@ -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 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 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; + } +@@ -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 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 56d8cd8ce6..7bb481fb4d 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) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) != 0; + } + + static inline bool isar_feature_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; + } + + static inline bool isar_feature_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; + } + + 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; + } + + 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; + } + + 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 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 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; + } + + 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 inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) + { +- 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_aa32_jscvt(const ARMISARegisters *id) + { +- 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_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_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_sb(const ARMISARegisters *id) + { +- 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_predinv(const ARMISARegisters *id) + { +- 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_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_fp_d32(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; + } + + static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr0, MVFR0, FPSHVEC) > 0; ++ return FIELD_EX64(id->regs[MVFR0], MVFR0, FPSHVEC) > 0; + } + + static inline bool isar_feature_aa32_fpdp(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; + } + + /* +@@ -3465,49 +3471,49 @@ static inline bool isar_feature_aa32_fpdp(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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR3], ID_MMFR3, PAN) != 0; + } + + static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; ++ return FIELD_EX32(id->regs[ID_MMFR3], 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; ++ return FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) >= 4 && ++ FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) != 0xf; + } + + /* +@@ -3515,92 +3521,92 @@ static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) + */ + static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, AES) != 0; + } + + static inline bool isar_feature_aa64_pmull(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) > 1; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, AES) > 1; + } + + static inline bool isar_feature_aa64_sha1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA1) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA1) != 0; + } + + static inline bool isar_feature_aa64_sha256(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA2) != 0; + } + + static inline bool isar_feature_aa64_sha512(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) > 1; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA2) > 1; + } + + static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, CRC32) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, CRC32) != 0; + } + + static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, ATOMIC) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, ATOMIC) != 0; + } + + static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RDM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, RDM) != 0; + } + + static inline bool isar_feature_aa64_sha3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA3) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA3) != 0; + } + + static inline bool isar_feature_aa64_sm3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM3) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SM3) != 0; + } + + static inline bool isar_feature_aa64_sm4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM4) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SM4) != 0; + } + + static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, DP) != 0; + } + + 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) +@@ -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) + + 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_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_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_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_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_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_any_pmu_8_1(const ARMISARegisters *id) +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index d450b8c8d7..fe64875216 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; +- 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->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 */ +@@ -170,31 +170,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->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ 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 */ +@@ -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->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 */ +@@ -275,10 +275,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 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; + +- 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; + + /* + * 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 49cd7a7ee4..459af43101 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], + }; + + /* 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) + static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) + { + ARMCPU *cpu = env_archcpu(env); +- uint64_t pfr0 = cpu->isar.id_aa64pfr0; ++ uint64_t pfr0 = cpu->isar.regs[ID_AA64PFR0]; + + 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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, +- .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, +- .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, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .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, +- .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, +- .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); + } + } +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 1d01ecc413..2da13ba807 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -237,7 +237,7 @@ static inline unsigned int arm_pamax(ARMCPU *cpu) + [5] = 48, + }; + unsigned int parange = +- FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); ++ FIELD_EX64(cpu->isar.regs[ID_AA64MMFR0], ID_AA64MMFR0, PARANGE); + + /* 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) + 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; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, BRPS) + 1; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, BRPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, BRPS) + 1; + } + } + +@@ -879,9 +879,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)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, WRPS) + 1; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, WRPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, WRPS) + 1; + } + } + +@@ -893,9 +893,10 @@ 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; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, CTX_CMPS) + 1; + } + } + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 2a88b8df37..06cf31e809 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); + } + +-static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) ++static int read_sys_reg32(int fd, uint64_t *pret, uint64_t id) + { + 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) + ahcf->target = init.target; + ahcf->dtb_compatible = "arm,arm-v8"; + +- err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, ++ err = read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64PFR0], + 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) + * ??? Either of these sounds like too much effort just + * to work around running a modern host kernel. + */ +- ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */ ++ ahcf->isar.regs[ID_AA64PFR0] = 0x00000011; /* EL1&0, AArch64 only */ + err = 0; + } else { +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64PFR1], + ARM64_SYS_REG(3, 0, 0, 4, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64DFR0], + ARM64_SYS_REG(3, 0, 0, 5, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64DFR1], + ARM64_SYS_REG(3, 0, 0, 5, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ISAR0], + ARM64_SYS_REG(3, 0, 0, 6, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ISAR1], + ARM64_SYS_REG(3, 0, 0, 6, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR0], + ARM64_SYS_REG(3, 0, 0, 7, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR1], + ARM64_SYS_REG(3, 0, 0, 7, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR2], + ARM64_SYS_REG(3, 0, 0, 7, 2)); + + /* +@@ -555,38 +555,38 @@ 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, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_DFR0], + ARM64_SYS_REG(3, 0, 0, 1, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR0], + ARM64_SYS_REG(3, 0, 0, 1, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR1], + ARM64_SYS_REG(3, 0, 0, 1, 5)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR2], + ARM64_SYS_REG(3, 0, 0, 1, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR3], + ARM64_SYS_REG(3, 0, 0, 1, 7)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR0], + ARM64_SYS_REG(3, 0, 0, 2, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR1], + ARM64_SYS_REG(3, 0, 0, 2, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR2], + ARM64_SYS_REG(3, 0, 0, 2, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR3], + ARM64_SYS_REG(3, 0, 0, 2, 3)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR4], + ARM64_SYS_REG(3, 0, 0, 2, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR5], + ARM64_SYS_REG(3, 0, 0, 2, 5)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR4], + ARM64_SYS_REG(3, 0, 0, 2, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR6], + ARM64_SYS_REG(3, 0, 0, 2, 7)); + +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR0], + ARM64_SYS_REG(3, 0, 0, 3, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR1], + ARM64_SYS_REG(3, 0, 0, 3, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR2], + ARM64_SYS_REG(3, 0, 0, 3, 2)); + + /* +@@ -599,14 +599,16 @@ 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. + */ +- 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); ++ 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 ctx_cmps = +- FIELD_EX64(ahcf->isar.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); ++ !!FIELD_EX32(ahcf->isar.regs[ID_AA64PFR0], ID_AA64PFR0, EL3); + uint32_t dbgdidr = 0; + + dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); +@@ -616,7 +618,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 */ +- ahcf->isar.dbgdidr = dbgdidr; ++ ahcf->isar.regs[DBGDIDR] = dbgdidr; + } + } + +-- +2.23.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 new file mode 100644 index 0000000000000000000000000000000000000000..41c67cf1b8024af9f48888ecd782e9927a2f166e --- /dev/null +++ b/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch @@ -0,0 +1,152 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..060d511ae1cad2bf14aa6d2d6f7608ac30374709 --- /dev/null +++ b/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch @@ -0,0 +1,67 @@ +From 5cd3062c5aed4b15d0df1af4e606b4e5ddbc78f7 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 + +evtstrm and cpuid cann't be controlled by VMM: +1. evtstrm: The generic timer is configured to generate events at a + frequency of approximately 100KHz. It's controlled by the linux + kernel config CONFIG_ARM_ARCH_TIMER_EVTSTREAM. +2. cpuid: EL0 access to certain ID registers is available. It's always + set by linux kernel after 77c97b4ee2129 ("arm64: cpufeature: Expose + CPUID registers by emulation"). +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 +(cherry-picked from commit 02f8ee8f420e62aff233748c7e848a1c1197b741) +--- + 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 7de208488c..726d123d8e 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, + } + } + ++static const char *unconfigurable_feats[] = { ++ "evtstrm", ++ "cpuid", ++ NULL ++}; ++ ++static bool is_configurable_feat(const char *name) ++{ ++ int i; ++ ++ for (i = 0; unconfigurable_feats[i]; ++i) { ++ if (g_strcmp0(unconfigurable_feats[i], name) == 0) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static void + cpu_add_feat_as_prop(const char *typename, const char *name, const char *val) + { +- GlobalProperty *prop = g_new0(typeof(*prop), 1); ++ GlobalProperty *prop; ++ ++ if (!is_configurable_feat(name)) { ++ info_report("CPU feature '%s' is not configurable by QEMU. Ignore it.", ++ name); ++ return; ++ } ++ ++ prop = g_new0(typeof(*prop), 1); + prop->driver = typename; + prop->property = g_strdup(name); + prop->value = g_strdup(val); +-- +2.23.0 + diff --git a/target-arm-introduce-CPU-feature-dependency-mechanis.patch b/target-arm-introduce-CPU-feature-dependency-mechanis.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b4752a62a457c80fadaa0d737998b71c64ba712 --- /dev/null +++ b/target-arm-introduce-CPU-feature-dependency-mechanis.patch @@ -0,0 +1,185 @@ +From f52bdbd22a9c0ab7e0cd602988fb2e0780e74766 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:46 +0800 +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 +value, which means FP and ADVSIMD are dependent on each other, FPHP and +ADVSIMDHP are dependent on each other. + +This commit introduces a mechanism for CPU feature dependency in +AArch64. We build a directed graph from the CPU feature dependency +relationship, each edge from->to means the `to` CPU feature is dependent +on the `from` CPU feature. And we will automatically enable/disable CPU +feature according to the directed graph. + +For example, a, b, and c CPU features are in relationship a->b->c, which +means c is dependent on b and b is dependent on a. If c is enabled by +user, then a and b is enabled automatically. And if a is disabled by +user, then b and c is disabled automatically. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit 9a16d2b2389664aa50e63c33af0ea94afb45185b) +--- + target/arm/cpu.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 129 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 3f63312c85..d55765386b 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1306,6 +1306,103 @@ static struct CPUFeatureInfo cpu_features[] = { + }, + }; + ++typedef struct CPUFeatureDep { ++ CPUFeatureInfo from, to; ++} CPUFeatureDep; ++ ++static const CPUFeatureDep feature_dependencies[] = { ++ { ++ .from = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ .to = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ }, ++ { ++ .from = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ .to = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ }, ++ { ++ .from = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ .to = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ .to = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ }, ++ { ++ ++ .from = FIELD_INFO("aes", ID_AA64ISAR0, AES, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_AES_LENGTH, ++ .shift = R_ID_AA64ISAR0_AES_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "pmull", .is_32bit = false, ++ }, ++ }, ++ { ++ ++ .from = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = FIELD_INFO("lrcpc", ID_AA64ISAR1, LRCPC, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_LRCPC_LENGTH, ++ .shift = R_ID_AA64ISAR1_LRCPC_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "ilrcpc", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ .to = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ .to = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ .to = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ }, ++}; ++ + 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, + } + + if (value) { ++ if (object_property_get_bool(obj, feat->name, NULL)) { ++ return; ++ } + isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], + feat->shift, feat->length, + feat->min_value); ++ /* Auto enable the features which current feature is dependent on. */ ++ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) { ++ const CPUFeatureDep *d = &feature_dependencies[i]; ++ if (strcmp(d->to.name, feat->name) != 0) { ++ continue; ++ } ++ ++ object_property_set_bool(obj, true, d->from.name, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } + } else { ++ if (!object_property_get_bool(obj, feat->name, NULL)) { ++ return; ++ } + isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], + feat->shift, feat->length, + feat->ni_value); ++ /* Auto disable the features which are dependent on current feature. */ ++ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) { ++ const CPUFeatureDep *d = &feature_dependencies[i]; ++ if (strcmp(d->from.name, feat->name) != 0) { ++ continue; ++ } ++ ++ object_property_set_bool(obj, false, d->to.name, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } + } + } + +-- +2.23.0 + diff --git a/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch new file mode 100644 index 0000000000000000000000000000000000000000..17f6e1fefa65b392b73a310cba8937a24c5208bd --- /dev/null +++ b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch @@ -0,0 +1,93 @@ +From b1fc3b2b4e4d846f00fa4baa1e298323d173821c Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:55 +0800 +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 +(cherry-picked from commit e55671b1d033f8815316407e0274fd85f48bc4df) +--- + linux-headers/linux/kvm.h | 2 ++ + target/arm/cpu.c | 5 +++++ + target/arm/kvm64.c | 14 ++++++++++++++ + target/arm/kvm_arm.h | 7 +++++++ + 4 files changed, 28 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 744e888e68..4844edc3a3 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 + ++#define KVM_CAP_ARM_CPU_FEATURE 555 ++ + #ifdef KVM_CAP_IRQ_ROUTING + + struct kvm_irq_routing_irqchip { +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index d55765386b..db46afba7b 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, + Error *local_err = NULL; + bool value; + ++ if (!kvm_arm_cpu_feature_supported()) { ++ warn_report("KVM doesn't support to set CPU feature in arm. " ++ "Setting to `%s` is ignored.", name); ++ return; ++ } + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 06cf31e809..05345556dd 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; + } + ++bool kvm_arm_cpu_feature_supported(void) ++{ ++ static bool cpu_feature_initialized; ++ static bool cpu_feature_supported; ++ ++ if (!cpu_feature_initialized) { ++ cpu_feature_supported = kvm_check_extension(kvm_state, ++ KVM_CAP_ARM_CPU_FEATURE); ++ cpu_feature_initialized = true; ++ } ++ ++ return cpu_feature_supported; ++} ++ + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 + + int kvm_arch_init_vcpu(CPUState *cs) +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 9b7104d622..49e80878f4 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); + */ + void kvm_arm_add_vcpu_properties(Object *obj); + ++/** ++ * kvm_arm_cpu_feature_supported: ++ * ++ * Returns true if KVM can set CPU features and false otherwise. ++ */ ++bool kvm_arm_cpu_feature_supported(void); ++ + /** + * kvm_arm_get_max_vm_ipa_size: + * @ms: Machine state handle +-- +2.23.0 + diff --git a/target-arm-kvm-Implement-virtual-time-adjustment.patch b/target-arm-kvm-Implement-virtual-time-adjustment.patch new file mode 100644 index 0000000000000000000000000000000000000000..86450c4d8f1739527a7065ec9242706605487b0e --- /dev/null +++ b/target-arm-kvm-Implement-virtual-time-adjustment.patch @@ -0,0 +1,290 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..8c28c63b1e9fa89ace5860f635f07e2d9b221bbe --- /dev/null +++ b/target-arm-kvm-trivial-Clean-up-header-documentation.patch @@ -0,0 +1,144 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..b8cec1bd36e2da9526a643229252ac6760eebecf --- /dev/null +++ b/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..987391c37e03f78c6db595c4cd7f220a03434f78 --- /dev/null +++ b/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch @@ -0,0 +1,374 @@ +From b98d65859769aa68deb34cb590aba35d8854ec07 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Thu, 31 Oct 2019 15:27:26 +0100 +Subject: [PATCH] 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 +(cherry-picked from commit e19afd5667819d74ab25d1a1171efe7b5002c6ee) +Signed-off-by: Peng Liang +--- + 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 0000000000..c79dcffb55 +--- /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 55310a6aa2..0462322472 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 6ec6dd04ac..560970de7f 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.23.0 + diff --git a/target-arm-monitor-query-cpu-model-expansion-crashed.patch b/target-arm-monitor-query-cpu-model-expansion-crashed.patch new file mode 100644 index 0000000000000000000000000000000000000000..5271190129fe04d2455c313a2af287c0a7d83f84 --- /dev/null +++ b/target-arm-monitor-query-cpu-model-expansion-crashed.patch @@ -0,0 +1,61 @@ +From ea20aeab55e8ec61cb9500d5a44d82a9f95e41b3 Mon Sep 17 00:00:00 2001 +From: Liang Yan +Date: Fri, 7 Feb 2020 14:04:21 +0000 +Subject: [PATCH] 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 +(cherry-picked from commit 0999a4ba8718aa96105b978d3567fc7e90244c7e) +Signed-off-by: Peng Liang +--- + 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 560970de7f..e2b1d117a4 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.23.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..18ae17021e8ac2fa396c4ed94234f0ebaa89afaf --- /dev/null +++ b/target-arm-only-set-ID_PFR1_EL1.GIC-for-AArch32-gues.patch @@ -0,0 +1,32 @@ +From 3f12c87017c6e052fc769a1b49278ca6bcce7a96 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 + +Some AArch64 CPU doesn't support AArch32 mode, and the values of AArch32 +registers are all 0. Hence, We'd better not to modify AArch32 registers +in AArch64 mode. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit 88e3146118230de8b99280db219a6a6c47bebce1) +--- + 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 +--- 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) + ARMCPU *cpu = env_archcpu(env); + uint64_t pfr1 = cpu->id_pfr1; + +- if (env->gicv3state) { ++ if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && env->gicv3state) { + pfr1 |= 1 << 28; + } + return pfr1; +-- +2.23.0 + diff --git a/target-arm-parse-cpu-feature-related-options.patch b/target-arm-parse-cpu-feature-related-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..b215a9c76baa7bbb9c01ffd681994cdce8138393 --- /dev/null +++ b/target-arm-parse-cpu-feature-related-options.patch @@ -0,0 +1,125 @@ +From 01dc5cdc6f8664601577c48d8d8b90775e2bb6d5 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:35 +0800 +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 +CPU feature string in "+feature/-feature" format. Hence, we need to +override CPUClass::parse_features to support CPU feature string in both +"feature=value" and "+feature/-feature" format. + +The logic of AArch64CPUClass::parse_features is similar to that of +X86CPUClass::parse_features. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit d7d6c711c44f18d34c7d5e730dd66da3664e02d5) +--- + target/arm/cpu64.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 83 insertions(+) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index fe64875216..7de208488c 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, + } + } + ++static void ++cpu_add_feat_as_prop(const char *typename, const char *name, const char *val) ++{ ++ GlobalProperty *prop = g_new0(typeof(*prop), 1); ++ prop->driver = typename; ++ prop->property = g_strdup(name); ++ prop->value = g_strdup(val); ++ qdev_prop_register_global(prop); ++} ++ ++static gint compare_string(gconstpointer a, gconstpointer b) ++{ ++ return g_strcmp0(a, b); ++} ++ ++static GList *plus_features, *minus_features; ++ ++static void aarch64_cpu_parse_features(const char *typename, char *features, ++ Error **errp) ++{ ++ GList *l; ++ char *featurestr; /* Single 'key=value" string being parsed */ ++ static bool cpu_globals_initialized; ++ ++ if (cpu_globals_initialized) { ++ return; ++ } ++ cpu_globals_initialized = true; ++ ++ if (!features) { ++ return; ++ } ++ for (featurestr = strtok(features, ","); ++ featurestr; ++ featurestr = strtok(NULL, ",")) { ++ const char *name; ++ const char *val = NULL; ++ char *eq = NULL; ++ ++ /* Compatibility syntax: */ ++ if (featurestr[0] == '+') { ++ plus_features = g_list_append(plus_features, ++ g_strdup(featurestr + 1)); ++ continue; ++ } else if (featurestr[0] == '-') { ++ minus_features = g_list_append(minus_features, ++ g_strdup(featurestr + 1)); ++ continue; ++ } ++ ++ eq = strchr(featurestr, '='); ++ name = featurestr; ++ if (eq) { ++ *eq++ = 0; ++ val = eq; ++ } else { ++ error_setg(errp, "Unsupported property format: %s", name); ++ return; ++ } ++ ++ if (g_list_find_custom(plus_features, name, compare_string)) { ++ warn_report("Ambiguous CPU model string. " ++ "Don't mix both \"+%s\" and \"%s=%s\"", ++ name, name, val); ++ } ++ if (g_list_find_custom(minus_features, name, compare_string)) { ++ warn_report("Ambiguous CPU model string. " ++ "Don't mix both \"-%s\" and \"%s=%s\"", ++ name, name, val); ++ } ++ cpu_add_feat_as_prop(typename, name, val); ++ } ++ ++ for (l = plus_features; l; l = l->next) { ++ cpu_add_feat_as_prop(typename, l->data, "on"); ++ } ++ ++ for (l = minus_features; l; l = l->next) { ++ cpu_add_feat_as_prop(typename, l->data, "off"); ++ } ++} ++ + 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) + 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) +-- +2.23.0 + diff --git a/target-arm-register-CPU-features-for-property.patch b/target-arm-register-CPU-features-for-property.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab2141989cf630661fa2099973fc5a1d1f5c4219 --- /dev/null +++ b/target-arm-register-CPU-features-for-property.patch @@ -0,0 +1,399 @@ +From eea75b5ba8bcfe97521306c6183708cd9596270b Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:37 +0800 +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 +identifies the presence, and possibly the level of support for, a +particular feature in an implementation of the architecture. [1] + +For most of the ID fields, there is a minimum presence value, equal to +or higher than which means the corresponding CPU feature is implemented. +Hence, we can use the minimum presence value to determine whether a CPU +feature is enabled and enable a CPU feature. + +To disable a CPU feature, setting the corresponding ID field to 0x0/0xf +(for unsigned/signed field) seems as a good idea. However, it maybe +lead to some problems. For example, ID_AA64PFR0_EL1.FP is a signed ID +field. ID_AA64PFR0_EL1.FP == 0x0 represents the implementation of FP +(floating-point) and ID_AA64PFR0_EL1.FP == 0x1 represents the +implementation of FPHP (half-precision floating-point). If +ID_AA64PFR0_EL1.FP is set to 0xf when FPHP is disabled (which is also +disable FP), guest kernel maybe stuck. Hence, we add a ni_value (means +not-implemented value) to disable a CPU feature safely. + +[1] D13.1.3 Principles of the ID scheme for fields in ID registers in + DDI.0487 + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +(cherry-picked from commit 234f15e02b3b6e7195cc2cba0de3b7053dc9da09) +--- + target/arm/cpu.c | 343 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 343 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 5bcdad0c5e..3f63312c85 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); + } + ++/** ++ * CPUFeatureInfo: ++ * @reg: The ID register where the ID field is in. ++ * @name: The name of the CPU feature. ++ * @length: The bit length of the ID field. ++ * @shift: The bit shift of the ID field in the ID register. ++ * @min_value: The minimum value equal to or larger than which means the CPU ++ * feature is implemented. ++ * @ni_value: Not-implemented value. It will be set to the ID field when ++ * disabling the CPU feature. Usually, it's min_value - 1. ++ * @sign: Whether the ID field is signed. ++ * @is_32bit: Whether the CPU feature is for 32-bit. ++ * ++ * In ARM, a CPU feature is described by an ID field, which is a 4-bit field in ++ * an ID register. ++ */ ++typedef struct CPUFeatureInfo { ++ CPUIDReg reg; ++ const char *name; ++ int length; ++ int shift; ++ int min_value; ++ int ni_value; ++ bool sign; ++ bool is_32bit; ++} CPUFeatureInfo; ++ ++#define FIELD_INFO(feature_name, id_reg, field, s, min_val, ni_val, is32bit) { \ ++ .reg = id_reg, \ ++ .length = R_ ## id_reg ## _ ## field ## _LENGTH, \ ++ .shift = R_ ## id_reg ## _ ## field ## _SHIFT, \ ++ .sign = s, \ ++ .min_value = min_val, \ ++ .ni_value = ni_val, \ ++ .name = feature_name, \ ++ .is_32bit = is32bit, \ ++} ++ ++static struct CPUFeatureInfo cpu_features[] = { ++ FIELD_INFO("swap", ID_ISAR0, SWAP, false, 1, 0, true), ++ FIELD_INFO("bitcount", ID_ISAR0, BITCOUNT, false, 1, 0, true), ++ FIELD_INFO("bitfield", ID_ISAR0, BITFIELD, false, 1, 0, true), ++ FIELD_INFO("cmpbranch", ID_ISAR0, CMPBRANCH, false, 1, 0, true), ++ FIELD_INFO("coproc", ID_ISAR0, COPROC, false, 1, 0, true), ++ FIELD_INFO("debug", ID_ISAR0, DEBUG, false, 1, 0, true), ++ FIELD_INFO("device", ID_ISAR0, DIVIDE, false, 1, 0, true), ++ ++ FIELD_INFO("endian", ID_ISAR1, ENDIAN, false, 1, 0, true), ++ FIELD_INFO("except", ID_ISAR1, EXCEPT, false, 1, 0, true), ++ FIELD_INFO("except_ar", ID_ISAR1, EXCEPT_AR, false, 1, 0, true), ++ FIELD_INFO("extend", ID_ISAR1, EXTEND, false, 1, 0, true), ++ FIELD_INFO("ifthen", ID_ISAR1, IFTHEN, false, 1, 0, true), ++ FIELD_INFO("immediate", ID_ISAR1, IMMEDIATE, false, 1, 0, true), ++ FIELD_INFO("interwork", ID_ISAR1, INTERWORK, false, 1, 0, true), ++ FIELD_INFO("jazelle", ID_ISAR1, JAZELLE, false, 1, 0, true), ++ ++ FIELD_INFO("loadstore", ID_ISAR2, LOADSTORE, false, 1, 0, true), ++ FIELD_INFO("memhint", ID_ISAR2, MEMHINT, false, 1, 0, true), ++ FIELD_INFO("multiaccessint", ID_ISAR2, MULTIACCESSINT, false, 1, 0, true), ++ FIELD_INFO("mult", ID_ISAR2, MULT, false, 1, 0, true), ++ FIELD_INFO("mults", ID_ISAR2, MULTS, false, 1, 0, true), ++ FIELD_INFO("multu", ID_ISAR2, MULTU, false, 1, 0, true), ++ FIELD_INFO("psr_ar", ID_ISAR2, PSR_AR, false, 1, 0, true), ++ FIELD_INFO("reversal", ID_ISAR2, REVERSAL, false, 1, 0, true), ++ ++ FIELD_INFO("saturate", ID_ISAR3, SATURATE, false, 1, 0, true), ++ FIELD_INFO("simd", ID_ISAR3, SIMD, false, 1, 0, true), ++ FIELD_INFO("svc", ID_ISAR3, SVC, false, 1, 0, true), ++ FIELD_INFO("synchprim", ID_ISAR3, SYNCHPRIM, false, 1, 0, true), ++ FIELD_INFO("tabbranch", ID_ISAR3, TABBRANCH, false, 1, 0, true), ++ FIELD_INFO("t32copy", ID_ISAR3, T32COPY, false, 1, 0, true), ++ FIELD_INFO("truenop", ID_ISAR3, TRUENOP, false, 1, 0, true), ++ FIELD_INFO("t32ee", ID_ISAR3, T32EE, false, 1, 0, true), ++ ++ FIELD_INFO("unpriv", ID_ISAR4, UNPRIV, false, 1, 0, true), ++ FIELD_INFO("withshifts", ID_ISAR4, WITHSHIFTS, false, 1, 0, true), ++ FIELD_INFO("writeback", ID_ISAR4, WRITEBACK, false, 1, 0, true), ++ FIELD_INFO("smc", ID_ISAR4, SMC, false, 1, 0, true), ++ FIELD_INFO("barrier", ID_ISAR4, BARRIER, false, 1, 0, true), ++ FIELD_INFO("synchprim_frac", ID_ISAR4, SYNCHPRIM_FRAC, false, 1, 0, true), ++ FIELD_INFO("psr_m", ID_ISAR4, PSR_M, false, 1, 0, true), ++ FIELD_INFO("swp_frac", ID_ISAR4, SWP_FRAC, false, 1, 0, true), ++ ++ FIELD_INFO("sevl", ID_ISAR5, SEVL, false, 1, 0, true), ++ FIELD_INFO("aes", ID_ISAR5, AES, false, 1, 0, true), ++ FIELD_INFO("sha1", ID_ISAR5, SHA1, false, 1, 0, true), ++ FIELD_INFO("sha2", ID_ISAR5, SHA2, false, 1, 0, true), ++ FIELD_INFO("crc32", ID_ISAR5, CRC32, false, 1, 0, true), ++ FIELD_INFO("rdm", ID_ISAR5, RDM, false, 1, 0, true), ++ FIELD_INFO("vcma", ID_ISAR5, VCMA, false, 1, 0, true), ++ ++ FIELD_INFO("jscvt", ID_ISAR6, JSCVT, false, 1, 0, true), ++ FIELD_INFO("dp", ID_ISAR6, DP, false, 1, 0, true), ++ 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), ++ ++ FIELD_INFO("cmaintva", ID_MMFR3, CMAINTVA, false, 1, 0, true), ++ FIELD_INFO("cmaintsw", ID_MMFR3, CMAINTSW, false, 1, 0, true), ++ FIELD_INFO("bpmaint", ID_MMFR3, BPMAINT, false, 1, 0, true), ++ FIELD_INFO("maintbcst", ID_MMFR3, MAINTBCST, false, 1, 0, true), ++ FIELD_INFO("pan", ID_MMFR3, PAN, false, 1, 0, true), ++ FIELD_INFO("cohwalk", ID_MMFR3, COHWALK, false, 1, 0, true), ++ FIELD_INFO("cmemsz", ID_MMFR3, CMEMSZ, false, 1, 0, true), ++ FIELD_INFO("supersec", ID_MMFR3, SUPERSEC, false, 1, 0, true), ++ ++ FIELD_INFO("specsei", ID_MMFR4, SPECSEI, false, 1, 0, true), ++ FIELD_INFO("ac2", ID_MMFR4, AC2, false, 1, 0, true), ++ FIELD_INFO("xnx", ID_MMFR4, XNX, false, 1, 0, true), ++ FIELD_INFO("cnp", ID_MMFR4, CNP, false, 1, 0, true), ++ FIELD_INFO("hpds", ID_MMFR4, HPDS, false, 1, 0, true), ++ FIELD_INFO("lsm", ID_MMFR4, LSM, false, 1, 0, true), ++ FIELD_INFO("ccidx", ID_MMFR4, CCIDX, false, 1, 0, true), ++ FIELD_INFO("evt", ID_MMFR4, EVT, false, 1, 0, true), ++ ++ FIELD_INFO("simdreg", MVFR0, SIMDREG, false, 1, 0, true), ++ FIELD_INFO("fpsp", MVFR0, FPSP, false, 1, 0, true), ++ FIELD_INFO("fpdp", MVFR0, FPDP, false, 1, 0, true), ++ FIELD_INFO("fptrap", MVFR0, FPTRAP, false, 1, 0, true), ++ FIELD_INFO("fpdivide", MVFR0, FPDIVIDE, false, 1, 0, true), ++ FIELD_INFO("fpsqrt", MVFR0, FPSQRT, false, 1, 0, true), ++ FIELD_INFO("fpshvec", MVFR0, FPSHVEC, false, 1, 0, true), ++ FIELD_INFO("fpround", MVFR0, FPROUND, false, 1, 0, true), ++ ++ FIELD_INFO("fpftz", MVFR1, FPFTZ, false, 1, 0, true), ++ FIELD_INFO("fpdnan", MVFR1, FPDNAN, false, 1, 0, true), ++ FIELD_INFO("simdls", MVFR1, SIMDLS, false, 1, 0, true), ++ FIELD_INFO("simdint", MVFR1, SIMDINT, false, 1, 0, true), ++ FIELD_INFO("simdsp", MVFR1, SIMDSP, false, 1, 0, true), ++ FIELD_INFO("simdhp", MVFR1, SIMDHP, false, 1, 0, true), ++ FIELD_INFO("fphp", MVFR1, FPHP, false, 1, 0, true), ++ FIELD_INFO("simdfmac", MVFR1, SIMDFMAC, false, 1, 0, true), ++ ++ FIELD_INFO("simdmisc", MVFR2, SIMDMISC, false, 1, 0, true), ++ FIELD_INFO("fpmisc", MVFR2, FPMISC, false, 1, 0, true), ++ ++ FIELD_INFO("debugver", ID_AA64DFR0, DEBUGVER, false, 1, 0, false), ++ FIELD_INFO("tracever", ID_AA64DFR0, TRACEVER, false, 1, 0, false), ++ FIELD_INFO("pmuver", ID_AA64DFR0, PMUVER, false, 1, 0, false), ++ FIELD_INFO("brps", ID_AA64DFR0, BRPS, false, 1, 0, false), ++ FIELD_INFO("wrps", ID_AA64DFR0, WRPS, false, 1, 0, false), ++ FIELD_INFO("ctx_cmps", ID_AA64DFR0, CTX_CMPS, false, 1, 0, false), ++ FIELD_INFO("pmsver", ID_AA64DFR0, PMSVER, false, 1, 0, false), ++ FIELD_INFO("doublelock", ID_AA64DFR0, DOUBLELOCK, false, 1, 0, false), ++ FIELD_INFO("tracefilt", ID_AA64DFR0, TRACEFILT, false, 1, 0, false), ++ ++ FIELD_INFO("aes", ID_AA64ISAR0, AES, false, 1, 0, false), ++ FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ FIELD_INFO("crc32", ID_AA64ISAR0, CRC32, false, 1, 0, false), ++ FIELD_INFO("atomics", ID_AA64ISAR0, ATOMIC, false, 1, 0, false), ++ FIELD_INFO("asimdrdm", ID_AA64ISAR0, RDM, false, 1, 0, false), ++ FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ FIELD_INFO("asimddp", ID_AA64ISAR0, DP, false, 1, 0, false), ++ FIELD_INFO("asimdfhm", ID_AA64ISAR0, FHM, false, 1, 0, false), ++ FIELD_INFO("flagm", ID_AA64ISAR0, TS, false, 1, 0, false), ++ FIELD_INFO("tlb", ID_AA64ISAR0, TLB, false, 1, 0, false), ++ FIELD_INFO("rng", ID_AA64ISAR0, RNDR, false, 1, 0, false), ++ ++ FIELD_INFO("dcpop", ID_AA64ISAR1, DPB, false, 1, 0, false), ++ FIELD_INFO("papa", ID_AA64ISAR1, APA, false, 1, 0, false), ++ FIELD_INFO("api", ID_AA64ISAR1, API, false, 1, 0, false), ++ FIELD_INFO("jscvt", ID_AA64ISAR1, JSCVT, false, 1, 0, false), ++ FIELD_INFO("fcma", ID_AA64ISAR1, FCMA, false, 1, 0, false), ++ FIELD_INFO("lrcpc", ID_AA64ISAR1, LRCPC, false, 1, 0, false), ++ FIELD_INFO("pacg", ID_AA64ISAR1, GPA, false, 1, 0, false), ++ FIELD_INFO("gpi", ID_AA64ISAR1, GPI, false, 1, 0, false), ++ FIELD_INFO("frint", ID_AA64ISAR1, FRINTTS, false, 1, 0, false), ++ FIELD_INFO("sb", ID_AA64ISAR1, SB, false, 1, 0, false), ++ FIELD_INFO("specres", ID_AA64ISAR1, SPECRES, false, 1, 0, false), ++ ++ FIELD_INFO("el0", ID_AA64PFR0, EL0, false, 1, 0, false), ++ FIELD_INFO("el1", ID_AA64PFR0, EL1, false, 1, 0, false), ++ FIELD_INFO("el2", ID_AA64PFR0, EL2, false, 1, 0, false), ++ FIELD_INFO("el3", ID_AA64PFR0, EL3, false, 1, 0, false), ++ FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ FIELD_INFO("gic", ID_AA64PFR0, GIC, false, 1, 0, false), ++ FIELD_INFO("ras", ID_AA64PFR0, RAS, false, 1, 0, false), ++ 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("mte", ID_AA64PFR1, MTE, false, 1, 0, false), ++ FIELD_INFO("ras_frac", ID_AA64PFR1, RAS_FRAC, false, 1, 0, false), ++ ++ FIELD_INFO("parange", ID_AA64MMFR0, PARANGE, false, 1, 0, false), ++ FIELD_INFO("asidbits", ID_AA64MMFR0, ASIDBITS, false, 1, 0, false), ++ FIELD_INFO("bigend", ID_AA64MMFR0, BIGEND, false, 1, 0, false), ++ FIELD_INFO("snsmem", ID_AA64MMFR0, SNSMEM, false, 1, 0, false), ++ FIELD_INFO("bigendel0", ID_AA64MMFR0, BIGENDEL0, false, 1, 0, false), ++ FIELD_INFO("tgran16", ID_AA64MMFR0, TGRAN16, false, 1, 0, false), ++ FIELD_INFO("tgran64", ID_AA64MMFR0, TGRAN64, false, 1, 0, false), ++ FIELD_INFO("tgran4", ID_AA64MMFR0, TGRAN4, false, 1, 0, false), ++ FIELD_INFO("tgran16_2", ID_AA64MMFR0, TGRAN16_2, false, 1, 0, false), ++ FIELD_INFO("tgran64_2", ID_AA64MMFR0, TGRAN64_2, false, 1, 0, false), ++ FIELD_INFO("tgran4_2", ID_AA64MMFR0, TGRAN4_2, false, 1, 0, false), ++ FIELD_INFO("exs", ID_AA64MMFR0, EXS, false, 1, 0, false), ++ ++ FIELD_INFO("hafdbs", ID_AA64MMFR1, HAFDBS, false, 1, 0, false), ++ FIELD_INFO("vmidbits", ID_AA64MMFR1, VMIDBITS, false, 1, 0, false), ++ FIELD_INFO("vh", ID_AA64MMFR1, VH, false, 1, 0, false), ++ FIELD_INFO("hpds", ID_AA64MMFR1, HPDS, false, 1, 0, false), ++ FIELD_INFO("lo", ID_AA64MMFR1, LO, false, 1, 0, false), ++ FIELD_INFO("pan", ID_AA64MMFR1, PAN, false, 1, 0, false), ++ FIELD_INFO("specsei", ID_AA64MMFR1, SPECSEI, false, 1, 0, false), ++ FIELD_INFO("xnx", ID_AA64MMFR1, XNX, false, 1, 0, false), ++ ++ FIELD_INFO("cnp", ID_AA64MMFR2, CNP, false, 1, 0, false), ++ FIELD_INFO("uao", ID_AA64MMFR2, UAO, false, 1, 0, false), ++ FIELD_INFO("lsm", ID_AA64MMFR2, LSM, false, 1, 0, false), ++ FIELD_INFO("iesb", ID_AA64MMFR2, IESB, false, 1, 0, false), ++ FIELD_INFO("varange", ID_AA64MMFR2, VARANGE, false, 1, 0, false), ++ FIELD_INFO("ccidx", ID_AA64MMFR2, CCIDX, false, 1, 0, false), ++ FIELD_INFO("nv", ID_AA64MMFR2, NV, false, 1, 0, false), ++ FIELD_INFO("st", ID_AA64MMFR2, ST, false, 1, 0, false), ++ FIELD_INFO("uscat", ID_AA64MMFR2, AT, false, 1, 0, false), ++ FIELD_INFO("ids", ID_AA64MMFR2, IDS, false, 1, 0, false), ++ FIELD_INFO("fwb", ID_AA64MMFR2, FWB, false, 1, 0, false), ++ FIELD_INFO("ttl", ID_AA64MMFR2, TTL, false, 1, 0, false), ++ FIELD_INFO("bbm", ID_AA64MMFR2, BBM, false, 1, 0, false), ++ FIELD_INFO("evt", ID_AA64MMFR2, EVT, false, 1, 0, false), ++ FIELD_INFO("e0pd", ID_AA64MMFR2, E0PD, false, 1, 0, false), ++ ++ FIELD_INFO("copdbg", ID_DFR0, COPDBG, false, 1, 0, false), ++ FIELD_INFO("copsdbg", ID_DFR0, COPSDBG, false, 1, 0, false), ++ FIELD_INFO("mmapdbg", ID_DFR0, MMAPDBG, false, 1, 0, false), ++ FIELD_INFO("coptrc", ID_DFR0, COPTRC, false, 1, 0, false), ++ FIELD_INFO("mmaptrc", ID_DFR0, MMAPTRC, false, 1, 0, false), ++ FIELD_INFO("mprofdbg", ID_DFR0, MPROFDBG, false, 1, 0, false), ++ FIELD_INFO("perfmon", ID_DFR0, PERFMON, false, 1, 0, false), ++ FIELD_INFO("tracefilt", ID_DFR0, TRACEFILT, false, 1, 0, false), ++ ++ { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_AES_LENGTH, ++ .shift = R_ID_AA64ISAR0_AES_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "pmull", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_TS_LENGTH, ++ .shift = R_ID_AA64ISAR0_TS_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "flagm2", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_DPB_LENGTH, ++ .shift = R_ID_AA64ISAR1_DPB_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "dcpodp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_LRCPC_LENGTH, ++ .shift = R_ID_AA64ISAR1_LRCPC_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "ilrcpc", .is_32bit = false, ++ }, ++}; ++ ++static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ ARMCPU *cpu = ARM_CPU(obj); ++ CPUFeatureInfo *feat = opaque; ++ int field_value = feat->sign ? sextract64(cpu->isar.regs[feat->reg], ++ feat->shift, feat->length) : ++ extract64(cpu->isar.regs[feat->reg], ++ feat->shift, feat->length); ++ bool value = field_value >= feat->min_value; ++ ++ visit_type_bool(v, name, &value, errp); ++} ++ ++static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ DeviceState *dev = DEVICE(obj); ++ ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; ++ CPUFeatureInfo *feat = opaque; ++ Error *local_err = NULL; ++ bool value; ++ ++ if (dev->realized) { ++ qdev_prop_set_after_realize(dev, name, errp); ++ return; ++ } ++ ++ visit_type_bool(v, name, &value, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ if (value) { ++ isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], ++ feat->shift, feat->length, ++ feat->min_value); ++ } else { ++ isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], ++ feat->shift, feat->length, ++ feat->ni_value); ++ } ++} ++ ++static void arm_cpu_register_feature_props(ARMCPU *cpu) ++{ ++ int i; ++ int num = ARRAY_SIZE(cpu_features); ++ ObjectProperty *op; ++ CPUARMState *env = &cpu->env; ++ ++ for (i = 0; i < num; i++) { ++ if ((arm_feature(env, ARM_FEATURE_AARCH64) && cpu_features[i].is_32bit) ++ || (!arm_feature(env, ARM_FEATURE_AARCH64) && ++ cpu_features[i].is_32bit)) { ++ continue; ++ } ++ op = object_property_find(OBJECT(cpu), cpu_features[i].name, NULL); ++ 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); ++ } ++ } ++} ++ + void arm_cpu_post_init(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); +@@ -1150,6 +1491,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); + } + + static void arm_cpu_finalizefn(Object *obj) +-- +2.23.0 + diff --git a/target-i386-Add-missed-security-features-to-Cooperla.patch b/target-i386-Add-missed-security-features-to-Cooperla.patch new file mode 100644 index 0000000000000000000000000000000000000000..42e90c6152728f35717440409bb6543352500857 --- /dev/null +++ b/target-i386-Add-missed-security-features-to-Cooperla.patch @@ -0,0 +1,35 @@ +From da65efa79676baad4d3377ebeae578481753e991 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-bit-definitions-of-MSR_IA32_ARCH.patch b/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff65bb8cded9430ad1bbd80273c6368cd10cb130 --- /dev/null +++ b/target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch @@ -0,0 +1,47 @@ +From 69aa3c3d8f57b4219ff6d725ac212a4940355be9 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Wed, 25 Dec 2019 14:30:17 +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. + +Signed-off-by: Xiaoyao Li +Message-Id: <20191225063018.20038-2-xiaoyao.li@intel.com> +Signed-off-by: Paolo Bonzini + +Signed-off-by: Jingyi Wang +--- + target/i386/cpu.h | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 58d8c48964..7ff8ddd464 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) + + #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) + +-- +2.27.0 + diff --git a/target-i386-Export-TAA_NO-bit-to-guests.patch b/target-i386-Export-TAA_NO-bit-to-guests.patch new file mode 100644 index 0000000000000000000000000000000000000000..68cf05c73dd55d5ff521c6a8201d12096ab48869 --- /dev/null +++ b/target-i386-Export-TAA_NO-bit-to-guests.patch @@ -0,0 +1,36 @@ +From 2ad9cf5be62515469e9c58dc2a2ef8703cefd5a6 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-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch b/target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch new file mode 100644 index 0000000000000000000000000000000000000000..df29639a1e8d287bf4b9cd6fb945d865453be5ec --- /dev/null +++ b/target-i386-add-PSCHANGE_NO-bit-for-the-ARCH_CAPABIL.patch @@ -0,0 +1,32 @@ +From 6fdd7126026a19c3292a8106917d901979501d80 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/tcp_emu-Fix-oob-access.patch b/tcp_emu-Fix-oob-access.patch deleted file mode 100644 index 5182f54363d585efd23f0a5c236d0e9c5153215e..0000000000000000000000000000000000000000 --- a/tcp_emu-Fix-oob-access.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0f7224535cdfec549cd43a5ae4ccde936f50ee95 Mon Sep 17 00:00:00 2001 -From: Samuel Thibault -Date: Wed, 11 Mar 2020 17:33:46 +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 fde9207b..4608942f 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -895,6 +895,9 @@ 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 -@@ -910,6 +913,9 @@ 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) --- -2.21.1 (Apple Git-122.3) - diff --git a/tcp_emu-fix-unsafe-snprintf-usages.patch b/tcp_emu-fix-unsafe-snprintf-usages.patch deleted file mode 100644 index cc13154ca1449831d6a91dbacc27234af4caf0e5..0000000000000000000000000000000000000000 --- a/tcp_emu-fix-unsafe-snprintf-usages.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 1db8bcc0ec91bb4374b3ffdd03da3c4ede381fb5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 11 Mar 2020 18:52:07 +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 | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index e898fd03..88dadc76 100644 ---- a/slirp/src/tcp_subr.c -+++ b/slirp/src/tcp_subr.c -@@ -707,7 +707,7 @@ 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; -@@ -740,7 +740,7 @@ 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), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - -@@ -766,7 +766,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (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), -+ m->m_len = slirp_fmt0(m->m_data, M_ROOM(m), - "%d", ntohs(so->so_fport)) + 1; - return 1; - -@@ -786,7 +786,7 @@ 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); -@@ -797,7 +797,7 @@ 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 SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); -@@ -808,7 +808,7 @@ 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 MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); --- -2.21.1 (Apple Git-122.3) - diff --git a/test-numa-Adjust-aarch64-numa-test.patch b/test-numa-Adjust-aarch64-numa-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..24145937724385b1ff8dd0bd280e5e62341ad659 --- /dev/null +++ b/test-numa-Adjust-aarch64-numa-test.patch @@ -0,0 +1,58 @@ +From 3ef97cc418d1061fc0ec70098270ce2d76005cc1 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 + +We have supported topology for arm/virt in previous patch, which +changes the meaning of "thread-id", so we must modify test case. + +Signed-off-by: Keqian Zhu +--- + tests/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; + QTestState *qts; + +- cli = make_cli(data, "-smp 2 " ++ cli = make_cli(data, "-smp 2,cores=2 " + "-numa node,nodeid=0 -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 " ++ "-numa cpu,node-id=0,core-id=1"); + 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) + + 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); +- } else if (thread == 1) { ++ } else if (core == 1) { + g_assert_cmpint(node, ==, 0); + } else { + g_assert(false); +-- +2.19.1 diff --git a/tests-Add-bios-tests-to-arm-virt.patch b/tests-Add-bios-tests-to-arm-virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..025afb506017f9bc1c6fdb26df35c9534a8f3672 --- /dev/null +++ b/tests-Add-bios-tests-to-arm-virt.patch @@ -0,0 +1,86 @@ +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-Disalbe-filemonitor-testcase.patch b/tests-Disalbe-filemonitor-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..b389299e35dd49154f6e660ee3d66237b15ec58b --- /dev/null +++ b/tests-Disalbe-filemonitor-testcase.patch @@ -0,0 +1,34 @@ +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-Replace-deprecated-ASN1-code.patch b/tests-Replace-deprecated-ASN1-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..65c8a6cf413da947fe031cb6b5ca45c966a147f4 --- /dev/null +++ b/tests-Replace-deprecated-ASN1-code.patch @@ -0,0 +1,98 @@ +From d3918f6f22ad23b18f83eb446ee787d41ffd4631 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Thu, 28 Jan 2021 18:15:23 +0100 +Subject: [PATCH 4/4] tests: Replace deprecated ASN1 code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes several compiler warnings on MacOS with Homebrew. The +git development branch for forthcoming libtasn1 4.17.0 has introduced +deprecation warnings for several macros/types that we use. + +Signed-off-by: Stefan Weil +Signed-off-by: Daniel P. Berrangé +--- + tests/crypto-tls-x509-helpers.c | 10 +++++----- + tests/crypto-tls-x509-helpers.h | 2 +- + tests/pkix_asn1_tab.c | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/tests/crypto-tls-x509-helpers.c b/tests/crypto-tls-x509-helpers.c +index 9b669c2a4b..5471434ca2 100644 +--- a/tests/crypto-tls-x509-helpers.c ++++ b/tests/crypto-tls-x509-helpers.c +@@ -30,7 +30,7 @@ + * This stores some static data that is needed when + * encoding extensions in the x509 certs + */ +-ASN1_TYPE pkix_asn1; ++asn1_node pkix_asn1; + + /* + * To avoid consuming random entropy to generate keys, +@@ -118,7 +118,7 @@ void test_tls_cleanup(const char *keyfile) + /* + * Turns an ASN1 object into a DER encoded byte array + */ +-static void test_tls_der_encode(ASN1_TYPE src, ++static void test_tls_der_encode(asn1_node src, + const char *src_name, + gnutls_datum_t *res) + { +@@ -296,7 +296,7 @@ test_tls_generate_cert(QCryptoTLSTestCertReq *req, + * the 'critical' field which we want control over + */ + if (req->basicConstraintsEnable) { +- ASN1_TYPE ext = ASN1_TYPE_EMPTY; ++ asn1_node ext = NULL; + + asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext); + asn1_write_value(ext, "cA", +@@ -323,7 +323,7 @@ test_tls_generate_cert(QCryptoTLSTestCertReq *req, + * to be 'critical' + */ + if (req->keyUsageEnable) { +- ASN1_TYPE ext = ASN1_TYPE_EMPTY; ++ asn1_node ext = NULL; + char str[2]; + + str[0] = req->keyUsageValue & 0xff; +@@ -353,7 +353,7 @@ test_tls_generate_cert(QCryptoTLSTestCertReq *req, + * set this the hard way building up ASN1 data ourselves + */ + if (req->keyPurposeEnable) { +- ASN1_TYPE ext = ASN1_TYPE_EMPTY; ++ asn1_node ext = NULL; + + asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext); + if (req->keyPurposeOID1) { +diff --git a/tests/crypto-tls-x509-helpers.h b/tests/crypto-tls-x509-helpers.h +index 08efba4e19..8fcd7785ab 100644 +--- a/tests/crypto-tls-x509-helpers.h ++++ b/tests/crypto-tls-x509-helpers.h +@@ -125,7 +125,7 @@ void test_tls_cleanup(const char *keyfile); + }; \ + test_tls_generate_cert(&varname, NULL) + +-extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; ++extern const asn1_static_node pkix_asn1_tab[]; + + #endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */ + +diff --git a/tests/pkix_asn1_tab.c b/tests/pkix_asn1_tab.c +index f15fc515cb..4aaf736d3f 100644 +--- a/tests/pkix_asn1_tab.c ++++ b/tests/pkix_asn1_tab.c +@@ -8,7 +8,7 @@ + + #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT + +-const ASN1_ARRAY_TYPE pkix_asn1_tab[] = { ++const asn1_static_node pkix_asn1_tab[] = { + {"PKIX1", 536875024, 0}, + {0, 1073741836, 0}, + {"id-ce", 1879048204, 0}, +-- +2.17.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 new file mode 100644 index 0000000000000000000000000000000000000000..e739883feb04d14f33a97a2a0b6690ac6c5ccc24 --- /dev/null +++ b/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch @@ -0,0 +1,44 @@ +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-add-empty-files.patch b/tests-acpi-add-empty-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..46e51c0de0e0ba84b6edf01fb62e3005acd37697 --- /dev/null +++ b/tests-acpi-add-empty-files.patch @@ -0,0 +1,88 @@ +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-allow-empty-expected-files.patch b/tests-allow-empty-expected-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..615fb2121d3ffd93d926fe4f3e9623ffce16eb88 --- /dev/null +++ b/tests-allow-empty-expected-files.patch @@ -0,0 +1,31 @@ +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-bios-tables-test-disable-this-testcase.patch b/tests-bios-tables-test-disable-this-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..993fee935546735c16bfe9a30ff856ac135f4d53 --- /dev/null +++ b/tests-bios-tables-test-disable-this-testcase.patch @@ -0,0 +1,48 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..c961069b6e77c2a193b34d606466f04c7b059611 --- /dev/null +++ b/tests-document-how-to-update-acpi-tables.patch @@ -0,0 +1,53 @@ +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-fdc-test-Add-a-regression-test-for-CVE-2021-20.patch b/tests-fdc-test-Add-a-regression-test-for-CVE-2021-20.patch new file mode 100644 index 0000000000000000000000000000000000000000..56aac5a8f059c1e4a2626fd8829fc411a218cec6 --- /dev/null +++ b/tests-fdc-test-Add-a-regression-test-for-CVE-2021-20.patch @@ -0,0 +1,100 @@ +From 2d3c9124817d4f01a1d241359a784f29006f9cc1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Wed, 24 Nov 2021 17:15:36 +0100 +Subject: [PATCH 3/5] tests/fdc-test: Add a regression test for CVE-2021-20196 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Without the previous commit, when running 'make check-qtest-i386' +with QEMU configured with '--enable-sanitizers' we get: + + AddressSanitizer:DEADLYSIGNAL + ================================================================= + ==287878==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000344 + ==287878==The signal is caused by a WRITE memory access. + ==287878==Hint: address points to the zero page. + #0 0x564b2e5bac27 in blk_inc_in_flight block/block-backend.c:1346:5 + #1 0x564b2e5bb228 in blk_pwritev_part block/block-backend.c:1317:5 + #2 0x564b2e5bcd57 in blk_pwrite block/block-backend.c:1498:11 + #3 0x564b2ca1cdd3 in fdctrl_write_data hw/block/fdc.c:2221:17 + #4 0x564b2ca1b2f7 in fdctrl_write hw/block/fdc.c:829:9 + #5 0x564b2dc49503 in portio_write softmmu/ioport.c:201:9 + +Add the reproducer for CVE-2021-20196. + +Suggested-by: Alexander Bulekov +Reviewed-by: Darren Kenny +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20211124161536.631563-4-philmd@redhat.com +Signed-off-by: John Snow +--- + tests/fdc-test.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/tests/fdc-test.c b/tests/fdc-test.c +index 31cd3295c1..644cafc060 100644 +--- a/tests/fdc-test.c ++++ b/tests/fdc-test.c +@@ -32,6 +32,9 @@ + /* TODO actually test the results and get rid of this */ + #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__)) + ++#define DRIVE_FLOPPY_BLANK \ ++ "-drive if=floppy,file=null-co://,file.read-zeroes=on,format=raw,size=1440k" ++ + #define TEST_IMAGE_SIZE 1440 * 1024 + + #define FLOPPY_BASE 0x3f0 +@@ -546,6 +549,40 @@ static void fuzz_registers(void) + } + } + ++static bool qtest_check_clang_sanitizer(void) ++{ ++#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) ++ return true; ++#else ++ g_test_skip("QEMU not configured using --enable-sanitizers"); ++ return false; ++#endif ++} ++static void test_cve_2021_20196(void) ++{ ++ QTestState *s; ++ ++ if (!qtest_check_clang_sanitizer()) { ++ return; ++ } ++ ++ s = qtest_initf("-nographic -m 32M -nodefaults " DRIVE_FLOPPY_BLANK); ++ ++ qtest_outw(s, 0x3f4, 0x0500); ++ qtest_outb(s, 0x3f5, 0x00); ++ qtest_outb(s, 0x3f5, 0x00); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outb(s, 0x3f5, 0x00); ++ qtest_outw(s, 0x3f1, 0x0400); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outw(s, 0x3f4, 0x0000); ++ qtest_outb(s, 0x3f5, 0x00); ++ qtest_outb(s, 0x3f5, 0x01); ++ qtest_outw(s, 0x3f1, 0x0500); ++ qtest_outb(s, 0x3f5, 0x00); ++ qtest_quit(s); ++} ++ + int main(int argc, char **argv) + { + int fd; +@@ -576,6 +613,7 @@ int main(int argc, char **argv) + qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18); + 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); + + ret = g_test_run(); + +-- +2.27.0 + diff --git a/tftp-check-tftp_input-buffer-size.patch b/tftp-check-tftp_input-buffer-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c642f67211af98d470831738cc1cda621461420 --- /dev/null +++ b/tftp-check-tftp_input-buffer-size.patch @@ -0,0 +1,37 @@ +From 968656cf302ba7f8a3dfaf1013f7d8e80663e63e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 16:34:30 +0400 +Subject: [PATCH 5/6] tftp: check tftp_input buffer size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2021-3595 +Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/46 + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/tftp.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c +index 2b4176cc..035a0cab 100644 +--- a/slirp/src/tftp.c ++++ b/slirp/src/tftp.c +@@ -449,7 +449,11 @@ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas, + + void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m) + { +- struct tftp_t *tp = (struct tftp_t *)m->m_data; ++ struct tftp_t *tp = mtod_check(m, offsetof(struct tftp_t, x.tp_buf)); ++ ++ if (tp == NULL) { ++ return; ++ } + + switch (ntohs(tp->tp_op)) { + case TFTP_RRQ: +-- +2.27.0 + diff --git a/tftp-introduce-a-header-structure.patch b/tftp-introduce-a-header-structure.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f9c7905bdd9578fcee1edb6050e316cf578db4c --- /dev/null +++ b/tftp-introduce-a-header-structure.patch @@ -0,0 +1,252 @@ +From 4330205483be65148e365d968d21efc3f56c4228 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 20:01:20 +0400 +Subject: [PATCH 6/6] tftp: introduce a header structure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Instead of using a composed structure and potentially reading past the +incoming buffer, use a different structure for the header. + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/tftp.c | 61 ++++++++++++++++++++++++------------------------ + slirp/src/tftp.h | 6 ++++- + 2 files changed, 36 insertions(+), 31 deletions(-) + +diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c +index 035a0cab..ed89e0b5 100644 +--- a/slirp/src/tftp.c ++++ b/slirp/src/tftp.c +@@ -50,7 +50,7 @@ static void tftp_session_terminate(struct tftp_session *spt) + } + + static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas, +- struct tftp_t *tp) ++ struct tftphdr *hdr) + { + struct tftp_session *spt; + int k; +@@ -75,7 +75,7 @@ found: + memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas)); + spt->fd = -1; + spt->block_size = 512; +- spt->client_port = tp->udp.uh_sport; ++ spt->client_port = hdr->udp.uh_sport; + spt->slirp = slirp; + + tftp_session_update(spt); +@@ -84,7 +84,7 @@ found: + } + + static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas, +- struct tftp_t *tp) ++ struct tftphdr *hdr) + { + struct tftp_session *spt; + int k; +@@ -94,7 +94,7 @@ static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas, + + if (tftp_session_in_use(spt)) { + if (sockaddr_equal(&spt->client_addr, srcsas)) { +- if (spt->client_port == tp->udp.uh_sport) { ++ if (spt->client_port == hdr->udp.uh_sport) { + return k; + } + } +@@ -146,13 +146,13 @@ static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt, + } + + static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m, +- struct tftp_t *recv_tp) ++ struct tftphdr *hdr) + { + if (spt->client_addr.ss_family == AF_INET6) { + struct sockaddr_in6 sa6, da6; + + sa6.sin6_addr = spt->slirp->vhost_addr6; +- sa6.sin6_port = recv_tp->udp.uh_dport; ++ sa6.sin6_port = hdr->udp.uh_dport; + da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr; + da6.sin6_port = spt->client_port; + +@@ -161,7 +161,7 @@ static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m, + struct sockaddr_in sa4, da4; + + sa4.sin_addr = spt->slirp->vhost_addr; +- sa4.sin_port = recv_tp->udp.uh_dport; ++ sa4.sin_port = hdr->udp.uh_dport; + da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr; + da4.sin_port = spt->client_port; + +@@ -183,7 +183,7 @@ static int tftp_send_oack(struct tftp_session *spt, const char *keys[], + + tp = tftp_prep_mbuf_data(spt, m); + +- tp->tp_op = htons(TFTP_OACK); ++ tp->hdr.tp_op = htons(TFTP_OACK); + for (i = 0; i < nb; i++) { + n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", + keys[i]) + +@@ -193,9 +193,8 @@ static int tftp_send_oack(struct tftp_session *spt, const char *keys[], + 1; + } + +- m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n - +- sizeof(struct udphdr); +- tftp_udp_output(spt, m, recv_tp); ++ m->m_len = G_SIZEOF_MEMBER(struct tftp_t, hdr.tp_op) + n; ++ tftp_udp_output(spt, m, &recv_tp->hdr); + + return 0; + } +@@ -216,21 +215,21 @@ static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode, + + tp = tftp_prep_mbuf_data(spt, m); + +- tp->tp_op = htons(TFTP_ERROR); ++ tp->hdr.tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), + msg); + + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + + strlen(msg) - sizeof(struct udphdr); +- tftp_udp_output(spt, m, recv_tp); ++ tftp_udp_output(spt, m, &recv_tp->hdr); + + out: + tftp_session_terminate(spt); + } + + static void tftp_send_next_block(struct tftp_session *spt, +- struct tftp_t *recv_tp) ++ struct tftphdr *hdr) + { + struct mbuf *m; + struct tftp_t *tp; +@@ -244,7 +243,7 @@ static void tftp_send_next_block(struct tftp_session *spt, + + tp = tftp_prep_mbuf_data(spt, m); + +- tp->tp_op = htons(TFTP_DATA); ++ tp->hdr.tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); + + nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, +@@ -262,7 +261,7 @@ static void tftp_send_next_block(struct tftp_session *spt, + + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) - + sizeof(struct udphdr); +- tftp_udp_output(spt, m, recv_tp); ++ tftp_udp_output(spt, m, hdr); + + if (nobytes == spt->block_size) { + tftp_session_update(spt); +@@ -285,12 +284,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, + int nb_options = 0; + + /* check if a session already exists and if so terminate it */ +- s = tftp_session_find(slirp, srcsas, tp); ++ s = tftp_session_find(slirp, srcsas, &tp->hdr); + if (s >= 0) { + tftp_session_terminate(&slirp->tftp_sessions[s]); + } + +- s = tftp_session_allocate(slirp, srcsas, tp); ++ s = tftp_session_allocate(slirp, srcsas, &tp->hdr); + + if (s < 0) { + return; +@@ -416,29 +415,29 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, + } + + spt->block_nr = 0; +- tftp_send_next_block(spt, tp); ++ tftp_send_next_block(spt, &tp->hdr); + } + + static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas, +- struct tftp_t *tp, int pktlen) ++ struct tftphdr *hdr) + { + int s; + +- s = tftp_session_find(slirp, srcsas, tp); ++ s = tftp_session_find(slirp, srcsas, hdr); + + if (s < 0) { + return; + } + +- tftp_send_next_block(&slirp->tftp_sessions[s], tp); ++ tftp_send_next_block(&slirp->tftp_sessions[s], hdr); + } + + static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas, +- struct tftp_t *tp, int pktlen) ++ struct tftphdr *hdr) + { + int s; + +- s = tftp_session_find(slirp, srcsas, tp); ++ s = tftp_session_find(slirp, srcsas, hdr); + + if (s < 0) { + return; +@@ -449,23 +448,25 @@ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas, + + void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m) + { +- struct tftp_t *tp = mtod_check(m, offsetof(struct tftp_t, x.tp_buf)); ++ struct tftphdr *hdr = mtod_check(m, sizeof(struct tftphdr)); + +- if (tp == NULL) { ++ if (hdr == NULL) { + return; + } + +- switch (ntohs(tp->tp_op)) { ++ switch (ntohs(hdr->tp_op)) { + case TFTP_RRQ: +- tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len); ++ tftp_handle_rrq(m->slirp, srcsas, ++ mtod(m, struct tftp_t *), ++ m->m_len); + break; + + case TFTP_ACK: +- tftp_handle_ack(m->slirp, srcsas, tp, m->m_len); ++ tftp_handle_ack(m->slirp, srcsas, hdr); + break; + + case TFTP_ERROR: +- tftp_handle_error(m->slirp, srcsas, tp, m->m_len); ++ tftp_handle_error(m->slirp, srcsas, hdr); + break; + } + } +diff --git a/slirp/src/tftp.h b/slirp/src/tftp.h +index c47bb43c..021f6cf1 100644 +--- a/slirp/src/tftp.h ++++ b/slirp/src/tftp.h +@@ -18,9 +18,13 @@ + #define TFTP_FILENAME_MAX 512 + #define TFTP_BLOCKSIZE_MAX 1428 + +-struct tftp_t { ++struct tftphdr { + struct udphdr udp; + uint16_t tp_op; ++} SLIRP_PACKED; ++ ++struct tftp_t { ++ struct tftphdr hdr; + union { + struct { + uint16_t tp_block_nr; +-- +2.27.0 + diff --git a/tx_pkt-switch-to-use-qemu_receive_packet_iov-for-loo.patch b/tx_pkt-switch-to-use-qemu_receive_packet_iov-for-loo.patch new file mode 100644 index 0000000000000000000000000000000000000000..cac19234efcefbebd2653b009a182f28f65fa857 --- /dev/null +++ b/tx_pkt-switch-to-use-qemu_receive_packet_iov-for-loo.patch @@ -0,0 +1,41 @@ +From c75b8239c9505269c2ea9704a7af890f084edd7b Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 14 May 2021 10:32:24 +0800 +Subject: [PATCH] tx_pkt: switch to use qemu_receive_packet_iov() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix CVE-2021-3416 + +This patch switches to use qemu_receive_receive_iov() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Jason Wang + +Signed-off-by: Jiajie Li +--- + hw/net/net_tx_pkt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c +index 54d4c3bbd0..646cdfaf4d 100644 +--- a/hw/net/net_tx_pkt.c ++++ b/hw/net/net_tx_pkt.c +@@ -544,7 +544,7 @@ static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt, + NetClientState *nc, const struct iovec *iov, int iov_cnt) + { + if (pkt->is_loopback) { +- nc->info->receive_iov(nc, iov, iov_cnt); ++ qemu_receive_packet_iov(nc, iov, iov_cnt); + } else { + qemu_sendv_packet(nc, iov, iov_cnt); + } +-- +2.27.0 + diff --git a/tz-ppc-add-dummy-read-write-methods.patch b/tz-ppc-add-dummy-read-write-methods.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0356ab95d7c8aeb1ff0b05979b072990760e817 --- /dev/null +++ b/tz-ppc-add-dummy-read-write-methods.patch @@ -0,0 +1,45 @@ +From bbe130bf59e2640f2f5a6ab24aac7763b17c636a 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-stream-number-sanity-checks.patch b/uas-add-stream-number-sanity-checks.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1a4a1ec795e2bf22b79c422ff0b6fe2d40254d0 --- /dev/null +++ b/uas-add-stream-number-sanity-checks.patch @@ -0,0 +1,61 @@ +From 8b9fcc2c362e88491eb1c7621797eb43d66d0193 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 18 Aug 2021 14:05:05 +0200 +Subject: [PATCH] uas: add stream number sanity checks. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The device uses the guest-supplied stream number unchecked, which can +lead to guest-triggered out-of-band access to the UASDevice->data3 and +UASDevice->status3 fields. Add the missing checks. + +Fixes: CVE-2021-3713 +Signed-off-by: Gerd Hoffmann +Reported-by: Chen Zhe +Reported-by: Tan Jingguo +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20210818120505.1258262-2-kraxel@redhat.com> +--- + hw/usb/dev-uas.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c +index abd8070d0c..82bbc0d083 100644 +--- a/hw/usb/dev-uas.c ++++ b/hw/usb/dev-uas.c +@@ -827,6 +827,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + } + break; + case UAS_PIPE_ID_STATUS: ++ if (p->stream > UAS_MAX_STREAMS) { ++ goto err_stream; ++ } + if (p->stream) { + QTAILQ_FOREACH(st, &uas->results, next) { + if (st->stream == p->stream) { +@@ -854,6 +857,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + break; + case UAS_PIPE_ID_DATA_IN: + case UAS_PIPE_ID_DATA_OUT: ++ if (p->stream > UAS_MAX_STREAMS) { ++ goto err_stream; ++ } + if (p->stream) { + req = usb_uas_find_request(uas, p->stream); + } else { +@@ -889,6 +895,11 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + p->status = USB_RET_STALL; + break; + } ++ ++err_stream: ++ error_report("%s: invalid stream %d", __func__, p->stream); ++ p->status = USB_RET_STALL; ++ return; + } + + static void usb_uas_unrealize(USBDevice *dev, Error **errp) +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..30724cedb050b52be09a0b081ffe36cd7599d268 --- /dev/null +++ b/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch @@ -0,0 +1,62 @@ +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-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..48e1bf5c506643d95ed10c4ebb9f0602cd86dc8c --- /dev/null +++ b/ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch @@ -0,0 +1,84 @@ +From 88e41fe7ae7e3344f075ae9b226c29c976adf0f4 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella +Date: Thu, 7 Apr 2022 10:17:12 +0200 +Subject: [PATCH 5/5] 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 4a63c382f6..bcef2a5fb0 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -240,6 +240,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 249a179bf6..1c977cedf7 100644 +--- a/hw/display/vmware_vga.c ++++ b/hw/display/vmware_vga.c +@@ -507,6 +507,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/upd6-check-udp6_input-buffer-size.patch b/upd6-check-udp6_input-buffer-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9402fe435016bd9ce9af7581a11208056bed5dd --- /dev/null +++ b/upd6-check-udp6_input-buffer-size.patch @@ -0,0 +1,36 @@ +From 054a233306e781ae3cf66b386b67b68e8ac33c37 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 4 Jun 2021 16:32:55 +0400 +Subject: [PATCH 4/6] upd6: check udp6_input buffer size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: CVE-2021-3593 +Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/45 + +Signed-off-by: Marc-André Lureau +Signed-off-by: imxcc +--- + slirp/src/udp6.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/slirp/src/udp6.c b/slirp/src/udp6.c +index 6f9486bb..8c490e4d 100644 +--- a/slirp/src/udp6.c ++++ b/slirp/src/udp6.c +@@ -28,7 +28,10 @@ void udp6_input(struct mbuf *m) + ip = mtod(m, struct ip6 *); + m->m_len -= iphlen; + m->m_data += iphlen; +- uh = mtod(m, struct udphdr *); ++ uh = mtod_check(m, sizeof(struct udphdr)); ++ if (uh == NULL) { ++ goto bad; ++ } + m->m_len += iphlen; + m->m_data -= iphlen; + +-- +2.27.0 + 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 new file mode 100644 index 0000000000000000000000000000000000000000..2764b7d66de95f5b0c6ea5d7676615abbaf85aef --- /dev/null +++ b/usb-limit-combined-packets-to-1-MiB-CVE-2021-3527.patch @@ -0,0 +1,39 @@ +From 83e4d94fc5601ae8aa329cd542d56f703c252d9f 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-fix-free-call.patch b/usbredir-fix-free-call.patch new file mode 100644 index 0000000000000000000000000000000000000000..f223db9fdfc037a3d215846ecbc9efdee69c219c --- /dev/null +++ b/usbredir-fix-free-call.patch @@ -0,0 +1,38 @@ +From 954de76bad35dc345445d2772b09a1615b315eab Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 22 Jul 2021 09:27:56 +0200 +Subject: [PATCH] usbredir: fix free call +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +data might point into the middle of a larger buffer, there is a separate +free_on_destroy pointer passed into bufp_alloc() to handle that. It is +only used in the normal workflow though, not when dropping packets due +to the queue being full. Fix that. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/491 +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-Id: <20210722072756.647673-1-kraxel@redhat.com> +Signed-off-by: imxcc +--- + hw/usb/redirect.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 998fc6e4b0..87338f76da 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -459,7 +459,7 @@ static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, + if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { + if (dev->endpoint[EP2I(ep)].bufpq_size > + dev->endpoint[EP2I(ep)].bufpq_target_size) { +- free(data); ++ free(free_on_destroy); + return -1; + } + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; +-- +2.27.0 + diff --git a/util-hbitmap-strict-hbitmap_reset.patch b/util-hbitmap-strict-hbitmap_reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7f568f1bc6d21ae6923a552c2536414d5d33fdd --- /dev/null +++ b/util-hbitmap-strict-hbitmap_reset.patch @@ -0,0 +1,77 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..0cca67b8b1ed17eb873514c177eb6e371ae21f17 --- /dev/null +++ b/util-iov-improve-qemu_iovec_is_zero.patch @@ -0,0 +1,102 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..0a488a63413b69816576ff8394f1e282c292e7d7 --- /dev/null +++ b/util-iov-introduce-qemu_iovec_init_extended.patch @@ -0,0 +1,177 @@ +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/vfio-add-quirk-device-write-method.patch b/vfio-add-quirk-device-write-method.patch new file mode 100644 index 0000000000000000000000000000000000000000..d185be1a99528414e439c0e4177695b430f23ba8 --- /dev/null +++ b/vfio-add-quirk-device-write-method.patch @@ -0,0 +1,40 @@ +From 80eaf4423763d215c589efcb96ccee7462728627 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/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 new file mode 100644 index 0000000000000000000000000000000000000000..f8f3f4ed04905c4da5dded25cdcd42d684a7c07d --- /dev/null +++ b/vhost-user-gpu-fix-OOB-write-in-virgl_cmd_get_capset.patch @@ -0,0 +1,51 @@ +From 87c04273387c6be06ba260a8ade6953fbb850a95 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 new file mode 100644 index 0000000000000000000000000000000000000000..8bffe282ee7854a9de29b1bcad7b801087ed77d9 --- /dev/null +++ b/vhost-user-gpu-fix-memory-disclosure-in-virgl_cmd_ge.patch @@ -0,0 +1,44 @@ +From faa84f70ddac04cf2794a9f94d08d7f5da4f4ee8 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 new file mode 100644 index 0000000000000000000000000000000000000000..4e65c0fd71fa1fc9f2bb7eb01bc0c9d7f8abe19f --- /dev/null +++ b/vhost-user-gpu-fix-memory-leak-in-vg_resource_attach.patch @@ -0,0 +1,49 @@ +From 70c7077375e1562c61532d15efd3073ca08ef8c3 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 new file mode 100644 index 0000000000000000000000000000000000000000..568f57a855e9c4c72b0a7273a0eb36236f70a1a9 --- /dev/null +++ b/vhost-user-gpu-fix-memory-leak-in-virgl_cmd_resource.patch @@ -0,0 +1,57 @@ +From 3fec4e1981039157ad30daaa7aaa226fed17ba33 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 new file mode 100644 index 0000000000000000000000000000000000000000..4e4e706692583cef52018e48700b9cdb79122f9f --- /dev/null +++ b/vhost-user-gpu-fix-memory-leak-in-virgl_resource_att.patch @@ -0,0 +1,50 @@ +From 802c87fe5e2c421191e9cf557b75d764e7f112a9 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 new file mode 100644 index 0000000000000000000000000000000000000000..07794fbb1056fb3decfcedf2a895b4d565c5169a --- /dev/null +++ b/vhost-user-gpu-fix-memory-leak-while-calling-vg_reso.patch @@ -0,0 +1,51 @@ +From 3adab03319b6330c4024a65fddb3369630c02231 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 new file mode 100644 index 0000000000000000000000000000000000000000..e6a533dec44c18255a3673db09783502aa3b174b --- /dev/null +++ b/vhost-user-gpu-fix-resource-leak-in-vg_resource_crea.patch @@ -0,0 +1,41 @@ +From 515231562068f819fa241a0400ae768d6cc0a695 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-save-features-if-the-char-dev-is-closed.patch b/vhost-user-save-features-if-the-char-dev-is-closed.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a0d04f4d7d98fd97e84bfba35f99d4871605b37 --- /dev/null +++ b/vhost-user-save-features-if-the-char-dev-is-closed.patch @@ -0,0 +1,42 @@ +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-prevent-using-uninitialized-vqs.patch b/vhost-user-scsi-prevent-using-uninitialized-vqs.patch index 9c4f92316d4da5e9e53ddc17e9915427e3cd9c36..d1bf2a087bf4fcbedf2a8c0fbb8b62188737d1e7 100644 --- a/vhost-user-scsi-prevent-using-uninitialized-vqs.patch +++ b/vhost-user-scsi-prevent-using-uninitialized-vqs.patch @@ -1,7 +1,7 @@ -From 19d56f560879081de411f359417eaaa2998c9e3a Mon Sep 17 00:00:00 2001 +From 4d8f2885b3f1219c3df2cf1a00dc0c55b23ee715 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz -Date: Tue, 11 Jun 2019 17:35:17 -0700 -Subject: [PATCH 5/5] vhost-user-scsi: prevent using uninitialized vqs +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 @@ -26,18 +26,17 @@ Signed-off-by: Stefan Hajnoczi 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c -index 8b1e687..241631f 100644 +index fcee67d5..affc2431 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c -@@ -90,7 +90,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) +@@ -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; - --- -1.8.3.1 - + vqs = vsc->dev.vqs; +-- +2.23.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..8cde941766ae0a8983631c5623895ae0b68bf165 --- /dev/null +++ b/vhost-vsock-detach-the-virqueue-element-in-case-of-e.patch @@ -0,0 +1,56 @@ +From 1f20e48288a39d9ea92e743707fd08de77bfe584 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_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.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c +index 0371493197..bcd8fa4967 100644 +--- a/hw/virtio/vhost-vsock.c ++++ b/hw/virtio/vhost-vsock.c +@@ -220,19 +220,23 @@ static void vhost_vsock_send_transport_reset(VHostVSock *vsock) + 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(vsock), vq); + +-out: ++ g_free(elem); ++ return; ++ ++err: ++ virtqueue_detach_element(vq, elem, 0); + g_free(elem); + } + +-- +2.27.0 + diff --git a/virtio-balloon-apply-upstream-patch.patch b/virtio-balloon-apply-upstream-patch.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d8f0d3246faefec50144778f56b0e8c6494d363 --- /dev/null +++ b/virtio-balloon-apply-upstream-patch.patch @@ -0,0 +1,31 @@ +From bcea62f545e85ad55c3e4fa245de58df42df5f28 Mon Sep 17 00:00:00 2001 +From: Ming Yang +Date: Tue, 16 Nov 2021 17:16:56 +0800 +Subject: [PATCH] virtio-balloon: apply upstream patch. + +Signed-off-by: Ming Yang +--- + hw/virtio/virtio-balloon.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c +index 25de154307..ae56c0d906 100644 +--- a/hw/virtio/virtio-balloon.c ++++ b/hw/virtio/virtio-balloon.c +@@ -830,6 +830,13 @@ static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) + } + balloon_stats_destroy_timer(s); + qemu_remove_balloon_handler(s); ++ ++ virtio_del_queue(vdev, 0); ++ virtio_del_queue(vdev, 1); ++ virtio_del_queue(vdev, 2); ++ if (s->free_page_vq) { ++ virtio_del_queue(vdev, 3); ++ } + virtio_cleanup(vdev); + } + +-- +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 new file mode 100644 index 0000000000000000000000000000000000000000..3c2a3f2a424bd30ff95b8fcb53ae23c324d43153 --- /dev/null +++ b/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch @@ -0,0 +1,80 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..b67f0cd1918434924c9c3d4c3cfed520867b15f4 --- /dev/null +++ b/virtio-blk-On-restart-process-queued-requests-in-the.patch @@ -0,0 +1,191 @@ +From 29e1896685b3c8b836bfc2a698aa7c9d6778cfb3 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 99916bc544..468f0fd347 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 new file mode 100644 index 0000000000000000000000000000000000000000..088b11b603b574a480639c91c452969ab4bc932a --- /dev/null +++ b/virtio-blk-Refactor-the-code-that-processes-queued-r.patch @@ -0,0 +1,70 @@ +From 75823c32e4713c6a4c551455fbc55f561cd51fa4 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 cbb3729158..99916bc544 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-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..9477045017040c85905b7eac1c74b29ff665bbe6 --- /dev/null +++ b/virtio-net-fix-map-leaking-on-error-during-receive.patch @@ -0,0 +1,39 @@ +From 72f59cd8d3c2a7a1f4a64cdfafd6c333d5bf4ad3 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 22d430c7c1..28e9cd52ff 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1382,6 +1382,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-use-after-unmap-free-for-sg.patch b/virtio-net-fix-use-after-unmap-free-for-sg.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1d255b712bb1cd228fba02b8af75c1b20d99041 --- /dev/null +++ b/virtio-net-fix-use-after-unmap-free-for-sg.patch @@ -0,0 +1,123 @@ +From eedfba47e6cf1c544541551c2c9b762c12857205 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Thu, 2 Sep 2021 13:44:12 +0800 +Subject: [PATCH] virtio-net: fix use after unmap/free for sg + +When mergeable buffer is enabled, we try to set the num_buffers after +the virtqueue elem has been unmapped. This will lead several issues, +E.g a use after free when the descriptor has an address which belongs +to the non direct access region. In this case we use bounce buffer +that is allocated during address_space_map() and freed during +address_space_unmap(). + +Fixing this by storing the elems temporarily in an array and delay the +unmap after we set the the num_buffers. + +This addresses CVE-2021-3748. + +Reported-by: Alexander Bulekov +Fixes: fbe78f4f55c6 ("virtio-net support") +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang +Signed-off-by: imxcc +--- + hw/net/virtio-net.c | 39 ++++++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 6adb0fe252..22d430c7c1 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1265,10 +1265,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); + VirtIODevice *vdev = VIRTIO_DEVICE(n); ++ VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; ++ size_t lens[VIRTQUEUE_MAX_SIZE]; + struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + struct virtio_net_hdr_mrg_rxbuf mhdr; + unsigned mhdr_cnt = 0; +- size_t offset, i, guest_offset; ++ size_t offset, i, guest_offset, j; ++ ssize_t err; + + if (!virtio_net_can_receive(nc)) { + return -1; +@@ -1291,6 +1294,12 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + + total = 0; + ++ if (i == VIRTQUEUE_MAX_SIZE) { ++ virtio_error(vdev, "virtio-net unexpected long buffer chain"); ++ err = size; ++ goto err; ++ } ++ + elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); + if (!elem) { + if (i) { +@@ -1302,7 +1311,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + n->guest_hdr_len, n->host_hdr_len, + vdev->guest_features); + } +- return -1; ++ err = -1; ++ goto err; + } + + if (elem->in_num < 1) { +@@ -1310,7 +1320,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + "virtio-net receive queue contains no in buffers"); + virtqueue_detach_element(q->rx_vq, elem, 0); + g_free(elem); +- return -1; ++ err = -1; ++ goto err; + } + + sg = elem->in_sg; +@@ -1342,12 +1353,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + if (!n->mergeable_rx_bufs && offset < size) { + virtqueue_unpop(q->rx_vq, elem, total); + g_free(elem); +- return size; ++ err = size; ++ goto err; + } + +- /* signal other side */ +- virtqueue_fill(q->rx_vq, elem, total, i++); +- g_free(elem); ++ elems[i] = elem; ++ lens[i] = total; ++ i++; + } + + if (mhdr_cnt) { +@@ -1357,10 +1369,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + &mhdr.num_buffers, sizeof mhdr.num_buffers); + } + ++ for (j = 0; j < i; j++) { ++ /* signal other side */ ++ virtqueue_fill(q->rx_vq, elems[j], lens[j], j); ++ g_free(elems[j]); ++ } ++ + virtqueue_flush(q->rx_vq, i); + virtio_notify(vdev, q->rx_vq); + + return size; ++ ++err: ++ for (j = 0; j < i; j++) { ++ g_free(elems[j]); ++ } ++ ++ return err; + } + + static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, +-- +2.27.0 + diff --git a/virtio-net-prevent-offloads-reset-on-migration.patch b/virtio-net-prevent-offloads-reset-on-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab8fbe26115279359c6a3928e93bf134ca88a2cb --- /dev/null +++ b/virtio-net-prevent-offloads-reset-on-migration.patch @@ -0,0 +1,122 @@ +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-new-post_load-hook.patch b/virtio-new-post_load-hook.patch new file mode 100644 index 0000000000000000000000000000000000000000..974f286c6730c66cc3cb0a64b046bea341dd262b --- /dev/null +++ b/virtio-new-post_load-hook.patch @@ -0,0 +1,63 @@ +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_blk-Add-support-for-retry-on-errors.patch b/virtio_blk-Add-support-for-retry-on-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..f874aba68a467d3b31c3edd0d2209db304ac8025 --- /dev/null +++ b/virtio_blk-Add-support-for-retry-on-errors.patch @@ -0,0 +1,89 @@ +From 0f45d18a204d13df344bcfd6e8278ed07e10978a 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 + +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 +--- + 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 468f0fd347..6f68cd4c97 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, + block_acct_failed(blk_get_stats(s->blk), &req->acct); + } + virtio_blk_free_request(req); ++ } else if (action == BLOCK_ERROR_ACTION_RETRY) { ++ req->mr_next = NULL; ++ req->next = s->rq; ++ s->rq = req; + } + + blk_error_action(s->blk, action, is_read, error); +@@ -142,6 +146,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) + } + } + ++ blk_error_retry_reset_timeout(s->blk); + 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) + } + } + ++ blk_error_retry_reset_timeout(s->blk); + 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) + } + } + ++ blk_error_retry_reset_timeout(s->blk); + 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) + + void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) + { +- VirtIOBlockReq *req = s->rq; ++ VirtIOBlockReq *req; + MultiReqBuffer mrb = {}; + +- s->rq = NULL; +- + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); ++ req = s->rq; ++ s->rq = NULL; + 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); + } + ++static void virtio_blk_retry_request(void *opaque) ++{ ++ VirtIOBlock *s = VIRTIO_BLK(opaque); ++ ++ virtio_blk_process_queued_requests(s, false); ++} ++ + static const BlockDevOps virtio_block_ops = { + .resize_cb = virtio_blk_resize, ++ .retry_request_cb = virtio_blk_retry_request, + }; + + static void virtio_blk_device_realize(DeviceState *dev, Error **errp) +-- +2.27.0 + diff --git a/vpc-Return-0-from-vpc_co_create-on-success.patch b/vpc-Return-0-from-vpc_co_create-on-success.patch new file mode 100644 index 0000000000000000000000000000000000000000..46fbd90d1bd39f5549ce5d0185d58bbd437a82aa --- /dev/null +++ b/vpc-Return-0-from-vpc_co_create-on-success.patch @@ -0,0 +1,49 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..726498fb6c778f8d5739e9614ae451d54a11bb56 --- /dev/null +++ b/vtimer-Drop-vtimer-virtual-timer-adjust.patch @@ -0,0 +1,144 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..f452948fd29818c9551899e5044de1e3b33bc235 --- /dev/null +++ b/vtimer-compat-cross-version-migration-from-v4.0.1.patch @@ -0,0 +1,41 @@ +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-Intel-AVX512_BF16-feature-enabling.patch b/x86-Intel-AVX512_BF16-feature-enabling.patch new file mode 100644 index 0000000000000000000000000000000000000000..b1f5c87400a5141234776b6a5f1b6eaefb4249d3 --- /dev/null +++ b/x86-Intel-AVX512_BF16-feature-enabling.patch @@ -0,0 +1,179 @@ +From 858a270c5e4081edd630f6257cb0f5e292591eb7 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-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch b/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch new file mode 100644 index 0000000000000000000000000000000000000000..fc17f48b7a395bafffaf7ef9763d04bff110af0a --- /dev/null +++ b/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch @@ -0,0 +1,60 @@ +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