Package: release.debian.org Severity: normal Tags: bookworm X-Debbugs-Cc: [email protected], [email protected] Control: affects -1 + src:qemu User: [email protected] Usertags: pu
[ Reason ] There are 2 new upstream stable/bugfix releases in the 7.2.x LTS branch. The number of fixes this time is relatively small, and many of them are to the testsuite, in an attempt to keep tests running. Among other things, this fixes two security issues: #1119917, CVE-2025-12464 (buffer overflow in e1000_receive_iov) #1117153, CVE-2025-11234 (UAF in websocket handshake code) [ Tests ] This release passes the usual local testing (a few different guests, including several versions of debian, several windows versions), and the upstream testsuite (where still applicable). [ Risks ] There aren't much risks this time, as the number of fixes is small and the fixes are mostly focused to the areas they're touching. Still, it'd be best if this release were available in the (o)s-p-u for a while, just in case. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] The changelog is below. For a description of every change, please see the git history at https://salsa.debian.org/qemu-team/qemu/-/commits/v7.2.22 (up to v7.2.20 tag which is debian release 1:7.2+dfsg-17). [ Other info ] Historically, qemu in bookworm and before used single upstream source tarball for all subsequent point releases, having two- component version number (7.2) instead of 3-component number (7.2.22). This is why next point release is shipped as a diff (in form of git diff) between previous and current tag. This has been fixed in trixie where each point release is shipped with its own original source. After extracting 7.2.0 tarball (shipped in qemu in bookworm) and applying all v7.2.x.diff pathches, the resulting tree is the same as after extracting upstream 7.2.22 tarball - besides files which we remove for DFSG. The complete debdiff between the version currently in debian (1:7.2+dfsg-7+deb12u17) and the suggested version is below. Thanks, /mjt diff -Nru qemu-7.2+dfsg/debian/changelog qemu-7.2+dfsg/debian/changelog --- qemu-7.2+dfsg/debian/changelog 2025-09-10 08:32:42.000000000 +0300 +++ qemu-7.2+dfsg/debian/changelog 2025-12-16 09:10:19.000000000 +0300 @@ -1,3 +1,59 @@ +qemu (1:7.2+dfsg-7+deb12u18) bookworm; urgency=medium + + * v7.2.22: + - Update version for 7.2.22 release + - hw/misc/npcm_clk: Don't divide by zero when calculating frequency + - hw/display/xlnx_dp: Don't abort for unsupported graphics formats + - hw/display/xlnx_dp.c: Don't abort on AUX FIFO overrun/underrun + - net: pad packets to minimum length in qemu_receive_packet() + Closes: #1119917, CVE-2025-12464 (buffer overflow in e1000_receive_iov) + - hw/net/e1000e_core: Adjust + e1000e_write_payload_frag_to_rx_buffers() assert + - hw/net/e1000e_core: Correct rx oversize packet checks + - hw/net/e1000e_core: Don't advance desc_offset + for NULL buffer RX descriptors + - qio: Protect NetListener callback with mutex + - qio: Remember context of qio_net_listener_set_client_func_full + - qio: Unwatch before notify in QIONetListener + - qio: Add trace points to net_listener + - block/curl.c: Fix CURLOPT_VERBOSE parameter type + - block/curl.c: Use explicit long constants in curl_easy_setopt calls + - crypto: stop requiring "key encipherment" usage in x509 certs + - io: fix use after free in websocket handshake code + Closes: #1117153, CVE-2025-11234 (UAF in websocket handshake code) + - io: move websock resource release to close method + - io: release active GSource in TLS channel finalizer + - io: add trace event when cancelling TLS handshake + - linux-user: permit sendto() with NULL buf and 0 len + - linux-user: Use correct type for FIBMAP and FIGETBSZ emulation + - target/i386: user: do not set up a valid LDT on reset + - async: access bottom half flags with qatomic_read + - i386/tcg/smm_helper: Properly apply DR values on SMM entry / exit + - i386/cpu: Prevent delivering SIPI during SMM in TCG mode + - target/i386: Fix CR2 handling for non-canonical addresses + * v7.2.21: + - Update version for 7.2.21 release + - ui/icons/qemu.svg: Add metadata information (author, license) to the logo + - hw/usb/hcd-uhci: don't assert for SETUP to non-0 endpoint + - tests/tcg/multiarch: Add tb-link test + - accel/tcg: Properly unlink a TB linked to itself + - multiboot: Fix the split lock + - python/qemu/machine: use socketpair() for QMP by default + - python/qmp/legacy: make QEMUMonitorProtocol accept a socket + - python/qmp/protocol: add open_with_socket() + - python/machine: Fix AF_UNIX path too long on macOS + - use fedora:37 for python container instead of :latest + - hw/usb/network: Remove hardcoded 0x40 prefix in STRING_ETHADDR response + - tests: Ensure TAP version is printed before other messages + - tests/qtest: Do not run lsi53c895a test if device is not present + - Revert "tests/qtest: use qos_printf instead of g_test_message" + - vhost-user-test: no set non-blocking for cal fd less than 0. + - tests: vhost-user-test: release mutex on protocol violation + - .gitmodules: move u-boot mirrors to qemu-project-mirrors + - hw/usb/hcd-ohci: Fix #1510, #303: pid not IN or OUT + + -- Michael Tokarev <[email protected]> Tue, 16 Dec 2025 09:10:19 +0300 + qemu (1:7.2+dfsg-7+deb12u17) bookworm; urgency=medium * v7.2.20: diff -Nru qemu-7.2+dfsg/debian/patches/series qemu-7.2+dfsg/debian/patches/series --- qemu-7.2+dfsg/debian/patches/series 2025-09-10 08:32:42.000000000 +0300 +++ qemu-7.2+dfsg/debian/patches/series 2025-12-16 08:05:32.000000000 +0300 @@ -18,6 +18,8 @@ v7.2.18.diff v7.2.19.diff v7.2.20.diff +v7.2.21.diff +v7.2.22.diff microvm-default-machine-type.patch skip-meson-pc-bios.diff linux-user-binfmt-P.diff diff -Nru qemu-7.2+dfsg/debian/patches/v7.2.20.diff qemu-7.2+dfsg/debian/patches/v7.2.20.diff --- qemu-7.2+dfsg/debian/patches/v7.2.20.diff 2025-09-10 08:32:42.000000000 +0300 +++ qemu-7.2+dfsg/debian/patches/v7.2.20.diff 2025-12-16 08:05:32.000000000 +0300 @@ -4,9 +4,9 @@ Forwarded: not-needed This is a difference between upstream qemu v7.2.19 -and upstream qemu v7.2.20. +and upstream qemu v7.2.20. -VERSION | 2 +- + VERSION | 2 +- block/curl.c | 7 ++--- hw/arm/stm32f205_soc.c | 10 +++---- hw/display/qxl-render.c | 11 +++++++- diff -Nru qemu-7.2+dfsg/debian/patches/v7.2.21.diff qemu-7.2+dfsg/debian/patches/v7.2.21.diff --- qemu-7.2+dfsg/debian/patches/v7.2.21.diff 1970-01-01 03:00:00.000000000 +0300 +++ qemu-7.2+dfsg/debian/patches/v7.2.21.diff 2025-12-16 08:05:32.000000000 +0300 @@ -0,0 +1,664 @@ +Subject: v7.2.21 +Date: Wed Oct 8 10:54:51 2025 +0300 +From: Michael Tokarev <[email protected]> +Forwarded: not-needed + +This is a difference between upstream qemu v7.2.20 and +upstream qemu v7.2.21 (without pc-bios/multiboot_dma.bin). + + .gitmodules | 4 +- + VERSION | 2 +- + accel/tcg/tb-maint.c | 8 ++++ + hw/usb/dev-network.c | 2 +- + hw/usb/hcd-ohci.c | 5 +++ + hw/usb/hcd-uhci.c | 10 ++++- + hw/usb/trace-events | 1 + + pc-bios/multiboot_dma.bin | Bin 1024 -> 1024 bytes + pc-bios/optionrom/multiboot.S | 2 +- + python/qemu/machine/machine.py | 29 +++++++++----- + python/qemu/qmp/legacy.py | 18 +++++++-- + python/qemu/qmp/protocol.py | 25 +++++++++--- + tests/avocado/avocado_qemu/__init__.py | 2 +- + tests/docker/dockerfiles/python.docker | 2 +- + tests/qtest/fuzz-lsi53c895a-test.c | 4 ++ + tests/qtest/qos-test.c | 5 --- + tests/qtest/rtl8139-test.c | 3 +- + tests/qtest/vhost-user-test.c | 33 ++++++++-------- + tests/tcg/multiarch/Makefile.target | 2 + + tests/tcg/multiarch/tb-link.c | 67 +++++++++++++++++++++++++++++++++ + ui/icons/qemu.svg | 21 ++++++++++- + 21 files changed, 196 insertions(+), 49 deletions(-) + +diff --git a/.gitmodules b/.gitmodules +index 24cffa87d4..570d895aa1 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -21,7 +21,7 @@ + url = https://gitlab.com/qemu-project/dtc.git + [submodule "roms/u-boot"] + path = roms/u-boot +- url = https://gitlab.com/qemu-project/u-boot.git ++ url = https://gitlab.com/qemu-project-mirrors/u-boot.git + [submodule "roms/skiboot"] + path = roms/skiboot + url = https://gitlab.com/qemu-project/skiboot.git +@@ -36,7 +36,7 @@ + url = https://gitlab.com/qemu-project/seabios-hppa.git + [submodule "roms/u-boot-sam460ex"] + path = roms/u-boot-sam460ex +- url = https://gitlab.com/qemu-project/u-boot-sam460ex.git ++ url = https://gitlab.com/qemu-project-mirrors/u-boot-sam460ex.git + [submodule "tests/fp/berkeley-testfloat-3"] + path = tests/fp/berkeley-testfloat-3 + url = https://gitlab.com/qemu-project/berkeley-testfloat-3.git +diff --git a/VERSION b/VERSION +index f3cd98c594..94e695c9f4 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-7.2.20 ++7.2.21 +diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c +index 9d9f651c78..077265172e 100644 +--- a/accel/tcg/tb-maint.c ++++ b/accel/tcg/tb-maint.c +@@ -186,6 +186,14 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) + * We first acquired the lock, and since the destination pointer matches, + * we know for sure that @orig is in the jmp list. + */ ++ if (dest == orig) { ++ /* ++ * In the case of a TB that links to itself, removing the entry ++ * from the list means that it won't be present later during ++ * tb_jmp_unlink -- unlink now. ++ */ ++ tb_reset_jump(orig, n_orig); ++ } + pprev = &dest->jmp_list_head; + TB_FOR_EACH_JMP(dest, tb, n) { + if (tb == orig && n == n_orig) { +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index 2c33e36cad..1b6004c902 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -1391,7 +1391,7 @@ static void usb_net_realize(USBDevice *dev, Error **errp) + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), + "%02x%02x%02x%02x%02x%02x", +- 0x40, ++ s->conf.macaddr.a[0], + s->conf.macaddr.a[1], + s->conf.macaddr.a[2], + s->conf.macaddr.a[3], +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index c3ab762f54..0ec786dd6a 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -904,6 +904,11 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) + case OHCI_TD_DIR_SETUP: + str = "setup"; + pid = USB_TOKEN_SETUP; ++ if (OHCI_BM(ed->flags, ED_EN) > 0) { /* setup only allowed to ep 0 */ ++ trace_usb_ohci_td_bad_pid(str, ed->flags, td.flags); ++ ohci_die(ohci); ++ return 1; ++ } + break; + default: + trace_usb_ohci_td_bad_direction(dir); +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index ef967c42a1..1e7fc728a0 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -724,6 +724,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + bool spd; + bool queuing = (q != NULL); + uint8_t pid = td->token & 0xff; ++ uint8_t ep_id = (td->token >> 15) & 0xf; + UHCIAsync *async; + + async = uhci_async_find_td(s, td_addr); +@@ -767,9 +768,14 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + + switch (pid) { + case USB_TOKEN_OUT: +- case USB_TOKEN_SETUP: + case USB_TOKEN_IN: + break; ++ case USB_TOKEN_SETUP: ++ /* SETUP is only valid to endpoint 0 */ ++ if (ep_id == 0) { ++ break; ++ } ++ /* fallthrough */ + default: + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; +@@ -816,7 +822,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV, + int_mask); + } +- ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); ++ ep = usb_ep_get(dev, pid, ep_id); + q = uhci_queue_new(s, qh_addr, td, ep); + } + async = uhci_async_alloc(q, td_addr); +diff --git a/hw/usb/trace-events b/hw/usb/trace-events +index b65269892c..743308c75d 100644 +--- a/hw/usb/trace-events ++++ b/hw/usb/trace-events +@@ -28,6 +28,7 @@ usb_ohci_iso_td_data_overrun(int ret, ssize_t len) "DataOverrun %d > %zu" + usb_ohci_iso_td_data_underrun(int ret) "DataUnderrun %d" + usb_ohci_iso_td_nak(int ret) "got NAK/STALL %d" + usb_ohci_iso_td_bad_response(int ret) "Bad device response %d" ++usb_ohci_td_bad_pid(const char *s, uint32_t edf, uint32_t tdf) "Bad pid %s: ed.flags 0x%x td.flags 0x%x" + usb_ohci_port_attach(int index) "port #%d" + usb_ohci_port_detach(int index) "port #%d" + usb_ohci_port_wakeup(int index) "port #%d" +diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S +index 181a4b03a3..c95e35c9cb 100644 +--- a/pc-bios/optionrom/multiboot.S ++++ b/pc-bios/optionrom/multiboot.S +@@ -208,7 +208,7 @@ ljmp2: + prot_jump: .long prot_mode + .short 8 + +-.align 4, 0 ++.align 8, 0 + gdt: + /* 0x00 */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py +index 37191f433b..b6cb366584 100644 +--- a/python/qemu/machine/machine.py ++++ b/python/qemu/machine/machine.py +@@ -157,18 +157,14 @@ def __init__(self, + self._wrapper = wrapper + self._qmp_timer = qmp_timer + +- self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" ++ self._name = name or f"{id(self):x}" ++ self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None + self._temp_dir: Optional[str] = None + self._base_temp_dir = base_temp_dir + self._sock_dir = sock_dir + self._log_dir = log_dir + +- if monitor_address is not None: +- self._monitor_address = monitor_address +- else: +- self._monitor_address = os.path.join( +- self.sock_dir, f"{self._name}-monitor.sock" +- ) ++ self._monitor_address = monitor_address + + self._console_log_path = console_log + if self._console_log_path: +@@ -192,7 +188,7 @@ def __init__(self, + self._console_set = False + self._console_device_type: Optional[str] = None + self._console_address = os.path.join( +- self.sock_dir, f"{self._name}-console.sock" ++ self.sock_dir, f"{self._name}.con" + ) + self._console_socket: Optional[socket.socket] = None + self._remove_files: List[str] = [] +@@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: + args = ['-display', 'none', '-vga', 'none'] + + if self._qmp_set: +- if isinstance(self._monitor_address, tuple): ++ if self._sock_pair: ++ fd = self._sock_pair[0].fileno() ++ os.set_inheritable(fd, True) ++ moncdev = f"socket,id=mon,fd={fd}" ++ elif isinstance(self._monitor_address, tuple): + moncdev = "socket,id=mon,host={},port={}".format( + *self._monitor_address + ) +@@ -337,10 +337,17 @@ def _pre_launch(self) -> None: + self._remove_files.append(self._console_address) + + if self._qmp_set: ++ monitor_address = None ++ sock = None ++ if self._monitor_address is None: ++ self._sock_pair = socket.socketpair() ++ sock = self._sock_pair[1] + if isinstance(self._monitor_address, str): + self._remove_files.append(self._monitor_address) ++ monitor_address = self._monitor_address + self._qmp_connection = QEMUMonitorProtocol( +- self._monitor_address, ++ address=monitor_address, ++ sock=sock, + server=True, + nickname=self._name + ) +@@ -360,6 +367,8 @@ def _pre_launch(self) -> None: + )) + + def _post_launch(self) -> None: ++ if self._sock_pair: ++ self._sock_pair[0].close() + if self._qmp_connection: + self._qmp.accept(self._qmp_timer) + +diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py +index 1951754455..8b09ee7dbb 100644 +--- a/python/qemu/qmp/legacy.py ++++ b/python/qemu/qmp/legacy.py +@@ -22,6 +22,7 @@ + # + + import asyncio ++import socket + from types import TracebackType + from typing import ( + Any, +@@ -69,22 +70,32 @@ class QEMUMonitorProtocol: + + :param address: QEMU address, can be either a unix socket path (string) + or a tuple in the form ( address, port ) for a TCP +- connection ++ connection or None ++ :param sock: a socket or None + :param server: Act as the socket server. (See 'accept') + :param nickname: Optional nickname used for logging. + """ + +- def __init__(self, address: SocketAddrT, ++ def __init__(self, ++ address: Optional[SocketAddrT] = None, ++ sock: Optional[socket.socket] = None, + server: bool = False, + nickname: Optional[str] = None): + ++ assert address or sock + self._qmp = QMPClient(nickname) + self._aloop = asyncio.get_event_loop() + self._address = address ++ self._sock = sock + self._timeout: Optional[float] = None + + if server: +- self._sync(self._qmp.start_server(self._address)) ++ if sock: ++ assert self._sock is not None ++ self._sync(self._qmp.open_with_socket(self._sock)) ++ else: ++ assert self._address is not None ++ self._sync(self._qmp.start_server(self._address)) + + _T = TypeVar('_T') + +@@ -139,6 +150,7 @@ def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: + :return: QMP greeting dict, or None if negotiate is false + :raise ConnectError: on connection errors + """ ++ assert self._address is not None + self._qmp.await_greeting = negotiate + self._qmp.negotiate = negotiate + +diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py +index 6ea86650ad..4710a57f91 100644 +--- a/python/qemu/qmp/protocol.py ++++ b/python/qemu/qmp/protocol.py +@@ -18,6 +18,7 @@ + from enum import Enum + from functools import wraps + import logging ++import socket + from ssl import SSLContext + from typing import ( + Any, +@@ -296,6 +297,19 @@ async def start_server_and_accept( + await self.accept() + assert self.runstate == Runstate.RUNNING + ++ @upper_half ++ @require(Runstate.IDLE) ++ async def open_with_socket(self, sock: socket.socket) -> None: ++ """ ++ Start connection with given socket. ++ ++ :param sock: A socket. ++ ++ :raise StateError: When the `Runstate` is not `IDLE`. ++ """ ++ self._reader, self._writer = await asyncio.open_connection(sock=sock) ++ self._set_state(Runstate.CONNECTING) ++ + @upper_half + @require(Runstate.IDLE) + async def start_server(self, address: SocketAddrT, +@@ -343,11 +357,12 @@ async def accept(self) -> None: + protocol-level failure occurs while establishing a new + session, the wrapped error may also be an `QMPError`. + """ +- if self._accepted is None: +- raise QMPError("Cannot call accept() before start_server().") +- await self._session_guard( +- self._do_accept(), +- 'Failed to establish connection') ++ if not self._reader: ++ if self._accepted is None: ++ raise QMPError("Cannot call accept() before start_server().") ++ await self._session_guard( ++ self._do_accept(), ++ 'Failed to establish connection') + await self._session_guard( + self._establish_session(), + 'Failed to establish session') +diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py +index 910f3ba1ea..25a546842f 100644 +--- a/tests/avocado/avocado_qemu/__init__.py ++++ b/tests/avocado/avocado_qemu/__init__.py +@@ -306,7 +306,7 @@ def require_netdev(self, netdevname): + self.cancel('no support for user networking') + + def _new_vm(self, name, *args): +- self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") ++ self._sd = tempfile.TemporaryDirectory(prefix="qemu_") + vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, + sock_dir=self._sd.name, log_dir=self.logdir) + self.log.debug('QEMUMachine "%s" created', name) +diff --git a/tests/docker/dockerfiles/python.docker b/tests/docker/dockerfiles/python.docker +index 175c10a34e..8cc5d3567e 100644 +--- a/tests/docker/dockerfiles/python.docker ++++ b/tests/docker/dockerfiles/python.docker +@@ -1,6 +1,6 @@ + # Python library testing environment + +-FROM fedora:latest ++FROM fedora:37 + MAINTAINER John Snow <[email protected]> + + # Please keep this list sorted alphabetically +diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c +index 9b007def26..1b55928b9f 100644 +--- a/tests/qtest/fuzz-lsi53c895a-test.c ++++ b/tests/qtest/fuzz-lsi53c895a-test.c +@@ -144,6 +144,10 @@ int main(int argc, char **argv) + { + g_test_init(&argc, &argv, NULL); + ++ if (!qtest_has_device("lsi53c895a")) { ++ return 0; ++ } ++ + qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", + test_lsi_do_dma_empty_queue); + +diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c +index 5da4091ec3..566cb3b00b 100644 +--- a/tests/qtest/qos-test.c ++++ b/tests/qtest/qos-test.c +@@ -321,11 +321,6 @@ static void walk_path(QOSGraphNode *orig_path, int len) + int main(int argc, char **argv, char** envp) + { + g_test_init(&argc, &argv, NULL); +- +- if (g_test_subprocess()) { +- qos_printf("qos_test running single test in subprocess\n"); +- } +- + if (g_test_verbose()) { + qos_printf("ENVIRONMENT VARIABLES: {\n"); + for (char **env = envp; *env != 0; env++) { +diff --git a/tests/qtest/rtl8139-test.c b/tests/qtest/rtl8139-test.c +index 8fa3313cc3..90bb616974 100644 +--- a/tests/qtest/rtl8139-test.c ++++ b/tests/qtest/rtl8139-test.c +@@ -196,9 +196,10 @@ int main(int argc, char **argv) + { + int ret; + ++ g_test_init(&argc, &argv, NULL); ++ + qtest_start("-device rtl8139"); + +- g_test_init(&argc, &argv, NULL); + qtest_add_func("/rtl8139/nop", nop); + qtest_add_func("/rtl8139/timer", test_init); + +diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c +index bf9f7c4248..9bfd7f7217 100644 +--- a/tests/qtest/vhost-user-test.c ++++ b/tests/qtest/vhost-user-test.c +@@ -26,7 +26,6 @@ + #include "libqos/virtio-pci.h" + + #include "libqos/malloc-pc.h" +-#include "libqos/qgraph_internal.h" + #include "hw/virtio/virtio-net.h" + + #include "standard-headers/linux/vhost_types.h" +@@ -338,7 +337,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + } + + if (size != VHOST_USER_HDR_SIZE) { +- qos_printf("%s: Wrong message size received %d\n", __func__, size); ++ g_test_message("Wrong message size received %d", size); + return; + } + +@@ -349,9 +348,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + p += VHOST_USER_HDR_SIZE; + size = qemu_chr_fe_read_all(chr, p, msg.size); + if (size != msg.size) { +- qos_printf("%s: Wrong message size received %d != %d\n", +- __func__, size, msg.size); +- return; ++ g_test_message("Wrong message size received %d != %d", ++ size, msg.size); ++ goto out; + } + } + +@@ -386,7 +385,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + * We don't need to do anything here, the remote is just + * letting us know it is in charge. Just log it. + */ +- qos_printf("set_owner: start of session\n"); ++ g_test_message("set_owner: start of session\n"); + break; + + case VHOST_USER_GET_PROTOCOL_FEATURES: +@@ -412,7 +411,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + * the remote end to send this. There is no handshake reply so + * just log the details for debugging. + */ +- qos_printf("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64); ++ g_test_message("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64); + break; + + /* +@@ -420,11 +419,11 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + * address of the vrings but we can simply report them. + */ + case VHOST_USER_SET_VRING_NUM: +- qos_printf("set_vring_num: %d/%d\n", ++ g_test_message("set_vring_num: %d/%d\n", + msg.payload.state.index, msg.payload.state.num); + break; + case VHOST_USER_SET_VRING_ADDR: +- qos_printf("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n", ++ g_test_message("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n", + msg.payload.addr.avail_user_addr, + msg.payload.addr.desc_user_addr, + msg.payload.addr.used_user_addr); +@@ -456,7 +455,10 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + case VHOST_USER_SET_VRING_KICK: + case VHOST_USER_SET_VRING_CALL: + /* consume the fd */ +- qemu_chr_fe_get_msgfds(chr, &fd, 1); ++ if (!qemu_chr_fe_get_msgfds(chr, &fd, 1) && fd < 0) { ++ g_test_message("call fd: %d, do not set non-blocking\n", fd); ++ break; ++ } + /* + * This is a non-blocking eventfd. + * The receive function forces it to be blocking, +@@ -500,15 +502,16 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) + * fully functioning vhost-user we would enable/disable the + * vring monitoring. + */ +- qos_printf("set_vring(%d)=%s\n", msg.payload.state.index, ++ g_test_message("set_vring(%d)=%s\n", msg.payload.state.index, + msg.payload.state.num ? "enabled" : "disabled"); + break; + + default: +- qos_printf("vhost-user: un-handled message: %d\n", msg.request); ++ g_test_message("vhost-user: un-handled message: %d\n", msg.request); + break; + } + ++out: + g_mutex_unlock(&s->data_mutex); + } + +@@ -528,7 +531,7 @@ static const char *init_hugepagefs(void) + } + + if (access(path, R_OK | W_OK | X_OK)) { +- qos_printf("access on path (%s): %s", path, strerror(errno)); ++ g_test_message("access on path (%s): %s", path, strerror(errno)); + g_test_fail(); + return NULL; + } +@@ -538,13 +541,13 @@ static const char *init_hugepagefs(void) + } while (ret != 0 && errno == EINTR); + + if (ret != 0) { +- qos_printf("statfs on path (%s): %s", path, strerror(errno)); ++ g_test_message("statfs on path (%s): %s", path, strerror(errno)); + g_test_fail(); + return NULL; + } + + if (fs.f_type != HUGETLBFS_MAGIC) { +- qos_printf("Warning: path not on HugeTLBFS: %s", path); ++ g_test_message("Warning: path not on HugeTLBFS: %s", path); + g_test_fail(); + return NULL; + } +diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target +index 5f0fee1aad..2fdec1f05f 100644 +--- a/tests/tcg/multiarch/Makefile.target ++++ b/tests/tcg/multiarch/Makefile.target +@@ -39,6 +39,8 @@ signals: LDFLAGS+=-lrt -lpthread + munmap-pthread: CFLAGS+=-pthread + munmap-pthread: LDFLAGS+=-pthread + ++tb-link: LDFLAGS+=-lpthread ++ + # We define the runner for test-mmap after the individual + # architectures have defined their supported pages sizes. If no + # additional page sizes are defined we only run the default test. +diff --git a/tests/tcg/multiarch/tb-link.c b/tests/tcg/multiarch/tb-link.c +new file mode 100644 +index 0000000000..4e40306fa1 +--- /dev/null ++++ b/tests/tcg/multiarch/tb-link.c +@@ -0,0 +1,67 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Verify that a single TB spin-loop is properly invalidated, ++ * releasing the thread from the spin-loop. ++ */ ++ ++#include <assert.h> ++#include <sys/mman.h> ++#include <pthread.h> ++#include <stdint.h> ++#include <stdbool.h> ++#include <unistd.h> ++#include <sched.h> ++ ++ ++#ifdef __x86_64__ ++#define READY 0x000047c6 /* movb $0,0(%rdi) */ ++#define LOOP 0xfceb9090 /* 1: nop*2; jmp 1b */ ++#define RETURN 0x909090c3 /* ret; nop*3 */ ++#define NOP 0x90909090 /* nop*4 */ ++#elif defined(__aarch64__) ++#define READY 0x3900001f /* strb wzr,[x0] */ ++#define LOOP 0x14000000 /* b . */ ++#define RETURN 0xd65f03c0 /* ret */ ++#define NOP 0xd503201f /* nop */ ++#elif defined(__riscv) ++#define READY 0x00050023 /* sb zero, (a0) */ ++#define LOOP 0x0000006f /* jal zero, #0 */ ++#define RETURN 0x00008067 /* jalr zero, ra, 0 */ ++#define NOP 0x00000013 /* nop */ ++#endif ++ ++ ++int main() ++{ ++#ifdef READY ++ int tmp; ++ pthread_t thread_id; ++ bool hold = true; ++ uint32_t *buf; ++ ++ buf = mmap(NULL, 3 * sizeof(uint32_t), ++ PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ assert(buf != MAP_FAILED); ++ ++ buf[0] = READY; ++ buf[1] = LOOP; ++ buf[2] = RETURN; ++ ++ alarm(2); ++ ++ tmp = pthread_create(&thread_id, NULL, (void *(*)(void *))buf, &hold); ++ assert(tmp == 0); ++ ++ while (hold) { ++ sched_yield(); ++ } ++ ++ buf[1] = NOP; ++ __builtin___clear_cache(&buf[1], &buf[2]); ++ ++ tmp = pthread_join(thread_id, NULL); ++ assert(tmp == 0); ++#endif ++ return 0; ++} +diff --git a/ui/icons/qemu.svg b/ui/icons/qemu.svg +index 24ca23a1e9..f2500de339 100644 +--- a/ui/icons/qemu.svg ++++ b/ui/icons/qemu.svg +@@ -918,7 +918,26 @@ + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> +- <dc:title /> ++ <dc:title>Kew the Angry Emu</dc:title> ++ <dc:creator> ++ <cc:Agent> ++ <dc:title>BenoƮt Canet</dc:title> ++ </cc:Agent> ++ </dc:creator> ++ <dc:rights> ++ <cc:Agent> ++ <dc:title>CC BY 3.0</dc:title> ++ </cc:Agent> ++ </dc:rights> ++ <dc:publisher> ++ <cc:Agent> ++ <dc:title>QEMU Community</dc:title> ++ </cc:Agent> ++ </dc:publisher> ++ <dc:date>2012-02-15</dc:date> ++ <cc:license ++ rdf:resource="http://creativecommons.org/licenses/by/3.0/" /> ++ <dc:source>https://lists.gnu.org/archive/html/qemu-devel/2012-02/msg02865.html</dc:source> + </cc:Work> + </rdf:RDF> + </metadata> diff -Nru qemu-7.2+dfsg/debian/patches/v7.2.22.diff qemu-7.2+dfsg/debian/patches/v7.2.22.diff --- qemu-7.2+dfsg/debian/patches/v7.2.22.diff 1970-01-01 03:00:00.000000000 +0300 +++ qemu-7.2+dfsg/debian/patches/v7.2.22.diff 2025-12-16 08:05:32.000000000 +0300 @@ -0,0 +1,1333 @@ +Subject: v7.2.22 +Date: Fri Dec 5 10:23:51 2025 +0300 +From: Michael Tokarev <[email protected]> +Forwarded: not-needed + +This is a difference between upstream qemu v7.2.21 +and upstream qemu v7.2.22. + + VERSION | 2 +- + block/curl.c | 12 ++--- + contrib/elf2dmp/download.c | 4 +- + crypto/tlscredsx509.c | 10 +---- + docs/system/tls.rst | 13 ++---- + hw/display/xlnx_dp.c | 83 ++++++++++++++++++++++++++++++---- + hw/intc/apic.c | 2 - + hw/misc/npcm7xx_clk.c | 5 ++- + hw/net/e1000e_core.c | 85 ++++++++++++++++++++++++----------- + include/io/channel-websock.h | 3 +- + include/io/net-listener.h | 2 + + io/channel-tls.c | 6 +++ + io/channel-websock.c | 33 +++++++++++--- + io/net-listener.c | 73 ++++++++++++++++++++++++------ + io/trace-events | 6 +++ + linux-user/ioctls.h | 4 +- + linux-user/syscall.c | 25 ++++++----- + net/net.c | 10 +++++ + target/i386/cpu.c | 4 ++ + target/i386/helper.c | 4 ++ + target/i386/tcg/sysemu/excp_helper.c | 3 +- + target/i386/tcg/sysemu/seg_helper.c | 1 + + target/i386/tcg/sysemu/smm_helper.c | 10 ++--- + tests/unit/crypto-tls-x509-helpers.h | 6 +-- + tests/unit/test-crypto-tlscredsx509.c | 36 +++++++-------- + tests/unit/test-crypto-tlssession.c | 14 +++--- + tests/unit/test-io-channel-tls.c | 4 +- + util/async.c | 11 +++-- + 28 files changed, 330 insertions(+), 141 deletions(-) + +diff --git a/VERSION b/VERSION +index 94e695c9f4..28a73c73a7 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-7.2.21 ++7.2.22 +diff --git a/block/curl.c b/block/curl.c +index f9c5a1c182..3b6f18d02c 100644 +--- a/block/curl.c ++++ b/block/curl.c +@@ -478,11 +478,11 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state) + (void *)curl_read_cb) || + curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state) || + curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state) || +- curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1) || +- curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1) || +- curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1) || ++ curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1L) || ++ curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1L) || ++ curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1L) || + curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg) || +- curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1)) { ++ curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1L)) { + goto err; + } + if (s->username) { +@@ -531,7 +531,7 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state) + #endif + + #ifdef DEBUG_VERBOSE +- if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) { ++ if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1L)) { + goto err; + } + #endif +@@ -805,7 +805,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, + } + + s->accept_range = false; +- if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) || ++ if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1L) || + curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) || + curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) { + pstrcpy(state->errmsg, CURL_ERROR_SIZE, +diff --git a/contrib/elf2dmp/download.c b/contrib/elf2dmp/download.c +index bd7650a7a2..e0c1075446 100644 +--- a/contrib/elf2dmp/download.c ++++ b/contrib/elf2dmp/download.c +@@ -28,8 +28,8 @@ int download_url(const char *name, const char *url) + if (curl_easy_setopt(curl, CURLOPT_URL, url) != CURLE_OK + || curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL) != CURLE_OK + || curl_easy_setopt(curl, CURLOPT_WRITEDATA, file) != CURLE_OK +- || curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK +- || curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK ++ || curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK ++ || curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L) != CURLE_OK + || curl_easy_perform(curl) != CURLE_OK) { + unlink(name); + fclose(file); +diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c +index d14313925d..27ed568637 100644 +--- a/crypto/tlscredsx509.c ++++ b/crypto/tlscredsx509.c +@@ -144,7 +144,7 @@ qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds, + if (status < 0) { + if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN : +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT; ++ GNUTLS_KEY_DIGITAL_SIGNATURE; + } else { + error_setg(errp, + "Unable to query certificate %s key usage: %s", +@@ -171,14 +171,6 @@ qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds, + return -1; + } + } +- if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) { +- if (critical) { +- error_setg(errp, +- "Certificate %s usage does not permit key " +- "encipherment", certFile); +- return -1; +- } +- } + } + + return 0; +diff --git a/docs/system/tls.rst b/docs/system/tls.rst +index e284c82801..a4f6781d62 100644 +--- a/docs/system/tls.rst ++++ b/docs/system/tls.rst +@@ -118,7 +118,6 @@ information for each server, and use it to issue server certificates. + ip_address = 2620:0:cafe::87 + ip_address = 2001:24::92 + tls_www_server +- encryption_key + signing_key + EOF + # certtool --generate-privkey > server-hostNNN-key.pem +@@ -134,9 +133,8 @@ the subject alt name extension data. The ``tls_www_server`` keyword is + the key purpose extension to indicate this certificate is intended for + usage in a web server. Although QEMU network services are not in fact + HTTP servers (except for VNC websockets), setting this key purpose is +-still recommended. The ``encryption_key`` and ``signing_key`` keyword is +-the key usage extension to indicate this certificate is intended for +-usage in the data session. ++still recommended. The ``signing_key`` keyword is the key usage extension ++to indicate this certificate is intended for usage in the data session. + + The ``server-hostNNN-key.pem`` and ``server-hostNNN-cert.pem`` files + should now be securely copied to the server for which they were +@@ -171,7 +169,6 @@ certificates. + organization = Name of your organization + cn = hostNNN.foo.example.com + tls_www_client +- encryption_key + signing_key + EOF + # certtool --generate-privkey > client-hostNNN-key.pem +@@ -187,9 +184,8 @@ the ``dns_name`` and ``ip_address`` fields are not included. The + ``tls_www_client`` keyword is the key purpose extension to indicate this + certificate is intended for usage in a web client. Although QEMU network + clients are not in fact HTTP clients, setting this key purpose is still +-recommended. The ``encryption_key`` and ``signing_key`` keyword is the +-key usage extension to indicate this certificate is intended for usage +-in the data session. ++recommended. The ``signing_key`` keyword is the key usage extension to ++indicate this certificate is intended for usage in the data session. + + The ``client-hostNNN-key.pem`` and ``client-hostNNN-cert.pem`` files + should now be securely copied to the client for which they were +@@ -222,7 +218,6 @@ client and server instructions in one. + ip_address = 2001:24::92 + tls_www_server + tls_www_client +- encryption_key + signing_key + EOF + # certtool --generate-privkey > both-hostNNN-key.pem +diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c +index b0828d65aa..2cbbfeef59 100644 +--- a/hw/display/xlnx_dp.c ++++ b/hw/display/xlnx_dp.c +@@ -432,7 +432,18 @@ static void xlnx_dp_aux_clear_rx_fifo(XlnxDPState *s) + + static void xlnx_dp_aux_push_rx_fifo(XlnxDPState *s, uint8_t *buf, size_t len) + { ++ size_t avail = fifo8_num_free(&s->rx_fifo); + DPRINTF("Push %u data in rx_fifo\n", (unsigned)len); ++ if (len > avail) { ++ /* ++ * Data sheet doesn't specify behaviour here: we choose to ignore ++ * the excess data. ++ */ ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: ignoring %zu bytes pushed to full RX_FIFO\n", ++ __func__, len - avail); ++ len = avail; ++ } + fifo8_push_all(&s->rx_fifo, buf, len); + } + +@@ -463,7 +474,18 @@ static void xlnx_dp_aux_clear_tx_fifo(XlnxDPState *s) + + static void xlnx_dp_aux_push_tx_fifo(XlnxDPState *s, uint8_t *buf, size_t len) + { ++ size_t avail = fifo8_num_free(&s->tx_fifo); + DPRINTF("Push %u data in tx_fifo\n", (unsigned)len); ++ if (len > avail) { ++ /* ++ * Data sheet doesn't specify behaviour here: we choose to ignore ++ * the excess data. ++ */ ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: ignoring %zu bytes pushed to full TX_FIFO\n", ++ __func__, len - avail); ++ len = avail; ++ } + fifo8_push_all(&s->tx_fifo, buf, len); + } + +@@ -472,8 +494,10 @@ static uint8_t xlnx_dp_aux_pop_tx_fifo(XlnxDPState *s) + uint8_t ret; + + if (fifo8_is_empty(&s->tx_fifo)) { +- error_report("%s: TX_FIFO underflow", __func__); +- abort(); ++ /* Data sheet doesn't specify behaviour here: we choose to return 0 */ ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: attempt to read empty TX_FIFO\n", ++ __func__); ++ return 0; + } + ret = fifo8_pop(&s->tx_fifo); + DPRINTF("pop 0x%2.2X from tx_fifo.\n", ret); +@@ -638,14 +662,28 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s) + case DP_GRAPHIC_BGR888: + s->g_plane.format = PIXMAN_b8g8r8; + break; ++ case DP_GRAPHIC_RGBA5551: ++ case DP_GRAPHIC_RGBA4444: ++ case DP_GRAPHIC_8BPP: ++ case DP_GRAPHIC_4BPP: ++ case DP_GRAPHIC_2BPP: ++ case DP_GRAPHIC_1BPP: ++ qemu_log_mask(LOG_UNIMP, "%s: unimplemented graphic format %u", ++ __func__, ++ s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); ++ s->g_plane.format = PIXMAN_r8g8b8a8; ++ break; + default: +- error_report("%s: unsupported graphic format %u", __func__, +- s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); +- abort(); ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid graphic format %u", ++ __func__, ++ s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); ++ s->g_plane.format = PIXMAN_r8g8b8a8; ++ break; + } + + switch (s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK) { + case 0: ++ /* This is DP_NL_VID_CB_Y0_CR_Y1 ??? */ + s->v_plane.format = PIXMAN_x8b8g8r8; + break; + case DP_NL_VID_Y0_CB_Y1_CR: +@@ -654,10 +692,39 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s) + case DP_NL_VID_RGBA8880: + s->v_plane.format = PIXMAN_x8b8g8r8; + break; ++ case DP_NL_VID_CR_Y0_CB_Y1: ++ case DP_NL_VID_Y0_CR_Y1_CB: ++ case DP_NL_VID_YV16: ++ case DP_NL_VID_YV24: ++ case DP_NL_VID_YV16CL: ++ case DP_NL_VID_MONO: ++ case DP_NL_VID_YV16CL2: ++ case DP_NL_VID_YUV444: ++ case DP_NL_VID_RGB888: ++ case DP_NL_VID_RGB888_10BPC: ++ case DP_NL_VID_YUV444_10BPC: ++ case DP_NL_VID_YV16CL2_10BPC: ++ case DP_NL_VID_YV16CL_10BPC: ++ case DP_NL_VID_YV16_10BPC: ++ case DP_NL_VID_YV24_10BPC: ++ case DP_NL_VID_Y_ONLY_10BPC: ++ case DP_NL_VID_YV16_420: ++ case DP_NL_VID_YV16CL_420: ++ case DP_NL_VID_YV16CL2_420: ++ case DP_NL_VID_YV16_420_10BPC: ++ case DP_NL_VID_YV16CL_420_10BPC: ++ case DP_NL_VID_YV16CL2_420_10BPC: ++ qemu_log_mask(LOG_UNIMP, "%s: unimplemented video format %u", ++ __func__, ++ s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); ++ s->v_plane.format = PIXMAN_x8b8g8r8; ++ break; + default: +- error_report("%s: unsupported video format %u", __func__, +- s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "%s: invalid video format %u", ++ __func__, ++ s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); ++ s->v_plane.format = PIXMAN_x8b8g8r8; ++ break; + } + + xlnx_dp_recreate_surface(s); +diff --git a/hw/intc/apic.c b/hw/intc/apic.c +index a7c2b301a8..315bef8f43 100644 +--- a/hw/intc/apic.c ++++ b/hw/intc/apic.c +@@ -499,8 +499,6 @@ void apic_sipi(DeviceState *dev) + { + APICCommonState *s = APIC(dev); + +- cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); +- + if (!s->wait_for_sipi) + return; + cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector); +diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c +index bc2b879feb..6d86f54113 100644 +--- a/hw/misc/npcm7xx_clk.c ++++ b/hw/misc/npcm7xx_clk.c +@@ -122,13 +122,14 @@ static void npcm7xx_clk_update_pll(void *opaque) + { + NPCM7xxClockPLLState *s = opaque; + uint32_t con = s->clk->regs[s->reg]; +- uint64_t freq; ++ uint64_t freq, freq_div; + + /* The PLL is grounded if it is not locked yet. */ + if (con & PLLCON_LOKI) { + freq = clock_get_hz(s->clock_in); + freq *= PLLCON_FBDV(con); +- freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con); ++ freq_div = PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con); ++ freq = freq_div ? freq / freq_div : 0; + } else { + freq = 0; + } +diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c +index 5def4cfc1c..14bf3ee948 100644 +--- a/hw/net/e1000e_core.c ++++ b/hw/net/e1000e_core.c +@@ -1411,10 +1411,13 @@ e1000e_write_to_rx_buffers(E1000ECore *core, + dma_addr_t data_len) + { + while (data_len > 0) { +- uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx]; +- uint32_t cur_buf_bytes_left = cur_buf_len - +- bastate->written[bastate->cur_idx]; +- uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left); ++ uint32_t cur_buf_len, cur_buf_bytes_left, bytes_to_write; ++ ++ assert(bastate->cur_idx < MAX_PS_BUFFERS); ++ ++ cur_buf_len = core->rxbuf_sizes[bastate->cur_idx]; ++ cur_buf_bytes_left = cur_buf_len - bastate->written[bastate->cur_idx]; ++ bytes_to_write = MIN(data_len, cur_buf_bytes_left); + + trace_e1000e_rx_desc_buff_write(bastate->cur_idx, + (*ba)[bastate->cur_idx], +@@ -1433,8 +1436,6 @@ e1000e_write_to_rx_buffers(E1000ECore *core, + if (bastate->written[bastate->cur_idx] == cur_buf_len) { + bastate->cur_idx++; + } +- +- assert(bastate->cur_idx < MAX_PS_BUFFERS); + } + } + +@@ -1512,7 +1513,6 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + PCIDevice *d = core->owner; + dma_addr_t base; + uint8_t desc[E1000_MAX_RX_DESC_LEN]; +- size_t desc_size; + size_t desc_offset = 0; + size_t iov_ofs = 0; + +@@ -1527,16 +1527,17 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + rxi = rxr->i; + + do { ++ /* ++ * Loop processing descriptors while we have packet data to ++ * DMA to the guest. desc_offset tracks how much data we have ++ * sent to the guest in total over all descriptors, and goes ++ * from 0 up to total_size (the size of everything to send to ++ * the guest including possible trailing 4 bytes of CRC data). ++ */ + hwaddr ba[MAX_PS_BUFFERS]; + e1000e_ba_state bastate = { { 0 } }; + bool is_last = false; + +- desc_size = total_size - desc_offset; +- +- if (desc_size > core->rx_desc_buf_size) { +- desc_size = core->rx_desc_buf_size; +- } +- + if (e1000e_ring_empty(core, rxi)) { + return; + } +@@ -1550,17 +1551,27 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + e1000e_read_rx_descr(core, desc, &ba); + + if (ba[0]) { ++ /* Total amount of data DMA'd to the guest in this iteration */ ++ size_t desc_size = 0; ++ /* ++ * Total space available in this descriptor (we will update ++ * this as we use it up) ++ */ ++ size_t rx_desc_buf_size = core->rx_desc_buf_size; ++ + if (desc_offset < size) { +- static const uint32_t fcs_pad; + size_t iov_copy; ++ /* Amount of data to copy from the incoming packet */ + size_t copy_size = size - desc_offset; +- if (copy_size > core->rx_desc_buf_size) { +- copy_size = core->rx_desc_buf_size; +- } + + /* For PS mode copy the packet header first */ + if (do_ps) { + if (is_first) { ++ /* ++ * e1000e_do_ps() guarantees that buffer 0 has enough ++ * space for the header; otherwise we will not split ++ * the packet (i.e. do_ps is false). ++ */ + size_t ps_hdr_copied = 0; + do { + iov_copy = MIN(ps_hdr_len - ps_hdr_copied, +@@ -1580,14 +1591,26 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + } while (ps_hdr_copied < ps_hdr_len); + + is_first = false; ++ desc_size += ps_hdr_len; + } else { + /* Leave buffer 0 of each descriptor except first */ + /* empty as per spec 7.1.5.1 */ + e1000e_write_hdr_to_rx_buffers(core, &ba, &bastate, + NULL, 0); + } ++ rx_desc_buf_size -= core->rxbuf_sizes[0]; + } + ++ /* ++ * Clamp the amount of packet data we copy into what will fit ++ * into the remaining buffers in the descriptor. ++ */ ++ if (copy_size > rx_desc_buf_size) { ++ copy_size = rx_desc_buf_size; ++ } ++ desc_size += copy_size; ++ rx_desc_buf_size -= copy_size; ++ + /* Copy packet payload */ + while (copy_size) { + iov_copy = MIN(copy_size, iov->iov_len - iov_ofs); +@@ -1602,20 +1625,30 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + iov_ofs = 0; + } + } ++ } + +- if (desc_offset + desc_size >= total_size) { +- /* Simulate FCS checksum presence in the last descriptor */ +- e1000e_write_to_rx_buffers(core, &ba, &bastate, +- (const char *) &fcs_pad, e1000x_fcs_len(core->mac)); +- } ++ if (rx_desc_buf_size && ++ desc_offset >= size && desc_offset < total_size) { ++ /* ++ * We are in the last 4 bytes corresponding to the FCS checksum. ++ * We only ever write zeroes here (unlike the hardware). ++ */ ++ static const uint32_t fcs_pad; ++ /* Amount of space for the trailing checksum */ ++ size_t fcs_len = MIN(rx_desc_buf_size, ++ total_size - desc_offset); ++ e1000e_write_to_rx_buffers(core, &ba, &bastate, ++ (const char *)&fcs_pad, ++ fcs_len); ++ desc_size += fcs_len; ++ } ++ 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); +diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h +index e180827c57..6700cf8946 100644 +--- a/include/io/channel-websock.h ++++ b/include/io/channel-websock.h +@@ -61,7 +61,8 @@ struct QIOChannelWebsock { + size_t payload_remain; + size_t pong_remain; + QIOChannelWebsockMask mask; +- guint io_tag; ++ guint hs_io_tag; /* tracking handshake task */ ++ guint io_tag; /* tracking watch task */ + Error *io_err; + gboolean io_eof; + uint8_t opcode; +diff --git a/include/io/net-listener.h b/include/io/net-listener.h +index ab9f291ed6..c2165dc166 100644 +--- a/include/io/net-listener.h ++++ b/include/io/net-listener.h +@@ -50,9 +50,11 @@ struct QIONetListener { + QIOChannelSocket **sioc; + GSource **io_source; + size_t nsioc; ++ GMainContext *context; + + bool connected; + ++ QemuMutex lock; /* Protects remaining fields */ + QIONetListenerClientFunc io_func; + gpointer io_data; + GDestroyNotify io_notify; +diff --git a/io/channel-tls.c b/io/channel-tls.c +index a91efb57f3..3b3934db72 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -255,6 +255,11 @@ static void qio_channel_tls_finalize(Object *obj) + { + QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj); + ++ if (ioc->hs_ioc_tag) { ++ trace_qio_channel_tls_handshake_cancel(ioc); ++ g_clear_handle_id(&ioc->hs_ioc_tag, g_source_remove); ++ } ++ + object_unref(OBJECT(ioc->master)); + qcrypto_tls_session_free(ioc->session); + } +@@ -380,6 +385,7 @@ static int qio_channel_tls_close(QIOChannel *ioc, + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + + if (tioc->hs_ioc_tag) { ++ trace_qio_channel_tls_handshake_cancel(ioc); + g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove); + } + +diff --git a/io/channel-websock.c b/io/channel-websock.c +index fb4932ade7..bc0bb80c9a 100644 +--- a/io/channel-websock.c ++++ b/io/channel-websock.c +@@ -545,6 +545,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); + qio_task_set_error(task, err); + qio_task_complete(task); ++ wioc->hs_io_tag = 0; + return FALSE; + } + +@@ -560,6 +561,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, + trace_qio_channel_websock_handshake_complete(ioc); + qio_task_complete(task); + } ++ wioc->hs_io_tag = 0; + return FALSE; + } + trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); +@@ -586,6 +588,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); + qio_task_set_error(task, err); + qio_task_complete(task); ++ wioc->hs_io_tag = 0; + return FALSE; + } + if (ret == 0) { +@@ -597,7 +600,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, + error_propagate(&wioc->io_err, err); + + trace_qio_channel_websock_handshake_reply(ioc); +- qio_channel_add_watch( ++ wioc->hs_io_tag = qio_channel_add_watch( + wioc->master, + G_IO_OUT, + qio_channel_websock_handshake_send, +@@ -906,11 +909,12 @@ void qio_channel_websock_handshake(QIOChannelWebsock *ioc, + + trace_qio_channel_websock_handshake_start(ioc); + trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); +- qio_channel_add_watch(ioc->master, +- G_IO_IN, +- qio_channel_websock_handshake_io, +- task, +- NULL); ++ ioc->hs_io_tag = qio_channel_add_watch( ++ ioc->master, ++ G_IO_IN, ++ qio_channel_websock_handshake_io, ++ task, ++ NULL); + } + + +@@ -921,13 +925,16 @@ static void qio_channel_websock_finalize(Object *obj) + buffer_free(&ioc->encinput); + buffer_free(&ioc->encoutput); + buffer_free(&ioc->rawinput); +- object_unref(OBJECT(ioc->master)); ++ if (ioc->hs_io_tag) { ++ g_source_remove(ioc->hs_io_tag); ++ } + if (ioc->io_tag) { + g_source_remove(ioc->io_tag); + } + if (ioc->io_err) { + error_free(ioc->io_err); + } ++ object_unref(OBJECT(ioc->master)); + } + + +@@ -1217,6 +1224,18 @@ static int qio_channel_websock_close(QIOChannel *ioc, + QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); + + trace_qio_channel_websock_close(ioc); ++ buffer_free(&wioc->encinput); ++ buffer_free(&wioc->encoutput); ++ buffer_free(&wioc->rawinput); ++ if (wioc->hs_io_tag) { ++ g_clear_handle_id(&wioc->hs_io_tag, g_source_remove); ++ } ++ if (wioc->io_tag) { ++ g_clear_handle_id(&wioc->io_tag, g_source_remove); ++ } ++ if (wioc->io_err) { ++ g_clear_pointer(&wioc->io_err, error_free); ++ } + return qio_channel_close(wioc->master, errp); + } + +diff --git a/io/net-listener.c b/io/net-listener.c +index 1c984d69c6..7352b5f8d4 100644 +--- a/io/net-listener.c ++++ b/io/net-listener.c +@@ -23,10 +23,16 @@ + #include "io/dns-resolver.h" + #include "qapi/error.h" + #include "qemu/module.h" ++#include "qemu/lockable.h" ++#include "trace.h" + + QIONetListener *qio_net_listener_new(void) + { +- return QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER)); ++ QIONetListener *listener; ++ ++ listener = QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER)); ++ qemu_mutex_init(&listener->lock); ++ return listener; + } + + void qio_net_listener_set_name(QIONetListener *listener, +@@ -43,6 +49,9 @@ static gboolean qio_net_listener_channel_func(QIOChannel *ioc, + { + QIONetListener *listener = QIO_NET_LISTENER(opaque); + QIOChannelSocket *sioc; ++ QIONetListenerClientFunc io_func; ++ gpointer io_data; ++ GMainContext *context; + + sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), + NULL); +@@ -50,8 +59,15 @@ static gboolean qio_net_listener_channel_func(QIOChannel *ioc, + return TRUE; + } + +- if (listener->io_func) { +- listener->io_func(listener, sioc, listener->io_data); ++ WITH_QEMU_LOCK_GUARD(&listener->lock) { ++ io_func = listener->io_func; ++ io_data = listener->io_data; ++ context = listener->context; ++ } ++ ++ trace_qio_net_listener_callback(listener, io_func, context); ++ if (io_func) { ++ io_func(listener, sioc, io_data); + } + + object_unref(OBJECT(sioc)); +@@ -108,6 +124,9 @@ int qio_net_listener_open_sync(QIONetListener *listener, + void qio_net_listener_add(QIONetListener *listener, + QIOChannelSocket *sioc) + { ++ QIONetListenerClientFunc io_func; ++ GMainContext *context; ++ + if (listener->name) { + char *name = g_strdup_printf("%s-listen", listener->name); + qio_channel_set_name(QIO_CHANNEL(sioc), name); +@@ -125,12 +144,18 @@ void qio_net_listener_add(QIONetListener *listener, + object_ref(OBJECT(sioc)); + listener->connected = true; + +- if (listener->io_func != NULL) { ++ WITH_QEMU_LOCK_GUARD(&listener->lock) { ++ io_func = listener->io_func; ++ context = listener->context; ++ } ++ ++ trace_qio_net_listener_watch(listener, io_func, context, "add"); ++ if (io_func) { + object_ref(OBJECT(listener)); + listener->io_source[listener->nsioc] = qio_channel_add_watch_source( + QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN, + qio_net_listener_channel_func, +- listener, (GDestroyNotify)object_unref, NULL); ++ listener, (GDestroyNotify)object_unref, context); + } + + listener->nsioc++; +@@ -145,12 +170,9 @@ void qio_net_listener_set_client_func_full(QIONetListener *listener, + { + size_t i; + +- if (listener->io_notify) { +- listener->io_notify(listener->io_data); +- } +- listener->io_func = func; +- listener->io_data = data; +- listener->io_notify = notify; ++ QEMU_LOCK_GUARD(&listener->lock); ++ trace_qio_net_listener_unwatch(listener, listener->io_func, ++ listener->context, "set_client_func"); + + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_source[i]) { +@@ -160,6 +182,16 @@ void qio_net_listener_set_client_func_full(QIONetListener *listener, + } + } + ++ if (listener->io_notify) { ++ listener->io_notify(listener->io_data); ++ } ++ listener->io_func = func; ++ listener->io_data = data; ++ listener->io_notify = notify; ++ listener->context = context; ++ ++ trace_qio_net_listener_watch(listener, listener->io_func, ++ listener->context, "set_client_func"); + if (listener->io_func != NULL) { + for (i = 0; i < listener->nsioc; i++) { + object_ref(OBJECT(listener)); +@@ -219,7 +251,15 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) + .loop = loop + }; + size_t i; ++ QIONetListenerClientFunc io_func; ++ GMainContext *context; + ++ WITH_QEMU_LOCK_GUARD(&listener->lock) { ++ io_func = listener->io_func; ++ context = listener->context; ++ } ++ ++ trace_qio_net_listener_unwatch(listener, io_func, context, "wait_client"); + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_source[i]) { + g_source_destroy(listener->io_source[i]); +@@ -249,13 +289,14 @@ QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) + g_main_loop_unref(loop); + g_main_context_unref(ctxt); + +- if (listener->io_func != NULL) { ++ trace_qio_net_listener_watch(listener, io_func, context, "wait_client"); ++ if (io_func != NULL) { + for (i = 0; i < listener->nsioc; i++) { + object_ref(OBJECT(listener)); + listener->io_source[i] = qio_channel_add_watch_source( + QIO_CHANNEL(listener->sioc[i]), G_IO_IN, + qio_net_listener_channel_func, +- listener, (GDestroyNotify)object_unref, NULL); ++ listener, (GDestroyNotify)object_unref, context); + } + } + +@@ -270,6 +311,9 @@ void qio_net_listener_disconnect(QIONetListener *listener) + return; + } + ++ QEMU_LOCK_GUARD(&listener->lock); ++ trace_qio_net_listener_unwatch(listener, listener->io_func, ++ listener->context, "disconnect"); + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_source[i]) { + g_source_destroy(listener->io_source[i]); +@@ -292,10 +336,10 @@ static void qio_net_listener_finalize(Object *obj) + QIONetListener *listener = QIO_NET_LISTENER(obj); + size_t i; + ++ qio_net_listener_disconnect(listener); + if (listener->io_notify) { + listener->io_notify(listener->io_data); + } +- qio_net_listener_disconnect(listener); + + for (i = 0; i < listener->nsioc; i++) { + object_unref(OBJECT(listener->sioc[i])); +@@ -303,6 +347,7 @@ static void qio_net_listener_finalize(Object *obj) + g_free(listener->io_source); + g_free(listener->sioc); + g_free(listener->name); ++ qemu_mutex_destroy(&listener->lock); + } + + static const TypeInfo qio_net_listener_info = { +diff --git a/io/trace-events b/io/trace-events +index 3cc5cf1efd..6f56f8ba2d 100644 +--- a/io/trace-events ++++ b/io/trace-events +@@ -43,6 +43,7 @@ qio_channel_tls_handshake_start(void *ioc) "TLS handshake start ioc=%p" + qio_channel_tls_handshake_pending(void *ioc, int status) "TLS handshake pending ioc=%p status=%d" + qio_channel_tls_handshake_fail(void *ioc) "TLS handshake fail ioc=%p" + qio_channel_tls_handshake_complete(void *ioc) "TLS handshake complete ioc=%p" ++qio_channel_tls_handshake_cancel(void *ioc) "TLS handshake cancel ioc=%p" + qio_channel_tls_credentials_allow(void *ioc) "TLS credentials allow ioc=%p" + qio_channel_tls_credentials_deny(void *ioc) "TLS credentials deny ioc=%p" + +@@ -66,3 +67,8 @@ qio_channel_command_new_pid(void *ioc, int writefd, int readfd, int pid) "Comman + qio_channel_command_new_spawn(void *ioc, const char *binary, int flags) "Command new spawn ioc=%p binary=%s flags=%d" + qio_channel_command_abort(void *ioc, int pid) "Command abort ioc=%p pid=%d" + qio_channel_command_wait(void *ioc, int pid, int ret, int status) "Command abort ioc=%p pid=%d ret=%d status=%d" ++ ++# net-listener.c ++qio_net_listener_watch(void *listener, void *func, void *ctx, const char *extra) "Net listener=%p watch enabled func=%p ctx=%p by %s" ++qio_net_listener_unwatch(void *listener, void *func, void *ctx, const char *extra) "Net listener=%p watch disabled func=%p ctx=%p by %s" ++qio_net_listener_callback(void *listener, void *func, void *ctx) "Net listener=%p callback forwarding to func=%p ctx=%p" +diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h +index 071f7ca253..261cef1e75 100644 +--- a/linux-user/ioctls.h ++++ b/linux-user/ioctls.h +@@ -129,13 +129,13 @@ + IOCTL(FDTWADDLE, 0, TYPE_NULL) + IOCTL(FDEJECT, 0, TYPE_NULL) + +- IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) ++ IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_INT)) + #ifdef FICLONE + IOCTL(FICLONE, IOC_W, TYPE_INT) + IOCTL(FICLONERANGE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_file_clone_range))) + #endif + +- IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) ++ IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_INT)) + #ifdef CONFIG_FIEMAP + IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, + MK_PTR(MK_STRUCT(STRUCT_fiemap))) +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 737065c28c..93b66bd2d7 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3529,7 +3529,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, + abi_ulong target_addr, socklen_t addrlen) + { + void *addr; +- void *host_msg; ++ void *host_msg = NULL; + void *copy_msg = NULL; + abi_long ret; + +@@ -3537,16 +3537,19 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, + return -TARGET_EINVAL; + } + +- host_msg = lock_user(VERIFY_READ, msg, len, 1); +- if (!host_msg) +- return -TARGET_EFAULT; +- if (fd_trans_target_to_host_data(fd)) { +- copy_msg = host_msg; +- host_msg = g_malloc(len); +- memcpy(host_msg, copy_msg, len); +- ret = fd_trans_target_to_host_data(fd)(host_msg, len); +- if (ret < 0) { +- goto fail; ++ if (len != 0) { ++ host_msg = lock_user(VERIFY_READ, msg, len, 1); ++ if (!host_msg) { ++ return -TARGET_EFAULT; ++ } ++ if (fd_trans_target_to_host_data(fd)) { ++ copy_msg = host_msg; ++ host_msg = g_malloc(len); ++ memcpy(host_msg, copy_msg, len); ++ ret = fd_trans_target_to_host_data(fd)(host_msg, len); ++ if (ret < 0) { ++ goto fail; ++ } + } + } + if (target_addr) { +diff --git a/net/net.c b/net/net.c +index c3391168f6..40db3b5dc0 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -728,10 +728,20 @@ 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) + { ++ uint8_t min_pkt[ETH_ZLEN]; ++ size_t min_pktsz = sizeof(min_pkt); ++ + if (!qemu_can_receive_packet(nc)) { + return 0; + } + ++ if (net_peer_needs_padding(nc)) { ++ if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) { ++ buf = min_pkt; ++ size = min_pktsz; ++ } ++ } ++ + return qemu_net_queue_receive(nc->incoming_queue, buf, size); + } + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 489ab9cd41..682d71be88 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5906,7 +5906,11 @@ static void x86_cpu_reset(DeviceState *dev) + + env->idt.limit = 0xffff; + env->gdt.limit = 0xffff; ++#if defined(CONFIG_USER_ONLY) ++ env->ldt.limit = 0; ++#else + env->ldt.limit = 0xffff; ++#endif + env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT); + env->tr.limit = 0xffff; + env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT); +diff --git a/target/i386/helper.c b/target/i386/helper.c +index 290d9d309c..723f50279a 100644 +--- a/target/i386/helper.c ++++ b/target/i386/helper.c +@@ -602,6 +602,10 @@ void do_cpu_init(X86CPU *cpu) + + void do_cpu_sipi(X86CPU *cpu) + { ++ CPUX86State *env = &cpu->env; ++ if (env->hflags & HF_SMM_MASK) { ++ return; ++ } + apic_sipi(cpu->apic_state); + } + #else +diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c +index 9e9e02e1ad..436d65d742 100644 +--- a/target/i386/tcg/sysemu/excp_helper.c ++++ b/target/i386/tcg/sysemu/excp_helper.c +@@ -582,7 +582,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, + if (sext != 0 && sext != -1) { + *err = (TranslateFault){ + .exception_index = EXCP0D_GPF, +- .cr2 = addr, ++ /* non-canonical #GP doesn't change CR2 */ ++ .cr2 = env->cr[2], + }; + return false; + } +diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c +index 2c9bd007ad..8294a668d6 100644 +--- a/target/i386/tcg/sysemu/seg_helper.c ++++ b/target/i386/tcg/sysemu/seg_helper.c +@@ -146,6 +146,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) + apic_poll_irq(cpu->apic_state); + break; + case CPU_INTERRUPT_SIPI: ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_SIPI); + do_cpu_sipi(cpu); + break; + case CPU_INTERRUPT_SMI: +diff --git a/target/i386/tcg/sysemu/smm_helper.c b/target/i386/tcg/sysemu/smm_helper.c +index a45b5651c3..f3d0bbb8c3 100644 +--- a/target/i386/tcg/sysemu/smm_helper.c ++++ b/target/i386/tcg/sysemu/smm_helper.c +@@ -168,7 +168,7 @@ void do_smm_enter(X86CPU *cpu) + env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | + CR0_PG_MASK)); + cpu_x86_update_cr4(env, 0); +- env->dr[7] = 0x00000400; ++ helper_set_dr(env, 7, 0x00000400); + + cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, + 0xffffffff, +@@ -233,8 +233,8 @@ void helper_rsm(CPUX86State *env) + env->eip = x86_ldq_phys(cs, sm_state + 0x7f78); + cpu_load_eflags(env, x86_ldl_phys(cs, sm_state + 0x7f70), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); +- env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7f68); +- env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7f60); ++ helper_set_dr(env, 6, x86_ldl_phys(cs, sm_state + 0x7f68)); ++ helper_set_dr(env, 7, x86_ldl_phys(cs, sm_state + 0x7f60)); + + cpu_x86_update_cr4(env, x86_ldl_phys(cs, sm_state + 0x7f48)); + cpu_x86_update_cr3(env, x86_ldq_phys(cs, sm_state + 0x7f50)); +@@ -268,8 +268,8 @@ void helper_rsm(CPUX86State *env) + env->regs[R_EDX] = x86_ldl_phys(cs, sm_state + 0x7fd8); + env->regs[R_ECX] = x86_ldl_phys(cs, sm_state + 0x7fd4); + env->regs[R_EAX] = x86_ldl_phys(cs, sm_state + 0x7fd0); +- env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7fcc); +- env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7fc8); ++ helper_set_dr(env, 6, x86_ldl_phys(cs, sm_state + 0x7fcc)); ++ helper_set_dr(env, 7, x86_ldl_phys(cs, sm_state + 0x7fc8)); + + env->tr.selector = x86_ldl_phys(cs, sm_state + 0x7fc4) & 0xffff; + env->tr.base = x86_ldl_phys(cs, sm_state + 0x7f64); +diff --git a/tests/unit/crypto-tls-x509-helpers.h b/tests/unit/crypto-tls-x509-helpers.h +index 247e7160eb..d422838ef6 100644 +--- a/tests/unit/crypto-tls-x509-helpers.h ++++ b/tests/unit/crypto-tls-x509-helpers.h +@@ -143,8 +143,7 @@ void test_tls_cleanup(const char *keyfile); + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ +- .keyUsageValue = \ +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ ++ .keyUsageValue = GNUTLS_KEY_DIGITAL_SIGNATURE, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_CLIENT, \ +@@ -163,8 +162,7 @@ void test_tls_cleanup(const char *keyfile); + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ +- .keyUsageValue = \ +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ ++ .keyUsageValue = GNUTLS_KEY_DIGITAL_SIGNATURE, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_SERVER, \ +diff --git a/tests/unit/test-crypto-tlscredsx509.c b/tests/unit/test-crypto-tlscredsx509.c +index 3c25d75ca1..2025d75365 100644 +--- a/tests/unit/test-crypto-tlscredsx509.c ++++ b/tests/unit/test-crypto-tlscredsx509.c +@@ -166,14 +166,14 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +@@ -196,7 +196,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + +@@ -211,7 +211,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + +@@ -226,7 +226,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + +@@ -250,7 +250,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* no-basic */ +@@ -264,7 +264,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* Key usage:dig-sig:critical */ +@@ -278,7 +278,7 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + +@@ -303,7 +303,7 @@ int main(int argc, char **argv) + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT | ++ GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); +@@ -406,7 +406,7 @@ int main(int argc, char **argv) + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT | ++ GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); +@@ -508,21 +508,21 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(servercertexp1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, -1); + TLS_CERT_REQ(clientcertexp1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, -1); + +@@ -546,21 +546,21 @@ int main(int argc, char **argv) + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(servercertnew1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 1, 2); + TLS_CERT_REQ(clientcertnew1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 1, 2); + +@@ -599,14 +599,14 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq, + "UK", "qemu client level 2b", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c +index 615a1344b4..10eaade834 100644 +--- a/tests/unit/test-crypto-tlssession.c ++++ b/tests/unit/test-crypto-tlssession.c +@@ -454,14 +454,14 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +@@ -469,7 +469,7 @@ int main(int argc, char **argv) + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +@@ -488,7 +488,7 @@ int main(int argc, char **argv) + "192.168.122.1", "fec0::dead:beaf", + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* This intentionally doesn't replicate */ +@@ -497,7 +497,7 @@ int main(int argc, char **argv) + "192.168.122.1", "fec0::dead:beaf", + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + +@@ -601,14 +601,14 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq, + "UK", "qemu client level 2b", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +diff --git a/tests/unit/test-io-channel-tls.c b/tests/unit/test-io-channel-tls.c +index cc39247556..ff73477671 100644 +--- a/tests/unit/test-io-channel-tls.c ++++ b/tests/unit/test-io-channel-tls.c +@@ -302,14 +302,14 @@ int main(int argc, char **argv) + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, +- GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, ++ GNUTLS_KEY_DIGITAL_SIGNATURE, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + +diff --git a/util/async.c b/util/async.c +index 0cc3037e0c..01961898be 100644 +--- a/util/async.c ++++ b/util/async.c +@@ -247,8 +247,9 @@ static int64_t aio_compute_bh_timeout(BHList *head, int timeout) + QEMUBH *bh; + + QSLIST_FOREACH_RCU(bh, head, next) { +- if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { +- if (bh->flags & BH_IDLE) { ++ int flags = qatomic_load_acquire(&bh->flags); ++ if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { ++ if (flags & BH_IDLE) { + /* idle bottom halves will be polled at least + * every 10ms */ + timeout = 10000000; +@@ -326,14 +327,16 @@ aio_ctx_check(GSource *source) + aio_notify_accept(ctx); + + QSLIST_FOREACH_RCU(bh, &ctx->bh_list, next) { +- if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { ++ int flags = qatomic_load_acquire(&bh->flags); ++ if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { + return true; + } + } + + QSIMPLEQ_FOREACH(s, &ctx->bh_slice_list, next) { + QSLIST_FOREACH_RCU(bh, &s->bh_list, next) { +- if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { ++ int flags = qatomic_load_acquire(&bh->flags); ++ if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { + return true; + } + }

